Merge "Update HarfBuzz to 3.1.1" am: 5546d81826

Original change: https://android-review.googlesource.com/c/platform/external/harfbuzz_ng/+/1877457

Change-Id: I98631b7462f329d36a86a925b711d41c9ef8a705
diff --git a/.ci/build-freetype.sh b/.ci/build-freetype.sh
deleted file mode 100644
index 0f09f92..0000000
--- a/.ci/build-freetype.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-set -x
-set -o errexit -o nounset
-
-# 22.0.16 is the libtool version of 2.9.0
-if pkg-config --atleast-version 22.0.16 freetype2; then exit; fi
-
-pushd $HOME
-wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2
-tar xf freetype-2.9.tar.bz2
-pushd freetype-2.9
-./autogen.sh
-./configure --prefix=$HOME/.local
-make -j4 install
-popd
-popd
diff --git a/.ci/build-win32.sh b/.ci/build-win32.sh
new file mode 100755
index 0000000..39ed42c
--- /dev/null
+++ b/.ci/build-win32.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+set -e
+
+meson 	--cross-file=.ci/win32-cross-file.txt \
+	--wrap-mode=forcefallback \
+	--buildtype=release \
+	-Dtests=disabled \
+	-Dcairo=enabled \
+	-Dcairo:fontconfig=disabled \
+	-Dglib=enabled \
+	-Dfreetype=enabled \
+	-Dgdi=enabled \
+	-Ddirectwrite=enabled \
+	-Dcairo=enabled \
+	win32build \
+	$@
+
+ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason
+
+rm -rf win32build/harfbuzz-win32
+mkdir win32build/harfbuzz-win32
+cp win32build/util/hb-*.exe win32build/harfbuzz-win32
+find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \;
+i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe}
+rm -f harfbuzz-win32.zip
+(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32)
+echo "harfbuzz-win32.zip is ready."
diff --git a/.ci/build-win64.sh b/.ci/build-win64.sh
new file mode 100644
index 0000000..652410a
--- /dev/null
+++ b/.ci/build-win64.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+set -e
+
+meson 	--cross-file=.ci/win64-cross-file.txt \
+	--wrap-mode=forcefallback \
+	--buildtype=release \
+	-Dtests=disabled \
+	-Dcairo=enabled \
+	-Dcairo:fontconfig=disabled \
+	-Dglib=enabled \
+	-Dfreetype=enabled \
+	-Dgdi=enabled \
+	-Ddirectwrite=enabled \
+	-Dcairo=enabled \
+	win64build \
+	$@
+
+ninja -Cwin64build -j3 # building with all the cores won't work fine with CricleCI for some reason
+
+rm -rf win64build/harfbuzz-win64
+mkdir win64build/harfbuzz-win64
+cp win64build/util/hb-*.exe win64build/harfbuzz-win64
+find win64build -name '*.dll' -exec cp {} win64build/harfbuzz-win64 \;
+x86_64-w64-mingw32-strip win64build/harfbuzz-win64/*.{dll,exe}
+rm -f harfbuzz-win64.zip
+(cd win64build && zip -r ../harfbuzz-win64.zip harfbuzz-win64)
+echo "harfbuzz-win64.zip is ready."
diff --git a/.ci/deploy-docs.sh b/.ci/deploy-docs.sh
index a8a8523..b644dfe 100755
--- a/.ci/deploy-docs.sh
+++ b/.ci/deploy-docs.sh
@@ -3,11 +3,6 @@
 set -x
 set -o errexit -o nounset
 
-if test "x$TRAVIS_SECURE_ENV_VARS" != xtrue; then exit; fi
-
-BRANCH="$TRAVIS_BRANCH"
-if test "x$BRANCH" != xmaster; then exit; fi
-
 TAG="$(git describe --exact-match --match "[0-9]*" HEAD 2>/dev/null || true)"
 
 DOCSDIR=build-docs
@@ -17,10 +12,11 @@
 mkdir $DOCSDIR
 cd $DOCSDIR
 
-cp ../docs/html/* .
-#cp ../docs/CNAME .
+cp ../build/docs/html/* .
+#cp ../build/docs/CNAME .
 
 git init
+git branch -m main
 git config user.name "Travis CI"
 git config user.email "travis@harfbuzz.org"
 set +x
@@ -28,9 +24,12 @@
 git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git"
 set -x
 git fetch upstream
-git reset upstream/master
+git reset upstream/main
 
 touch .
 git add -A .
-git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
-git push -q upstream HEAD:master
+
+if [[ $(git status -s) ]]; then
+  git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
+  git push -q upstream HEAD:main
+fi
diff --git a/.ci/fail.sh b/.ci/fail.sh
deleted file mode 100755
index 4e0069e..0000000
--- a/.ci/fail.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-for f in $(find . -name '*.log' -not -name 'config.log'); do
-    last=$(tail -1 $f)
-    if [[ $last = FAIL* ]]; then
-        echo '====' $f '===='
-        cat $f
-    elif [[ $last = PASS* ]]; then
-        # Do nothing.
-        true
-    else
-	# Travis Linux images has an old automake that does not match the
-	# patterns above, so in case of doubt just print the file.
-        cat $f
-    fi
-done
-
-exit 1
diff --git a/.ci/publish_release_artifact.sh b/.ci/publish_release_artifact.sh
new file mode 100755
index 0000000..272d90b
--- /dev/null
+++ b/.ci/publish_release_artifact.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -z $GITHUB_TOKEN ]]; then
+	echo "No GITHUB_TOKEN secret found, artifact publishing skipped"
+	exit
+fi
+
+if ! hash ghr 2> /dev/null; then
+	_GHR_VER=v0.14.0
+	_GHR=ghr_${_GHR_VER}_linux_amd64
+	mkdir -p $HOME/.local/bin
+	curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz |
+		tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr
+fi
+
+ghr -replace \
+	-u $CIRCLE_PROJECT_USERNAME \
+	-r $CIRCLE_PROJECT_REPONAME \
+	$CIRCLE_TAG \
+	$1
diff --git a/.ci/run-coveralls.sh b/.ci/run-coveralls.sh
deleted file mode 100755
index 8d1ceb5..0000000
--- a/.ci/run-coveralls.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-set -x
-set -o errexit -o nounset
-
-if test x"$TRAVIS_REPO_SLUG" != x"harfbuzz/harfbuzz"; then exit; fi
-
-pip install --user nose
-pip install --user cpp-coveralls
-export PATH=$HOME/.local/bin:$PATH
-
-rm -f src/.libs/NONE.gcov
-touch src/NONE
-coveralls -e docs
diff --git a/.ci/trigger-coverity.sh b/.ci/trigger-coverity.sh
deleted file mode 100644
index 19852bd..0000000
--- a/.ci/trigger-coverity.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-set -x
-set -o errexit -o nounset
-
-if test x"$TRAVIS_EVENT_TYPE" != x"cron"; then exit; fi
-if test x"$TRAVIS_BRANCH" != x"master"; then exit; fi
-
-git fetch --unshallow
-git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.git"
-git push -q upstream master:coverity_scan
diff --git a/.ci/win32-cross-file.txt b/.ci/win32-cross-file.txt
new file mode 100644
index 0000000..982a909
--- /dev/null
+++ b/.ci/win32-cross-file.txt
@@ -0,0 +1,20 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
+
+[properties]
+c_args = []
+c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
+cpp_args = []
+cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread']
+
+[binaries]
+c = 'i686-w64-mingw32-gcc'
+cpp = 'i686-w64-mingw32-g++'
+ar = 'i686-w64-mingw32-ar'
+ld = 'i686-w64-mingw32-ld'
+objcopy = 'i686-w64-mingw32-objcopy'
+strip = 'i686-w64-mingw32-strip'
+windres = 'i686-w64-mingw32-windres'
diff --git a/.ci/win64-cross-file.txt b/.ci/win64-cross-file.txt
new file mode 100644
index 0000000..e906e08
--- /dev/null
+++ b/.ci/win64-cross-file.txt
@@ -0,0 +1,20 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[properties]
+c_args = []
+c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
+cpp_args = []
+cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread']
+
+[binaries]
+c = 'x86_64-w64-mingw32-gcc'
+cpp = 'x86_64-w64-mingw32-g++'
+ar = 'x86_64-w64-mingw32-ar'
+ld = 'x86_64-w64-mingw32-ld'
+objcopy = 'x86_64-w64-mingw32-objcopy'
+strip = 'x86_64-w64-mingw32-strip'
+windres = 'x86_64-w64-mingw32-windres'
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 2975ea8..84f59bb 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,345 +1,201 @@
-version: 2
+version: 2.1
+
+executors:
+  win32-executor:
+    docker:
+      - image: cimg/base:edge-20.04
+  win64-executor:
+    docker:
+      - image: cimg/base:edge-20.04
+  autotools-executor:
+    docker:
+      - image: cimg/base:edge-20.04
 
 jobs:
 
-  macos-10.12.6-aat-fonts:
+  macos-aat-fonts:
     macos:
-      xcode: "9.0.1"
+      xcode: "12.5.1"
     steps:
       - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
-      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
-      - run: make -j4
-      - run: make check || .ci/fail.sh
+      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection gtk-doc ninja
+      - run: pip3 install meson --upgrade
+      - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled
+      - run: meson compile -Cbuild
+      - run: meson test -Cbuild --print-errorlogs
+      - store_artifacts:
+          path: build/meson-logs/
 
-  macos-10.13.6-aat-fonts:
-    macos:
-      xcode: "10.1.0"
-    steps:
-      - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
-      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
-      - run: make -j4
-      - run: make check || .ci/fail.sh
-
-  macos-10.14.4-aat-fonts:
-    macos:
-      xcode: "11.0.0"
-    steps:
-      - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 cmake
-      - run: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2
-      - run: make -j4
-      - run: make check || .ci/fail.sh
-      - run: cmake -Bbuild -H. -DHB_HAVE_CORETEXT=1 -DHB_BUILD_TESTS=0 && cmake --build build
-
+  # will be dropped with autotools removal
   distcheck:
-    docker:
-      - image: ubuntu:19.04
+    executor: autotools-executor
     steps:
       - checkout
-      - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
+      - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip
+      - run: pip3 install fonttools meson --upgrade
       - run: ./autogen.sh
-      - run: make -j32
-      - run: make distcheck || .ci/fail.sh
-      - run: rm -rf harfbuzz-*
-      - run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
+      - run: make -j2 distcheck
+      - run: rm harfbuzz-* && make distdir
+      - run: cd harfbuzz-* && meson build && ninja -j2 -Cbuild test
+      - run: make dist
+      - persist_to_workspace:
+          root: .
+          paths: harfbuzz-*.tar.xz
 
-  alpine-O3-Os-NOMMAP:
+  publish-dist:
+    executor: autotools-executor
+    steps:
+      - checkout
+      - attach_workspace:
+          at: .
+      - run: |
+          .ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz
+
+  fedora-valgrind:
+    docker:
+      - image: fedora:33
+    steps:
+      - checkout
+      - run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true
+      - run: meson build --buildtype=debugoptimized
+      - run: ninja -Cbuild -j9
+      # TOOD: increase timeouts and remove --no-suite=slow
+      - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs
+
+  alpine:
     docker:
       - image: alpine
     steps:
       - checkout
-      - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev python
-      # C??FLAGS are not needed for a regular build
-      - run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
-      - run: make -j32
-      - run: make check || .ci/fail.sh
-      - run: make clean
-      - run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
-      - run: make -j32
-      - run: make check || .ci/fail.sh
+      - run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
+      - run: pip3 install meson==0.52.0
+      - run: meson build --buildtype=minsize
+      - run: ninja -Cbuild -j9
+      - run: meson test -Cbuild --print-errorlogs
 
-  archlinux-py3-all:
+  archlinux:
     docker:
       - image: archlinux/base
     steps:
       - checkout
-      - run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip make which base-devel
+      - run: pacman --noconfirm -Syu freetype2 meson git clang cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip base-devel gtk-doc
       - run: pip install flake8 fonttools
       - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
-      # C??FLAGS are not needed for a regular build
-      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
-      - run: make -j32 CPPFLAGS="-Werror"
-      - run: make check CPPFLAGS="-Werror" || .ci/fail.sh
+      - run: meson build -Dgraphite=enabled -Dauto_features=enabled -Dexperimental_api=true
+      - run: meson compile -Cbuild -j9
+      - run: meson test -Cbuild --print-errorlogs
+      - run: meson dist -Cbuild
+      - run: clang -c src/harfbuzz.cc -DHB_NO_MT
+      - run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT
 
-  ## Doesn't play well with CircleCI apparently
-  #void-notest:
-  #  docker:
-  #    - image: voidlinux/voidlinux
-  #  steps:
-  #    - checkout
-  #    - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make
-  #    - run: ./autogen.sh && make -j32 && make check
-
-  clang-O3-O0-and-nobuildsystem:
+  sanitizers:
     docker:
-      - image: ubuntu:18.10
+      - image: ubuntu:20.04
     steps:
       - checkout
       - run: apt update || true
-      - run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd ..
-      - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
-      - run: make -j32
-      - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
-      - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
-      - run: make -j32
-      - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
-      - run: make clean
-      - run: make -Csrc CPPFLAGS="-DHB_TINY -DHB_NO_OT_FONT" libharfbuzz-subset.la && make clean
-      - run: clang -c src/hb-*.cc -DHB_NO_MT
+      - run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils meson pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+      # asan+ubsan
+      - run: rm -rf build && meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
+      - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      # tsan
+      - run: rm -rf build && meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
+      - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
+      - run: rm -rf build && meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
+      - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
+      - run: clang -c src/harfbuzz.cc src/hb-subset*.cc -DHB_NO_MT -Werror -std=c++2a
 
-  gcc-valgrind:
-    docker:
-      - image: ubuntu:18.10
+  crossbuild-win32:
+    executor: win32-executor
     steps:
       - checkout
-      - run: apt update || true
-      - run: apt install -y gcc binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip valgrind
-      - run: pip install fonttools
-      - run: ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
-      - run: make -j32
-      # run-shape-fuzzer-tests.py automatically runs valgrind if see available
-      # but test/api runs it by request, we probably should normalize the approaches
-      - run: HB_TEST_SHAPE_FUZZER_TIMEOUT=3 HB_TEST_SUBSET_FUZZER_TIMEOUT=30 RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
-      # informational for now
-      - run: make -Ctest/api check-symbols || true
-
-  clang-everything:
-    docker:
-      - image: ubuntu:18.10
-    steps:
-      - checkout
-      - run: apt update || true; apt install -y wget gnupg
-      - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
-      - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      - run: apt update || true
-      - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command -DHB_WITH_WIN1256" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template -DHB_WITH_WIN1256" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
-      - run: make -j32 CPPFLAGS="-Werror"
-      - run: make check CPPFLAGS="-Werror" || .ci/fail.sh
-
-  clang-asan:
-    docker:
-      - image: ubuntu:18.10
-    steps:
-      - checkout
-      - run: apt update || true; apt install -y wget gnupg
-      - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
-      - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      - run: apt update || true
-      - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
-      - run: make -j32
-      - run: make check || .ci/fail.sh | asan_symbolize | c++filt
-
-  clang-msan:
-    docker:
-      - image: ubuntu:18.10
-    steps:
-      - checkout
-      - run: apt update || true; apt install -y wget gnupg
-      - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
-      - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      - run: apt update || true
-      - run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 10
-      - run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
-      - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
-      - run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu
-      - run: make -j32 && MSAN_OPTIONS=exitcode=42 HB_TEST_SUBSET_FUZZER_TIMEOUT=12 make check || .ci/fail.sh | asan_symbolize | c++filt
-
-  clang-tsan:
-    docker:
-      - image: ubuntu:18.10
-    steps:
-      - checkout
-      - run: apt update || true; apt install -y wget gnupg
-      - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
-      - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      - run: apt update || true
-      - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
-      - run: make -j32
-      - run: HB_TEST_SUBSET_FUZZER_TIMEOUT=40 make check || .ci/fail.sh | asan_symbolize | c++filt
-
-  clang-ubsan:
-    docker:
-      - image: ubuntu:18.10
-    steps:
-      - checkout
-      - run: apt update || true; apt install -y wget gnupg
-      - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
-      - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      - run: apt update || true
-      - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: CPPFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined" LDFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
-      - run: make -j32
-      - run: UBSAN_OPTIONS=print_stacktrace=1 make check || .ci/fail.sh | asan_symbolize | c++filt
-
-  fedora-O0-debug-outoftreebuild-mingw:
-    docker:
-      - image: fedora
-    steps:
-      - checkout
-      - run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
-      - run: NOCONFIGURE=1 ./autogen.sh
-      - run: mkdir build && cd build && CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ../configure --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && make -j32 && (make check || ../.ci/fail.sh)
-      - run: pip install pefile
-      - run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip
-      - run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip
+      - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-i686 zip
+      - run: pip3 install meson==0.56.0 --upgrade
+      - run: .ci/build-win32.sh
       - store_artifacts:
-          path: winbuild32/harfbuzz-win32.zip
-          destination: harfbuzz-win32.zip
+          path: harfbuzz-win32.zip
+      - persist_to_workspace:
+          root: .
+          paths: harfbuzz-win32.zip
+
+  publish-win32:
+    executor: win32-executor
+    steps:
+      - checkout
+      - attach_workspace:
+          at: .
+      - run: |
+          mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
+          .ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
+
+  crossbuild-win64:
+    executor: win64-executor
+    steps:
+      - checkout
+      - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-x86-64 zip
+      - run: pip3 install meson==0.56.0 --upgrade
+      - run: bash .ci/build-win64.sh
       - store_artifacts:
-          path: winbuild64/harfbuzz-win64.zip
-          destination: harfbuzz-win64.zip
+          path: harfbuzz-win64.zip
+      - persist_to_workspace:
+          root: .
+          paths: harfbuzz-win64.zip
 
-  cmake-gcc:
-    docker:
-      - image: ubuntu:19.04
+  publish-win64:
+    executor: win64-executor
     steps:
       - checkout
-      - run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
-      - run: pip install fonttools
-      - run: cmake -DHB_CHECK=ON -Bbuild -H. -GNinja
-      - run: ninja -Cbuild
-      - run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
-      - run: ninja -Cbuild install
+      - attach_workspace:
+          at: .
+      - run: |
+          mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
+          .ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
 
-  #cmake-oracledeveloperstudio:
-  #  docker:
-  #    - image: fedora
-  #  steps:
-  #    - checkout
-  #    - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
-  #    - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
-  #    - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
-  #    - run: make -Cbuild -j32
-  #    - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
-  #    - run: make -Cbuild install
-
-  crosscompile-notest-djgpp:
-    docker:
-      # https://gist.github.com/ebraminio/8551fc74f27951e668102baa2f6b1175
-      - image: quay.io/ebraminio/djgpp
-    steps:
-      - checkout
-      - run: apt update && apt install -y ragel pkg-config libtool autoconf
-      - run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
-      - run: make -j32
-
-  crosscompile-notest-psvita:
-    docker:
-      - image: dockcross/base
-    steps:
-      - checkout
-      - run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
-      - run: echo '#!/bin/true' > /usr/bin/ragel && chmod +x /usr/bin/ragel
-      - run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
-      - run: make -j32
-
-  crosscompile-cmake-notest-android-arm:
-    docker:
-      - image: dockcross/android-arm
-    steps:
-      - checkout
-      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
-      - run: ninja -Cbuild
-
-  crosscompile-cmake-notest-browser-asmjs-hb_tiny:
-    docker:
-      - image: dockcross/browser-asmjs
-    steps:
-      - checkout
-      - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF
-      - run: ninja -Cbuild
-
-  crosscompile-cmake-notest-linux-arm64:
-    docker:
-      - image: dockcross/linux-arm64
-    steps:
-      - checkout
-      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
-      - run: ninja -Cbuild
-
-  crosscompile-cmake-notest-linux-mips:
-    docker:
-      - image: dockcross/linux-mips
-    steps:
-      - checkout
-      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
-      - run: ninja -Cbuild
-
-  #crosscompile-cmake-notest-windows-x64:
-  #  docker:
-  #    - image: dockcross/windows-x64
-  #  steps:
-  #    - checkout
-  #    - run: cmake -Bbuild -H. -GNinja
-  #    - run: ninja -Cbuild
 
 workflows:
   version: 2
+
   build:
     jobs:
-      # macOS
-      - macos-10.12.6-aat-fonts
-      - macos-10.13.6-aat-fonts
-      - macos-10.14.4-aat-fonts
-
-      # both autotools and cmake
-      - distcheck
-
-      # autotools based builds
-      - alpine-O3-Os-NOMMAP
-      - archlinux-py3-all
-      #- void-notest
-      - gcc-valgrind
-      - clang-O3-O0-and-nobuildsystem
-      - clang-everything
-      - clang-asan
-      - clang-msan
-      - clang-tsan
-      - clang-ubsan
-      - fedora-O0-debug-outoftreebuild-mingw
-
-      # cmake based builds
-      - cmake-gcc
-      #- cmake-oracledeveloperstudio
-
-      # crosscompiles
-      # they can't be test thus are without tests
-      ## autotools
-      - crosscompile-notest-djgpp
-      - crosscompile-notest-psvita
-
-      ## cmake
-      - crosscompile-cmake-notest-android-arm
-      - crosscompile-cmake-notest-browser-asmjs-hb_tiny
-      - crosscompile-cmake-notest-linux-arm64
-      - crosscompile-cmake-notest-linux-mips
-      #- crosscompile-cmake-notest-windows-x64
+      - macos-aat-fonts
+      - distcheck:
+          filters: # must have filter or won't work as a dependency
+            tags:
+              only: /.*/
+      - publish-dist:
+          requires:
+            - distcheck
+          filters:
+            tags:
+              only: /^\d+\.\d+\.\d+$/
+            branches:
+              ignore: /.*/
+      - fedora-valgrind
+      - alpine
+     #- archlinux
+      - sanitizers
+      - crossbuild-win32:
+          filters: # must have filter or won't work as a dependency
+            tags:
+              only: /.*/
+      - crossbuild-win64:
+          filters: # must have filter or won't work as a dependency
+            tags:
+              only: /.*/
+      - publish-win32:
+          requires:
+            - crossbuild-win32
+          filters:
+            tags:
+              only: /^\d+\.\d+\.\d+$/
+            branches:
+              ignore: /.*/
+      - publish-win64:
+          requires:
+            - crossbuild-win64
+          filters:
+            tags:
+              only: /^\d+\.\d+\.\d+$/
+            branches:
+              ignore: /.*/
diff --git a/.codecov.yml b/.codecov.yml
index e9b8ab4..abd04ca 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -5,3 +5,4 @@
     project:
       default:
         threshold: 1%
+    patch: off
diff --git a/.editorconfig b/.editorconfig
index 4291676..cac917b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,5 +17,7 @@
 [{Makefile.am,Makefile.sources,configure.ac}]
 tab_width = 8
 
-[{CMakeLists.txt,*.cmake}]
+[{meson.build,meson_options.txt}]
+tab_width = 8
+indent_style = space
 indent_size = 2
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
new file mode 100644
index 0000000..a9d4eb0
--- /dev/null
+++ b/.github/workflows/cifuzz.yml
@@ -0,0 +1,24 @@
+name: CIFuzz
+on: [pull_request]
+jobs:
+  Fuzzing:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'harfbuzz'
+        dry-run: false
+    - name: Run Fuzzers
+      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'harfbuzz'
+        fuzz-seconds: 600
+        dry-run: false
+    - name: Upload Crash
+      uses: actions/upload-artifact@v1
+      if: failure() && steps.build.outcome == 'success'
+      with:
+        name: artifacts
+        path: ./out/artifacts
diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml
new file mode 100644
index 0000000..6fcb4e5
--- /dev/null
+++ b/.github/workflows/coverity-scan.yml
@@ -0,0 +1,39 @@
+name: coverity-scan
+
+on:
+  schedule:
+    - cron: '0 10 * * *' # Daily at 10:00 UTC
+
+jobs:
+  latest:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+
+      - run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev
+
+      - name: Download Coverity
+        run: |
+          wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=behdad/harfbuzz" -O cov-analysis-linux64.tar.gz
+          mkdir cov-analysis-linux64
+          tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
+        env:
+          TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
+
+      # ideally we should've used meson and ninja here but it complains about coverage or something
+      - run: cov-analysis-linux64/bin/cov-build --dir cov-int clang src/hb-*.cc -DHAVE_FREETYPE -DHAVE_GRAPHITE2 -DHAVE_GLIB -DHAVE_ICU `pkg-config --cflags freetype2 graphite2 glib-2.0 icu-uc` -DHAVE_ROUNDF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H -DHAVE_GETPAGESIZE -DHB_EXPERIMENTAL_API -c
+
+      - run: tar czvf harfbuzz.tgz cov-int
+
+      - name: submit to coverity
+        run: |
+          curl \
+            --form project=behdad/harfbuzz \
+            --form token=$TOKEN \
+            --form email=harfbuzz-bots-chatter@googlegroups.com \
+            --form file=@harfbuzz.tgz \
+            --form version=trunk \
+            --form description="`git rev-parse --short HEAD`" \
+            https://scan.coverity.com/builds?project=behdad-harfbuzz
+        env:
+          TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
new file mode 100644
index 0000000..c6d6e6d
--- /dev/null
+++ b/.github/workflows/linux-ci.yml
@@ -0,0 +1,53 @@
+name: linux-ci
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  build:
+    runs-on: ubuntu-18.04
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: install dependencies
+      run: sudo apt-get install pkg-config gcc gcovr gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev
+    - run: sudo pip3 install fonttools meson==0.56.0
+    - name: run
+      run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Dragel_subproject=true -Doptimization=2
+    - name: ci
+      run: meson test --print-errorlogs -Cbuild
+
+    - name: generate documentations
+      run: ninja -Cbuild harfbuzz-doc
+    - name: deploy documentations
+      if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+      run: .ci/deploy-docs.sh
+      env:
+        GH_TOKEN: ${{ secrets.GH_TOKEN }}
+        REVISION: ${{ github.sha }}
+
+    # waiting for https://github.com/rhysd/github-action-benchmark/issues/36 to happen
+    # - name: benchmark
+    #   run: build/perf/perf --benchmark_format=json > perf/result.json
+    # - name: store benchmark result
+    #   uses: rhysd/github-action-benchmark@b2ee598
+    #   if: github.event_name != 'pull_request'
+    #   with:
+    #     name: C++ Benchmark
+    #     tool: 'googlecpp'
+    #     output-file-path: perf/result.json
+    #     gh-pages-branch: gh-pages
+    #     github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
+    #     auto-push: true
+    #     alert-threshold: '150%'
+    #     comment-on-alert: true
+    #     fail-on-alert: true
+
+    - name: cov
+      run: ninja -Cbuild coverage-xml
+    - uses: codecov/codecov-action@v1
+      with:
+        file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml
new file mode 100644
index 0000000..84e54df
--- /dev/null
+++ b/.github/workflows/macos-ci.yml
@@ -0,0 +1,27 @@
+name: macos-ci
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  build:
+    runs-on: macos-10.15
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: install dependencies
+      run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config freetype glib cairo icu4c graphite2 gobject-introspection gtk-doc ninja gcovr
+    - run: pip3 install meson fonttools --upgrade
+    - name: run
+      run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Db_coverage=true -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2
+    - name: ci
+      run: meson test --print-errorlogs -Cbuild
+
+    - name: cov
+      run: ninja -Cbuild coverage-xml
+    - uses: codecov/codecov-action@v1
+      with:
+        file: build/meson-logs/coverage.xml
diff --git a/.github/workflows/msvc-ci.yml b/.github/workflows/msvc-ci.yml
new file mode 100644
index 0000000..7c9f5bc
--- /dev/null
+++ b/.github/workflows/msvc-ci.yml
@@ -0,0 +1,52 @@
+name: msvc
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  msvc:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        os: [windows-2016, windows-latest]
+        include:
+          - name: msvc-2017-x86
+            os: windows-2016
+            ARCH: x86
+          - name: msvc-2019-amd64
+            os: windows-latest
+            ARCH: amd64
+    name: ${{ matrix.name }}
+
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v1
+        with:
+          python-version: '3.x'
+      - uses: ilammy/msvc-dev-cmd@v1
+        with:
+          arch : ${{ matrix.ARCH }}
+      - name: Install Dependencies
+        run: |
+          pip install --upgrade meson ninja fonttools
+      - name: Build
+        run: |
+          # This dir contains a pkg-config which meson will happily use and later fail, so remove it
+          $env:path = ($env:path.Split(';') | Where-Object { $_ -ne 'C:\Strawberry\perl\bin' }) -join ';'
+
+          meson setup build `
+            --wrap-mode=default `
+            --buildtype=release `
+            -Dglib=enabled `
+            -Dfreetype=enabled `
+            -Dgdi=enabled `
+            -Ddirectwrite=enabled
+
+          meson compile -C build
+      - name: Test
+        run: |
+          meson test --print-errorlogs --suite=harfbuzz -C build
diff --git a/.github/workflows/msys2-ci.yml b/.github/workflows/msys2-ci.yml
new file mode 100644
index 0000000..b8b2fc3
--- /dev/null
+++ b/.github/workflows/msys2-ci.yml
@@ -0,0 +1,65 @@
+name: msys2
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  msys2:
+    runs-on: windows-latest
+
+    strategy:
+      matrix:
+        include:
+          - MSYSTEM: MINGW32
+            MSYS2_ARCH: i686
+          - MSYSTEM: MINGW64
+            MSYS2_ARCH: x86_64
+    name: ${{ matrix.MSYSTEM }}
+
+    defaults:
+      run:
+        shell: msys2 {0}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: msys2/setup-msys2@v2
+        with:
+          msystem: ${{ matrix.MSYSTEM }}
+          update: true
+          install: >-
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-python
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
+            mingw-w64-${{ matrix.MSYS2_ARCH }}-ragel
+      - name: Install Python Dependencies
+        run: |
+          pip install --upgrade fonttools
+      - name: Build
+        run: |
+          meson build \
+            --wrap-mode=nodownload \
+            --auto-features=enabled \
+            -Ddirectwrite=enabled \
+            -Dgdi=enabled \
+            -Dgraphite=enabled \
+            -Dchafa=disabled
+          ninja -C build
+      - name: Test
+        run: |
+          meson test \
+            --print-errorlogs \
+            --suite=harfbuzz \
+            -C build
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 703fac2..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-# Build Configuration for Travis
-dist: trusty
-
-language: cpp
-
-env:
-  global:
-    - CPPFLAGS=""
-    - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
-    - NOCONFIGURE=1
-    # COVERITY_SCAN_TOKEN
-    - secure: "k6l/18dpsoPAf0E5RQWCr+rgjbHns0H3k0WzSYovCoVg0B7RVlV8x8OjyEOBzEvXI4aaHRdH6MHCPDFnX4fa7ysImlT6LxxIG8YhDdLkJWyS0hHbcJiGxko9AhAGzOZcDl8fZi13d697wagMqqXpjN5v2T/AQm8t4X9z2otJosY="
-
-matrix:
-  include:
-    - os: linux
-      compiler: gcc
-      script:
-        # Remove the following three lines when Travis updates its distro
-        - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
-        - export LD_LIBRARY_PATH="$HOME/.local/lib"
-        - bash .ci/build-freetype.sh
-
-        - ./autogen.sh
-        - ./configure $CONFIGURE_OPTS --enable-gtk-doc --enable-code-coverage
-        - make
-        - make check || .ci/fail.sh
-        - rm -rf freetype-2.9
-      after_success:
-        - bash .ci/run-coveralls.sh # coveralls.io code coverage
-        - bash <(curl -s https://codecov.io/bash) # codecov.io code coverage
-        - bash .ci/deploy-docs.sh
-        - bash .ci/trigger-coverity.sh
-
-    - os: linux
-      compiler: clang
-      script:
-        # Remove the following three lines when Travis updates its distro
-        - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
-        - export LD_LIBRARY_PATH="$HOME/.local/lib"
-        - bash .ci/build-freetype.sh
-
-        - ./autogen.sh
-        - ./configure $CONFIGURE_OPTS
-        - make
-        - make check || .ci/fail.sh
-
-notifications:
-  irc: "irc.freenode.org#harfbuzz"
-  email: harfbuzz-bots-chatter@googlegroups.com
-
-cache:
-  directories:
-    - /home/travis/.local
-
-addons:
-  apt:
-    packages:
-      - pkg-config # for autogen.sh
-      - ragel
-      - lcov
-      - gtk-doc-tools
-      - libfreetype6-dev # for font function
-      - libglib2.0-dev # for font functions / tests / utils
-      - libcairo2-dev # for utils
-      - libicu-dev # for extra unicode functions
-      - libgraphite2-dev # for extra shapers
-      #- libgirepository1.0-dev # for gobject-introspection
-
-  coverity_scan:
-    project:
-      name: behdad/harfbuzz
-      version: 1.0
-      description: HarfBuzz OpenType text shaping engine
-    notification_email: harfbuzz-bots-chatter@googlegroups.com
-    build_command_prepend: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
-    build_command: make
-    branch_pattern: coverity_scan
diff --git a/Android.bp b/Android.bp
index d69ed2b..57ae0b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -131,8 +131,8 @@
         "src/hb-ot-shape-complex-indic.cc",
         "src/hb-ot-shape-complex-khmer.cc",
         "src/hb-ot-shape-complex-myanmar.cc",
+        "src/hb-ot-shape-complex-syllabic.cc",
         "src/hb-ot-shape-complex-thai.cc",
-        "src/hb-ot-shape-complex-use-table.cc",
         "src/hb-ot-shape-complex-use.cc",
         "src/hb-ot-shape-complex-vowel-constraints.cc",
         "src/hb-ot-shape-fallback.cc",
@@ -181,8 +181,8 @@
 
     export_include_dirs: ["src"],
     cflags: [
+        "-DHAVE_PTHREAD",
         "-DHB_NO_PRAGMA_GCC_DIAGNOSTIC",
-        "-DHAVE_INTEL_ATOMIC_PRIMITIVES",
         "-DHAVE_OT",
         "-DHAVE_ICU",
         "-DHAVE_ICU_BUILTIN",
diff --git a/BUILD.md b/BUILD.md
index 4c1c306..f64f868 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,50 +1,27 @@
 On Linux, install the development packages for FreeType,
 Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
 
-    sudo apt-get install 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 yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
+    sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-dev
 
-on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg),
-provided by Microsoft, for building HarfBuzz and other open-source libraries
-but if you need to build harfbuzz from source, put ragel binary on your
-PATH and follow appveyor CI's cmake
-[build steps](https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml).
+and on ArchLinux and Manjaro:
 
-on macOS, using MacPorts:
+    sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
 
-    sudo port install freetype glib2 cairo
+then use meson to build the project like `meson build && meson test -Cbuild`.
 
-or using Homebrew:
+On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` then use
+meson like above.
 
-    brew install freetype glib cairo
+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.
 
-If you are using a tarball, you can now proceed to running configure and make
-as with any other standard package. That should leave you with a shared
-library in `src/`, and a few utility programs including `hb-view` and `hb-shape`
-under `util/`.
+Our CI configurations is also a good source of learning how to build HarfBuzz.
 
-If you are bootstrapping from git, you need a few more tools before you can
-run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`.
-
-Again, on Ubuntu / Debian:
-
-    sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools
-
-and on Fedora, RHEL, CentOS:
-
-    sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc
-
-on the Mac, using MacPorts:
-
-    sudo port install autoconf automake libtool pkgconfig ragel gtk-doc
-
-or using Homebrew:
-
-    brew install autoconf automake libtool pkgconfig ragel gtk-doc
-
-To build the Python bindings, you also need:
-
-    brew install pygobject3
+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.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a8fd8b..295cff8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
-cmake_minimum_required(VERSION 2.8.0)
+cmake_minimum_required(VERSION 3.1)
 project(harfbuzz)
 
-enable_testing()
+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.")
 
 ## Limit framework build to Xcode generator
 if (BUILD_FRAMEWORK)
@@ -53,7 +53,6 @@
 endif ()
 
 option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
-option(HB_BUILD_TESTS "Build harfbuzz tests" ON)
 
 option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
 if (HB_HAVE_GOBJECT)
@@ -66,25 +65,6 @@
   set (HB_HAVE_GLIB ON)
 endif ()
 
-option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and enable all options)")
-if (HB_CHECK)
-  set (BUILD_SHARED_LIBS ON)
-  set (HB_BUILD_UTILS ON)
-  set (HB_HAVE_ICU)
-  set (HB_HAVE_GLIB ON)
-  #set (HB_HAVE_GOBJECT ON)
-  #set (HB_HAVE_INTROSPECTION ON)
-  set (HB_HAVE_FREETYPE ON)
-  set (HB_HAVE_GRAPHITE2 ON)
-  if (WIN32)
-    set (HB_HAVE_UNISCRIBE ON)
-    set (HB_HAVE_GDI ON)
-    set (HB_HAVE_DIRECTWRITE ON)
-  elseif (APPLE)
-    set (HB_HAVE_CORETEXT ON)
-  endif ()
-endif ()
-
 include_directories(AFTER
   ${PROJECT_SOURCE_DIR}/src
   ${PROJECT_BINARY_DIR}/src
@@ -108,7 +88,7 @@
 if (UNIX)
   list(APPEND CMAKE_REQUIRED_LIBRARIES m)
 endif ()
-check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
+check_funcs(atexit mprotect sysconf getpagesize mmap isatty)
 check_include_file(unistd.h HAVE_UNISTD_H)
 if (${HAVE_UNISTD_H})
   add_definitions(-DHAVE_UNISTD_H)
@@ -117,15 +97,19 @@
 if (${HAVE_SYS_MMAN_H})
   add_definitions(-DHAVE_SYS_MMAN_H)
 endif ()
-check_include_file(xlocale.h HAVE_XLOCALE_H)
-if (${HAVE_XLOCALE_H})
-  add_definitions(-DHAVE_XLOCALE_H)
-endif ()
 check_include_file(stdbool.h HAVE_STDBOOL_H)
 if (${HAVE_STDBOOL_H})
   add_definitions(-DHAVE_STDBOOL_H)
 endif ()
 
+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)
+  endif ()
+endif ()
 
 if (MSVC)
   add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
@@ -147,7 +131,7 @@
   set (${variable} ${listVar} PARENT_SCOPE)
 endfunction ()
 
-# http://stackoverflow.com/a/27630120
+# https://stackoverflow.com/a/27630120
 function (add_prefix_to_list var prefix)
   set (listVar "")
   foreach (f ${${var}})
@@ -257,7 +241,7 @@
 if (HB_HAVE_ICU)
   add_definitions(-DHAVE_ICU)
 
-  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake
+  # https://github.com/WebKit/webkit/blob/fdd7733f2f30eab7fe096a9791f98c60f62f49c0/Source/cmake/FindICU.cmake
   find_package(PkgConfig)
   pkg_check_modules(PC_ICU QUIET icu-uc)
 
@@ -326,6 +310,7 @@
 endif ()
 
 if (HB_HAVE_GOBJECT)
+  add_definitions(-DHAVE_GOBJECT)
   include (FindPerl)
 
   # Use the hints from glib-2.0.pc to find glib-mkenums
@@ -429,45 +414,30 @@
   )
 endif ()
 
-## Atomic ops availability detection
-file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
-"		void memory_barrier (void) { __sync_synchronize (); }
-		int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
-		int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
-		void mutex_unlock (int *m) { __sync_lock_release (m); }
-		int main () { return 0; }
-")
-try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES
-  ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives
-  ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c)
-if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES)
-  add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES)
-endif ()
-
-file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c"
-"		#include <atomic.h>
-		/* This requires Solaris Studio 12.2 or newer: */
-		#include <mbarrier.h>
-		void memory_barrier (void) { __machine_rw_barrier (); }
-		int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
-		void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
-		int main () { return 0; }
-")
-try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS
-  ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops
-  ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c)
-if (HB_HAVE_SOLARIS_ATOMIC_OPS)
-  add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS)
-endif ()
-
 
 ## Define harfbuzz library
 add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
 target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
+target_include_directories(harfbuzz PUBLIC
+                           "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
+                           "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
+
+## Define harfbuzz-icu library
+if (HB_HAVE_ICU)
+  add_library(harfbuzz-icu ${PROJECT_SOURCE_DIR}/src/hb-icu.cc ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
+  add_dependencies(harfbuzz-icu harfbuzz)
+  target_link_libraries(harfbuzz-icu harfbuzz ${THIRD_PARTY_LIBS})
+
+  if (BUILD_SHARED_LIBS)
+    set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
+  endif ()
+endif ()
+
 
 ## Define harfbuzz-subset library
 if (HB_BUILD_SUBSET)
   add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
+  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h)
   add_dependencies(harfbuzz-subset harfbuzz)
   target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
 
@@ -615,12 +585,14 @@
     POST_BUILD
     COMMAND ${G_IR_SCANNER_CMD}
       --warn-all --no-libtool --verbose
-      -n hb
       --namespace=HarfBuzz
       --nsversion=0.0
+      --symbol-prefix=hb
+      --symbol-prefix=hb_gobject
       --identifier-prefix=hb_
       --include GObject-2.0
-      --pkg-export=harfbuzz
+      --pkg-export=harfbuzz-gobject
+      --c-include=hb-gobject.h
       --cflags-begin
       -I${PROJECT_SOURCE_DIR}/src
       -I${PROJECT_BINARY_DIR}/src
@@ -723,6 +695,19 @@
       NAMESPACE harfbuzz::
       DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
   )
+  if (HB_HAVE_ICU)
+    install(TARGETS harfbuzz-icu
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+      FRAMEWORK DESTINATION Library/Frameworks
+    )
+  endif ()
+  if (HB_BUILD_SUBSET)
+    install(TARGETS harfbuzz-subset
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+  endif ()
   if (HB_BUILD_UTILS)
     if (WIN32 AND BUILD_SHARED_LIBS)
       install(TARGETS harfbuzz-subset
@@ -767,54 +752,3 @@
     endif ()
   endif ()
 endif ()
-
-if (HB_BUILD_TESTS)
-  ## src/ executables
-  foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize test-unicode-ranges) # hb-ot-tag
-    set (prog_name ${prog})
-    if (${prog_name} STREQUAL "test")
-      # test can not be used as a valid executable name on cmake, lets special case it
-      set (prog_name test-test)
-    endif ()
-    add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
-    target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
-  endforeach ()
-  # set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
-
-  ## Tests
-  if (UNIX OR MINGW)
-    if (BUILD_SHARED_LIBS)
-      # generate harfbuzz.def after build completion
-      add_custom_command(TARGET harfbuzz POST_BUILD
-        COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers}
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
-
-      add_test(NAME check-static-inits.sh
-        COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
-        WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
-      )
-      add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
-      add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
-
-      set_tests_properties(
-        check-static-inits.sh check-libstdc++.sh check-symbols.sh
-        PROPERTIES
-          ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
-          SKIP_RETURN_CODE 77)
-    endif ()
-
-    add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
-    add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
-    add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
-    add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
-    set_tests_properties(
-      check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
-      PROPERTIES
-        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
-        SKIP_RETURN_CODE 77)
-  endif ()
-
-  # Needs to come last so that variables defined above are passed to
-  # subdirectories.
-  add_subdirectory(test)
-endif ()
diff --git a/CONFIG.md b/CONFIG.md
index 46971b0..2ca0293 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -1,9 +1,9 @@
 # Configuring HarfBuzz
 
 Most of the time you will not need any custom configuration.  The configuration
-options provided by `configure` or `cmake` should be enough.  In particular,
-if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure
-FreeType and Cairo are available and found during configuration.
+options provided by `meson` should be enough.  In particular, if you just want
+HarfBuzz library plus hb-shape / hb-view utilities, make sure FreeType and Cairo
+are available and found during configuration.
 
 If you are building for distribution, you should more carefully consider whether
 you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite.  Make
@@ -18,9 +18,9 @@
 ## Compiler Options
 
 Make sure you build with your compiler's "optimize for size" option.  On `gcc`
-this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os` either to `configure`
-(sticky) or to `make` (non-sticky).  On clang there is an even more extreme flag,
-`-Oz`.
+this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os`.  On clang there
+is an even more extreme flag, `-Oz`.  Meson also provides `--buildtype=minsize`
+for more convenience.
 
 HarfBuzz heavily uses inline functions and the optimize-size flag can make the
 library smaller by 20% or more.  Moreover, sometimes, based on the target CPU,
@@ -32,8 +32,7 @@
 other compilers, or continue reading.
 
 Another compiler option to consider is "link-time optimization", also known as
-'lto'.  To enable that, with `gcc` or `clang`, add `-flto` to both `CXXFLAGS`
-and `LDFLAGS`, either on `configure` invocation (sticky) or on `make` (non-sticky).
+'lto'.  To enable that, feel free to use `-Db_lto=true` of meson.
 This, also, can have a huge impact on the final size, 20% or more.
 
 Finally, if you are making a static library build or otherwise linking the
@@ -109,7 +108,7 @@
 By default HarfBuzz builds as a thread-safe library.  The exception is that
 the `HB_TINY` predefined configuring (more below) disables thread-safety.
 
-If you do /not/ need thread-safety in the library (eg. you always call into
+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
 `HB_NO_MT`.  As noted already, this is enabled by `HB_TINY`.
 
@@ -145,7 +144,7 @@
 ## Notes
 
 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.
+`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 exntents
+This option disables (among other things) the code to calculate glyph extents
 for CFF fonts.
diff --git a/COPYING b/COPYING
index 0278e60..48d1b30 100644
--- a/COPYING
+++ b/COPYING
@@ -2,15 +2,16 @@
 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  Google, Inc.
-Copyright © 2019  Facebook, Inc.
+Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020  Google, Inc.
+Copyright © 2018,2019,2020  Ebrahim Byagowi
+Copyright © 2019,2020  Facebook, Inc.
 Copyright © 2012  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 © 2007  Chris Wilson
-Copyright © 2006  Behdad Esfahbod
+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
diff --git a/Makefile.am b/Makefile.am
index 2bbd3c5..3055e5a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,7 +10,6 @@
 	autogen.sh \
 	harfbuzz.doap \
 	README.md \
-	README.mingw.md \
 	README.python.md \
 	BUILD.md \
 	CONFIG.md \
@@ -18,10 +17,29 @@
 	TESTING.md \
 	CMakeLists.txt \
 	replace-enum-strings.cmake \
+	meson.build \
+	meson_options.txt \
+	subprojects/cairo.wrap \
+	subprojects/freetype2.wrap \
+	subprojects/glib.wrap \
+	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 \
-	mingw-ldd.py \
-	mingw32.sh \
-	mingw64.sh \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
@@ -75,29 +93,4 @@
 dist-clear-sticky-bits:
 	chmod -R a-s $(distdir)
 
-tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.xz
-sha256_file = $(tar_file).sha256
-gpg_file = $(sha256_file).asc
-$(sha256_file): $(tar_file)
-	sha256sum $^ > $@
-$(gpg_file): $(sha256_file)
-	@echo "Please enter your GPG password to sign the checksum."
-	gpg --armor --sign $^
-
-release-files: $(tar_file) $(sha256_file) $(gpg_file)
-
-dist-win:
-	@case $(host_triplet) in *-w64-mingw32) ;; *) echo "Error: Requires mingw build. See README.mingw.md.">&2; exit 1 ;; esac
-	@DIR=$(PACKAGE_TARNAME)-$(VERSION)-win`case $(host_triplet) in i686-*) echo 32 ;; x86_64-*) echo 64 ;; esac`; \
-	$(RM) -r $$DIR; $(MKDIR_P) $$DIR || exit 1; \
-	cp util/.libs/hb-{shape,view,subset}.exe $$DIR && \
-	$(top_srcdir)/mingw-ldd.py $$DIR/hb-view.exe | grep -v 'not found' | cut -d '>' -f 2 | xargs cp -t $$DIR && \
-	cp src/.libs/libharfbuzz{,-subset}-0.dll $$DIR && \
-	chmod a+x $$DIR/*.{exe,dll} && \
-	$(STRIP) $$DIR/*.{exe,dll} && \
-	zip -r $$DIR.zip $$DIR && \
-	$(RM) -r $$DIR && \
-	echo "$$DIR.zip is ready."
-
-
 -include $(top_srcdir)/git.mk
diff --git a/NEWS b/NEWS
index 7dde119..da7d8db 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,272 @@
+Overview of changes leading to 3.1.1
+Wednesday, November 8, 2021
+====================================
+- Work around GCC cast-align error/warning on some platforms. (Behdad Esfahbod)
+- Documentation improvements. (Matthias Clasen)
+
+
+Overview of changes leading to 3.1.0
+Wednesday, November 3, 2021
+====================================
+- Better offset-overflow handling in the subsetter library. (Garret Rieger)
+- Improved Unicode 14 properties in the USE shaper, and various other USE
+  shaper fixes. (David Corbett)
+- MATH and COLR v1 tables subsetting support, and various other subsetter fixes.
+  (Qunxin Liu)
+- Support for Pwo Karen / Ason Chin medial la. (Simon Cozens)
+- Apply GPOS positioning when substituting with morx table, if kerx is missing.
+  (Behdad Esfahbod)
+- Apply calt and clig features across syllable boundaries in Indic shaper.
+  (Behdad Esfahbod)
+- meson option for enabling Graphite 2 has been renamed to graphite2.
+- Build and documentation fixes.
+
+- New API:
++hb_buffer_set_not_found_glyph()
++hb_buffer_get_not_found_glyph()
+
+
+Overview of changes leading to 3.0.0
+Friday, September 17, 2021
+====================================
+- Unicode 14.0 support (David Corbett).
+- The hb-subset API and the harfbuzz-subset library's ABI are now declared
+  stable. The harfbuzz-subset library would not have been possible without the
+  work of Garret Rieger and Qunxin Liu from Google Fonts, and the earlier work
+  of Michiharu Ariza from Adobe.
+- The hb-style API is now stable and no longer experimental.
+
+- New API:
++hb_style_tag_t
++hb_style_get_value()
++hb_subset_input_t
++hb_subset_flags_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_unicode_set()
++hb_subset_input_glyph_set()
++hb_subset_input_set()
++hb_subset_input_get_flags()
++hb_subset_input_set_flags()
++hb_subset_or_fail()
+
+- Removed old unstable harfbuzz-subset API:
+-hb_subset_input_nameid_set()
+-hb_subset_input_namelangid_set()
+-hb_subset_input_layout_features_set()
+-hb_subset_input_no_subset_tables_set()
+-hb_subset_input_drop_tables_set()
+-hb_subset_input_set_drop_hints()
+-hb_subset_input_get_drop_hints()
+-hb_subset_input_set_desubroutinize()
+-hb_subset_input_get_desubroutinize()
+-hb_subset_input_set_retain_gids()
+-hb_subset_input_get_retain_gids()
+-hb_subset_input_set_name_legacy()
+-hb_subset_input_get_name_legacy()
+-hb_subset_input_set_overlaps_flag()
+-hb_subset_input_get_overlaps_flag()
+-hb_subset_input_set_notdef_outline()
+-hb_subset_input_get_notdef_outline()
+-hb_subset_input_set_no_prune_unicode_ranges()
+-hb_subset_input_get_no_prune_unicode_ranges()
+-hb_subset()
+
+
+Overview of changes leading to 2.9.1
+Tuesday, September 7, 2021
+====================================
+- Final subset API is in place and if no issues are discovered, it will be the
+  stable subset API of HarfBuzz 3.0.0. Old API is kept to ease transition, but
+  will be removed in 3.0.0.
+- Various fuzzer-found bug fixes.
+- hb_buffer_append() now handles the pre- and post-context which previously
+  were left unchanged in the destination buffer.
+- hb-view / hb-shape now accept following new arguments:
+  o --unicodes-before/after: takes a list of hex numbers that represent Unicode
+    codepoints.
+- Undeprecated API:
+  hb_set_invert()
+
+
+Overview of changes leading to 2.9.0
+Wednesday, August 18, 2021
+History Repeats Itself (Afghanistan)
+====================================
+- Subsetter API is being stabilized, with the first stable API to happen in
+  3.0.0 release (https://github.com/harfbuzz/harfbuzz/issues/3078).
+- Support multiple variation axes with same tag, aka HOI.
+- The “coretext” testing shaper now passes font variations to CoreText.
+- hb-shape/hb-view does not break line at new lines unless text is read from
+  file.
+- hb-view and hb-subset has a --batch now, similar to hb-shape.
+- The --batch mode now uses ; as argument separator instead of : used previously.
+- The --batch in hb-shape does not expect 0th argument anymore. That is, the
+  lines read are interpreted as argv[1:], instead of argv[0:].
+- The --batch option has been undocumented. We are ready to document it; send
+  feedback if you find it useful.
+- hb-subset got arguments revamps. Added much-requested --gids-file, --glyphs,
+  --glyphs-file, --unicodes-file, supporting ranges in --unicodes.
+- Various bug fixes.
+
+
+Overview of changes leading to 2.8.2
+Tuesday, July 8, 2021
+====================================
+- Shaping LTR digits for RTL scripts now makes the native direction of the
+  digits LTR, applying shaping and positioning rules on the same glyph order as
+  Uniscribe. (Jonathan Kew, Khaled Hosny).
+- Subsetting COLR v1 and CPAL tables is now supported. (Garret Rieger, Qunxin Liu)
+- Various fixes and improvements to the subsetter. (Garret Rieger, Qunxin Liu, Behdad)
+- When applying morx table, mark glyph widths should not be zeroed. (Jonathan Kew)
+- GPOS is preferred over kerx, if GSUB was applied. (Behdad)
+- Regional_Indicator pairs are grouped together when clustering. (Behdad)
+- New API:
++hb_blob_create_or_fail()
++hb_blob_create_from_file_or_fail()
++hb_set_copy()
+
+
+Overview of changes leading to 2.8.1
+Tuesday, May 4, 2021
+====================================
+- Subsetter now fully supports GSUB/GPOS/GDEF tables (including variations); as
+  such, layout tables are retained by subsetter by default. (Garret Rieger, Qunxin Liu)
+- Build scripts no longer check for FontConfig as HarfBuzz does not use it.
+- hb-view supports iTerm2 and kitty inline image protocols (Khaled Hosny),
+  it can also use Chafa for terminal graphics if available (Hans Petter Jansson).
+
+Overview of changes leading to 2.8.0
+Tuesday, March 16, 2021
+====================================
+- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine.
+  Previously these were shaped using the generalized Arabic shaper. (David Corbett)
+- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett)
+- Update language tags. (David Corbett)
+- Variations: reduce error: do not round each interpolated delta. (Just van Rossum) 
+- Documentation improvements. (Khaled Hosny, Nathan Willis)
+- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu)
+- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad)
+- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad)
+- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad)
+
+
+Overview of changes leading to 2.7.4
+Sunday, December 27, 2020
+====================================
+- Fix missing --enable-introspection configure option from previous release
+  tarball.
+- Documentation updates.
+
+
+Overview of changes leading to 2.7.3
+Wednesday, December 23, 2020
+====================================
+- Update USE shaper to 2020-08-13 specification, and other improvements.
+- Don’t disable liga feature in myanmar shaper, to match Uniscribe.
+- Improvements to language and script tags handling.
+- Update language system tag registry to OpenType 1.8.4
+- Support for serializing and deserializing Unicode buffers. Serialized buffers
+  are now delimited with `<>` or `[]` based on whether it is a Unicode or
+  glyphs buffer.
+- Increase buffer work limits to handle fonts with many complex lookups.
+- Handle more shaping operations in trace output.
+- Memory access fixes.
+- More OOM fixes.
+- Improved documentation.
+- Build system improvements.
+- New API:
++hb_buffer_has_positions()
++hb_buffer_serialize()
++hb_buffer_serialize_unicode()
++hb_buffer_deserialize_unicode()
+
+
+Overview of changes leading to 2.7.2
+Saturday, August 29, 2020
+====================================
+- Fix a regression in the previous release that caused a crash with Kaithi.
+- More OOM fixes.
+
+
+Overview of changes leading to 2.7.1
+Thursday, August 13, 2020
+====================================
+- ot-funcs now handles variable empty glyphs better when hvar/vvar isn't present.
+- Reverted a GDEF processing regression.
+- A couple of fixes to handle OOM better.
+
+
+Overview of changes leading to 2.7.0
+Saturday, July 25, 2020
+====================================
+- Use an implementation for round that always rounds up, some minor fluctuations
+  are expected on var font specially when hb-ot callback is used.
+- Fix an AAT's `kerx` issue on broken rendering of Devanagari Sangam MN.
+- Remove AAT's `lcar` table support from _get_ligature_carets API, not even much
+  use on macOS installed fonts (only two files).  GDEF support is the recommended
+  one and expected to work properly after issues fixed two releases ago.
+- Minor memory fixes to handle OOM better specially in hb-ft.
+- Minor .so files versioning scheme change and remove stable/unstable scheme
+  differences, was never used in practice (always default to stable scheme).
+- We are now suggesting careful packaging of the library using meson,
+  https://github.com/harfbuzz/harfbuzz/wiki/Notes-on-migration-to-meson
+  for more information.
+- Distribution package URL is changed, either use GitHub generated tarballs,
+  `https://github.com/harfbuzz/harfbuzz/archive/$pkgver.tar.gz`
+  or, even more preferably use commit hash of the release and git checkouts like,
+  `git+https://github.com/harfbuzz/harfbuzz#commit=$commit`
+
+
+Overview of changes leading to 2.6.8
+Monday, June 22, 2020
+====================================
+- New API to fetch glyph alternates from GSUB table.
+- hb-coretext build fix for macOS < 10.10.
+- Meson build fixes, cmake port removal is postponed but please prepare for
+  it and give us feedback.
+  Autotools is still our main build system however please consider
+  experimenting with meson also for packaging the library.
+- New API:
++hb_ot_layout_lookup_get_glyph_alternates()
+
+
+Overview of changes leading to 2.6.7
+Wednesday, June 3, 2020
+====================================
+- Update to Unicode 13.0.0.
+- Fix hb_ot_layout_get_ligature_carets for fonts without lcar table, it was
+  completely broken for all the other fonts since 2.1.2.
+- As a part of our migration to meson, this release will be the last one
+  to provide cmake port files but autotools still is our main build system.
+  There is a possibility that the next version or the after be released
+  using meson.
+
+
+Overview of changes leading to 2.6.6
+Tuesday, May 12, 2020
+====================================
+- A fix in AAT kerning for Geeza Pro.
+- Better support for resource fork fonts on macOS.
+
+
+Overview of changes leading to 2.6.5
+Friday, April 17, 2020
+====================================
+- Add experimental meson build system.  Autotools is still the primary
+  and supported build system.
+- AAT is now always preferred for horizontal scripts when both AAT and OT
+  layout tables exist at the same time.
+- Subsetter improvements.
+- New API:
++hb_ft_font_lock_face()
++hb_ft_font_unlock_face()
+
+
 Overview of changes leading to 2.6.4
 Monday, October 29, 2019
 ====================================
diff --git a/README b/README
deleted file mode 120000
index 42061c0..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-README.md
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..84c542f
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+This is HarfBuzz, a text shaping library.
+
+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 build information, see https://github.com/harfbuzz/harfbuzz/blob/main/BUILD.md
+
+For custom configurations, see https://github.com/harfbuzz/harfbuzz/blob/main/CONFIG.md
+
+For test execution, see https://github.com/harfbuzz/harfbuzz/blob/main/TESTING.md
+
+Documentation: https://harfbuzz.github.io
diff --git a/README.md b/README.md
index e0ef935..9deb32c 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,9 @@
-[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg?branch=master)](https://travis-ci.org/harfbuzz/harfbuzz)
-[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true&branch=master)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
-[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
+[![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)
-[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
+[![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/)
@@ -27,8 +26,8 @@
 
 
 <details>
-  <summary>Packaging status of HarfBuzz</summary
+  <summary>Packaging status of HarfBuzz</summary>
 
-[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)  
+[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
 
 </details>
diff --git a/README.mingw.md b/README.mingw.md
index 76d1a87..d9bd347 100644
--- a/README.mingw.md
+++ b/README.mingw.md
@@ -4,28 +4,35 @@
 is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
 steps are recommended:
 
-1. Install Wine from your favorite package manager.  On Fedora that's `dnf install wine`.
+You want to follow the 32bit instructions. The 64bit equivalents are included
+for reference.
 
-2. And `mingw-w64` compiler.
-   With `brew` on macOS, you can have it like `brew install mingw-w64`.
-   On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the
-   64-bit Windows.
+1. Install Wine.
+   - Fedora: `dnf install wine`.
 
-3. Install cross-compiled dependency packages.  Alternatively see [^1] below.
-   On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
-   for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit.
+2. Install `mingw-w64` compiler.
+   - Fedora, 32bit: `dnf install mingw32-gcc-c++`
+   - Fedora, 64bit: `dnf install mingw64-gcc-c++`
+   - Debian: `apt install g++-mingw-w64`
+   - Mac: `brew install mingw-w64`
 
-5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
+3. If you have drank the `meson` koolaid, look at `.ci/build-win32.sh` to see how to
+   invoke `meson` now, or just run that script.  Otherwise, here's how to use the
+   old trusty autotools instead:
 
-6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit.  This configures
-   HarfBuzz for cross-compiling.  It enables Uniscribe backend as well.
+   a) Install dependencies.
+      - Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
+      - Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
 
-7. `make`
+   b) Configure:
+     - `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
+     - 32bit: `../mingw-configure.sh i686`
+     - 64bit: `../mingw-configure.sh x86_64`
 
-Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with
-the Microsoft Uniscribe,
+Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)`
+but if you like to shape with the Microsoft Uniscribe:
 
-8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
+4. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
    Windows installation (assuming you have a 64-bit installation, otherwise
    `C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
    ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
@@ -35,14 +42,6 @@
 
    Put the DLL in the folder you are going to run the next command,
 
-9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
+5. `WINEDLLOVERRIDES="usp10=n" wine hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
 
 (`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
-
-
-[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
-     in your `~/.local/i686-w64-mingw32`.  Then replace all the instances of
-     `/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32`
-     with `<$HOME>/.local/i686-w64-mingw32` on that folder.
-     (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
-     You shouldn't replace the instances of those inside binary files.
diff --git a/README.python.md b/README.python.md
index d9aaf89..7496f04 100644
--- a/README.python.md
+++ b/README.python.md
@@ -6,13 +6,8 @@
 sudo apt-get install libgirepository1.0-dev
 ```
 
-And then run `autogen.sh` (if building from git), and then:
-
-```bash
-./configure --with-gobject --enable-introspection
-```
-
-Make sure that gobject-introspection is reported enabled then in the `configure` script output.
+And then run `meson setup` and make sure that `Introspection` is reported
+enabled in output.
 
 Compile and install.
 
diff --git a/README.version b/README.version
index 787f6dd..6a89497 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: https://github.com/harfbuzz/harfbuzz/commit/4941e95f10fe0fe658752134a42b58896fb19c42
-Version: 2.3.0
+URL: https://github.com/harfbuzz/harfbuzz/commit/cd5c6cd0419ac5e4de975d6c476fb760bf06d2ce
+Version: 3.1.1
 BugComponent: 25699
diff --git a/RELEASING.md b/RELEASING.md
index 360aea7..67d6310 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -1,72 +1,37 @@
-HarfBuzz release walk-through checklist:
+# HarfBuzz release walk-through checklist:
 
-1. Open gitk and review changes since last release.
+- [ ] Open gitk and review changes since last release.
 
-   * `git diff $(git describe | sed 's/-.*//').. src/*.h` prints all public API
-     changes.
+	- [ ] Print all public API changes:
+        `git diff $(git describe | sed 's/-.*//').. src/*.h`
 
-     Document them in NEWS.  All API and API semantic changes should be clearly
-     marked as API additions, API changes, or API deletions.  Document
-     deprecations.  Ensure all new API / deprecations are in listed correctly in
-     docs/harfbuzz-sections.txt.  If release added new API, add entry for new
-     API index at the end of docs/harfbuzz-docs.xml.
+    - [ ]  Document them in NEWS.
+        All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
 
-     If there's a backward-incompatible API change (including deletions for API
-     used anywhere), that's a release blocker.  Do NOT release.
+    - [ ] Document deprecations.
+        Ensure all new API / deprecations are in listed correctly in docs/harfbuzz-sections.txt.
+        If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
 
-2. Based on severity of changes, decide whether it's a minor or micro release
-   number bump,
+     If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
+     Do NOT release.
 
-3. Search for REPLACEME on the repository and replace it with the chosen version
-   for the release.
+- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
 
-4. Make sure you have correct date and new version at the top of NEWS file,
+- [ ] Search for REPLACEME on the repository and replace it with the chosen version for the release.
 
-5. Bump version in configure.ac line 3,
+- [ ] Make sure you have correct date and new version at the top of NEWS file.
 
-6. Do "make distcheck", if it passes, you get a tarball.
-   Otherwise, fix things and commit them separately before making release,
-   Note: Check src/hb-version.h and make sure the new version number is
-   there.  Sometimes, it does not get updated.  If that's the case,
-   "touch configure.ac" and rebuild.  Also check that there is no hb-version.h
-   in your build/src file. Typically it will fail the distcheck if there is.
-   That's what happened to 2.0.0 going out with 1.8.0 hb-version.h...  So, that's
-   a clue.
+- [ ] Bump version in line 3 of meson.build and configure.ac.
 
-7. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
-   as well as any REPLACEME changes you made.  The commit message is simply the
-   release number.  Eg. "1.4.7"
+- [ ] Do a `meson test -Cbuild` so it both checks the tests and updates hb-version.h (use `git diff` to see if is really updated).
 
-8. "make dist" again to get a tarball with your new commit in the ChangeLog.  Then
-   "make release-files".  Enter your GPG password.  This creates a sha256 hash
-   and signs it.  Check the size of the three resulting files.
+- [ ] Commit NEWS, meson.build, configure.ac, and src/hb-version.h, as well as any REPLACEME changes you made.
+        The commit message is simply the release number, e. g. "1.4.7"
 
-9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7".  Enter your
-   GPG password again.
+- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest commited changes.
+   If doesn't pass, something fishy is going on, reset the repo and start over.
 
-10. Build win32 bundle.
+- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
+	  Enter your GPG password.
 
-   a. Build Win32 binaries.  See [README.mingw.md](README.mingw.md).
-
-   b. Run "make dist-win" to build Win32 bundle.
-
-11. Copy all artefacts to users.freedesktop.org and move them into
-    `/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
-    files.  Eg.:
- ```
--rw-r--r--  1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz
--rw-r--r--  1 behdad eng      89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256
--rw-r--r--  1 behdad eng     339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc
--rw-r--r--  1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
-```
-
-12. While doing that, quickly double-check the size of the .tar.xz and .zip
-    files against their previous releases to make sure nothing bad happened.
-    They should be in the ballpark, perhaps slightly larger.  Sometimes they
-    do shrink, that's not by itself a stopper.
-
-13. Push the commit and tag out: "git push --follow-tags".  Make sure it's
-    pushed both to freedesktop repo and github.
-
-14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
-    edit the tag, upload artefacts and NEWS entry and save.
+- [ ] Push the commit and tag out: `git push --follow-tags`.
diff --git a/TESTING.md b/TESTING.md
index 94be3a0..c722834 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -1,86 +1,55 @@
-## Build & Run
+## Build and Test
+
+```shell
+meson build
+ninja -Cbuild
+meson test -Cbuild
+```
+
+### Debug with GDB
+
+```shell
+meson test -Cbuild --gdb testname
+```
+
+## Build and Run
 
 Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
 Values defined in `hb-debug.hh`.
 
 ```shell
-# quick sanity check
-time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
-  && (make -j4 -C test/api check || cat test/api/test-suite.log))
-
-# slower sanity check
-time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
-   && make -j4 -C src check \
-   && make -j4 -C test/api check \
-   && make -j4 -C test/subset check)
-
-# confirm you didn't break anything else
-time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
-  && make -j4 check)
-
-# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
-make distcheck
+CPPFLAGS='-DHB_DEBUG_SUBSET=100' meson setup build --reconfigure
+meson test -C build
 ```
 
 ### Run tests with asan
 
-**NOTE**: this sometimes yields harder to read results than the full fuzzer
-
 ```shell
-# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
-# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
-# ex
-export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
-
-./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
-# make/run tests as usual
-```
-
-### Debug with GDB
-
-```
-cd ./util
-../libtool --mode=execute gdb --args ./hb-subset ...
+meson setup build -Db_sanitize=address --reconfigure
+meson compile -C build
+meson test -C build
 ```
 
 ### Enable Debug Logging
 
 ```shell
-# make clean if you previously build w/o debug logging
-make CPPFLAGS=-DHB_DEBUG_SUBSET=100
+CPPFLAGS=-DHB_DEBUG_SUBSET=100 meson build --reconfigure
+ninja -C build
 ```
 
-## Build and Test via CMake
-
-Note: You'll need to first install ninja-build via apt-get.
-
-```shell
-cd harfbuzz
-mkdir buid
-cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
-```
 ## Test with the Fuzzer
 
 ```shell
-# push your changs to a branch on googlefonts/harfbuzz
-# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
-# Change the git clone to pull your branch
-
-# Do this periodically
-sudo python infra/helper.py build_image harfbuzz
-
-# Do these to update/run
-sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
-sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
+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
 ```
 
 ## Profiling
 
 ```
-make clean
-./configure CXXFLAGS="-fno-omit-frame-pointer -g"
-make
-perf record -o <perf output file> -g <command to run>
-perf report -i<perf output file>
+meson build --reconfigure
+meson compile -C build
+build/perf/perf
 ```
 
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 7fbcf49..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-platform: x64
-
-environment:
-  matrix:
-
-    #- compiler: msvc
-    #  generator: Visual Studio 14
-    #  platform: Win32
-    #  configuration: Debug
-    #  triplet: x86-windows
-
-    #- compiler: msvc
-    #  generator: Visual Studio 14 Win64
-    #  platform: x64
-    #  configuration: Debug
-    #  triplet: x64-windows
-
-    - compiler: msvc
-      generator: Visual Studio 14 ARM
-      platform: ARM
-      configuration: Debug
-
-
-    # Build only
-
-    #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
-    #  compiler: msvc2
-    #  generator: Visual Studio 12
-    #  platform: Win32
-    #  configuration: Release
-    #  triplet: x86-windows
-
-    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
-      compiler: msvc2
-      generator: Visual Studio 15
-      platform: Win32
-      configuration: Release
-      triplet: x86-windows
-
-    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-      compiler: msvc2
-      generator: Visual Studio 16
-      platform: Win32
-      configuration: Release
-      triplet: x86-windows
-
-
-    - compiler: msys2
-      MINGW_PREFIX: /mingw64
-      MINGW_CHOST: x86_64-w64-mingw32
-      MSYS2_ARCH: x86_64
-
-    - compiler: msys2
-      MINGW_PREFIX: /mingw32
-      MINGW_CHOST: i686-w64-mingw32
-      MSYS2_ARCH: i686
-
-
-install:
-  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"'
-  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
-
-build_script:
-  - 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"'
-  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake'
-
-  - 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
-  - 'if "%compiler%"=="msvc" cd build'
-  - 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
-  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
-
-  - 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.'
-  - 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%'
-
-  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
-  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --with-gdi --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
-
-cache:
-  - c:\tools\vcpkg\installed\
-
-notifications:
-  - provider: Email
-    to:
-      - harfbuzz-bots-chatter@googlegroups.com
-    on_build_success: false
-    on_build_failure: true
-    on_build_status_changed: true
-
-# Do not build feature branch with open Pull Requests
-skip_branch_with_pr: true
-
-# disable automatic tests
-test: off
diff --git a/autogen.sh b/autogen.sh
index fd5c198..085b4d8 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -7,24 +7,24 @@
 olddir=`pwd`
 cd $srcdir
 
-#echo -n "checking for ragel... "
+#printf "checking for ragel... "
 #which ragel || {
 #	echo "You need to install ragel... See http://www.complang.org/ragel/"
 #	exit 1
 #}
 
-echo -n "checking for pkg-config... "
+printf "checking for pkg-config... "
 which pkg-config || {
 	echo "*** No pkg-config found, please install it ***"
 	exit 1
 }
 
-echo -n "checking for libtoolize... "
+printf "checking for libtoolize... "
 which glibtoolize || which libtoolize || {
 	echo "*** No libtoolize (libtool) found, please install it ***"
 	exit 1
 }
-echo -n "checking for gtkdocize... "
+printf "checking for gtkdocize... "
 if which gtkdocize ; then
 	gtkdocize --copy || exit 1
 else
@@ -32,7 +32,7 @@
 	echo "EXTRA_DIST = " > gtk-doc.make
 fi
 
-echo -n "checking for autoreconf... "
+printf "checking for autoreconf... "
 which autoreconf || {
 	echo "*** No autoreconf (autoconf) found, please install it ***"
 	exit 1
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 88c0a98..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-pool:
-  vmImage: 'VS2017-Win2016'
-
-variables:
-  buildPlatform: 'x86'
-  buildConfiguration: 'Debug'
-  triplet: 'x86-windows'
-
-steps:
-- script: |
-    git clone https://github.com/Microsoft/vcpkg
-    cd vcpkg
-    .\bootstrap-vcpkg.bat
-    .\vcpkg integrate install
-    .\vcpkg install glib:x86-windows freetype:x86-windows cairo:x86-windows
-    cd ..
-    cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ../
-    msbuild harfbuzz.sln /p:Configuration=Debug /p:Platform=Win32
-    cd build
-    ctest --output-on-failure -C Debug
-  displayName: Build and test
diff --git a/configure.ac b/configure.ac
index 4125756..0acbba3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [2.6.4],
+        [3.1.1],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -23,9 +23,9 @@
 AC_PROG_CC_C99
 AM_PROG_CC_C_O
 AC_PROG_CXX
-AX_CXX_COMPILE_STDCXX(11,, optional)
+AX_CXX_COMPILE_STDCXX(11)
 AC_SYS_LARGEFILE
-PKG_PROG_PKG_CONFIG([0.20])
+PKG_PROG_PKG_CONFIG([0.28])
 AM_MISSING_PROG([RAGEL], [ragel])
 AM_MISSING_PROG([GIT], [git])
 
@@ -46,16 +46,7 @@
 # Libtool version
 m4_define([hb_version_int],
 	  m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro))
-m4_if(m4_eval(hb_version_minor % 2), [1],
-      dnl for unstable releases
-      [m4_define([hb_libtool_revision], 0)],
-      dnl for stable releases
-      [m4_define([hb_libtool_revision], hb_version_micro)])
-m4_define([hb_libtool_age],
-	  m4_eval(hb_version_int - hb_libtool_revision))
-m4_define([hb_libtool_current],
-	  m4_eval(hb_libtool_age))
-HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age
+HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int
 AC_SUBST(HB_LIBTOOL_VERSION_INFO)
 
 AC_ARG_WITH([libstdc++],
@@ -77,8 +68,8 @@
 ])
 
 # Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
-AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
+AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h)
 
 # Compiler flags
 AC_CANONICAL_HOST
@@ -223,21 +214,21 @@
 
 dnl ==========================================================================
 
-AC_ARG_WITH(fontconfig,
-	[AS_HELP_STRING([--with-fontconfig=@<:@yes/no/auto@:>@],
-			[Use fontconfig @<:@default=auto@:>@])],,
-	[with_fontconfig=auto])
-have_fontconfig=false
-if test "x$with_fontconfig" = "xyes" -o "x$with_fontconfig" = "xauto"; then
-	PKG_CHECK_MODULES(FONTCONFIG, fontconfig, have_fontconfig=true, :)
+AC_ARG_WITH(chafa,
+	[AS_HELP_STRING([--with-chafa=@<:@yes/no/auto@:>@],
+			[Use chafa @<:@default=auto@:>@])],,
+	[with_chafa=auto])
+have_chafa=false
+if test "x$with_chafa" = "xyes" -o "x$with_chafa" = "xauto"; then
+	PKG_CHECK_MODULES(CHAFA, chafa >= 1.6.0, have_chafa=true, :)
 fi
-if test "x$with_fontconfig" = "xyes" -a "x$have_fontconfig" != "xtrue"; then
-	AC_MSG_ERROR([fontconfig support requested but not found])
+if test "x$with_chafa" = "xyes" -a "x$have_chafa" != "xtrue"; then
+	AC_MSG_ERROR([chafa support requested but not found])
 fi
-if $have_fontconfig; then
-	AC_DEFINE(HAVE_FONTCONFIG, 1, [Have fontconfig library])
+if $have_chafa; then
+	AC_DEFINE(HAVE_CHAFA, 1, [Have chafa terminal graphics library])
 fi
-AM_CONDITIONAL(HAVE_FONTCONFIG, $have_fontconfig)
+AM_CONDITIONAL(HAVE_CHAFA, $have_chafa)
 
 dnl ==========================================================================
 
@@ -248,25 +239,6 @@
 have_icu=false
 if test "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" -o "x$with_icu" = "xauto"; then
 	PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :)
-
-	dnl Fallback to icu-config if ICU pkg-config files could not be found
-	if test "$have_icu" != "true"; then
-		AC_CHECK_TOOL(ICU_CONFIG, icu-config, no)
-		AC_MSG_CHECKING([for ICU by using icu-config fallback])
-		if test "$ICU_CONFIG" != "no" && "$ICU_CONFIG" --version >/dev/null; then
-			have_icu=true
-			# We don't use --cflags as this gives us a lot of things that we don't
-			# necessarily want, like debugging and optimization flags
-			# See man (1) icu-config for more info.
-			ICU_CFLAGS=`$ICU_CONFIG --cppflags`
-			ICU_LIBS=`$ICU_CONFIG --ldflags-searchpath --ldflags-libsonly`
-			AC_SUBST(ICU_CFLAGS)
-			AC_SUBST(ICU_LIBS)
-			AC_MSG_RESULT([yes])
-		else
-			AC_MSG_RESULT([no])
-		fi
-	fi
 fi
 if test \( "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" \) -a "x$have_icu" != "xtrue"; then
 	AC_MSG_ERROR([icu support requested but icu-uc not found])
@@ -445,45 +417,6 @@
 
 dnl ===========================================================================
 
-AC_CACHE_CHECK([for Intel atomic primitives], hb_cv_have_intel_atomic_primitives, [
-	hb_cv_have_intel_atomic_primitives=false
-	AC_TRY_LINK([
-		void memory_barrier (void) { __sync_synchronize (); }
-		int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
-		int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
-		void mutex_unlock (int *m) { __sync_lock_release (m); }
-		], [], hb_cv_have_intel_atomic_primitives=true
-	)
-])
-if $hb_cv_have_intel_atomic_primitives; then
-	AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1, [Have Intel __sync_* atomic primitives])
-fi
-
-dnl ===========================================================================
-
-AC_CACHE_CHECK([for Solaris atomic operations], hb_cv_have_solaris_atomic_ops, [
-	hb_cv_have_solaris_atomic_ops=false
-	AC_TRY_LINK([
-		#include <atomic.h>
-		/* This requires Solaris Studio 12.2 or newer: */
-		#include <mbarrier.h>
-		void memory_barrier (void) { __machine_rw_barrier (); }
-		int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
-		void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
-		], [], hb_cv_have_solaris_atomic_ops=true
-	)
-])
-if $hb_cv_have_solaris_atomic_ops; then
-	AC_DEFINE(HAVE_SOLARIS_ATOMIC_OPS, 1, [Have Solaris __machine_*_barrier and atomic_* operations])
-fi
-
-if test "$os_win32" = no && ! $have_pthread; then
-	AC_CHECK_HEADERS(sched.h)
-	AC_SEARCH_LIBS(sched_yield,rt,AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield]))
-fi
-
-dnl ===========================================================================
-
 AC_CONFIG_FILES([
 Makefile
 src/Makefile
@@ -492,13 +425,14 @@
 test/Makefile
 test/api/Makefile
 test/fuzzing/Makefile
-test/shaping/Makefile
-test/shaping/data/Makefile
-test/shaping/data/aots/Makefile
-test/shaping/data/in-house/Makefile
-test/shaping/data/text-rendering-tests/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
 ])
@@ -512,6 +446,14 @@
 
 AC_MSG_NOTICE([
 
+Autotools is no longer our supported build system for building the library
+for *nix distributions, please migrate to meson.
+
+])
+
+
+AC_MSG_NOTICE([
+
 Build configuration:
 
 Unicode callbacks (you want at least one):
@@ -524,9 +466,9 @@
 
 Tools used for command-line utilities:
 	Cairo:			${have_cairo}
-	Fontconfig:		${have_fontconfig}
+	Chafa:			${have_chafa}
 
-Additional shapers (the more the merrier):
+Additional shapers:
 	Graphite2:		${have_graphite2}
 
 Platform shapers (not normally needed):
diff --git a/docs/HarfBuzz.png b/docs/HarfBuzz.png
index 771d955..c9d2e7b 100644
--- a/docs/HarfBuzz.png
+++ b/docs/HarfBuzz.png
Binary files differ
diff --git a/docs/HarfBuzz.svg b/docs/HarfBuzz.svg
index 4e2df25..beb13ad 100644
--- a/docs/HarfBuzz.svg
+++ b/docs/HarfBuzz.svg
@@ -1,277 +1,8 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   version="1.1"
-   id="svg2"
-   width="682.66669"
-   height="682.66669"
-   viewBox="0 0 682.66669 682.66669"
-   sodipodi:docname="harfbuzz2.svg"
-   inkscape:version="0.92.2 5c3e80d, 2017-08-06"
-   inkscape:export-filename="harfbuzz2.png"
-   inkscape:export-xdpi="72"
-   inkscape:export-ydpi="72">
-  <metadata
-     id="metadata8">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <defs
-     id="defs6">
-    <g
-       id="g50">
-      <symbol
-         id="glyph0-0"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path26"
-           d="M 32,0 V -192 H 224 V 0 Z M 48,-16 H 208 V -176 H 48 Z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-1"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path29"
-           d="m 52.5,-64.875 c -0.08594,2.25 -0.9375,6.335938 -2.5625,12.25 -1.625,5.917969 -3.75,12.375 -6.375,19.375 -2.625,7 -4.9375,12.292969 -6.9375,15.875 -2,3.585938 -4.1875,6.3125 -6.5625,8.1875 -2.375,1.875 -6.210938,3.585938 -11.5,5.125 -5.292969,1.542969 -9.542969,2.585938 -12.75,3.125 -3.210938,0.542969 -5.230469,0.8125 -6.0625,0.8125 -0.832031,-0.082031 -1.332031,-0.414062 -1.5,-1 -0.164062,-0.582031 0.085938,-1.332031 0.75,-2.25 0.9179688,-1.414062 3.226562,-3.269531 6.9375,-5.5625 3.707031,-2.289062 8.019531,-5.164062 12.9375,-8.625 4.914062,-3.457031 8.414062,-6.476562 10.5,-9.0625 2.082031,-2.582031 4.4375,-6.457031 7.0625,-11.625 2.625,-5.164062 5,-10.375 7.125,-15.625 2.125,-5.25 3.644531,-8.832031 4.5625,-10.75 0.914062,-1.914062 1.914062,-2.832031 3,-2.75 0.914062,0.167969 1.375,1 1.375,2.5 z M 41.75,-117.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-2"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path32"
-           d="m 19.75,-47.125 c -0.167969,3.167969 -0.5,6.023438 -1,8.5625 -0.5,2.542969 -1.167969,4.710938 -2,6.5 -0.835938,1.792969 -1.898438,3.125 -3.1875,4 -1.292969,0.875 -2.855469,1.1875 -4.6875,0.9375 0.082031,-6.5 0.769531,-15.5625 2.0625,-27.1875 1.289062,-11.625 3.226562,-24.476562 5.8125,-38.5625 1.332031,-4.082031 4.039062,-11.28906 8.125,-21.625 0.414062,-1 0.851562,-1.41406 1.3125,-1.25 0.457031,0.16797 0.6875,0.58594 0.6875,1.25 -0.25,5.08594 -1.292969,14.792969 -3.125,29.125 -1.835938,14.335938 -2.960938,24.167969 -3.375,29.5 -0.417969,5.335938 -0.625,8.25 -0.625,8.75 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-3"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path35"
-           d="m -10.875,-27.25 c 1.667969,-7.164062 3.5625,-12.457031 5.6875,-15.875 2.125,-3.414062 3.855469,-5.289062 5.1875,-5.625 v 5.5 c 0,7 1.875,11.875 5.625,14.625 2.25,1.5 4.5,2 6.75,1.5 2.25,-0.5 3.976562,-1.664062 5.1875,-3.5 1.207031,-1.832031 2.226562,-3.976562 3.0625,-6.4375 0.832031,-2.457031 1.625,-3.6875 2.375,-3.6875 0.914062,0 1.289062,0.875 1.125,2.625 -0.08594,3 -1.023438,7.875 -2.8125,14.625 C 19.519531,-16.75 17.082031,-11.207031 14,-6.875 10.914062,-2.539062 7.164062,-0.25 2.75,0 c -4.5,-0.164062 -8,-2.707031 -10.5,-7.625 -2.25,-4.832031 -3.289062,-11.082031 -3.125,-18.75 z m 6.625,111.5 c 0,-1.835938 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.644531 8,4.1875 3.5,3.539062 5.375,6.3125 5.625,8.3125 0,2.664062 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 C 8.875,94.375 7.144531,93.269531 4.1875,91.3125 1.226562,89.351562 -0.957031,87.875 -2.375,86.875 -3.625,86.039062 -4.25,85.164062 -4.25,84.25 Z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-4"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path38"
-           d=""
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-5"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path41"
-           d="m 118.5,-33 c 15.33203,-3.914062 27.375,-8.289062 36.125,-13.125 7.5,-4.082031 11.25,-7.5 11.25,-10.25 0,-0.832031 -0.5625,-1.894531 -1.6875,-3.1875 -1.125,-1.289062 -1.9375,-1.9375 -2.4375,-1.9375 -0.83594,0 -2.02344,0.148438 -3.5625,0.4375 -1.54297,0.292969 -2.64844,0.4375 -3.3125,0.4375 -2.91797,0 -4.98047,-0.769531 -6.1875,-2.3125 -1.21094,-1.539062 -1.8125,-3.601562 -1.8125,-6.1875 0,-1.5 2.16406,-6.539062 6.5,-15.125 1.66406,-3.414062 3.0625,-5.8125 4.1875,-7.1875 1.125,-1.375 2.76953,-2.0625 4.9375,-2.0625 3.58203,0 6.91406,1.9375 10,5.8125 3.08203,3.875 4.625,8.855469 4.625,14.9375 0,6 -0.8125,11.4375 -2.4375,16.3125 -1.625,4.875 -4.14844,9.605469 -7.5625,14.1875 -3.41797,4.585938 -7.83594,9.042969 -13.25,13.375 -8.08594,6.085938 -17.625,11.230469 -28.625,15.4375 -11,4.210938 -23.83594,7.5 -38.5,9.875 C 72.082031,-1.1875 58.082031,0 44.75,0 37.082031,0 30.082031,-0.375 23.75,-1.125 17.414062,-1.875 12.582031,-3.289062 9.25,-5.375 3.082031,-8.789062 0.25,-14.5 0.75,-22.5 c 0.332031,-4.082031 0.832031,-8.4375 1.5,-13.0625 0.664062,-4.625 1.351562,-8.3125 2.0625,-11.0625 0.707031,-2.75 1.5625,-4.125 2.5625,-4.125 0.832031,0 1.332031,1.75 1.5,5.25 0.164062,3.5 0.6875,6.0625 1.5625,7.6875 0.875,1.625 2.207031,3 4,4.125 1.789062,1.125 4.6875,2.210938 8.6875,3.25 4,1.042969 8.6875,1.855469 14.0625,2.4375 5.375,0.585938 12.519531,0.875 21.4375,0.875 12.414062,0 23.019531,-0.4375 31.8125,-1.3125 C 98.726562,-29.3125 108.25,-30.832031 118.5,-33 Z m -38.75,-86.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.46094,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-6"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path44"
-           d="m 78,-56.875 c -1.335938,2.25 -2.25,3.875 -2.75,4.875 -1.417969,2.335938 -2.875,4.210938 -4.375,5.625 -1.75,1.75 -4.042969,3.292969 -6.875,4.625 -6.085938,2.917969 -10.460938,5.75 -13.125,8.5 -1.75,1.75 -3.792969,4.960938 -6.125,9.625 -4.25,8.585938 -8.417969,14.292969 -12.5,17.125 -4.085938,2.917969 -11.417969,5 -22,6.25 C 9.414062,-0.0820312 8.414062,0 7.25,0 H 4.375 c -1.5,0 -2.25,-0.164062 -2.25,-0.5 0,-1.914062 2.539062,-4.5 7.625,-7.75 4,-2.414062 7,-4.207031 9,-5.375 6,-3.414062 10.414062,-6.125 13.25,-8.125 4,-2.914062 6.625,-5.75 7.875,-8.5 4.164062,-8.5 7.625,-14.414062 10.375,-17.75 3.082031,-3.664062 6.625,-6.5 10.625,-8.5 C 67.289062,-60.082031 71,-62.207031 72,-62.875 l 10,2.375 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-7"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path47"
-           d="m 13,-17.625 c -1,1.75 -2.0625,3.480469 -3.1875,5.1875 C 8.6875,-10.726562 7.539062,-9.082031 6.375,-7.5 5.207031,-5.914062 4.0625,-4.476562 2.9375,-3.1875 1.8125,-1.894531 0.832031,-0.832031 0,0 c -0.5,-2.582031 -0.832031,-5.125 -1,-7.625 -0.164062,-2.5 0.167969,-5.039062 1,-7.625 1.25,-0.75 2.207031,-1.414062 2.875,-2 1.664062,-1.5 5.375,-6.582031 11.125,-15.25 -0.667969,-0.664062 -2.585938,-1.601562 -5.75,-2.8125 -3.167969,-1.207031 -6.167969,-1.894531 -9,-2.0625 -2.582031,-0.164062 -4.726562,0.3125 -6.4375,1.4375 -1.707031,1.125 -3.25,2.710938 -4.625,4.75 -1.375,2.042969 -2.5625,2.980469 -3.5625,2.8125 -0.332031,-0.164062 -0.375,-0.851562 -0.125,-2.0625 0.25,-1.207031 0.625,-2.394531 1.125,-3.5625 2.085938,-4.832031 4.480469,-8.4375 7.1875,-10.8125 2.710938,-2.375 5.9375,-3.5625 9.6875,-3.5625 2.75,0 6.164062,0.667969 10.25,2 2.582031,0.917969 4.789062,1.375 6.625,1.375 3.832031,0 7.625,-1.375 11.375,-4.125 0.832031,0 1.125,0.542969 0.875,1.625 -0.25,1.085938 -0.605469,2.355469 -1.0625,3.8125 -0.460938,1.460938 -0.773438,2.4375 -0.9375,2.9375 -0.835938,2.585938 -1.5,4.085938 -2,4.5 -0.5,0.417969 -1.960938,1.5 -4.375,3.25 -1.335938,1 -2.480469,2.148438 -3.4375,3.4375 -0.960938,1.292969 -1.9375,2.835938 -2.9375,4.625 -1,1.792969 -2.292969,4.230469 -3.875,7.3125 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-    </g>
-    <g
-       id="g184">
-      <symbol
-         id="glyph0-0-3"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path163"
-           d=""
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-1-6"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path166"
-           d="m 79.625,-103.25 c -3.585938,22 -6.8125,38.417969 -9.6875,49.25 -2.875,10.835938 -5.480469,19.105469 -7.8125,24.8125 -2.335938,5.710938 -4.898438,10.0625 -7.6875,13.0625 -2.792969,3 -7.917969,5.855469 -15.375,8.5625 -7.460938,2.710938 -13.6875,4.605469 -18.6875,5.6875 -5,1.085938 -8.125,1.667969 -9.375,1.75 C 9.75,-0.207031 8.957031,-0.4375 8.625,-0.8125 8.289062,-1.1875 8.582031,-2.082031 9.5,-3.5 c 1.582031,-2.25 4.894531,-5.332031 9.9375,-9.25 5.039062,-3.914062 11,-8.789062 17.875,-14.625 6.875,-5.832031 12.019531,-10.976562 15.4375,-15.4375 3.414062,-4.457031 6.4375,-10.539062 9.0625,-18.25 C 64.4375,-68.769531 67,-76.832031 69.5,-85.25 c 2.5,-8.414062 4.3125,-14.125 5.4375,-17.125 1.125,-3 2.269531,-4.45703 3.4375,-4.375 1.332031,0.25 1.75,1.41797 1.25,3.5 z m 8.875,-68.625 c 0.664062,2.41797 0.644531,4.91797 -0.0625,7.5 -0.710938,2.58594 -2.023438,5.29297 -3.9375,8.125 -1.167969,1.91797 -2.398438,3.64844 -3.6875,5.1875 -1.292969,1.54297 -2.648438,3.02344 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.960938,1.14844 -2.875,1.4375 -0.917969,0.29297 -1.585938,0.1875 -2,-0.3125 -3,-2.41406 -5.960938,-4.875 -8.875,-7.375 -2.917969,-2.5 -6.125,-4.83203 -9.625,-7 -0.585938,-0.41406 -0.855469,-0.8125 -0.8125,-1.1875 0.03906,-0.375 0.269531,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.83203 1.164062,-1.22656 1.75,-1.1875 0.582031,0.043 1.207031,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-2-7"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path169"
-           d="m 29.625,-70.625 c -0.667969,8.335938 -2.542969,15.417969 -5.625,21.25 -3.085938,5.835938 -6.585938,8.75 -10.5,8.75 0,-3.164062 1.019531,-13 3.0625,-29.5 2.039062,-16.5 3.582031,-28.3125 4.625,-35.4375 1.039062,-7.125 2.226562,-14.6875 3.5625,-22.6875 1.332031,-8 2.625,-14.45703 3.875,-19.375 1.414062,-4.08203 2.9375,-8.20703 4.5625,-12.375 1.625,-4.16406 3.3125,-8.28906 5.0625,-12.375 1.164062,-1.83203 1.914062,-1.53906 2.25,0.875 -2.085938,13.83594 -4,28.1875 -5.75,43.0625 -1.75,14.875 -2.9375,25.52344 -3.5625,31.9375 -0.625,6.417969 -0.9375,10.167969 -0.9375,11.25 -0.417969,6.835938 -0.625,11.710938 -0.625,14.625 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-3-5"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path172"
-           d="m -16.125,-40.625 c 1.25,-5.332031 2.625,-10 4.125,-14 1.5,-4 2.960938,-7.3125 4.375,-9.9375 1.417969,-2.625 2.792969,-4.644531 4.125,-6.0625 1.335938,-1.414062 2.5,-2.25 3.5,-2.5 v 8.25 c 0,10.5 2.789062,17.835938 8.375,22 3.414062,2.25 6.8125,3 10.1875,2.25 3.375,-0.75 5.957031,-2.5 7.75,-5.25 1.789062,-2.75 3.3125,-5.976562 4.5625,-9.6875 1.25,-3.707031 2.457031,-5.5625 3.625,-5.5625 1.332031,0 1.875,1.335938 1.625,4 -0.08594,4.5 -1.480469,11.8125 -4.1875,21.9375 -2.710938,10.125 -6.375,18.4375 -11,24.9375 -4.625,6.5 -10.230469,9.917969 -16.8125,10.25 -6.75,-0.25 -12,-4.039062 -15.75,-11.375 -3.414062,-7.25 -4.914062,-16.625 -4.5,-28.125 z M 28.5,82.125 c 0.664062,2.414062 0.644531,4.914062 -0.0625,7.5 -0.710938,2.582031 -2.023438,5.289062 -3.9375,8.125 -1.167969,1.914062 -2.398438,3.64453 -3.6875,5.1875 -1.292969,1.53906 -2.648438,3.01953 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.45703 -2.875,2.125 -1,0.66406 -1.960938,1.14453 -2.875,1.4375 C 8.082031,113.10156 7.414062,113 7,112.5 c -3,-2.41797 -5.960938,-4.875 -8.875,-7.375 -2.914062,-2.5 -6.125,-4.83594 -9.625,-7 -0.582031,-0.417969 -0.851562,-0.8125 -0.8125,-1.1875 0.04297,-0.375 0.273438,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.835938 1.164062,-1.230469 1.75,-1.1875 0.582031,0.03906 1.207031,0.269531 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.601562 4.875,4.0625 1.5,1.457031 2.8125,3.039062 3.9375,4.75 1.125,1.707031 1.9375,3.601562 2.4375,5.6875 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-4-3"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path175"
-           d=""
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-5-5"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path178"
-           d="M 72.125,0.125 C 58.039062,0.0390625 47.164062,-0.582031 39.5,-1.75 26.164062,-3.832031 16.664062,-7.832031 11,-13.75 5.914062,-18.332031 3.375,-24.582031 3.375,-32.5 c 0,-3.082031 0.289062,-7.5 0.875,-13.25 0.582031,-5.75 1.375,-11.5 2.375,-17.25 0.414062,-2.414062 0.789062,-4.582031 1.125,-6.5 0.25,-1.332031 0.582031,-2.414062 1,-3.25 0.414062,-0.832031 0.875,-1.3125 1.375,-1.4375 0.5,-0.125 0.976562,0.210938 1.4375,1 0.457031,0.792969 0.894531,2.148438 1.3125,4.0625 0.332031,2.085938 0.789062,4.25 1.375,6.5 1.332031,5.417969 4.957031,9.460938 10.875,12.125 15,6.417969 37.914062,9.75 68.75,10 12.75,-0.164062 24.58203,-0.625 35.5,-1.375 11.16406,-0.832031 23.75,-2.789062 37.75,-5.875 14,-3.082031 25.14453,-6.457031 33.4375,-10.125 8.28906,-3.664062 15.35156,-7.625 21.1875,-11.875 4.58203,-3.332031 6.875,-6.539062 6.875,-9.625 0,-1.25 -1.1875,-2.726562 -3.5625,-4.4375 -2.375,-1.707031 -3.9375,-2.5625 -4.6875,-2.5625 -1.41797,0.667969 -3.08594,1.1875 -5,1.5625 -1.91797,0.375 -3.66797,0.480469 -5.25,0.3125 -4.41797,-0.5 -7.71094,-1.875 -9.875,-4.125 -2.16797,-2.25 -3.25,-5.289062 -3.25,-9.125 0,-2.41406 3.20703,-10 9.625,-22.75 2.58203,-5.16406 4.85156,-8.76953 6.8125,-10.8125 1.95703,-2.03906 4.64453,-3.0625 8.0625,-3.0625 5.41406,0 10.4375,2.91797 15.0625,8.75 4.625,5.83594 6.9375,13.29297 6.9375,22.375 0,9 -1.21094,16.792969 -3.625,23.375 -3,9 -7.08594,17.335938 -12.25,25 -6.5,9.25 -13.625,16.5625 -21.375,21.9375 -7.75,5.375 -15.58594,9.648438 -23.5,12.8125 -7.08594,3.5 -16.23047,6.773438 -27.4375,9.8125 -11.21094,3.042969 -24.8125,5.523438 -40.8125,7.4375 -15.835938,1.917969 -29.960938,2.9140625 -42.375,3 z m 82.375,-172 c 0.66406,2.41797 0.64453,4.91797 -0.0625,7.5 -0.71094,2.58594 -2.02344,5.29297 -3.9375,8.125 -1.16797,1.91797 -2.39844,3.64844 -3.6875,5.1875 -1.29297,1.54297 -2.64844,3.02344 -4.0625,4.4375 -0.41797,0.5 -1.08594,1.125 -2,1.875 -0.91797,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.96094,1.14844 -2.875,1.4375 -0.91797,0.29297 -1.58594,0.1875 -2,-0.3125 -3,-2.41406 -5.96094,-4.875 -8.875,-7.375 -2.91797,-2.5 -6.125,-4.83203 -9.625,-7 -0.58594,-0.41406 -0.85547,-0.8125 -0.8125,-1.1875 0.0391,-0.375 0.26953,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.58203,-0.83203 1.16406,-1.22656 1.75,-1.1875 0.58203,0.043 1.20703,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-      <symbol
-         id="glyph0-6-6"
-         overflow="visible"
-         style="overflow:visible">
-        <path
-           id="path181"
-           d="m 115,-102.5 c -1.83594,3.25 -3.75,6.523438 -5.75,9.8125 -2,3.292969 -4.23047,6.398438 -6.6875,9.3125 -2.46094,2.917969 -5.167969,5.5625 -8.125,7.9375 -2.960938,2.375 -6.3125,4.273438 -10.0625,5.6875 -3.085938,1.25 -5.710938,2.648438 -7.875,4.1875 -2.167969,1.542969 -3.960938,3.1875 -5.375,4.9375 -2.167969,2.335938 -4.042969,5.5625 -5.625,9.6875 -1.585938,4.125 -3.230469,8.480469 -4.9375,13.0625 -1.710938,4.585938 -3.585938,9.0625 -5.625,13.4375 -2.042969,4.375 -4.605469,7.980469 -7.6875,10.8125 C 43,-9.125 36.707031,-6.082031 28.375,-4.5 L 5.5,-0.625 C 4.832031,-0.539062 4.019531,-0.476562 3.0625,-0.4375 2.101562,-0.394531 1.414062,-0.414062 1,-0.5 -0.914062,-1.082031 -1.5,-2.351562 -0.75,-4.3125 0,-6.269531 1.957031,-8.25 5.125,-10.25 c 6.414062,-4.25 11.539062,-7.6875 15.375,-10.3125 3.832031,-2.625 6.957031,-4.769531 9.375,-6.4375 2.414062,-1.664062 4.351562,-3.039062 5.8125,-4.125 1.457031,-1.082031 3.019531,-2.289062 4.6875,-3.625 6.75,-5.082031 11.414062,-10.414062 14,-16 1.5,-2.914062 2.875,-5.75 4.125,-8.5 1.25,-2.75 2.5625,-5.457031 3.9375,-8.125 1.375,-2.664062 2.851562,-5.3125 4.4375,-7.9375 1.582031,-2.625 3.414062,-5.269531 5.5,-7.9375 2.164062,-2.664062 5.082031,-5.269531 8.75,-7.8125 3.664062,-2.539062 8.082031,-5.0625 13.25,-7.5625 0.582031,-0.25 1.539062,-0.8125 2.875,-1.6875 1.332031,-0.875 2.95703,-2.26953 4.875,-4.1875 1.91406,-1.91406 4.10156,-4.51953 6.5625,-7.8125 2.45703,-3.28906 5.0625,-7.47656 7.8125,-12.5625 -1,-1 -3.875,-2.375 -8.625,-4.125 -4.75,-1.83203 -9.25,-2.875 -13.5,-3.125 -3.917969,-0.25 -7.148438,0.46094 -9.6875,2.125 -2.542969,1.66797 -4.855469,4.04297 -6.9375,7.125 -2.085938,3.08594 -3.875,4.5 -5.375,4.25 -0.5,-0.25 -0.585938,-1.28906 -0.25,-3.125 0.414062,-1.83203 1,-3.625 1.75,-5.375 3.164062,-7.25 6.75,-12.625 10.75,-16.125 4.082031,-3.58203 8.957031,-5.375 14.625,-5.375 4.08203,0 9.20703,1 15.375,3 3.83203,1.33594 7.125,2 9.875,2 5.75,0 11.45703,-2.03906 17.125,-6.125 1.25,0 1.6875,0.8125 1.3125,2.4375 -0.375,1.625 -0.9375,3.52344 -1.6875,5.6875 -0.66797,2.16797 -1.125,3.625 -1.375,4.375 -1.25,3.91797 -2.25,6.21094 -3,6.875 -0.75,0.58594 -2.91797,2.16797 -6.5,4.75 -2,1.5 -3.73047,3.23047 -5.1875,5.1875 -1.46094,1.96094 -2.9375,4.27344 -4.4375,6.9375 -1.5,2.66797 -3.41797,6.33594 -5.75,11 z m 0,0"
-           style="stroke:none"
-           inkscape:connector-curvature="0" />
-      </symbol>
-    </g>
-  </defs>
-  <sodipodi:namedview
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1"
-     objecttolerance="10"
-     gridtolerance="10"
-     guidetolerance="10"
-     inkscape:pageopacity="0"
-     inkscape:pageshadow="2"
-     inkscape:window-width="2560"
-     inkscape:window-height="1471"
-     id="namedview4"
-     showgrid="false"
-     inkscape:zoom="0.59454973"
-     inkscape:cx="-165.7731"
-     inkscape:cy="361.75575"
-     inkscape:window-x="0"
-     inkscape:window-y="55"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="svg2" />
-  <path
-     id="path871"
-     d="m 205.59223,196.11402 c -5.97657,36.66667 -11.35417,64.02995 -16.14583,82.08333 -4.79167,18.0599 -9.13412,31.84245 -13.02084,41.35417 -3.89323,9.51823 -8.16406,16.77083 -12.8125,21.77083 -4.65495,5 -13.19661,9.75912 -25.625,14.27083 -12.43489,4.51823 -22.8125,7.67579 -31.14583,9.47917 -8.333331,1.8099 -13.541664,2.77995 -15.624997,2.91667 -2.083334,-0.13672 -3.404949,-0.52084 -3.958334,-1.14584 -0.559896,-0.625 -0.07161,-2.11588 1.458334,-4.47916 2.636718,-3.75 8.157551,-8.88672 16.562497,-15.41667 8.39844,-6.52344 18.33333,-14.64844 29.79167,-24.375 11.45833,-9.72005 20.03255,-18.29427 25.72916,-25.72916 5.69011,-7.42839 10.72917,-17.56511 15.10417,-30.41667 4.375,-12.84505 8.64583,-26.28255 12.8125,-40.3125 4.16667,-14.02343 7.1875,-23.54166 9.0625,-28.54166 1.875,-5 3.78255,-7.42839 5.72916,-7.29167 2.22006,0.41667 2.91667,2.36328 2.08334,5.83333 z M 220.38389,81.739028 c 1.10677,4.02995 1.07422,8.196616 -0.10416,12.5 -1.1849,4.309899 -3.3724,8.821612 -6.5625,13.541662 -1.94662,3.19662 -3.9974,6.08074 -6.14584,8.64584 -2.15494,2.57161 -4.41406,5.03906 -6.77083,7.39583 -0.69661,0.83333 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.4349 -4.79167,3.54167 -1.66666,1.11328 -3.26823,1.91406 -4.79166,2.39583 -1.52995,0.48828 -2.64323,0.3125 -3.33334,-0.52083 -5,-4.02344 -9.93489,-8.125 -14.79166,-12.29167 -4.86329,-4.16667 -10.20834,-8.05338 -16.04167,-11.66667 -0.97656,-0.6901 -1.42578,-1.35416 -1.35417,-1.97916 0.0651,-0.625 0.44922,-1.5625 1.14584,-2.8125 l 33.33333,-50.833334 c 0.97005,-1.386717 1.9401,-2.044267 2.91667,-1.979167 0.97005,0.07167 2.01171,0.455734 3.125,1.145834 2.91666,1.666666 5.83333,3.541666 8.74999,5.624999 2.91667,2.083334 5.625,4.34245 8.125,6.770833 2.5,2.4349 4.6875,5.071617 6.5625,7.916667 1.875,2.851566 3.22917,6.009116 4.0625,9.479166 z m 0,0"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     inkscape:connector-curvature="0" />
-  <path
-     inkscape:connector-curvature="0"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     d="m 256.21722,250.48902 c -1.11328,13.89323 -4.23828,25.69662 -9.375,35.41667 -5.14323,9.72656 -10.97656,14.58333 -17.5,14.58333 0,-5.27344 1.69922,-21.66667 5.10417,-49.16667 3.39843,-27.49999 5.97005,-47.18749 7.70833,-59.06249 1.73177,-11.875 3.71094,-24.47917 5.9375,-37.8125 2.22005,-13.33333 4.375,-24.09505 6.45833,-32.29167 2.35677,-6.80338 4.89583,-13.67838 7.60417,-20.625 2.70833,-6.940096 5.52083,-13.815095 8.4375,-20.624995 1.9401,-3.053383 3.1901,-2.5651 3.75,1.458333 -3.47657,23.059902 -6.66667,46.979162 -9.58334,71.770832 -2.91666,24.79166 -4.89583,42.53906 -5.9375,53.22916 -1.04166,10.69662 -1.5625,16.94662 -1.5625,18.75 -0.69661,11.39323 -1.04166,19.51823 -1.04166,24.375 z m 0,0"
-     id="path875" />
-  <path
-     id="path945"
-     d="m 229.34222,300.48902 c 2.08333,-8.88672 4.375,-16.66667 6.875,-23.33333 2.5,-6.66667 4.9349,-12.1875 7.29167,-16.5625 2.36328,-4.375 4.65495,-7.74089 6.875,-10.10417 2.22656,-2.35677 4.16666,-3.75 5.83333,-4.16667 v 13.75 c 0,17.5 4.64844,29.72657 13.95833,36.66667 5.69011,3.75 11.35417,5 16.97917,3.75 5.625,-1.25 9.92838,-4.16667 12.91666,-8.75 2.98177,-4.58333 5.52084,-9.96094 7.60417,-16.14583 2.08333,-6.17839 4.09505,-9.27084 6.04167,-9.27084 2.22005,0 3.125,2.22657 2.70833,6.66667 -0.14323,7.5 -2.46745,19.6875 -6.97917,36.5625 -4.51823,16.875 -10.625,30.72916 -18.33333,41.5625 -7.70833,10.83333 -17.05078,16.52995 -28.02083,17.08333 -11.25,-0.41667 -20,-6.73177 -26.25,-18.95833 -5.6901,-12.08334 -8.1901,-27.70833 -7.5,-46.875 z"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     inkscape:connector-curvature="0" />
-  <path
-     id="path943"
-     d="m 286.78334,583.03989 c 1.10677,4.02343 1.07422,8.1901 -0.10416,12.5 -1.1849,4.30338 -3.3724,8.8151 -6.5625,13.54167 -1.94662,3.1901 -3.9974,6.07421 -6.14584,8.64583 -2.15495,2.5651 -4.41406,5.03255 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.42839 -4.79167,3.54167 -1.66667,1.10677 -3.26823,1.90755 -4.79167,2.39583 -1.52994,0.48177 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02995 -9.9349,-8.125 -14.79167,-12.29167 -4.85677,-4.16666 -10.20833,-8.0599 -16.04166,-11.66666 -0.97005,-0.69662 -1.41927,-1.35417 -1.35417,-1.97917 0.0716,-0.625 0.45573,-1.5625 1.14583,-2.8125 l 33.33334,-50.83333 c 0.97005,-1.39323 1.9401,-2.05078 2.91666,-1.97917 0.97006,0.0652 2.01172,0.44922 3.125,1.14584 2.91667,1.66666 5.83334,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.33593 8.125,6.77083 2.5,2.42838 4.6875,5.0651 6.5625,7.91667 1.875,2.84505 3.22917,6.00259 4.0625,9.47916 z"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     inkscape:connector-curvature="0" />
-  <path
-     id="path879"
-     d="M 303.71722,505.07234"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     inkscape:connector-curvature="0" />
-  <path
-     inkscape:connector-curvature="0"
-     id="path925"
-     d="m 168.42167,500.82557 c -23.47656,-0.14323 -41.60156,-1.17838 -54.375,-3.125 -22.226562,-3.47005 -38.059894,-10.13671 -47.499997,-20 -8.476563,-7.63671 -12.708333,-18.05338 -12.708333,-31.24999 0,-5.13672 0.48177,-12.5 1.458333,-22.08334 0.970052,-9.58333 2.291667,-19.16666 3.958333,-28.75 0.690104,-4.02343 1.315104,-7.63671 1.875,-10.83333 0.416667,-2.22005 0.970052,-4.02344 1.666667,-5.41667 0.690103,-1.38671 1.458333,-2.1875 2.291666,-2.39583 0.833334,-0.20833 1.627604,0.35156 2.395834,1.66667 0.761718,1.32161 1.490885,3.58073 2.187499,6.77083 0.553385,3.47656 1.315104,7.08333 2.291667,10.83333 2.220052,9.02995 8.261718,15.76823 18.124999,20.20834 25.000002,10.69661 63.190102,16.25 114.583332,16.66666 21.25,-0.27343 40.97005,-1.04166 59.16666,-2.29166 18.60677,-1.38672 39.58333,-4.64844 62.91667,-9.79167 23.33333,-5.13672 41.90754,-10.76172 55.72916,-16.875 13.8151,-6.10677 25.58593,-12.70833 35.3125,-19.79167 7.63671,-5.55338 11.45833,-10.89843 11.45833,-16.04166 0,-2.08333 -1.97917,-4.54427 -5.9375,-7.39583 -3.95833,-2.84506 -6.5625,-4.27084 -7.8125,-4.27084 -2.36328,1.11328 -5.14323,1.97917 -8.33333,2.60417 -3.19662,0.625 -6.11328,0.80078 -8.75,0.52083 -7.36328,-0.83333 -12.85157,-3.125 -16.45833,-6.875 -3.61329,-3.75 -5.41667,-8.8151 -5.41667,-15.20833 0,-4.02343 5.34505,-16.66667 16.04167,-37.91667 4.30338,-8.60676 8.08593,-14.61588 11.35416,-18.02083 3.26172,-3.39843 7.74089,-5.10416 13.4375,-5.10416 9.02343,0 17.39583,4.86328 25.10417,14.58333 7.70833,9.72656 11.5625,22.15495 11.5625,37.29166 0,15 -2.01824,27.98828 -6.04167,38.95834 -5,14.99999 -11.8099,28.89322 -20.41667,41.66666 -10.83333,15.41667 -22.70833,27.60417 -35.62499,36.5625 -12.91667,8.95833 -25.97657,16.08073 -39.16667,21.35416 -11.8099,5.83334 -27.05078,11.28907 -45.72916,16.35417 -18.6849,5.07162 -41.35417,9.20573 -68.02083,12.39583 -26.39323,3.19662 -49.9349,4.85677 -70.625,5 z"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
-  <path
-     inkscape:connector-curvature="0"
-     id="path923"
-     d="m 430.22191,133.16177 c 1.10676,4.02995 1.07421,8.19662 -0.10417,12.5 -1.1849,4.3099 -3.3724,8.82162 -6.5625,13.54167 -1.94661,3.19661 -3.9974,6.08073 -6.14583,8.64583 -2.15495,2.57162 -4.41407,5.03907 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33334,3.125 -1.52995,1.25 -3.125,2.4349 -4.79166,3.54167 -1.66667,1.11328 -3.26824,1.91407 -4.79167,2.39583 -1.52995,0.48829 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02343 -9.9349,-8.125 -14.79167,-12.29167 -4.86328,-4.16666 -10.20833,-8.05338 -16.04167,-11.66666 -0.97656,-0.6901 -1.42578,-1.35417 -1.35416,-1.97917 0.0652,-0.625 0.44921,-1.5625 1.14583,-2.8125 l 33.33333,-50.83333 c 0.97005,-1.38672 1.9401,-2.04427 2.91667,-1.97917 0.97005,0.0717 2.01172,0.45574 3.125,1.14584 2.91667,1.66666 5.83333,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.34245 8.125,6.77083 2.5,2.4349 4.6875,5.07162 6.5625,7.91667 1.875,2.85156 3.22916,6.00911 4.0625,9.47916 z"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
-  <path
-     inkscape:connector-curvature="0"
-     id="path883"
-     d="M 305.71333,214.15892"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
-  <path
-     id="path887"
-     d="m 599.12998,319.78391 c -3.0599,5.41667 -6.25,10.8724 -9.58333,16.35417 -3.33334,5.48828 -7.05079,10.66406 -11.14584,15.52083 -4.10156,4.86328 -8.61328,9.27084 -13.54166,13.22917 -4.9349,3.95833 -10.52084,7.12239 -16.77084,9.47916 -5.14323,2.08334 -9.51823,4.41407 -13.125,6.97917 -3.61328,2.57162 -6.60156,5.3125 -8.95833,8.22917 -3.61328,3.89323 -6.73828,9.27083 -9.375,16.14583 -2.64323,6.875 -5.38411,14.13411 -8.22916,21.77083 -2.85157,7.64323 -5.97657,15.10417 -9.375,22.39583 -3.40495,7.29167 -7.67579,13.30079 -12.8125,18.02084 -7.08334,7.5 -17.57162,12.57161 -31.45834,15.20833 l -38.12499,6.45833 c -1.11329,0.14323 -2.46745,0.2474 -4.0625,0.3125 -1.60157,0.0716 -2.7474,0.0391 -3.4375,-0.10416 -3.19011,-0.97005 -4.16667,-3.08594 -2.91667,-6.35417 1.25,-3.26172 4.51172,-6.5625 9.79167,-9.89583 10.6901,-7.08334 19.23177,-12.8125 25.625,-17.1875 6.38671,-4.375 11.59505,-7.94922 15.62499,-10.72917 4.02344,-2.77343 7.25261,-5.0651 9.6875,-6.875 2.42839,-1.80338 5.03256,-3.8151 7.8125,-6.04166 11.25,-8.47006 19.02344,-17.35677 23.33334,-26.66667 2.5,-4.85677 4.79166,-9.58333 6.875,-14.16667 2.08333,-4.58333 4.27083,-9.09505 6.5625,-13.54166 2.29166,-4.44011 4.7526,-8.85417 7.39583,-13.22917 2.63672,-4.375 5.6901,-8.78255 9.16667,-13.22916 3.60677,-4.44011 8.47005,-8.78256 14.58333,-13.02084 6.10677,-4.23177 13.47005,-8.4375 22.08333,-12.60416 0.97005,-0.41667 2.5651,-1.35417 4.79167,-2.8125 2.22005,-1.45834 4.92838,-3.78255 8.125,-6.97917 3.1901,-3.1901 6.83593,-7.53255 10.9375,-13.02083 4.09505,-5.48177 8.4375,-12.46094 13.02083,-20.9375 -1.66667,-1.66667 -6.45833,-3.95833 -14.375,-6.875 -7.91667,-3.05338 -15.41667,-4.79167 -22.5,-5.20833 -6.52995,-0.41667 -11.91406,0.76823 -16.14583,3.54166 -4.23828,2.77995 -8.09245,6.73829 -11.5625,11.875 -3.47657,5.14323 -6.45833,7.5 -8.95833,7.08333 -0.83334,-0.41666 -0.97657,-2.14843 -0.41667,-5.20833 0.6901,-3.05338 1.66667,-6.04166 2.91667,-8.95833 5.27343,-12.08333 11.24999,-21.04167 17.91666,-26.875 6.80339,-5.97005 14.92839,-8.95833 24.375,-8.95833 6.80338,0 15.34505,1.66666 25.625,5 6.38672,2.22656 11.875,3.33333 16.45833,3.33333 9.58333,0 19.09505,-3.39843 28.54167,-10.20833 2.08333,0 2.8125,1.35416 2.1875,4.0625 -0.625,2.70833 -1.5625,5.8724 -2.8125,9.47916 -1.11329,3.61329 -1.875,6.04167 -2.29167,7.29167 -2.08333,6.52995 -3.75,10.35157 -5,11.45833 -1.25,0.97657 -4.86328,3.61329 -10.83333,7.91667 -3.33334,2.5 -6.21745,5.38411 -8.64584,8.64583 -2.43489,3.26823 -4.89583,7.1224 -7.39583,11.5625 -2.5,4.44662 -5.69661,10.5599 -9.58333,18.33333 z m 0,0"
-     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
-     inkscape:connector-curvature="0" />
-  <use
-     style="fill:#000000;fill-opacity:1"
-     id="use62"
-     y="291"
-     x="119.25"
-     xlink:href="#glyph0-4"
-     width="100%"
-     height="100%"
-     transform="matrix(1.3333333,0,0,1.3333333,72.589732,-189.32751)" />
-  <use
-     style="fill:#000000;fill-opacity:1"
-     id="use196"
-     y="391"
-     x="168.375"
-     xlink:href="#glyph0-4-3"
-     width="100%"
-     height="100%"
-     transform="matrix(1.3333333,0,0,1.3333333,-861.41828,-631.73483)" />
+<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 682.667 682.667">
+  <!-- Harf -->
+  <path d="M168.422 500.826c-23.477-.144-41.602-1.179-54.375-3.125-22.227-3.47-38.06-10.137-47.5-20-8.477-7.637-12.709-18.054-12.709-31.25 0-5.137.482-12.5 1.459-22.084a406.941 406.941 0 013.958-28.75c.69-4.023 1.315-7.636 1.875-10.833.417-2.22.97-4.024 1.667-5.417.69-1.386 1.458-2.187 2.291-2.396.834-.208 1.628.352 2.396 1.667.762 1.322 1.491 3.58 2.188 6.77a114.35 114.35 0 002.291 10.834c2.22 9.03 8.262 15.768 18.125 20.209 25 10.696 63.19 16.25 114.584 16.666 21.25-.273 40.97-1.041 59.166-2.291 18.607-1.387 39.584-4.649 62.917-9.792 23.333-5.137 41.908-10.762 55.73-16.875 13.814-6.107 25.585-12.708 35.312-19.792 7.636-5.553 11.458-10.898 11.458-16.041 0-2.084-1.98-4.545-5.938-7.396-3.958-2.845-6.562-4.271-7.812-4.271-2.363 1.113-5.143 1.98-8.333 2.604-3.197.625-6.114.8-8.75.52-7.364-.832-12.852-3.124-16.459-6.874-3.613-3.75-5.416-8.815-5.416-15.208 0-4.024 5.345-16.667 16.041-37.917 4.304-8.607 8.086-14.616 11.354-18.02 3.262-3.4 7.741-5.105 13.438-5.105 9.023 0 17.396 4.863 25.104 14.583 7.708 9.727 11.563 22.155 11.563 37.292 0 15-2.019 27.988-6.042 38.958-5 15-11.81 28.893-20.417 41.667-10.833 15.417-22.708 27.604-35.625 36.562-12.916 8.959-25.976 16.081-39.166 21.355-11.81 5.833-27.051 11.289-45.73 16.354-18.684 5.071-41.354 9.205-68.02 12.396-26.394 3.196-49.935 4.856-70.625 5zM430.222 133.162c1.107 4.03 1.074 8.196-.104 12.5-1.185 4.31-3.373 8.821-6.563 13.541-1.946 3.197-3.997 6.081-6.146 8.646a114.073 114.073 0 01-6.77 7.396c-.697.833-1.81 1.875-3.334 3.125a60.28 60.28 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.024-9.935-8.125-14.792-12.292-4.863-4.167-10.208-8.053-16.042-11.667-.976-.69-1.426-1.354-1.354-1.979.065-.625.45-1.562 1.146-2.812l33.333-50.834c.97-1.386 1.94-2.044 2.917-1.979.97.072 2.012.456 3.125 1.146a102.942 102.942 0 018.75 5.625 70.208 70.208 0 018.125 6.77 47.58 47.58 0 016.562 7.918c1.875 2.851 3.23 6.009 4.063 9.479zM599.13 319.784a589.994 589.994 0 01-9.583 16.354 123.488 123.488 0 01-11.146 15.52 97.741 97.741 0 01-13.542 13.23c-4.935 3.958-10.52 7.122-16.77 9.48-5.144 2.083-9.519 4.413-13.126 6.978-3.613 2.572-6.601 5.313-8.958 8.23-3.613 3.893-6.738 9.27-9.375 16.145a2240.458 2240.458 0 00-8.23 21.771 307.032 307.032 0 01-9.374 22.396c-3.405 7.292-7.676 13.3-12.813 18.02-7.083 7.5-17.571 12.573-31.458 15.21l-38.125 6.458c-1.113.143-2.467.247-4.063.312-1.601.072-2.747.04-3.437-.104-3.19-.97-4.167-3.086-2.917-6.354 1.25-3.262 4.512-6.563 9.792-9.896 10.69-7.083 19.232-12.813 25.625-17.188a6164.29 6164.29 0 0015.625-10.729c4.023-2.773 7.253-5.065 9.687-6.875a271.19 271.19 0 007.813-6.041c11.25-8.47 19.023-17.357 23.333-26.667 2.5-4.857 4.792-9.583 6.875-14.167a305.502 305.502 0 016.563-13.541 226.164 226.164 0 017.396-13.23c2.636-4.375 5.69-8.782 9.166-13.229 3.607-4.44 8.47-8.782 14.584-13.02 6.106-4.232 13.47-8.438 22.083-12.605.97-.416 2.565-1.354 4.792-2.812 2.22-1.459 4.928-3.783 8.125-6.98 3.19-3.19 6.836-7.532 10.937-13.02 4.095-5.482 8.438-12.461 13.021-20.938-1.667-1.666-6.458-3.958-14.375-6.875-7.917-3.053-15.417-4.791-22.5-5.208-6.53-.417-11.914.768-16.146 3.542-4.238 2.78-8.092 6.738-11.562 11.875-3.477 5.143-6.459 7.5-8.959 7.083-.833-.417-.976-2.149-.416-5.208a51.587 51.587 0 012.916-8.959c5.274-12.083 11.25-21.041 17.917-26.875 6.803-5.97 14.928-8.958 24.375-8.958 6.803 0 15.345 1.667 25.625 5 6.387 2.226 11.875 3.333 16.458 3.333 9.584 0 19.095-3.398 28.542-10.208 2.083 0 2.812 1.354 2.187 4.062-.625 2.709-1.562 5.873-2.812 9.48-1.113 3.613-1.875 6.041-2.292 7.291-2.083 6.53-3.75 10.352-5 11.459-1.25.976-4.863 3.613-10.833 7.916a42.505 42.505 0 00-8.646 8.646c-2.435 3.268-4.896 7.122-7.396 11.563-2.5 4.446-5.696 10.56-9.583 18.333zm0 0"/>
+  <!-- B -->
+  <path d="M229.342 300.489c2.084-8.887 4.375-16.667 6.875-23.333 2.5-6.667 4.935-12.188 7.292-16.563 2.363-4.375 4.655-7.74 6.875-10.104 2.226-2.357 4.167-3.75 5.833-4.167v13.75c0 17.5 4.649 29.727 13.959 36.667 5.69 3.75 11.354 5 16.979 3.75s9.928-4.167 12.916-8.75c2.982-4.583 5.521-9.96 7.605-16.146 2.083-6.178 4.095-9.27 6.041-9.27 2.22 0 3.125 2.226 2.709 6.666-.144 7.5-2.468 19.688-6.98 36.563-4.518 16.875-10.625 30.729-18.333 41.562-7.708 10.833-17.05 16.53-28.02 17.083-11.25-.416-20-6.731-26.25-18.958-5.69-12.083-8.19-27.708-7.5-46.875zM286.783 583.04c1.107 4.023 1.075 8.19-.104 12.5-1.185 4.303-3.372 8.815-6.562 13.542-1.947 3.19-3.998 6.074-6.146 8.645a117.59 117.59 0 01-6.771 7.396c-.697.834-1.81 1.875-3.333 3.125a61.927 61.927 0 01-4.792 3.542c-1.667 1.107-3.268 1.907-4.792 2.396-1.53.481-2.643.312-3.333-.521-5-4.03-9.935-8.125-14.792-12.292-4.856-4.166-10.208-8.06-16.041-11.666-.97-.697-1.42-1.355-1.354-1.98.071-.625.455-1.562 1.145-2.812l33.334-50.833c.97-1.394 1.94-2.051 2.916-1.98.97.066 2.012.45 3.125 1.146a102.94 102.94 0 018.75 5.625 69.555 69.555 0 018.125 6.771 47.057 47.057 0 016.563 7.917c1.875 2.845 3.229 6.002 4.062 9.479z"/>
+  <!-- uzz -->
+  <path d="M205.592 196.114c-5.976 36.667-11.354 64.03-16.146 82.083-4.791 18.06-9.134 31.843-13.02 41.355-3.894 9.518-8.164 16.77-12.813 21.77-4.655 5-13.197 9.76-25.625 14.271-12.435 4.518-22.812 7.676-31.146 9.48-8.333 1.81-13.541 2.78-15.625 2.916-2.083-.137-3.405-.52-3.958-1.146-.56-.625-.072-2.116 1.458-4.479 2.637-3.75 8.158-8.887 16.563-15.417 8.398-6.523 18.333-14.648 29.791-24.375 11.459-9.72 20.033-18.294 25.73-25.729 5.69-7.428 10.729-17.565 15.104-30.416 4.375-12.846 8.646-26.283 12.812-40.313 4.167-14.023 7.188-23.542 9.063-28.542 1.875-5 3.782-7.428 5.729-7.291 2.22.416 2.917 2.363 2.083 5.833zm14.792-114.375c1.107 4.03 1.074 8.197-.104 12.5-1.185 4.31-3.373 8.822-6.563 13.542-1.946 3.196-3.997 6.08-6.146 8.646a114.072 114.072 0 01-6.77 7.395c-.697.834-1.81 1.875-3.334 3.125a60.279 60.279 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.023-9.935-8.125-14.792-12.292-4.863-4.166-10.208-8.053-16.042-11.666-.976-.69-1.426-1.354-1.354-1.98.065-.624.45-1.562 1.146-2.812l33.333-50.833c.97-1.387 1.94-2.045 2.917-1.98.97.072 2.012.456 3.125 1.146a102.945 102.945 0 018.75 5.625 70.208 70.208 0 018.125 6.771 47.58 47.58 0 016.562 7.917c1.875 2.851 3.23 6.009 4.063 9.479zm0 0M256.217 250.489c-1.113 13.893-4.238 25.697-9.375 35.417-5.143 9.726-10.976 14.583-17.5 14.583 0-5.273 1.7-21.667 5.104-49.167 3.399-27.5 5.97-47.187 7.709-59.062 1.731-11.875 3.71-24.48 5.937-37.813 2.22-13.333 4.375-24.095 6.459-32.291a574.618 574.618 0 017.604-20.625 683.688 683.688 0 018.437-20.625c1.94-3.054 3.19-2.565 3.75 1.458-3.476 23.06-6.666 46.98-9.583 71.77-2.917 24.793-4.896 42.54-5.938 53.23-1.041 10.697-1.562 16.947-1.562 18.75-.697 11.393-1.042 19.518-1.042 24.375zm0 0"/>
 </svg>
diff --git a/docs/Makefile.am b/docs/Makefile.am
index f4bf2fd..5c03209 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -29,15 +29,12 @@
 # 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"
+	--ignore-decorators='HB_EXTERN|HB_DEPRECATED'
 
 # Header files or dirs to ignore when scanning. Use base file/dir names
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
-if HAVE_GOBJECT
-else
 IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
-endif
 
 # Extra options to supply to gtkdoc-mkdb.
 # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
@@ -83,6 +80,7 @@
 	usermanual-opentype-features.xml \
 	usermanual-clusters.xml \
 	usermanual-utilities.xml \
+	usermanual-integration.xml \
 	version.xml
 
 # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
@@ -106,7 +104,7 @@
 
 # Other files to distribute
 # e.g. EXTRA_DIST += version.xml.in
-EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in meson.build
 
 # Files not to distribute
 # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 433c206..5fa3658 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -11,8 +11,7 @@
       <title>HarfBuzz</title>
       <graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
       <para>
-        HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
-        text shaping engine. Using the HarfBuzz library allows
+        HarfBuzz is a text shaping library. Using the HarfBuzz library allows
 	programs to convert a sequence of Unicode input into
 	properly formatted and positioned glyph output&mdash;for any writing
 	system and language.
@@ -27,7 +26,7 @@
     </abstract>
   </bookinfo>
 
-  <part>
+  <part id="user-manual">
     <title>User's manual</title>
       <xi:include href="usermanual-what-is-harfbuzz.xml"/>
       <xi:include href="usermanual-install-harfbuzz.xml"/>
@@ -39,9 +38,10 @@
       <xi:include href="usermanual-opentype-features.xml"/>
       <xi:include href="usermanual-clusters.xml"/>
       <xi:include href="usermanual-utilities.xml"/>
+      <xi:include href="usermanual-integration.xml"/>
   </part>
 
-  <part>
+  <part id="reference-manual">
     <partinfo>
       <releaseinfo>
         This document is for HarfBuzz &version;.
@@ -50,39 +50,8 @@
       </releaseinfo>
     </partinfo>
 
-    <note>
-      <para>
-        The current HarfBuzz codebase is versioned 2.x.x and 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. 
-      </para>
-      <para>
-        Prior to 2012, the original HarfBuzz codebase (which, these
-	days, is referred to as <emphasis>harfbuzz-old</emphasis>) was 
-        derived from code in <ulink
-	url="http://freetype.org/">FreeType</ulink>, <ulink
-	url="http://pango.org/">Pango</ulink>, and 
-        <ulink url="http://qt-project.org/">Qt</ulink>.
-        It is <emphasis>not</emphasis> actively developed or
-	maintained, and is extremely buggy. All users of harfbuzz-old
-	are encouraged to switch over to the new HarfBuzz as soon as possible.
-      </para>
-      <para>
-	To make this distinction clearer in discussions, the current
-	HarfBuzz codebase is sometimes referred to as
-	<emphasis>harfbuzz-ng</emphasis>.
-      </para>
-      <para>
-	For reference purposes, the harfbuzz-old source tree is archived 
-        <ulink
-	    url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>. There
-	are no release tarballs of harfbuzz-old whatsoever.
-      </para>
-    </note>
-      
     <title>Reference manual</title>
-      <chapter>
+      <chapter id="core-api">
         <title>Core API</title>
         <xi:include href="xml/hb-blob.xml"/>
         <xi:include href="xml/hb-buffer.xml"/>
@@ -98,33 +67,47 @@
         <xi:include href="xml/hb-version.xml"/>
       </chapter>
 
-      <chapter>
+      <chapter id="opentype-api">
         <title>OpenType API</title>
         <xi:include href="xml/hb-ot-color.xml"/>
         <xi:include href="xml/hb-ot-font.xml"/>
         <xi:include href="xml/hb-ot-layout.xml"/>
         <xi:include href="xml/hb-ot-math.xml"/>
+        <xi:include href="xml/hb-ot-meta.xml"/>
+        <xi:include href="xml/hb-ot-metrics.xml"/>
         <xi:include href="xml/hb-ot-name.xml"/>
         <xi:include href="xml/hb-ot-shape.xml"/>
         <xi:include href="xml/hb-ot-var.xml"/>
       </chapter>
 
-      <chapter>
+      <chapter id="apple-advanced-typography-api">
         <title>Apple Advanced Typography API</title>
         <xi:include href="xml/hb-aat-layout.xml"/>
       </chapter>
 
-      <chapter>
+      <chapter id="integration-api">
         <title>Integration API</title>
         <xi:include href="xml/hb-coretext.xml"/>
         <xi:include href="xml/hb-ft.xml"/>
         <xi:include href="xml/hb-glib.xml"/>
-        <xi:include href="xml/hb-gobject.xml"/>
         <xi:include href="xml/hb-graphite2.xml"/>
         <xi:include href="xml/hb-icu.xml"/>
         <xi:include href="xml/hb-uniscribe.xml"/>
+        <xi:include href="xml/hb-gdi.xml"/>
+        <xi:include href="xml/hb-directwrite.xml"/>
       </chapter>
 
+      <chapter id="style-api">
+        <title>Style API</title>
+        <xi:include href="xml/hb-style.xml"/>
+      </chapter>
+
+      <chapter id="subset-api">
+        <title>Subset API</title>
+        <xi:include href="xml/hb-subset.xml"/>
+      </chapter>
+
+
       <!--chapter id="object-tree">
         <title>Object Hierarchy</title>
          <xi:include href="xml/tree_index.sgml"/>
@@ -133,6 +116,15 @@
       <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-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>
@@ -147,10 +139,12 @@
       <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>
@@ -160,10 +154,13 @@
       <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>
@@ -171,7 +168,37 @@
       <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>
 
       <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
+      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.
+    </para>
+    <para>
+      Prior to 2012, the original HarfBuzz codebase (which, these days, is
+      referred to as <emphasis>harfbuzz-old</emphasis>) was derived from code
+      in <ulink url="http://freetype.org/">FreeType</ulink>,
+      <ulink url="http://pango.org/">Pango</ulink>, and
+      <ulink url="http://qt-project.org/">Qt</ulink>.
+      It is <emphasis>not</emphasis> actively developed or  maintained, and is
+      extremely buggy. All users of harfbuzz-old are encouraged to switch over
+      to the new HarfBuzz as soon as possible.
+    </para>
+    <para>
+      To make this distinction clearer in discussions, the current HarfBuzz
+      codebase is sometimes referred to as <emphasis>harfbuzz-ng</emphasis>.
+    </para>
+    <para>
+      For reference purposes, the harfbuzz-old source tree is archived
+      <ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
+      There are no release tarballs of harfbuzz-old whatsoever.
+    </para>
+  </note>
+
 </book>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index c625b92..f2c7593 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -21,7 +21,9 @@
 <SECTION>
 <FILE>hb-blob</FILE>
 hb_blob_create
+hb_blob_create_or_fail
 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_destroy
@@ -80,16 +82,22 @@
 hb_buffer_get_user_data
 hb_buffer_get_glyph_infos
 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_set_not_found_glyph
 hb_buffer_set_replacement_codepoint
 hb_buffer_get_replacement_codepoint
 hb_buffer_normalize_glyphs
 hb_buffer_reverse
 hb_buffer_reverse_range
 hb_buffer_reverse_clusters
+hb_buffer_serialize
 hb_buffer_serialize_glyphs
 hb_buffer_deserialize_glyphs
+hb_buffer_serialize_unicode
+hb_buffer_deserialize_unicode
 hb_buffer_serialize_format_from_string
 hb_buffer_serialize_format_to_string
 hb_buffer_serialize_list_formats
@@ -141,7 +149,6 @@
 hb_tag_t
 hb_script_t
 hb_user_data_key_t
-hb_var_int_t
 HB_TAG
 HB_TAG_NONE
 HB_TAG_MAX
@@ -159,6 +166,7 @@
 <SUBSECTION Private>
 HB_BEGIN_DECLS
 HB_END_DECLS
+hb_var_int_t
 int16_t
 int32_t
 int64_t
@@ -189,7 +197,6 @@
 hb_ot_var_axis_t
 hb_ot_var_find_axis
 hb_ot_var_get_axes
-hb_set_invert
 hb_unicode_eastasian_width_func_t
 hb_unicode_eastasian_width
 hb_unicode_funcs_set_eastasian_width_func
@@ -354,6 +361,11 @@
 hb_font_get_font_v_extents_func_t
 hb_font_get_h_extents
 hb_font_get_v_extents
+hb_font_extents_t
+hb_glyph_extents_t
+<SUBSECTION Private>
+hb_font_get_var_coords_design
+hb_font_draw_glyph
 </SECTION>
 
 <SECTION>
@@ -365,6 +377,8 @@
 hb_ft_font_create_referenced
 hb_ft_font_changed
 hb_ft_font_get_face
+hb_ft_font_lock_face
+hb_ft_font_unlock_face
 hb_ft_font_set_load_flags
 hb_ft_font_get_load_flags
 hb_ft_font_set_funcs
@@ -384,78 +398,6 @@
 </SECTION>
 
 <SECTION>
-<FILE>hb-gobject</FILE>
-HB_GOBJECT_TYPE_BLOB
-HB_GOBJECT_TYPE_BUFFER
-HB_GOBJECT_TYPE_BUFFER_CONTENT_TYPE
-HB_GOBJECT_TYPE_BUFFER_DIFF_FLAGS
-HB_GOBJECT_TYPE_BUFFER_FLAGS
-HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FLAGS
-HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FORMAT
-HB_GOBJECT_TYPE_DIRECTION
-HB_GOBJECT_TYPE_FACE
-HB_GOBJECT_TYPE_FONT
-HB_GOBJECT_TYPE_FONT_FUNCS
-HB_GOBJECT_TYPE_GLYPH_FLAGS
-HB_GOBJECT_TYPE_MAP
-HB_GOBJECT_TYPE_MEMORY_MODE
-HB_GOBJECT_TYPE_OT_COLOR_PALETTE_FLAGS
-HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
-HB_GOBJECT_TYPE_OT_MATH_CONSTANT
-HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART
-HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART_FLAGS
-HB_GOBJECT_TYPE_OT_MATH_GLYPH_VARIANT
-HB_GOBJECT_TYPE_OT_MATH_KERN
-HB_GOBJECT_TYPE_SCRIPT
-HB_GOBJECT_TYPE_SHAPE_PLAN
-HB_GOBJECT_TYPE_UNICODE_COMBINING_CLASS
-HB_GOBJECT_TYPE_UNICODE_FUNCS
-HB_GOBJECT_TYPE_UNICODE_GENERAL_CATEGORY
-HB_GOBJECT_TYPE_BUFFER_CLUSTER_LEVEL
-HB_GOBJECT_TYPE_FEATURE
-HB_GOBJECT_TYPE_GLYPH_INFO
-HB_GOBJECT_TYPE_GLYPH_POSITION
-HB_GOBJECT_TYPE_SEGMENT_PROPERTIES
-HB_GOBJECT_TYPE_SET
-HB_GOBJECT_TYPE_USER_DATA_KEY
-hb_gobject_blob_get_type
-hb_gobject_buffer_content_type_get_type
-hb_gobject_buffer_diff_flags_get_type
-hb_gobject_buffer_flags_get_type
-hb_gobject_buffer_get_type
-hb_gobject_buffer_serialize_flags_get_type
-hb_gobject_buffer_serialize_format_get_type
-hb_gobject_direction_get_type
-hb_gobject_face_get_type
-hb_gobject_font_funcs_get_type
-hb_gobject_font_get_type
-hb_gobject_glyph_flags_get_type
-hb_gobject_map_get_type
-hb_gobject_memory_mode_get_type
-hb_gobject_ot_color_palette_flags_get_type
-hb_gobject_ot_layout_glyph_class_get_type
-hb_gobject_ot_math_constant_get_type
-hb_gobject_ot_math_glyph_part_get_type
-hb_gobject_ot_math_glyph_part_flags_get_type
-hb_gobject_ot_math_glyph_variant_get_type
-hb_gobject_ot_math_kern_get_type
-hb_gobject_script_get_type
-hb_gobject_shape_plan_get_type
-hb_gobject_unicode_combining_class_get_type
-hb_gobject_unicode_funcs_get_type
-hb_gobject_unicode_general_category_get_type
-hb_gobject_buffer_cluster_level_get_type
-hb_gobject_feature_get_type
-hb_gobject_glyph_info_get_type
-hb_gobject_glyph_position_get_type
-hb_gobject_segment_properties_get_type
-hb_gobject_set_get_type
-hb_gobject_user_data_key_get_type
-<SUBSECTION Private>
-HB_GOBJECT_H_IN
-</SECTION>
-
-<SECTION>
 <FILE>hb-graphite2</FILE>
 HB_GRAPHITE2_TAG_SILF
 hb_graphite2_face_get_gr_face
@@ -562,7 +504,6 @@
 hb_ot_layout_get_ligature_carets
 hb_ot_layout_get_size_params
 hb_ot_layout_glyph_class_t
-hb_ot_layout_glyph_sequence_func_t
 hb_ot_layout_has_glyph_classes
 hb_ot_layout_has_positioning
 hb_ot_layout_has_substitution
@@ -571,6 +512,7 @@
 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_substitute_closure
 hb_ot_layout_lookups_substitute_closure
 hb_ot_layout_lookup_would_substitute
@@ -588,6 +530,8 @@
 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
 </SECTION>
 
 <SECTION>
@@ -658,6 +602,7 @@
 hb_set_add
 hb_set_add_range
 hb_set_allocation_successful
+hb_set_copy
 hb_set_clear
 hb_set_create
 hb_set_del
@@ -670,6 +615,7 @@
 hb_set_get_user_data
 hb_set_has
 hb_set_intersect
+hb_set_invert
 hb_set_is_empty
 hb_set_is_equal
 hb_set_is_subset
@@ -762,3 +708,27 @@
 hb_version_atleast
 hb_version_string
 </SECTION>
+
+<SECTION>
+<FILE>hb-style</FILE>
+hb_style_tag_t
+hb_style_get_value
+</SECTION>
+
+<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_set_flags
+hb_subset_input_unicode_set
+hb_subset_input_glyph_set
+hb_subset_input_set
+hb_subset_or_fail
+</SECTION>
diff --git a/docs/meson.build b/docs/meson.build
new file mode 100644
index 0000000..73d9521
--- /dev/null
+++ b/docs/meson.build
@@ -0,0 +1,66 @@
+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()
+endif
+
+conf.set('HAVE_GTK_DOC', 1)
+
+gnome = import('gnome')
+
+docconf = configuration_data()
+docconf.set('HB_VERSION', meson.project_version())
+
+version_xml = configure_file(input: 'version.xml.in',
+  output: 'version.xml',
+  configuration: docconf)
+
+content_files = [
+  'usermanual-what-is-harfbuzz.xml',
+  'usermanual-install-harfbuzz.xml',
+  'usermanual-getting-started.xml',
+  'usermanual-glyph-information.xml',
+  'usermanual-shaping-concepts.xml',
+  'usermanual-object-model.xml',
+  'usermanual-buffers-language-script-and-direction.xml',
+  'usermanual-fonts-and-faces.xml',
+  'usermanual-opentype-features.xml',
+  'usermanual-clusters.xml',
+  'usermanual-utilities.xml',
+  'usermanual-integration.xml',
+  version_xml,
+]
+
+html_images = [
+  'HarfBuzz.png',
+  'HarfBuzz.svg',
+]
+
+ignore_headers = [
+  'hb-gobject.h',
+  'hb-gobject-enums.h',
+  'hb-gobject-enums-tmp.h',
+  'hb-gobject-structs.h',
+]
+
+gnome.gtkdoc('harfbuzz',
+  main_sgml: 'harfbuzz-docs.xml',
+  src_dir: [join_paths(meson.current_source_dir(), '../src'),
+            join_paths(meson.current_build_dir(), '../src'),
+           ],
+  scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
+              '--ignore-decorators=HB_EXTERN|HB_DEPRECATED',
+             ],
+  mkdb_args: ['--source-suffixes=h,cc',
+              '--xml-mode',
+              '--output-format=xml',
+             ],
+  content_files: content_files,
+  html_assets: html_images,
+  ignore_headers: ignore_headers,
+  dependencies: [libharfbuzz_dep],
+  install: true)
diff --git a/docs/repacker.md b/docs/repacker.md
new file mode 100644
index 0000000..b7aacc4
--- /dev/null
+++ b/docs/repacker.md
@@ -0,0 +1,265 @@
+# Introduction
+
+Several tables in the opentype format are formed internally by a graph of subtables. Parent node's
+reference their children through the use of positive offsets, which are typically 16 bits wide.
+Since offsets are always positive this forms a directed acyclic graph. For storage in the font file
+the graph must be given a topological ordering and then the subtables packed in serial according to
+that ordering. Since 16 bit offsets have a maximum value of 65,535 if the distance between a parent
+subtable and a child is more then 65,535 bytes then it's not possible for the offset to encode that
+edge.
+
+For many fonts with complex layout rules (such as Arabic) it's not unusual for the tables containing
+layout rules ([GSUB/GPOS](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub)) to be
+larger than 65kb. As a result these types of fonts are susceptible to offset overflows when
+serializing to the binary font format.
+
+Offset overflows can happen for a variety of reasons and require different strategies to resolve:
+*  Simple overflows can often be resolved with a different topological ordering.
+*  If a subtable has many parents this can result in the link from furthest parent(s)
+   being at risk for overflows. In these cases it's possible to duplicate the shared subtable which
+   allows it to be placed closer to it's parent.
+*  If subtables exist which are themselves larger than 65kb it's not possible for any offsets to point
+   past them. In these cases the subtable can usually be split into two smaller subtables to allow
+   for more flexibility in the ordering.
+*  In GSUB/GPOS overflows from Lookup subtables can be resolved by changing the Lookup to an extension
+   lookup which uses a 32 bit offset instead of 16 bit offset.
+   
+In general there isn't a simple solution to produce an optimal topological ordering for a given graph.
+Finding an ordering which doesn't overflow is a NP hard problem. Existing solutions use heuristics
+which attempt a combination of the above strategies to attempt to find a non-overflowing configuration.
+   
+The harfbuzz subsetting library
+[includes a repacking algorithm](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh)
+which is used to resolve offset overflows that are present in the subsetted tables it produces. This
+document provides a deep dive into how the harfbuzz repacking algorithm works.
+
+Other implementations exist, such as in
+[fontTools](https://github.com/fonttools/fonttools/blob/7af43123d49c188fcef4e540fa94796b3b44e858/Lib/fontTools/ttLib/tables/otBase.py#L72), however these are not covered in this document.
+
+# Foundations
+
+There's four key pieces to the harfbuzz approach:
+
+*  Subtable Graph: a table's internal structure is abstraced out into a lightweight graph
+   representation where each subtable is a node and each offset forms an edge. The nodes only need
+   to know how many bytes the corresponding subtable occupies. This lightweight representation can
+   be easily modified to test new ordering's and strategies as the repacking algorithm iterates.
+
+*  [Topological sorting algorithm](https://en.wikipedia.org/wiki/Topological_sorting): an algorithm
+   which given a graph gives a linear sorting of the nodes such that all offsets will be positive.
+   
+*  Overflow check: given a graph and a topological sorting it checks if there will be any overflows
+   in any of the offsets. If there are overflows it returns a list of (parent, child) tuples that
+   will overflow. Since the graph has information on the size of each subtable it's straightforward
+   to calculate the final position of each subtable and then check if any offsets to it will
+   overflow.
+   
+*  Offset resolution strategies: given a particular occurence of an overflow these strategies
+   modify the graph to attempt to resolve the overflow.
+   
+# High Level Algorithm
+
+```
+def repack(graph):
+  graph.topological_sort()
+
+  if (graph.will_overflow())
+    assign_spaces(graph)
+    graph.topological_sort()
+
+  while (overflows = graph.will_overflow()):
+    for overflow in overflows:
+      apply_offset_resolution_strategy (overflow, graph)
+    graph.topological_sort()
+```
+
+The actual code for this processing loop can be found in the function hb_resolve_overflows () of
+[hb-repacker.hh](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh).
+
+# Topological Sorting Algorithms
+
+The harfbuzz repacker uses two different algorithms for topological sorting:
+*  [Kahn's Algorithm](https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm)
+*  Sorting by shortest distance
+
+Kahn's algorithm is approximately twice as fast as the shortest distance sort so that is attempted
+first (only on the first topological sort). If it fails to eliminate overflows then shortest distance
+sort will be used for all subsequent topological sorting operations.
+   
+## Shortest Distance Sort
+
+This algorithm orders the nodes based on total distance to each node. Nodes with a shorter distance
+are ordered first.
+
+The "weight" of an edge is the sum of the size of the sub-table being pointed to plus 2^16 for a 16 bit
+offset and 2^32 for a 32 bit offset.
+
+The distance of a node is the sum of all weights along the shortest path from the root to that node
+plus a priority modifier (used to change where nodes are placed by moving increasing or
+decreasing the effective distance). Ties between nodes with the same distance are broken based
+on the order of the offset in the sub table bytes.
+
+The shortest distance to each node is determined using
+[Djikstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). Then the topological
+ordering is produce by applying a modified version of Kahn's algorithm that uses a priority queue
+based on the shortest distance to each node.
+
+## Optimizing the Sorting
+
+The topological sorting operation is the core of the repacker and is run on each iteration so it needs
+to be as fast as possible. There's a few things that are done to speed up subsequent sorting
+operations:
+
+*  The number of incoming edges to each node is cached. This is required by the Kahn's algorithm
+   portion of boths sorts. Where possible when the graph is modified we manually update the cached
+   edge counts of affected nodes.
+   
+*  The distance to each node is cached. Where possible when the graph is modified we manually update
+   the cached distances of any affected nodes.
+
+Caching these values allows the repacker to avoid recalculating them for the full graph on each
+iteration.
+
+The other important factor to speed is a fast priority queue which is a core datastructure to
+the topological sorting algorithm. Currently a basic heap based queue is used. Heap based queue's
+don't support fast priority decreases, but that can be worked around by just adding redundant entries
+to the priority queue and filtering the older ones out when poppping off entries. This is based
+on the recommendations in
+[a study of the practical performance of priority queues in Dijkstra's algorithm](https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf)
+
+## Special Handling of 32 bit Offsets
+
+If a graph contains multiple 32 bit offsets then the shortest distance sorting will be likely be
+suboptimal. For example consider the case where a graph contains two 32 bit offsets that each point
+to a subgraph which are not connected to each other. The shortest distance sort will interleave the
+subtables of the two subgraphs, potentially resulting in overflows. Since each of these subgraphs are
+independent of each other, and 32 bit offsets can point extremely long distances a better strategy is
+to pack the first subgraph in it's entirety and then have the second subgraph packed after with the 32
+bit offset pointing over the first subgraph. For example given the graph:
+
+
+```
+a--- b -- d -- f
+ \
+  \_ c -- e -- g
+```
+
+Where the links from a to b and a to c are 32 bit offsets, the shortest distance sort would be:
+
+```
+a, b, c, d, e, f, g
+
+```
+
+If nodes d and e have a combined size greater than 65kb then the offset from d to f will overflow.
+A better ordering is:
+
+```
+a, b, d, f, c, e, g
+```
+
+The ability for 32 bit offsets to point long distances is utilized to jump over the subgraph of
+b which gives the remaining 16 bit offsets a better chance of not overflowing.
+
+The above is an ideal situation where the subgraphs are disconnected from each other, in practice
+this is often not this case. So this idea can be generalized as follows:
+
+If there is a subgraph that is only reachable from one or more 32 bit offsets, then:
+*  That subgraph can be treated as an indepedent unit and all nodes of the subgraph packed in isolation
+   from the rest of the graph.
+*  In a table that occupies less than 4gb of space (in practice all fonts), that packed independent
+   subgraph can be placed anywhere after the parent nodes without overflowing the 32 bit offsets from
+   the parent nodes.
+
+The sorting algorithm incorporates this via a "space" modifier that can be applied to nodes in the
+graph. By default all nodes are treated as being in space zero. If a node is given a non-zero space, n,
+then the computed distance to the node will be modified by adding `n * 2^32`. This will cause that
+node and it's descendants to be packed between all nodes in space n-1 and space n+1. Resulting in a
+topological sort like:
+
+```
+| space 0 subtables | space 1 subtables | .... | space n subtables |
+```
+
+The assign_spaces() step in the high level algorithm is responsible for identifying independent
+subgraphs and assigning unique spaces to each one. More information on the space assignment can be
+found in the next section.
+
+
+# Offset Resolution Strategies
+
+## Space Assignment
+
+The goal of space assignment is to find connected subgraphs that are only reachable via 32 bit offsets
+and then assign each such subgraph to a unique non-zero space. The algorithm is roughly:
+
+1.  Collect the set, `S`, of nodes that are children of 32 bit offsets.
+
+2.  Do a directed traversal from each node in `S` and collect all encountered nodes into set `T`.
+    Mark all nodes in the graph that are not in `T` as being in space 0.
+
+3.  Set `next_space = 1`.
+
+4.  While set `S` is not empty:
+
+    a.  Pick a node `n` in set `S` then perform an undirected graph traversal and find the set `Q` of
+        nodes that are reachable from `n`.
+       
+    b.  During traversal if a node, `m`, has a edge to a node in space 0 then `m` must be duplicated
+        to disconnect it from space 0.
+  
+    d.  Remove all nodes in `Q` from `S` and assign all nodes in `Q` to `next_space`.
+       
+       
+    c.  Increment `next_space` by one.
+
+
+## Manual Iterative Resolutions
+
+For each overflow in each iteration the algorithm will attempt to apply offset overflow resolution
+strategies to eliminate the overflow. The type of strategy applied is dependant on the characteristics
+of the overflowing link:
+
+*  If the overflowing offset is inside a space other than space 0 and the subgraph space has more
+   than one 32 bit offset pointing into the subgraph then subdivide the space by moving subgraph
+   from one of the 32 bit offsets into a new space via the duplication of shared nodes.
+
+*  If the overflowing offset is pointing to a subtable with more than one incoming edge: duplicate
+   the node so that the overflowing offset is pointing at it's own copy of that node.
+   
+*  Otherwise, attempt to move the child subtable closer to it's parent. This is accomplished by
+   raising the priority of all children of the parent. Next time the topological sort is run the
+   children will be ordered closer to the parent.
+   
+# Test Cases
+
+The harfbuzz repacker has tests defined using generic graphs: https://github.com/harfbuzz/harfbuzz/blob/main/src/test-repacker.cc
+   
+# Future Improvments
+
+The above resolution strategies are not sufficient to resolve all overflows. For example consider
+the case where a single subtable is 65k and the graph structure requires an offset to point over it.
+
+The current harfbuzz implementation is suitable for the vast majority of subsetting related overflows.
+Subsetting related overflows are typically easy to solve since all subsets are derived from a font
+that was originally overflow free. A more general purpose version of the algorithm suitable for font
+creation purposes will likely need some additional offset resolution strategies:
+
+*  Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
+   node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
+   should use a heuristic (based on parent and child subtable sizes) to decide if the children's
+   priority should be increased or the parent's priority decreased.
+   
+*  Many subtables can be split into two smaller subtables without impacting the overall functionality.
+   This should be done when an overflow is the result of a very large table which can't be moved
+   to avoid offsets pointing over it.
+   
+*  Lookup subtables in GSUB/GPOS can be upgraded to extension lookups which uses a 32 bit offset.
+   Overflows from a Lookup subtable to it's child should be resolved by converting to an extension
+   lookup.
+   
+Once additional resolution strategies are added to the algorithm it's likely that we'll need to
+switch to using a [backtracking algorithm](https://en.wikipedia.org/wiki/Backtracking) to explore
+the various combinations of resolution strategies until a non-overflowing combination is found. This
+will require the ability to restore the graph to an earlier state. It's likely that using a stack
+of undoable resolution commands could be used to accomplish this.
diff --git a/docs/usermanual-buffers-language-script-and-direction.xml b/docs/usermanual-buffers-language-script-and-direction.xml
index 2865426..0235d2d 100644
--- a/docs/usermanual-buffers-language-script-and-direction.xml
+++ b/docs/usermanual-buffers-language-script-and-direction.xml
@@ -136,10 +136,12 @@
       determine which glyph to return.
     </para>
     <para>
-      The safest approach is to add all of the text available, then
-      use <parameter>item_offset</parameter> and
+      The safest approach is to add all of the text available (even
+      if your text contains a mix of scripts, directions, languages
+      and fonts), then use <parameter>item_offset</parameter> and
       <parameter>item_length</parameter> to indicate which characters you
-      want shaped, so that HarfBuzz has access to any context.
+      want shaped (which must all have the same script, direction,
+      language and font), so that HarfBuzz has access to any context.
     </para>
     <para>
       You can also add Unicode code points directly with
@@ -193,7 +195,7 @@
       hb_buffer_set_language(buf, hb_language_from_string("en", -1));
     </programlisting>
     <para>
-      However, since these properties are often the repeated for
+      However, since these properties are often repeated for
       multiple text runs, you can also save them in a
       <literal>hb_segment_properties_t</literal> for reuse:
     </para>
diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml
index 1258bec..abf5dc2 100644
--- a/docs/usermanual-fonts-and-faces.xml
+++ b/docs/usermanual-fonts-and-faces.xml
@@ -260,18 +260,18 @@
       </listitem>
     </itemizedlist>
     <para>
-      You can fetch the font-functions configuration for a font object
-      by calling <function>hb_font_get_font_funcs()</function>:
+      You can create new font-functions by calling
+      <function>hb_font_funcs_create()</function>:
     </para>
     <programlisting language="C">
-      hb_font_funcs_t *ffunctions;
-      ffunctions = hb_font_get_font_funcs (font);
+      hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
+      hb_font_set_funcs (font, ffunctions, font_data, destroy);
     </programlisting>
     <para>
-      The individual methods can each be replaced with their own setter
+      The individual methods can each be set with their own setter
       function, such as
-      <function>hb_font_funcs_set_nominal_glyph_func(*ffunctions,
-      func, *user_data, destroy)</function>. 
+      <function>hb_font_funcs_set_nominal_glyph_func(ffunctions,
+      func, user_data, destroy)</function>.
     </para>
     <para>
       Font-functions structures can be reused for multiple font
@@ -291,6 +291,20 @@
       programs from changing the configuration and introducing
       inconsistencies and errors downstream.
     </para>
+    <para>
+      To override only some functions while using the default implementation
+      for the others, you will need to create a sub-font. By default, the
+      sub-font uses the font functions of its parent except for the functions
+      that were explicitly set. The following code will override only the
+      <function>hb_font_get_nominal_glyph_func_t</function> for the sub-font:
+    </para>
+    <programlisting language="C">
+      hb_font_t *subfont = hb_font_create_sub_font (font)
+      hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
+      hb_font_funcs_set_nominal_glyph_func (ffunctions, func, user_data, destroy);
+      hb_font_set_funcs (subfont, ffunctions, font_data, destroy);
+      hb_font_funcs_destroy (ffunctions);
+    </programlisting>
   </section>
 
   <section id="fonts-and-faces-native-opentype">
diff --git a/docs/usermanual-getting-started.xml b/docs/usermanual-getting-started.xml
index 1f26df8..e7241a6 100644
--- a/docs/usermanual-getting-started.xml
+++ b/docs/usermanual-getting-started.xml
@@ -6,7 +6,7 @@
 ]>
 <chapter id="getting-started">
   <title>Getting started with HarfBuzz</title>
-  <section>
+  <section id="an-overview-of-the-harfbuzz-shaping-api">
     <title>An overview of the HarfBuzz shaping API</title>
     <para>
       The core of the HarfBuzz shaping API is the function
@@ -51,7 +51,7 @@
 
     <para>
       Although the default <function>hb_shape()</function> function is
-      sufficient for most use cases, a variant is also provide that
+      sufficient for most use cases, a variant is also provided that
       lets you specify which of HarfBuzz's shapers to use on a buffer. 
     </para>
 
@@ -73,7 +73,7 @@
     </para>
   </section>
 
-  <section>
+  <section id="terminology">
     <title>Terminology</title>
     <para>
       
@@ -201,7 +201,7 @@
   </section>
 
 
-  <section>
+  <section id="a-simple-shaping-example">
     <title>A simple shaping example</title>
 
     <para>
@@ -216,6 +216,7 @@
     </orderedlist>
     <programlisting language="C">
       #include &lt;hb.h&gt;
+
       hb_buffer_t *buf;
       buf = hb_buffer_create();
       hb_buffer_add_utf8(buf, text, -1, 0, -1);
@@ -235,15 +236,14 @@
     <orderedlist numeration="arabic">
       <listitem override="3">
 	<para>
-          Create a face and a font, using FreeType for now.
+          Create a face and a font from a font file.
 	</para>
       </listitem>
     </orderedlist>
     <programlisting language="C">
-      #include &lt;hb-ft.h&gt;
-      FT_New_Face(ft_library, font_path, index, &amp;face);
-      FT_Set_Char_Size(face, 0, 1000, 0, 0);
-      hb_font_t *font = hb_ft_font_create(face);
+      hb_blob_t *blob = hb_blob_create_from_file(filename); /* or hb_blob_create_from_file_or_fail() */
+      hb_face_t *face = hb_face_create(blob, 0);
+      hb_font_t *font = hb_font_create(face);
     </programlisting>
     <orderedlist numeration="arabic">
       <listitem override="4">
@@ -263,6 +263,7 @@
       </listitem>
     </orderedlist>
     <programlisting language="C">
+      unsigned int glyph_count;
       hb_glyph_info_t *glyph_info    = hb_buffer_get_glyph_infos(buf, &amp;glyph_count);
       hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
     </programlisting>
@@ -274,13 +275,15 @@
       </listitem>
     </orderedlist>
     <programlisting language="C">
-      for (i = 0; i &lt; glyph_count; ++i) {
-          glyphid = glyph_info[i].codepoint;
-          x_offset = glyph_pos[i].x_offset / 64.0;
-          y_offset = glyph_pos[i].y_offset / 64.0;
-          x_advance = glyph_pos[i].x_advance / 64.0;
-          y_advance = glyph_pos[i].y_advance / 64.0;
-          draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
+      hb_position_t cursor_x = 0;
+      hb_position_t cursor_y = 0;
+      for (unsigned int i = 0; i &lt; glyph_count; i++) {
+          hb_codepoint_t glyphid  = glyph_info[i].codepoint;
+          hb_position_t x_offset  = glyph_pos[i].x_offset;
+          hb_position_t y_offset  = glyph_pos[i].y_offset;
+          hb_position_t x_advance = glyph_pos[i].x_advance;
+          hb_position_t y_advance = glyph_pos[i].y_advance;
+       /* draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); */
           cursor_x += x_advance;
           cursor_y += y_advance;
       }
@@ -294,7 +297,9 @@
     </orderedlist>
     <programlisting language="C">
       hb_buffer_destroy(buf);
-      hb_font_destroy(hb_ft_font);
+      hb_font_destroy(font);
+      hb_face_destroy(face);
+      hb_blob_destroy(blob);
     </programlisting>
     
     <para>
diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml
index 2b61ce8..760b9c5 100644
--- a/docs/usermanual-install-harfbuzz.xml
+++ b/docs/usermanual-install-harfbuzz.xml
@@ -11,27 +11,20 @@
     <title id="download.title">Downloading HarfBuzz</title>
     <para>
       The HarfBuzz source code is hosted at <ulink
-      url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>. The
-      same source tree is also available at the
-      <ulink
-	  url="http://cgit.freedesktop.org/harfbuzz/">Freedesktop.org</ulink>
-      site.
+      url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
     </para>
     <para>
       Tarball releases and Win32 binary bundles (which include the
       libharfbuzz DLL, hb-view.exe, hb-shape.exe, and all
       dependencies) of HarfBuzz can be downloaded from <ulink
-      url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz/releases</ulink>
-      or from 
-      <ulink url="http://www.freedesktop.org/software/harfbuzz/release/">Freedesktop.org</ulink>.
+      url="https://github.com/harfbuzz/harfbuzz/releases">github.com/harfbuzz/harfbuzz/releases</ulink>.
     </para>
     <para>
       Release notes are posted with each new release to provide an
       overview of the changes. The project <ulink url="https://github.com/harfbuzz/harfbuzz/issues">tracks bug
       reports and other issues</ulink> on GitHub. Discussion and
-      questions are welcome on the <ulink
-      url="http://freedesktop.org/mailman/listinfo/harfbuzz/">HarfBuzz
-      mailing list</ulink>.
+      questions are welcome on <ulink
+      url="https://github.com/harfbuzz/harfbuzz/discussions">GitHub</ulink> as well.
     </para>
     <para>
       The API included in the <filename
@@ -56,13 +49,9 @@
     </para>
     <para>
       For example, on an Ubuntu or Debian system, you would run:
-      <programlisting>
-	<command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
-      </programlisting>
+      <programlisting><command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package></programlisting>
       On Fedora, RHEL, CentOS, or other Red-Hat&ndash;based systems, you would run:
-      <programlisting>
-	<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
-      </programlisting>
+      <programlisting><command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package></programlisting>
 
     </para>
     
@@ -77,8 +66,8 @@
     </para>
     <para>
       From a shell in the top-level directory of the extracted source
-      code, you can run <command>./configure</command> followed by
-      <command>make</command> as with any other standard package.
+      code, you can run <command>meson build</command> followed by
+      <command>meson compile -C build</command> as with any other standard package.
     </para>
     <para>
       This should leave you with a shared
@@ -91,25 +80,19 @@
       <emphasis>(2)(b)</emphasis> If you are building from the source in the HarfBuzz git
       repository, rather than installing from a downloaded tarball
       release, then you must install two more auxiliary tools before you 
-      can build for the first time: <package>pkg-config</package> and
-      <ulink url="http://www.complang.org/ragel/">ragel</ulink>.
+      can build for the first time: <package>pkg-config</package>.
     </para>
     <para>
       On Ubuntu or Debian, run:
-      <programlisting>
-	<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
-      </programlisting>
+      <programlisting><command>sudo apt-get install</command> <package>meson pkg-config gtk-doc-tools</package></programlisting>
       On Fedora, RHEL, CentOS, run:
-      <programlisting>
-	<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
-      </programlisting>
+      <programlisting><command>sudo yum install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
       
     </para>
     <para>
-      With <package>pkg-config</package> and <package>ragel</package>
-      installed, you can now run <command>./autogen.sh</command>,
-      followed by <command>./configure</command> and
-      <command>make</command> to build HarfBuzz.
+      With <package>pkg-config</package> installed, you can now run
+      <command>meson build</command> then
+      <command>meson compile -C build</command> to build HarfBuzz.
     </para>
     </section>
 
@@ -118,18 +101,11 @@
       <title>Building on Windows</title>
 
       <para>
-	On Windows, consider using Microsoft's free <ulink
-	url="https://github.com/Microsoft/vcpkg">vcpkg</ulink> utility
-	to build HarfBuzz, its dependencies, and other open-source
-	libraries. 
-      </para>
-      <para>
-	If you need to build HarfBuzz from source, first put the
-	<package>ragel</package> binary on your
-	<literal>PATH</literal>, then follow the appveyor CI cmake
-	<ulink
-	    url="https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml">build
-	instructions</ulink>. 
+        <ulink url="https://mesonbuild.com/Getting-meson.html">Install meson</ulink>
+        and run (from the console) <command>meson build</command> (by default
+        bundled dependencies are not built, <command>--wrap-mode=default</command>
+        overrides this), then <command>meson compile -C build</command> to
+	build HarfBuzz.
       </para>
     </section>
 
@@ -146,15 +122,11 @@
 	<emphasis>(1)</emphasis> You must first install the
 	development packages for FreeType, Cairo, and GLib. If you are
 	using MacPorts, you should run:
-      <programlisting>
-	<command>sudo port install</command> <package>freetype glib2 cairo</package>
-      </programlisting>
+      <programlisting><command>sudo port install</command> <package>freetype glib2 cairo</package></programlisting>
       </para>
       <para>
 	If you are using Homebrew, you should run:
-	<programlisting>	
-	  <command>brew install</command> <package>freetype glib cairo</package>
-	</programlisting>
+	<programlisting><command>brew install</command> <package>freetype glib cairo</package></programlisting>
       </para>
       <para>
 	<emphasis>(2)</emphasis> The next step depends on whether you are building from the
@@ -165,13 +137,9 @@
 	<emphasis>(2)(a)</emphasis> If you are installing HarfBuzz
 	from a downloaded tarball release, extract the tarball and
 	open a Terminal in the extracted source-code directory. Run:
-	<programlisting>
-	  <command>./configure</command>
-	</programlisting>
+	<programlisting><command>meson build</command></programlisting>
 	followed by:
-	<programlisting>	
-	  <command>make</command>
-	</programlisting>
+	<programlisting><command>meson compile -C build</command></programlisting>
 	to build HarfBuzz.
       </para>
       <para>
@@ -182,30 +150,20 @@
       </para>
       <para>If you are
 	using MacPorts, you should run:
-      <programlisting>
-	<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package> 
-      </programlisting>
+      <programlisting><command>sudo port install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
       to install the build dependencies.
       </para>
       <para>If you are using Homebrew, you should run:
-	<programlisting>	
-	  <command>brew install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
-	</programlisting>
+	<programlisting><command>brew install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
       	Finally, you can run:
-	<programlisting>
-	  <command>./autogen.sh</command>
-	</programlisting>
+	<programlisting><command>meson build</command></programlisting>
       </para>
       <para>
 	<emphasis>(3)</emphasis> You can now build HarfBuzz (on either
 	a MacPorts or a Homebrew system) by running:
-	<programlisting>
-	  <command>./configure</command>
-	</programlisting>
+	<programlisting><command>meson build</command></programlisting>
 	followed by:
-	<programlisting>
-	  <command>make</command>
-	</programlisting>
+	<programlisting><command>meson compile -C build</command></programlisting>
       </para>
       <para>
 	This should leave you with a shared
@@ -227,22 +185,9 @@
       </para>
 
       <variablelist>
-	<?dbfo list-presentation="blocks"?> 
+	<?dbfo list-presentation="blocks"?>	
 	<varlistentry>
-	  <term><command>--with-libstdc++</command></term>
-	  <listitem>
-	    <para>
-	      Allow linking with libstdc++. <emphasis>(Default = no)</emphasis>
-	    </para>
-	    <para>
-	      This option enables or disables linking HarfBuzz to the
-	      system's libstdc++ library.
-	    </para>
-	  </listitem>
-	</varlistentry>
-	
-	<varlistentry>
-	  <term><command>--with-glib</command></term>
+	  <term><command>-Dglib=enabled</command></term>
 	  <listitem>
 	    <para>
 	     Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
@@ -258,7 +203,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-gobject</command></term>
+	  <term><command>-Dgobject=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
@@ -274,7 +219,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-cairo</command></term>
+	  <term><command>-Dcairo=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
@@ -293,27 +238,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-fontconfig</command></term>
-	  <listitem>
-	    <para>
-	      Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
-	    </para>
-	    <para>
-	      This option enables or disables usage of the Fontconfig
-	      library, which provides font-matching functions and
-	      provides access to font properties. The default setting
-	      is to check for the presence of Fontconfig and, if it is
-	      found, build with Fontconfig support.
-	    </para>
-	    <para>
-	      Note: Fontconfig is used only by the HarfBuzz
-	      command-line utilities, and not by the HarfBuzz library.
-	    </para>
-	  </listitem>
-	</varlistentry>
-	
-	<varlistentry>
-	  <term><command>--with-icu</command></term>
+	  <term><command>-Dicu=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
@@ -331,7 +256,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-graphite2</command></term>
+	  <term><command>-Dgraphite=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
@@ -345,7 +270,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-freetype</command></term>
+	  <term><command>-Dfreetype=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
@@ -360,7 +285,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-uniscribe</command></term>
+	  <term><command>-Dgdi=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink
@@ -378,7 +303,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-directwrite</command></term>
+	  <term><command>-Ddirectwrite=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
@@ -394,7 +319,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term><command>--with-coretext</command></term>
+	  <term><command>-Dcoretext=enabled</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
@@ -407,10 +332,10 @@
 	</varlistentry>	
 
 	<varlistentry>
-	  <term><command>--enable-gtk-doc</command></term>
+	  <term><command>-Ddocs=enabled</command></term>
 	  <listitem>
 	    <para>
-	      Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
+	      Use <ulink url="https://github.com/GNOME/gtk-doc">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
 	    </para>
 	    <para>
 	      This option enables the building of the documentation.
diff --git a/docs/usermanual-integration.xml b/docs/usermanual-integration.xml
new file mode 100644
index 0000000..78c9a0e
--- /dev/null
+++ b/docs/usermanual-integration.xml
@@ -0,0 +1,603 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<chapter id="integration">
+  <title>Platform Integration Guide</title>
+  <para>
+    HarfBuzz was first developed for use with the GNOME and GTK
+    software stack commonly found in desktop Linux
+    distributions. Nevertheless, it can be used on other operating
+    systems and platforms, from iOS and macOS to Windows. It can also
+    be used with other application frameworks and components, such as
+    Android, Qt, or application-specific widget libraries.
+  </para>
+  <para>
+    This chapter will look at how HarfBuzz fits into a typical
+    text-rendering pipeline, and will discuss the APIs available to
+    integrate HarfBuzz with contemporary Linux, Mac, and Windows
+    software. It will also show how HarfBuzz integrates with popular
+    external libraries like FreeType and International Components for
+    Unicode (ICU) and describe the HarfBuzz language bindings for
+    Python.
+  </para>
+  <para>
+    On a GNOME system, HarfBuzz is designed to tie in with several
+    other common system libraries. The most common architecture uses
+    Pango at the layer directly "above" HarfBuzz; Pango is responsible
+    for text segmentation and for ensuring that each input
+    <type>hb_buffer_t</type> passed to HarfBuzz for shaping contains
+    Unicode code points that share the same segment properties
+    (namely, direction, language, and script, but also higher-level
+    properties like the active font, font style, and so on).
+  </para>
+  <para>
+    The layer directly "below" HarfBuzz is typically FreeType, which
+    is used to rasterize glyph outlines at the necessary optical size,
+    hinting settings, and pixel resolution. FreeType provides APIs for
+    accessing font and face information, so HarfBuzz includes
+    functions to create <type>hb_face_t</type> and
+    <type>hb_font_t</type> objects directly from FreeType
+    objects. HarfBuzz can use FreeType's built-in functions for
+    <structfield>font_funcs</structfield> vtable in an <type>hb_font_t</type>.
+  </para>
+  <para>
+    FreeType's output is bitmaps of the rasterized glyphs; on a
+    typical Linux system these will then be drawn by a graphics
+    library like Cairo, but those details are beyond HarfBuzz's
+    control. On the other hand, at the top end of the stack, Pango is
+    part of the larger GNOME framework, and HarfBuzz does include APIs
+    for working with key components of GNOME's higher-level libraries
+    &mdash; most notably GLib.
+  </para>
+  <para>
+    For other operating systems or application frameworks, the
+    critical integration points are where HarfBuzz gets font and face
+    information about the font used for shaping and where HarfBuzz
+    gets Unicode data about the input-buffer code points.
+  </para>
+  <para>
+    The font and face information is necessary for text shaping
+    because HarfBuzz needs to retrieve the glyph indices for
+    particular code points, and to know the extents and advances of
+    glyphs. Note that, in an OpenType variable font, both of those
+    types of information can change with different variation-axis
+    settings.
+  </para>
+  <para>
+    The Unicode information is necessary for shaping because the
+    properties of a code point (such as its General Category (gc),
+    Canonical Combining Class (ccc), and decomposition) can directly
+    impact the shaping moves that HarfBuzz performs.
+  </para>
+  
+  <section id="integration-glib">
+    <title>GNOME integration, GLib, and GObject</title>
+    <para>
+      As mentioned in the preceding section, HarfBuzz offers
+      integration APIs to help client programs using the
+      GNOME and GTK framework commonly found in desktop Linux
+      distributions. 
+    </para>
+    <para>
+      GLib is the main utility library for GNOME applications. It
+      provides basic data types and conversions, file abstractions,
+      string manipulation, and macros, as well as facilities like
+      memory allocation and the main event loop.
+    </para>
+    <para>
+      Where text shaping is concerned, GLib provides several utilities
+      that HarfBuzz can take advantage of, including a set of
+      Unicode-data functions and a data type for script
+      information. Both are useful when working with HarfBuzz
+      buffers. To make use of them, you will need to include the
+      <filename>hb-glib.h</filename> header file.
+    </para>
+    <para>
+      GLib's <ulink
+      url="https://developer.gnome.org/glib/stable/glib-Unicode-Manipulation.html">Unicode
+      manipulation API</ulink> includes all the functionality
+      necessary to retrieve Unicode data for the
+      <structfield>unicode_funcs</structfield> structure of a HarfBuzz
+      <type>hb_buffer_t</type>. 
+    </para>
+    <para>
+      The function <function>hb_glib_get_unicode_funcs()</function>
+      sets up a <type>hb_unicode_funcs_t</type> structure configured
+      with the GLib Unicode functions and returns a pointer to it.
+    </para>
+    <para>
+      You can attach this Unicode-functions structure to your buffer,
+      and it will be ready for use with GLib:
+    </para>
+    <programlisting language="C">
+      #include &lt;hb-glib.h&gt;
+      ...
+      hb_unicode_funcs_t *glibufunctions;
+      glibufunctions = hb_glib_get_unicode_funcs();
+      hb_buffer_set_unicode_funcs(buf, glibufunctions);
+    </programlisting>
+    <para>
+      For script information, GLib uses the
+      <type>GUnicodeScript</type> type. Like HarfBuzz's own
+      <type>hb_script_t</type>, this data type is an enumeration
+      of Unicode scripts, but text segments passed in from GLib code
+      will be tagged with a <type>GUnicodeScript</type>. Therefore,
+      when setting the script property on a <type>hb_buffer_t</type>,
+      you will need to convert between the <type>GUnicodeScript</type>
+      of the input provided by GLib and HarfBuzz's
+      <type>hb_script_t</type> type.
+    </para>
+    <para>
+      The <function>hb_glib_script_to_script()</function> function
+      takes an <type>GUnicodeScript</type> script identifier as its
+      sole argument and returns the corresponding <type>hb_script_t</type>.
+      The <function>hb_glib_script_from_script()</function> does the
+      reverse, taking an <type>hb_script_t</type> and returning the
+      <type>GUnicodeScript</type> identifier for GLib.
+    </para>
+    <para>
+      Finally, GLib also provides a reference-counted object type called <ulink
+      url="https://developer.gnome.org/glib/stable/glib-Byte-Arrays.html#GBytes"><type>GBytes</type></ulink>
+      that is used for accessing raw memory segments with the benefits
+      of GLib's lifecycle management. HarfBuzz provides a
+      <function>hb_glib_blob_create()</function> function that lets
+      you create an <type>hb_blob_t</type> directly from a
+      <type>GBytes</type> object. This function takes only the
+      <type>GBytes</type> object as its input; HarfBuzz registers the
+      GLib <function>destroy</function> callback automatically.
+    </para>
+    <para>
+      The GNOME platform also features an object system called
+      GObject. For HarfBuzz, the main advantage of GObject is a
+      feature called <ulink
+      url="https://gi.readthedocs.io/en/latest/">GObject
+      Introspection</ulink>. This is a middleware facility that can be
+      used to generate language bindings for C libraries. HarfBuzz uses it
+      to build its Python bindings, which we will look at in a separate section.
+    </para>
+  </section>
+  
+  <section id="integration-freetype">
+    <title>FreeType integration</title>
+    <para>
+      FreeType is the free-software font-rendering engine included in
+      desktop Linux distributions, Android, ChromeOS, iOS, and multiple Unix
+      operating systems, and used by cross-platform programs like
+      Chrome, Java, and GhostScript. Used together, HarfBuzz can
+      perform shaping on Unicode text segments, outputting the glyph
+      IDs that FreeType should rasterize from the active font as well
+      as the positions at which those glyphs should be drawn.
+    </para>
+    <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
+      FreeType-integration API, include the
+      <filename>hb-ft.h</filename> header.
+    </para>
+    <para>
+      In a typical client program, you will create your
+      <type>hb_face_t</type> face object and <type>hb_font_t</type>
+      font object from a FreeType <type>FT_Face</type>. HarfBuzz
+      provides a suite of functions for doing this.
+    </para>
+    <para>
+      In the most common case, you will want to use
+      <function>hb_ft_font_create_referenced()</function>, which
+      creates both an <type>hb_face_t</type> face object and
+      <type>hb_font_t</type> font object (linked to that face object),
+      and provides lifecycle management.
+    </para>
+    <para>
+      It is important to note,
+      though, that while HarfBuzz makes a distinction between its face and
+      font objects, FreeType's <type>FT_Face</type> does not. After
+      you create your <type>FT_Face</type>, you must set its size
+      parameter using <function>FT_Set_Char_Size()</function>, because
+      an <type>hb_font_t</type> is defined as an instance of an
+      <type>hb_face_t</type> with size specified.
+    </para>
+    <programlisting language="C">
+      #include &lt;hb-ft.h&gt;
+      ...
+      FT_New_Face(ft_library, font_path, index, &amp;face);
+      FT_Set_Char_Size(face, 0, 1000, 0, 0);
+      hb_font_t *font = hb_ft_font_create(face);
+    </programlisting>
+    <para>
+      <function>hb_ft_font_create_referenced()</function> is
+      the recommended function for creating an <type>hb_face_t</type> face
+      object. This function calls <function>FT_Reference_Face()</function>
+      before using the <type>FT_Face</type> and calls 
+      <function>FT_Done_Face()</function> when it is finished using the
+      <type>FT_Face</type>. Consequently, your client program does not need
+      to worry about destroying the <type>FT_Face</type> while HarfBuzz
+      is still using it.
+    </para>
+    <para>
+      Although <function>hb_ft_font_create_referenced()</function> is
+      the recommended function, there is another variant for client code
+      where special circumstances make it necessary. The simpler
+      version of the function is <function>hb_ft_font_create()</function>,
+      which takes an <type>FT_Face</type> and an optional destroy callback 
+      as its arguments. Because <function>hb_ft_font_create()</function> 
+      does not offer lifecycle management, however, your client code will
+      be responsible for tracking references to the <type>FT_Face</type>
+      objects and destroying them when they are no longer needed. If you
+      do not have a valid reason for doing this, use
+      <function>hb_ft_font_create_referenced()</function>. 
+    </para>
+    <para>
+      After you have created your font object from your
+      <type>FT_Face</type>, you can set or retrieve the
+      <structfield>load_flags</structfield> of the
+      <type>FT_Face</type> through the <type>hb_font_t</type>
+      object. HarfBuzz provides
+      <function>hb_ft_font_set_load_flags()</function> and
+      <function>hb_ft_font_get_load_flags()</function> for this
+      purpose. The ability to set the
+      <structfield>load_flags</structfield> through the font object
+      could be useful for enabling or disabling hinting, for example,
+      or to activate vertical layout.
+    </para>
+    <para>
+      HarfBuzz also provides a utility function called
+      <function>hb_ft_font_has_changed()</function> that you should
+      call whenever you have altered the properties of your underlying
+      <type>FT_Face</type>, as well as a
+      <function>hb_ft_get_face()</function> that you can call on an
+      <type>hb_font_t</type> font object to fetch its underlying <type>FT_Face</type>.
+    </para>
+    <para>
+      With an <type>hb_face_t</type> and <type>hb_font_t</type> both linked
+      to your <type>FT_Face</type>, you will typically also want to
+      use FreeType for the <structfield>font_funcs</structfield>
+      vtable of your <type>hb_font_t</type>. As a reminder, this
+      font-functions structure is the set of methods that HarfBuzz
+      will use to fetch important information from the font, such as
+      the advances and extents of individual glyphs. 
+    </para>
+    <para>
+      All you need to do is call
+    </para>
+    <programlisting language="C">
+      hb_ft_font_set_funcs(font);
+    </programlisting>
+    <para>
+      and HarfBuzz will use FreeType for the font-functions in
+      <literal>font</literal>. 
+    </para>
+    <para>
+      As we noted above, an <type>hb_font_t</type> is derived from an
+      <type>hb_face_t</type> with size (and, perhaps, other
+      parameters, such as variation-axis coordinates)
+      specified. Consequently, you can reuse an <type>hb_face_t</type>
+      with several <type>hb_font_t</type> objects, and HarfBuzz
+      provides functions to simplify this.
+    </para>
+    <para>
+      The <function>hb_ft_face_create_referenced()</function>
+      function creates just an <type>hb_face_t</type> from a FreeType
+      <type>FT_Face</type> and, as with
+      <function>hb_ft_font_create_referenced()</function> above,
+      provides lifecycle management for the <type>FT_Face</type>.
+    </para>
+    <para>
+      Similarly, there is an <function>hb_ft_face_create()</function>
+      function variant that does not provide the lifecycle-management
+      feature. As with the font-object case, if you use this version
+      of the function, it will be your client code's respsonsibility
+      to track usage of the <type>FT_Face</type> objects.
+    </para>
+    <para>
+      A third variant of this function is
+      <function>hb_ft_face_create_cached()</function>, which is the
+      same as <function>hb_ft_face_create()</function> except that it
+      also uses the <structfield>generic</structfield> field of the
+      <type>FT_Face</type> structure to save a pointer to the newly
+      created <type>hb_face_t</type>. Subsequently, function calls
+      that pass the same <type>FT_Face</type> will get the same
+      <type>hb_face_t</type> returned &mdash; and the
+      <type>hb_face_t</type> will be correctly reference
+      counted. Still, as with
+      <function>hb_ft_face_create()</function>, your client code must
+      track references to the <type>FT_Face</type> itself, and destroy
+      it when it is unneeded.
+    </para>
+  </section>
+  
+  <section id="integration-uniscribe">
+    <title>Uniscribe integration</title>
+    <para>
+      If your client program is running on Windows, HarfBuzz offers
+      an additional API that can help integrate with Microsoft's
+      Uniscribe engine and the Windows GDI.
+    </para>
+    <para>
+      Overall, the Uniscribe API covers a broader set of typographic
+      layout functions than HarfBuzz implements, but HarfBuzz's
+      shaping API can serve as a drop-in replacement for Uniscribe's shaping
+      functionality. In fact, one of HarfBuzz's design goals is to
+      accurately reproduce the same output for shaping a given text
+      segment that Uniscribe produces &mdash; even to the point of
+      duplicating known shaping bugs or deviations from the
+      specification &mdash; so you can be confident that your users'
+      documents with their existing fonts will not be affected adversely by
+      switching to HarfBuzz.
+    </para>
+    <para>
+      At a basic level, HarfBuzz's <function>hb_shape()</function>
+      function replaces both the <ulink url=""><function>ScriptShape()</function></ulink>
+      and <ulink
+      url="https://docs.microsoft.com/en-us/windows/desktop/api/Usp10/nf-usp10-scriptplace"><function>ScriptPlace()</function></ulink>
+      functions from Uniscribe. 
+    </para>
+    <para>
+      However, whereas <function>ScriptShape()</function> returns the
+      glyphs and clusters for a shaped sequence and
+      <function>ScriptPlace()</function> returns the advances and
+      offsets for those glyphs, <function>hb_shape()</function>
+      handles both. After <function>hb_shape()</function> shapes a
+      buffer, the output glyph IDs and cluster IDs are returned as
+      an array of <structname>hb_glyph_info_t</structname> structures, and the
+      glyph advances and offsets are returned as an array of
+      <structname>hb_glyph_position_t</structname> structures. 
+    </para>
+    <para>
+      Your client program only needs to ensure that it coverts
+      correctly between HarfBuzz's low-level data types (such as
+      <type>hb_position_t</type>) and Windows's corresponding types
+      (such as <type>GOFFSET</type> and <type>ABC</type>). Be sure you
+      read the <xref linkend="buffers-language-script-and-direction"
+      /> 
+      chapter for a full explanation of how HarfBuzz input buffers are
+      used, and see <xref linkend="shaping-buffer-output" /> for the
+      details of what <function>hb_shape()</function> returns in the
+      output buffer when shaping is complete. 
+    </para>
+    <para>
+      Although <function>hb_shape()</function> itself is functionally
+      equivalent to Uniscribe's shaping routines, there are two
+      additional HarfBuzz functions you may want to use to integrate
+      the libraries in your code. Both are used to link HarfBuzz font
+      objects to the equivalent Windows structures.
+    </para>
+    <para>
+      The <function>hb_uniscribe_font_get_logfontw()</function>
+      function takes a <type>hb_font_t</type> font object and returns
+      a pointer to the <ulink
+      url="https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-logfontw"><type>LOGFONTW</type></ulink>
+      "logical font" that corresponds to it. A <type>LOGFONTW</type>
+      structure holds font-wide attributes, including metrics, size,
+      and style information.
+    </para>
+<!--      
+     <para>
+       In Uniscribe's model, the <type>SCRIPT_CACHE</type> holds the
+       device context, including the logical font that the shaping
+       functions apply.
+       https://docs.microsoft.com/en-us/windows/desktop/Intl/script-cache
+    </para>
+-->
+    <para>
+      The <function>hb_uniscribe_font_get_hfont()</function> function
+      also takes a <type>hb_font_t</type> font object, but it returns
+      an <type>HFONT</type> &mdash; a handle to the underlying logical
+      font &mdash; instead.
+    </para>
+    <para>
+      <type>LOGFONTW</type>s and <type>HFONT</type>s are both needed
+      by other Uniscribe functions.
+    </para>
+    <para>
+      As a final note, you may notice a reference to an optional
+      <literal>uniscribe</literal> shaper back-end in the <xref
+      linkend="configuration" /> section of the HarfBuzz manual. This
+      option is not a Uniscribe-integration facility.
+    </para>
+    <para>
+      Instead, it is a internal code path used in the
+      <command>hb-shape</command> command-line utility, which hands
+      shaping functionality over to Uniscribe entirely, when run on a
+      Windows system. That allows testing HarfBuzz's native output
+      against the Uniscribe engine, for tracking compatibility and
+      debugging.
+    </para>
+    <para>
+      Because this back-end is only used when testing HarfBuzz
+      functionality, it is disabled by default when building the
+      HarfBuzz binaries.
+    </para>
+  </section>
+   
+  <section id="integration-coretext">
+    <title>Core Text integration</title>
+    <para>
+      If your client program is running on macOS or iOS, HarfBuzz offers
+      an additional API that can help integrate with Apple's
+      Core Text engine and the underlying Core Graphics
+      framework. HarfBuzz does not attempt to offer the same
+      drop-in-replacement functionality for Core Text that it strives
+      for with Uniscribe on Windows, but you can still use HarfBuzz
+      to perform text shaping in native macOS and iOS applications.
+    </para>
+    <para>
+      Note, though, that if your interest is just in using fonts that
+      contain Apple Advanced Typography (AAT) features, then you do
+      not need to add Core Text integration. HarfBuzz natively
+      supports AAT features and will shape AAT fonts (on any platform)
+      automatically, without requiring additional work on your
+      part. This includes support for AAT-specific TrueType tables
+      such as <literal>mort</literal>, <literal>morx</literal>, and
+      <literal>kerx</literal>, which AAT fonts use instead of
+      <literal>GSUB</literal> and <literal>GPOS</literal>.
+    </para>
+    <para>
+      On a macOS or iOS system, the primary integration points offered
+      by HarfBuzz are for face objects and font objects. 
+    </para>
+    <para>
+      The Apple APIs offer a pair of data structures that map well to
+      HarfBuzz's face and font objects. The Core Graphics API, which
+      is slightly lower-level than Core Text, provides
+      <ulink url="https://developer.apple.com/documentation/coregraphics/cgfontref"><type>CGFontRef</type></ulink>, which enables access to typeface
+      properties, but does not include size information. Core Text's
+      <ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analagous to a HarfBuzz font object,
+      with all of the properties required to render text at a specific
+      size and configuration.
+      Consequently, a HarfBuzz <type>hb_font_t</type> font object can
+      be hooked up to a Core Text <type>CTFontRef</type>, and a HarfBuzz
+      <type>hb_face_t</type> face object can be hooked up to a
+      <type>CGFontRef</type>.
+    </para>
+    <para>
+      You can create a <type>hb_face_t</type> from a
+      <type>CGFontRef</type> by using the
+      <function>hb_coretext_face_create()</function>. Subsequently,
+      you can retrieve the <type>CGFontRef</type> from a
+      <type>hb_face_t</type> with <function>hb_coretext_face_get_cg_font()</function>.
+    </para>
+    <para>
+      Likewise, you create a <type>hb_font_t</type> from a
+      <type>CTFontRef</type> by calling
+      <function>hb_coretext_font_create()</function>, and you can
+      fetch the associated <type>CTFontRef</type> from a
+      <type>hb_font_t</type> font object with
+      <function>hb_coretext_face_get_ct_font()</function>. 
+    </para>
+    <para>
+      HarfBuzz also offers a <function>hb_font_set_ptem()</function>
+      that you an use to set the nominal point size on any
+      <type>hb_font_t</type> font object. Core Text uses this value to
+      implement optical scaling. 
+    </para>
+    <para>
+      When integrating your client code with Core Text, it is
+      important to recognize that Core Text <literal>points</literal>
+      are not typographic points (standardized at 72 per inch) as the
+      term is used elsewhere in OpenType. Instead, Core Text points
+      are CSS points, which are standardized at 96 per inch.
+    </para>
+    <para>
+      HarfBuzz's font functions take this distinction into account,
+      but it can be an easy detail to miss in cross-platform
+      code. 
+    </para>
+    <para>
+      As a final note, you may notice a reference to an optional
+      <literal>coretext</literal> shaper back-end in the <xref
+      linkend="configuration" /> section of the HarfBuzz manual. This
+      option is not a Core Text-integration facility.
+    </para>
+    <para>
+      Instead, it is a internal code path used in the
+      <command>hb-shape</command> command-line utility, which hands
+      shaping functionality over to Core Text entirely, when run on a
+      macOS system. That allows testing HarfBuzz's native output
+      against the Core Text engine, for tracking compatibility and debugging.
+    </para>
+    <para>
+      Because this back-end is only used when testing HarfBuzz
+      functionality, it is disabled by default when building the
+      HarfBuzz binaries.
+    </para>
+  </section>
+  
+  <section id="integration-icu">
+    <title>ICU integration</title>
+    <para>
+      Although HarfBuzz includes its own Unicode-data functions, it
+      also provides integration APIs for using the International
+      Components for Unicode (ICU) library as a source of Unicode data
+      on any supported platform.
+    </para>
+    <para>
+      The principal integration point with ICU is the
+      <type>hb_unicode_funcs_t</type> Unicode-functions structure
+      attached to a buffer. This structure holds the virtual methods
+      used for retrieving Unicode character properties, such as
+      General Category, Script, Combining Class, decomposition
+      mappings, and mirroring information.
+    </para>
+    <para>
+      To use ICU in your client program, you need to call
+      <function>hb_icu_get_unicode_funcs()</function>, which creates a
+      Unicode-functions structure populated with the ICU function for
+      each included method. Subsequently, you can attach the
+      Unicode-functions structure to your buffer:
+    </para>
+    <programlisting language="C">
+      hb_unicode_funcs_t *icufunctions;
+      icufunctions = hb_icu_get_unicode_funcs();
+      hb_buffer_set_unicode_funcs(buf, icufunctions);
+    </programlisting>
+    <para>
+      and ICU will be used for Unicode-data access.
+    </para>
+    <para>
+      HarfBuzz also supplies a pair of functions
+      (<function>hb_icu_script_from_script()</function> and
+      <function>hb_icu_script_to_script()</function>) for converting
+      between ICU's and HarfBuzz's internal enumerations of Unicode
+      scripts. The <function>hb_icu_script_from_script()</function>
+      function converts from a HarfBuzz <type>hb_script_t</type> to an
+      ICU <type>UScriptCode</type>. The
+      <function>hb_icu_script_to_script()</function> function does the
+      reverse: converting from a <type>UScriptCode</type> identifier
+      to a <type>hb_script_t</type>.
+    </para>
+    <para>
+      By default, HarfBuzz's ICU support is built as a separate shared
+      library (<filename class="libraryfile">libharfbuzz-icu.so</filename>)
+      when compiling HarfBuzz from source. This allows client programs
+      that do not need ICU to link against HarfBuzz without unnecessarily
+      adding ICU as a dependency. You can also build HarfBuzz with ICU
+      support built directly into the main HarfBuzz shared library
+      (<filename class="libraryfile">libharfbuzz.so</filename>),
+      by specifying the <literal>--with-icu=builtin</literal>
+      compile-time option.
+    </para>
+
+  </section>
+  
+  <section id="integration-python">
+    <title>Python bindings</title>
+    <para>
+      As noted in the <xref linkend="integration-glib" /> section,
+      HarfBuzz uses a feature called <ulink
+      url="https://wiki.gnome.org/Projects/GObjectIntrospection">GObject
+      Introspection</ulink> (GI) to provide bindings for Python.
+    </para>
+    <para>
+      At compile time, the GI scanner analyzes the HarfBuzz C source
+      and builds metadata objects connecting the language bindings to
+      the C library. Your Python code can then use the HarfBuzz binary
+      through its Python interface.
+    </para>
+    <para>
+      HarfBuzz's Python bindings support Python 2 and Python 3. To use
+      them, you will need to have the <literal>pygobject</literal>
+      package installed. Then you should import
+      <literal>HarfBuzz</literal> from
+      <literal>gi.repository</literal>: 
+    </para>
+    <programlisting language="Python">
+      from gi.repository import HarfBuzz
+    </programlisting>
+    <para>
+      and you can call HarfBuzz functions from Python. Sample code can
+      be found in the <filename>sample.py</filename> script in the
+      HarfBuzz <filename>src</filename> directory.
+    </para>
+    <para>
+      Do note, however, that the Python API is subject to change
+      without advance notice. GI allows the bindings to be
+      automatically updated, which is one of its advantages, but you
+      may need to update your Python code.
+    </para>
+  </section>
+  
+</chapter>
diff --git a/docs/usermanual-object-model.xml b/docs/usermanual-object-model.xml
index f571c47..23065bf 100644
--- a/docs/usermanual-object-model.xml
+++ b/docs/usermanual-object-model.xml
@@ -232,7 +232,7 @@
       different.
     </para>
     <para>
-      Blobs are an abstraction desgined to negotiate lifecycle and
+      Blobs are an abstraction designed to negotiate lifecycle and
       permissions for raw pieces of data.  For example, when you load
       the raw font data into memory and want to pass it to HarfBuzz,
       you do so in a <literal>hb_blob_t</literal> wrapper.
@@ -244,7 +244,7 @@
       <function>malloc()</function>, you would create the blob using
     </para>
     <programlisting language="C">
-      hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
+      hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free)
     </programlisting>
     <para>
       That way, HarfBuzz will call <function>free()</function> on the
diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml
index 881af2a..e9ea145 100644
--- a/docs/usermanual-opentype-features.xml
+++ b/docs/usermanual-opentype-features.xml
@@ -48,14 +48,14 @@
     <para>
       If a font has a GDEF table, then that is used for
       glyph classes; if not, HarfBuzz will fall back to Unicode
-      categorization by code point. If a font has an AAT "morx" table,
+      categorization by code point. If a font has an AAT <literal>morx</literal> table,
       then it is used for substitutions; if not, but there is a GSUB
       table, then the GSUB table is used. If the font has an AAT
-      "kerx" table, then it is used for positioning; if not, but
+      <literal>kerx</literal> table, then it is used for positioning; if not, but
       there is a GPOS table, then the GPOS table is used. If neither
-      table is found, but there is a "kern" table, then HarfBuzz will
-      use the "kern" table. If there is no "kerx", no GPOS, and no
-      "kern", HarfBuzz will fall back to positioning marks itself.
+      table is found, but there is a <literal>kern</literal> table, then HarfBuzz will
+      use the <literal>kern</literal> table. If there is no <literal>kerx</literal>, no GPOS, and no
+      <literal>kern</literal>, HarfBuzz will fall back to positioning marks itself.
     </para>
     <para>
       With a well-behaved OpenType font, you expect GDEF, GSUB, and
@@ -149,10 +149,40 @@
       also applies the <literal>calt</literal>,
       <literal>clig</literal>, <literal>curs</literal>,
       <literal>dist</literal>, <literal>kern</literal>,
-      <literal>liga</literal>, <literal>rclt</literal>,
-      and <literal>frac</literal> features.
+      <literal>liga</literal> and <literal>rclt</literal>, features.
     </para>
     <para>
+      Additionally, when HarfBuzz encounters a fraction slash
+      (<literal>U+2044</literal>), it looks backward and forward for decimal
+      digits (Unicode General Category = Nd), and enables features
+      <literal>numr</literal> on the sequence before the fraction slash,
+      <literal>dnom</literal> on the sequence after the fraction slash,
+      and <literal>frac</literal> on the whole sequence including the fraction
+      slash.
+    </para>
+    <para>
+      Some script-specific shaping models
+      (see <xref linkend="opentype-shaping-models" />) disable some of the
+      features listed above:
+    </para>
+    <itemizedlist>
+      <listitem>
+        <para>
+          Hangul: <literal>calt</literal>
+	</para>
+      </listitem>
+      <listitem>
+        <para>
+          Indic: <literal>liga</literal>
+	</para>
+      </listitem>
+      <listitem>
+        <para>
+          Khmer: <literal>liga</literal>
+	</para>
+      </listitem>
+    </itemizedlist>
+    <para>
       If the text direction is vertical, HarfBuzz applies
       the <literal>vert</literal> feature by default.
     </para>
diff --git a/docs/usermanual-utilities.xml b/docs/usermanual-utilities.xml
index 1c5370c..0208dbf 100644
--- a/docs/usermanual-utilities.xml
+++ b/docs/usermanual-utilities.xml
@@ -10,16 +10,15 @@
     HarfBuzz includes several auxiliary components in addition to the
     main APIs. These include a set of command-line tools, a set of
     lower-level APIs for common data types that may be of interest to
-    client programs, and an embedded library for working with
-    Unicode Character Database (UCD) data.
+    client programs.
   </para>
   
   <section id="utilities-command-line-tools">
     <title>Command-line tools</title>
     <para>
       HarfBuzz include three command-line tools:
-      <program>hb-shape</program>, <program>hb-view</program>, and
-      <program>hb-subset</program>. They can be used to examine
+      <command>hb-shape</command>, <command>hb-view</command>, and
+      <command>hb-subset</command>. They can be used to examine
       HarfBuzz's functionality, debug font binaries, or explore the
       various shaping models and features from a terminal.
     </para>
@@ -27,12 +26,12 @@
     <section id="utilities-command-line-hbshape">
       <title>hb-shape</title>
       <para>
-	<emphasis><program>hb-shape</program></emphasis> allows you to run HarfBuzz's
+	<emphasis><command>hb-shape</command></emphasis> allows you to run HarfBuzz's
 	<function>hb_shape()</function> function on an input string and
 	to examine the outcome, in human-readable form, as terminal
-	output. <program>hb-shape</program> does
+	output. <command>hb-shape</command> does
 	<emphasis>not</emphasis> render the results of the shaping call
-	into rendered text (you can use <program>hb-view</program>, below, for
+	into rendered text (you can use <command>hb-view</command>, below, for
 	that). Instead, it prints out the final glyph indices and
 	positions, taking all shaping operations into account, as if the
 	input string were a HarfBuzz input buffer.
@@ -80,10 +79,10 @@
     <section id="utilities-command-line-hbview">
       <title>hb-view</title>
       <para>
-	<emphasis><program>hb-view</program></emphasis> allows you to
+	<emphasis><command>hb-view</command></emphasis> allows you to
 	see the shaped output of an input string in rendered
-	form. Like <program>hb-shape</program>,
-	<program>hb-view</program> takes a font file and a text string
+	form. Like <command>hb-shape</command>,
+	<command>hb-view</command> takes a font file and a text string
 	as its arguments:
       </para>
       <programlisting>
@@ -92,7 +91,7 @@
 	<parameter>yourinputtext</parameter>
       </programlisting>
       <para>
-	By default, <program>hb-view</program> renders the shaped
+	By default, <command>hb-view</command> renders the shaped
 	text in ASCII block-character images as terminal output. By
 	appending the
 	<command>--output-file=<optional>filename</optional></command>
@@ -100,7 +99,7 @@
 	(among other formats).
       </para>
       <para>
-	As with <program>hb-shape</program>, a lengthy set of options
+	As with <command>hb-shape</command>, a lengthy set of options
 	is available, with which you can  enable or disable
 	specific font features, set variation-font axis values,
 	alter the language, script, direction, and clustering settings
@@ -114,10 +113,10 @@
 	with 
       </para>
       <para>
-	In general, <program>hb-view</program> is a quick way to
+	In general, <command>hb-view</command> is a quick way to
 	verify that the output of HarfBuzz's shaping operation looks
 	correct for a given text-and-font combination, but you may
-	want to use <program>hb-shape</program> to figure out exactly
+	want to use <command>hb-shape</command> to figure out exactly
 	why something does not appear as expected.
       </para>
     </section>
@@ -125,13 +124,13 @@
     <section id="utilities-command-line-hbsubset">
       <title>hb-subset</title>
       <para>
-	<emphasis><program>hb-subset</program></emphasis> allows you
+	<emphasis><command>hb-subset</command></emphasis> allows you
 	to generate a subset of a given font, with a limited set of
 	supported characters, features, and variation settings.
       </para>
       <para>
 	By default, you provide an input font and an input text string
-	as the arguments to <program>hb-subset</program>, and it will
+	as the arguments to <command>hb-subset</command>, and it will
 	generate a font that covers the input text exactly like the
 	input font does, but includes no other characters or features.
       </para>
@@ -216,29 +215,4 @@
     </para>
   </section>
 
-  <section id="utilities-ucdn">
-    <title>UCDN</title>
-    <para>
-      HarfBuzz includes a copy of the <ulink
-      url="https://github.com/grigorig/ucdn">UCDN</ulink> (Unicode
-      Database and Normalization) library, which provides functions
-      for accessing basic Unicode character properties, performing
-      canonical composition, and performing both canonical and
-      compatibility decomposition.
-    </para>
-    <para>
-      Currently, UCDN supports direct queries for several more character
-      properties than HarfBuzz's built-in set of Unicode functions
-      does, such as the BiDirectional Class, East Asian Width, Paired
-      Bracket and Resolved Linebreak properties. If you need to access
-      more properties than HarfBuzz's internal implementation
-      provides, using the built-in UCDN functions may be a useful solution.
-    </para>
-    <para>
-      The built-in UCDN functions are compiled by default when
-      building HarfBuzz from source, but this can be disabled with a
-      compile-time switch.
-    </para>
-  </section>
-
 </chapter>
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml
index 3513fb2..4534783 100644
--- a/docs/usermanual-what-is-harfbuzz.xml
+++ b/docs/usermanual-what-is-harfbuzz.xml
@@ -226,7 +226,7 @@
   </section>
   
 
-  <section>
+  <section id="what-does-harfbuzz-do">
     <title>What does HarfBuzz do?</title>
     <para>
       HarfBuzz provides text shaping through a cross-platform
diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4
index 5032bba..8b6df5a 100644
--- a/m4/ax_cxx_compile_stdcxx.m4
+++ b/m4/ax_cxx_compile_stdcxx.m4
@@ -422,7 +422,7 @@
 
   }
 
-  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
   // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
   // because of this.
   namespace test_template_alias_sfinae
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..cd7acff
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,405 @@
+project('harfbuzz', 'c', 'cpp',
+  meson_version: '>= 0.52.0',
+  version: '3.1.1',
+  default_options: [
+    'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway
+    'cpp_std=c++11',
+    'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
+  ],
+)
+
+hb_version_arr = meson.project_version().split('.')
+hb_version_major = hb_version_arr[0].to_int()
+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_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'
+  # 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([
+  '-Bsymbolic-functions'
+]), language: 'c')
+
+add_project_arguments(cpp.get_supported_arguments([
+  '-fno-exceptions',
+  '-fno-rtti',
+  '-fno-threadsafe-statics',
+  '-fvisibility-inlines-hidden',
+]), language: 'cpp')
+
+if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1
+  if cpp.has_argument('-mstructure-size-boundary=8')
+    add_project_arguments('-mstructure-size-boundary=8', language: 'cpp')
+  endif
+endif
+
+check_headers = [
+  ['unistd.h'],
+  ['sys/mman.h'],
+  ['stdbool.h'],
+]
+
+check_funcs = [
+  ['atexit'],
+  ['mprotect'],
+  ['sysconf'],
+  ['getpagesize'],
+  ['mmap'],
+  ['isatty'],
+]
+
+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)
+  endif
+
+  if not freetype_dep.found()
+    # https://github.com/harfbuzz/harfbuzz/pull/2498
+    freetype_dep = dependency('freetype2', required: get_option('freetype'),
+                              fallback: ['freetype2', 'freetype_dep'],
+                              default_options: ['harfbuzz=disabled'])
+  endif
+endif
+
+glib_dep = dependency('glib-2.0', required: get_option('glib'),
+                      fallback: ['glib', 'libglib_dep'])
+gobject_dep = dependency('gobject-2.0', required: get_option('gobject'),
+                         fallback: ['glib', 'libgobject_dep'])
+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
+  endif
+
+  if not icu_dep.found()
+    icu_dep = dependency('icu-uc', required: get_option('icu'))
+  endif
+endif
+
+cairo_dep = null_dep
+cairo_ft_dep = null_dep
+if not get_option('cairo').disabled()
+  cairo_dep = dependency('cairo', required: false)
+  cairo_ft_dep = dependency('cairo-ft', required: false)
+
+  if (not cairo_dep.found() and
+      cpp.get_id() == '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',
+                                              prefix: '#include <cairo-ft.h>',
+                                              dependencies: cairo_dep)
+      cairo_ft_dep = cairo_dep
+    endif
+  endif
+
+  if not cairo_dep.found()
+    # Requires Meson 0.54.0 to use cairo subproject
+    if meson.version().version_compare('>=0.54.0')
+      # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback
+      # dependency cycle here because we have configured freetype2 above with
+      # harfbuzz support disabled, so when cairo will lookup freetype2 dependency
+      # it will be forced to use that one.
+      cairo_dep = dependency('cairo', fallback: 'cairo', required: get_option('cairo'))
+      cairo_ft_dep = dependency('cairo-ft', fallback: 'cairo', required: get_option('cairo'))
+    elif get_option('cairo').enabled()
+      error('cairo feature is enabled but it cannot be found on the system and ' +
+            'meson>=0.54.0 is required to build it as subproject')
+    endif
+  endif
+endif
+
+chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa'))
+
+conf = configuration_data()
+incconfig = include_directories('.')
+
+add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
+
+warn_cflags = [
+  '-Wno-non-virtual-dtor',
+]
+
+cpp_args = cpp.get_supported_arguments(warn_cflags)
+
+if glib_dep.found()
+  conf.set('HAVE_GLIB', 1)
+endif
+
+if gobject_dep.found()
+  conf.set('HAVE_GOBJECT', 1)
+endif
+
+if cairo_dep.found()
+  conf.set('HAVE_CAIRO', 1)
+endif
+
+if cairo_ft_dep.found()
+  conf.set('HAVE_CAIRO_FT', 1)
+endif
+
+if chafa_dep.found()
+  conf.set('HAVE_CHAFA', 1)
+endif
+
+if graphite2_dep.found() or graphite_dep.found()
+  conf.set('HAVE_GRAPHITE2', 1)
+endif
+
+if icu_dep.found()
+  conf.set('HAVE_ICU', 1)
+endif
+
+if get_option('icu_builtin')
+  conf.set('HAVE_ICU_BUILTIN', 1)
+endif
+
+if get_option('experimental_api')
+  conf.set('HB_EXPERIMENTAL_API', 1)
+endif
+
+if freetype_dep.found()
+  conf.set('HAVE_FREETYPE', 1)
+  check_freetype_funcs = [
+    ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
+    ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
+    ['FT_Done_MM_Var', {'deps': freetype_dep}],
+  ]
+
+  if freetype_dep.type_name() == 'internal'
+    foreach func: check_freetype_funcs
+      name = func[0]
+      conf.set('HAVE_@0@'.format(name.to_upper()), 1)
+    endforeach
+  else
+    check_funcs += check_freetype_funcs
+  endif
+endif
+
+gdi_uniscribe_deps = []
+# GDI (Uniscribe) (Windows)
+if host_machine.system() == 'windows' and not get_option('gdi').disabled()
+  if (get_option('directwrite').enabled() and
+      not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
+    error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
+  endif
+
+  gdi_deps_found = true
+  foreach usplib : ['usp10', 'gdi32', 'rpcrt4']
+    dep = cpp.find_library(usplib, required: get_option('gdi'))
+    gdi_deps_found = gdi_deps_found and dep.found()
+    gdi_uniscribe_deps += dep
+  endforeach
+
+  if gdi_deps_found
+    conf.set('HAVE_UNISCRIBE', 1)
+    conf.set('HAVE_GDI', 1)
+  endif
+endif
+
+# DirectWrite (Windows)
+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
+
+  conf.set('HAVE_DIRECTWRITE', 1)
+endif
+
+# CoreText (macOS)
+coretext_deps = []
+if host_machine.system() == 'darwin' and not get_option('coretext').disabled()
+  app_services_dep = dependency('appleframeworks', modules: ['ApplicationServices'], required: false)
+  if cpp.has_type('CTFontRef', prefix: '#include <ApplicationServices/ApplicationServices.h>', dependencies: app_services_dep)
+    coretext_deps += [app_services_dep]
+    conf.set('HAVE_CORETEXT', 1)
+  # On iOS CoreText and CoreGraphics are stand-alone frameworks
+  # Check for a different symbol to avoid getting cached result
+  else
+    coretext_dep = dependency('appleframeworks', modules: ['CoreText'], required: false)
+    coregraphics_dep = dependency('appleframeworks', modules: ['CoreGraphics'], required: false)
+    corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: false)
+    if cpp.has_type('CTRunRef', prefix: '#include <CoreText/CoreText.h>', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep])
+      coretext_deps += [coretext_dep, coregraphics_dep, corefoundation_dep]
+      conf.set('HAVE_CORETEXT', 1)
+    elif get_option('coretext').enabled()
+      error('CoreText was enabled explicitly, but required headers or frameworks are missing.')
+    endif
+  endif
+endif
+
+# threads
+thread_dep = null_dep
+if host_machine.system() != 'windows'
+  thread_dep = dependency('threads', required: false)
+
+  if thread_dep.found()
+    conf.set('HAVE_PTHREAD', 1)
+  endif
+endif
+
+conf.set_quoted('PACKAGE_NAME', 'HarfBuzz')
+conf.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+foreach check : check_headers
+  name = check[0]
+
+  if cpp.has_header(name)
+    conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1)
+  endif
+endforeach
+
+harfbuzz_extra_deps = []
+foreach check : check_funcs
+  name = check[0]
+  opts = check.get(1, {})
+  link_withs = opts.get('link_with', [])
+  check_deps = opts.get('deps', [])
+  extra_deps = []
+  found = true
+
+  # First try without linking
+  found = cpp.has_function(name, dependencies: check_deps)
+
+  if not found and link_withs.length() > 0
+    found = true
+
+    foreach link_with : link_withs
+      dep = cpp.find_library(link_with, required: false)
+      if dep.found()
+        extra_deps += dep
+      else
+        found = false
+      endif
+    endforeach
+
+    if found
+      found = cpp.has_function(name, dependencies: check_deps + extra_deps)
+    endif
+  endif
+
+  if found
+    harfbuzz_extra_deps += extra_deps
+    conf.set('HAVE_@0@'.format(name.to_upper()), 1)
+  endif
+endforeach
+
+subdir('src')
+subdir('util')
+
+if not get_option('tests').disabled()
+  subdir('test')
+endif
+
+if not get_option('benchmark').disabled()
+  subdir('perf')
+endif
+
+if not get_option('docs').disabled()
+  subdir('docs')
+endif
+
+configure_file(output: 'config.h', configuration: conf)
+
+build_summary = {
+  'Directories':
+    {'prefix': get_option('prefix'),
+     'bindir': get_option('bindir'),
+     'libdir': get_option('libdir'),
+     'includedir': get_option('includedir'),
+     'datadir': get_option('datadir'),
+    },
+  'Unicode callbacks (you want at least one)':
+    {'Builtin': true,
+     'Glib': conf.get('HAVE_GLIB', 0) == 1,
+     'ICU': conf.get('HAVE_ICU', 0) == 1,
+    },
+  'Font callbacks (the more the merrier)':
+    {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
+    },
+  'Dependencies used for command-line utilities':
+    {'Cairo': conf.get('HAVE_CAIRO', 0) == 1,
+     'Chafa': conf.get('HAVE_CHAFA', 0) == 1,
+    },
+  'Additional shapers':
+    {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1,
+    },
+  'Platform shapers (not normally needed)':
+    {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1,
+     'DirectWrite': 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,
+     'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1,
+     'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1,
+    },
+  'Testing':
+    {'Tests': get_option('tests').enabled(),
+     'Benchmark': get_option('benchmark').enabled(),
+    },
+}
+if meson.version().version_compare('>=0.53')
+  foreach section_title, section : build_summary
+    summary(section, bool_yn: true, section: section_title)
+  endforeach
+else
+  summary = ['']
+  foreach section_title, section : build_summary
+    summary += '  @0@:'.format(section_title)
+    foreach feature, value : section
+      summary += '    @0@:'.format(feature)
+      summary += '          @0@'.format(value)
+    endforeach
+    summary += ''
+  endforeach
+  message('\n'.join(summary))
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..9ebba72
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,42 @@
+# HarfBuzz feature options
+option('glib', type: 'feature', value: 'auto',
+  description: 'Enable GLib unicode functions')
+option('gobject', type: 'feature', value: 'auto',
+  description: 'Enable GObject bindings')
+option('cairo', type: 'feature', value: 'auto',
+  description: 'Use Cairo graphics library')
+option('chafa', type: 'feature', value: 'auto',
+  description: 'Use Chafa terminal graphics library')
+option('icu', type: 'feature', value: 'auto',
+  description: 'Enable ICU library unicode functions')
+option('graphite', type: 'feature', value: 'disabled',
+  description: 'Deprecated use graphite2 option instead')
+option('graphite2', type: 'feature', value: 'disabled',
+  description: 'Enable Graphite2 complementary shaper')
+option('freetype', type: 'feature', value: 'auto',
+  description: 'Enable freetype interop helpers')
+option('gdi', type: 'feature', value: 'disabled',
+  description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
+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')
+
+# Common feature options
+option('tests', type: 'feature', value: 'enabled', yield: true,
+  description: 'Enable or disable unit tests')
+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('benchmark', type: 'feature', value: 'disabled',
+  description: 'Enable benchmark tests')
+option('icu_builtin', type: 'boolean', value: false,
+  description: 'Don\'t separate ICU support as harfbuzz-icu module')
+option('experimental_api', type: 'boolean', value: false,
+  description: 'Enable experimental APIs')
+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')
diff --git a/mingw-ldd.py b/mingw-ldd.py
deleted file mode 100755
index 1d659ef..0000000
--- a/mingw-ldd.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-
-# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
-# Modified to point to right prefix location on Fedora.
-
-# WTFPL - Do What the Fuck You Want to Public License
-from __future__ import print_function
-import pefile
-import os
-import sys
-
-
-def get_dependency(filename):
-    deps = []
-    pe = pefile.PE(filename)
-    for imp in pe.DIRECTORY_ENTRY_IMPORT:
-        deps.append(imp.dll.decode())
-    return deps
-
-
-def dep_tree(root, prefix=None):
-    if not prefix:
-        arch = get_arch(root)
-        #print('Arch =', arch)
-        prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
-        #print('Using default prefix', prefix)
-    dep_dlls = dict()
-
-    def dep_tree_impl(root, prefix):
-        for dll in get_dependency(root):
-            if dll in dep_dlls:
-                continue
-            full_path = os.path.join(prefix, dll)
-            if os.path.exists(full_path):
-                dep_dlls[dll] = full_path
-                dep_tree_impl(full_path, prefix=prefix)
-            else:
-                dep_dlls[dll] = 'not found'
-
-    dep_tree_impl(root, prefix)
-    return (dep_dlls)
-
-
-def get_arch(filename):
-    type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
-                pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
-    pe = pefile.PE(filename)
-    try:
-        return type2arch[pe.PE_TYPE]
-    except KeyError:
-        sys.stderr.write('Error: unknown architecture')
-        sys.exit(1)
-
-if __name__ == '__main__':
-    filename = sys.argv[1]
-    for dll, full_path in dep_tree(filename).items():
-        print(' ' * 7, dll, '=>', full_path)
-
diff --git a/mingw32.sh b/mingw32.sh
deleted file mode 100755
index 77edffa..0000000
--- a/mingw32.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"
diff --git a/mingw64.sh b/mingw64.sh
deleted file mode 100755
index 28724a4..0000000
--- a/mingw64.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"
diff --git a/perf/fonts/Amiri-Regular.ttf b/perf/fonts/Amiri-Regular.ttf
new file mode 100644
index 0000000..e328e06
--- /dev/null
+++ b/perf/fonts/Amiri-Regular.ttf
Binary files differ
diff --git a/perf/fonts/NotoNastaliqUrdu-Regular.ttf b/perf/fonts/NotoNastaliqUrdu-Regular.ttf
new file mode 100644
index 0000000..891f633
--- /dev/null
+++ b/perf/fonts/NotoNastaliqUrdu-Regular.ttf
Binary files differ
diff --git a/perf/fonts/NotoSansDevanagari-Regular.ttf b/perf/fonts/NotoSansDevanagari-Regular.ttf
new file mode 100644
index 0000000..a9884a5
--- /dev/null
+++ b/perf/fonts/NotoSansDevanagari-Regular.ttf
Binary files differ
diff --git a/perf/fonts/Roboto-Regular.ttf b/perf/fonts/Roboto-Regular.ttf
new file mode 100644
index 0000000..500b104
--- /dev/null
+++ b/perf/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/perf/meson.build b/perf/meson.build
new file mode 100644
index 0000000..c3b0e3e
--- /dev/null
+++ b/perf/meson.build
@@ -0,0 +1,27 @@
+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
+
+if ttf_parser_dep.found()
+  benchmark_cpp_args = ['-DHAVE_TTFPARSER']
+else
+  benchmark_cpp_args = []
+endif
+
+benchmark('perf', executable('perf', 'perf.cc',
+  dependencies: [
+    google_benchmark_dep, freetype_dep,
+
+    # 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'),
+  ],
+  cpp_args: benchmark_cpp_args,
+  include_directories: [incconfig, incsrc],
+  link_with: [libharfbuzz],
+  install: false,
+), workdir: join_paths(meson.current_source_dir(), '..'), timeout: 100)
diff --git a/perf/perf-draw.hh b/perf/perf-draw.hh
new file mode 100644
index 0000000..12581bc
--- /dev/null
+++ b/perf/perf-draw.hh
@@ -0,0 +1,177 @@
+#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
new file mode 100644
index 0000000..c7bc84c
--- /dev/null
+++ b/perf/perf-extents.hh
@@ -0,0 +1,98 @@
+#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
new file mode 100644
index 0000000..85ee19b
--- /dev/null
+++ b/perf/perf-shaping.hh
@@ -0,0 +1,65 @@
+#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
new file mode 100644
index 0000000..a364b91
--- /dev/null
+++ b/perf/perf.cc
@@ -0,0 +1,16 @@
+#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/run.sh b/perf/run.sh
new file mode 100755
index 0000000..c7dc6e0
--- /dev/null
+++ b/perf/run.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+CXX=clang++
+FONT=fonts/NotoNastaliqUrdu-Regular.ttf
+TEXT=texts/fa-monologue.txt
+
+$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
+  -lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
+  -I../src $FLAGS $SOURCES \
+  -DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
+  -DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
+  -o hb-shape -g -O2 # -O3 \
+  #-march=native -mtune=native \
+  #-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
+  #-Rpass-analysis=loop-vectorize -fsave-optimization-record
+
+# -march=native: enable all vector instructions current CPU can offer
+# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
+
+#sudo rm capture.syscap > /dev/null
+#sysprof-cli -c "./a.out $@"
+#sysprof capture.syscap
+
+perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
+#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
+#perf report -g
diff --git a/perf/texts/en-thelittleprince.txt b/perf/texts/en-thelittleprince.txt
new file mode 100644
index 0000000..7bf4abc
--- /dev/null
+++ b/perf/texts/en-thelittleprince.txt
@@ -0,0 +1,1893 @@
+Downloaded from https://archive.org/details/TheLittlePrince-English
+
+THE LITTLE PRINCE
+
+
+
+Antoine De Saint-Exupery
+
+
+
+
+Antoine de Saint-Exupery, who was a French author, journalist and pilot wrote
+The Little Prince in 1943, one year before his death.
+
+The Little Prince appears to be a simple children’s tale,
+some would say that it is actually a profound and deeply moving tale,
+written in riddles and laced with philosophy and poetic metaphor.
+
+
+
+
+Once when I was six years old I saw a magnificent picture in a book, called True Stories from
+Nature, about the primeval forest. It was a picture of a boa constrictor in the act of swallowing an
+animal. Here is a copy of the drawing.
+
+In the book it said: “Boa constrictors swallow their prey whole, without chewing it. After that they
+are not able to move, and they sleep through the six months that they need for digestion.” I
+pondered deeply, then, over the adventures of the jungle. And after some work with a coloured
+pencil I succeeded in making my first drawing. My Drawing Number One. It looked like this:
+
+
+
+
+I showed my masterpiece to the grown-ups, and asked them whether the drawing frightened them.
+But they answered: “Frighten? Why should any one be frightened by a hat?” My drawing was not
+a picture of a hat. It was a picture of a boa constrictor digesting an elephant. But since the grown-
+ups were not able to understand it, I made another drawing: I drew the inside of the boa
+constrictor, so that the grown-ups could see it clearly. They always need to have things explained.
+
+
+
+My Drawing Number Two looked like this:
+
+
+
+
+The grown-ups’ response, this time, was to advise me to lay aside my drawings of boa
+constrictors, whether from the inside or the outside, and devote myself instead to geography,
+history, arithmetic and grammar. That is why, at the age of six, I gave up what might have been a
+magnificent career as a painter. I had been disheartened by the failure of my Drawing Number
+One and my Drawing Number Two. Grown-ups never understand anything by themselves, and it is
+tiresome for children to be always and forever explaining things to them.
+
+So then I chose another profession, and learned to pilot air-planes. I have flown a little over all
+parts of the world; and it is true that geography has been very useful to me. At a glance I can
+distinguish China from Arizona. If one gets lost in the night, such knowledge is valuable. In the
+course of this life I have had a great many encounters with a great many people who have been
+concerned with matters of consequence. I have lived a great deal among grown-ups. I have seen
+them intimately, close at hand. And that hasn’t much improved my opinion of them.
+
+Whenever I met one of them who seemed to me at all clear-sighted, I tried the experiment of
+showing him my Drawing Number One, which I have always kept. I would try to find out, so, if this
+was a person of true understanding. But, whoever it was, he, or she, would always say: “That is a
+hat.” Then I would never talk to that person about boa constrictors, or primeval forests, or stars. I
+would bring myself down to his level. I would talk to him about bridge, and golf, and politics, and
+neckties. And the grown-up would be greatly pleased to have met such a sensible man.
+
+So I lived my life alone, without anyone that I could really talk to, until I had an accident with my
+plane in the Desert of Sahara, six years ago. Something was broken in my engine. And as I had
+with me neither a mechanic nor any passengers, I set myself to attempt the difficult repairs all
+alone. It was a question of life or death for me: I had scarcely enough drinking water to last a
+week.
+
+The first night, then, I went to sleep on the sand, a thousand miles from any human habitation. I
+was more isolated than a shipwrecked sailor on a raft in the middle of the ocean. Thus you can
+imagine my amazement, at sunrise, when I was awakened by an odd little voice.
+
+
+
+
+It said: “If you please, draw me a sheep!”
+
+“What!”
+
+“Draw me a sheep!”
+
+I jumped to my feet, completely thunderstruck. I blinked my eyes hard. I looked carefully all
+around me. And I saw a most extraordinary small person, who stood there examining me with
+great seriousness. Here you may see the best portrait that, later, I was able to make of him. But
+my drawing is certainly very much less charming than its model.
+
+That, however, is not my fault. The grown-ups discouraged me in my painter’s career when I was
+six years old, and I never learned to draw anything, except boas from the outside and boas from
+the inside.
+
+Now I stared at this sudden apparition with my eyes fairly starting out of my head in
+astonishment. Remember, I had crashed in the desert a thousand miles from any inhabited region.
+And yet my little man seemed neither to be straying uncertainly among the sands, nor to be
+fainting from fatigue or hunger or thirst or fear. Nothing about him gave any suggestion of a child
+lost in the middle of the desert, a thousand miles from any human habitation.
+
+When at last I was able to speak, I said to him: “But, what are you doing here?” And in answer he
+repeated, very slowly, as if he were speaking of a matter of great consequence:
+
+“If you please, draw me a sheep...”
+
+When a mystery is too overpowering, one dare not disobey. Absurd as it might seem to me, a
+thousand miles from any human habitation and in danger of death, I took out of my pocket a sheet
+of paper and my fountain pen. But then I remembered how my studies had been concentrated on
+geography, history, arithmetic, and grammar, and I told the little chap (a little crossly, too) that I
+did not know how to draw. He answered me: “That doesn’t matter. Draw me a sheep...”
+
+
+
+
+But I had never drawn a sheep. So I drew for him one of the two pictures I had drawn so often. It
+was that of the boa constrictor from the outside. And I was astounded to hear the little fellow
+greet it with, “No, no, no! I do not want an elephant inside a boa constrictor. A boa constrictor is a
+very dangerous creature, and an elephant is very cumbersome. Where I live, everything is very
+small. What I need is a sheep. Draw me a sheep.
+
+
+
+
+So then I made a drawing. He looked at it carefully, then he said: “No. This sheep is already very
+sickly. Make me another.” So I made another drawing. My friend smiled gently and indulgently.
+“You see yourself,” he said, “that this is not a sheep. This is a ram. It has horns.
+
+
+
+
+So then I did my drawing over once more. But it was rejected too, just like the others. “This one is
+too old. I want a sheep that will live a long time.
+
+By this time my patience was exhausted, because I was in a hurry to start taking my engine apart.
+So I tossed off this drawing. And I threw out an explanation with it.
+
+“This is only his box. The sheep you asked for is inside.”
+
+
+
+
+I was very surprised to see a light break over the face of my young judge:
+
+“That is exactly the way I wanted it! Do you think that this sheep will have to have a great deal of
+grass?”
+
+“Why?”
+
+“Because where I live everything is very small...”
+
+“There will surely be enough grass for him,” I said.
+
+“It is a very small sheep that I have given you.”
+
+He bent his head over the drawing: “Not so small that, Look! He has gone to sleep...”
+
+And that is how I made the acquaintance of the little prince.
+
+It took me a long time to learn where he came from. The little prince, who asked me so many
+questions, never seemed to hear the ones I asked him. It was from words dropped by chance that,
+little by little, everything was revealed to me.
+
+The first time he saw my air-plane, for instance (I shall not draw my air-plane; that would be much
+too complicated for me), he asked me: “What is that object?”
+
+“That is not an object. It flies. It is an air-plane. It is my air-plane.” And I was proud to have him
+learn that I could fly. He cried out, then: “What! You dropped down from the sky?”
+
+
+
+“Yes,” I answered, modestly.
+
+
+
+“Oh! That is funny!” And the little prince broke into a lovely peal of laughter, which irritated me
+very much. I like my misfortunes to be taken seriously.
+
+Then he added: “So you, too, come from the sky! Which is your planet?” At that moment I caught
+a gleam of light in the impenetrable mystery of his presence; and I demanded, abruptly: “Do you
+come from another planet?” But he did not reply. He tossed his head gently, without taking his
+eyes from my plane: “It is true that on that you can’t have come from very far away...” And he
+sank into a reverie, which lasted a long time. Then, taking my sheep out of his pocket, he buried
+himself in the contemplation of his treasure.
+
+You can imagine how my curiosity was aroused by this half-confidence about the “other planets.” I
+made a great effort, therefore, to find out more on this subject.
+
+“My little man, where do you come from? What is this ‘where I live,’ of which you speak? Where
+do you want to take your sheep?”
+
+After a reflective silence he answered: “The thing that is so good about the box you have given
+me is that at night he can use it as his house.”
+
+“That is so. And if you are good I will give you a string, too, so that you can tie him during the day,
+and a post to tie him to.”
+
+But the little prince seemed shocked by this offer: “Tie him! What a queer idea!”
+
+“But if you don’t tie him,” I said, “he will wander off somewhere, and get lost.”
+
+My friend broke into another peal of laughter: “But where do you think he would go?”
+“Anywhere. Straight ahead of him.”
+
+Then the little prince said, earnestly: “That doesn’t matter. Where I live, everything is so small!”
+And, with perhaps a hint of sadness, he added: “Straight ahead of him, nobody can go very far...”
+
+
+
+
+I had thus learned a second fact of great importance: this was that the planet the little prince
+came from was scarcely any larger than a house! But that did not really surprise me much. I knew
+very well that in addition to the great planets, such as the Earth, Jupiter, Mars, Venus, to which
+we have given names, there are also hundreds of others, some of which are so small that one has
+a hard time seeing them through the telescope.
+
+
+
+When an astronomer discovers one of these he does not give it a name, but only a number. He
+might call it, for example, “Asteroid 325.”
+
+
+
+
+I have serious reason to believe that the planet from which the little prince came is the asteroid
+known as B-612. This asteroid has only once been seen through the telescope. That was by a
+Turkish astronomer, in 1909.
+
+On making his discovery, the astronomer had presented it to the International Astronomical
+Congress, in a great demonstration. But he was in Turkish costume, and so nobody would believe
+what he said. Grown-ups are like that...
+
+Fortunately, however, for the reputation of Asteroid B-612, a Turkish dictator made a law that his
+subjects, under pain of death, should change to European costume. So in 1920 the astronomer
+gave his demonstration all over again, dressed with impressive style and elegance. And this time
+everybody accepted his report.
+
+If I have told you these details about the asteroid, and made a note of its number for you, it is on
+account of the grown-ups and their ways. When you tell them that you have made a new friend,
+they never ask you any questions about essential matters. They never say to you, “What does his
+voice sound like? What games does he love best? Does he collect butterflies?” Instead, they
+demand: “How old is he? How many brothers has he? How much does he weigh? How much
+money does his father make?”
+
+Only from these figures do they think they have learned anything about him.
+
+If you were to say to the grown-ups: “I saw a beautiful house made of rosy brick, with geraniums
+in the windows and doves on the roof,” they would not be able to get any idea of that house at all.
+
+You would have to say to them: “I saw a house that cost $ 20,000.” Then they would exclaim: “Oh,
+what a pretty house that is!” Just so, you might say to them: “The proof that the little prince
+existed is that he was charming, that he laughed, and that he was looking for a sheep. If anybody
+wants a sheep, that is a proof that he exists.” And what good would it do to tell them that? They
+would shrug their shoulders, and treat you like a child. But if you said to them: “The planet he
+came from is Asteroid B-612,” then they would be convinced, and leave you in peace from their
+questions. They are like that. One must not hold it against them. Children should always show
+great forbearance toward grown-up people. But certainly, for us who understand life, figures are a
+matter of indifference.
+
+I should have liked to begin this story in the fashion of the fairy-tales. I should have like to say:
+“Once upon a time there was a little prince who lived on a planet that was scarcely any bigger
+
+
+
+than himself, and who had need of a sheep...”
+
+
+
+To those who understand life, that would have given a much greater air of truth to my story. Fori
+do not want any one to read my book carelessly. I have suffered too much grief in setting down
+these memories. Six years have already passed since my friend went away from me, with his
+sheep. If I try to describe him here, it is to make sure that I shall not forget him. To forget a friend
+is sad. Not every one has had a friend. And if I forget him, I may become like the grown-ups who
+are no longer interested in anything but figures... It is for that purpose, again, that I have bought a
+box of paints and some pencils.
+
+It is hard to take up drawing again at my age, when I have never made any pictures except those
+of the boa constrictor from the outside and the boa constrictor from the inside, since I was six. I
+shall certainly try to make my portraits as true to life as possible. But I am not at all sure of
+success. One drawing goes along all right, and another has no resemblance to its subject. I make
+some errors, too, in the little prince’s height: in one place he is too tall and in another too short.
+And I feel some doubts about the colour of his costume. So I fumble along as best I can, now good,
+now bad, and I hope generally fair-to- middling. In certain more important details I shall make
+mistakes, also. But that is something that will not be my fault. My friend never explained anything
+to me. He thought, perhaps, that I was like himself. But I, alas, do not know how to see sheep
+through the walls of boxes. Perhaps I am a little like the grown-ups. I have had to grow old.
+
+As each day passed I would learn, in our talk, something about the little prince’s planet, his
+departure from it, his journey. The information would come very slowly, as it might chance to fall
+from his thoughts. It was in this way that I heard, on the third day, about the catastrophe of the
+baobabs.
+
+This time, once more, I had the sheep to thank for it. For the little prince asked me abruptly, as if
+seized by a grave doubt,
+
+“It is true, isn’t it, that sheep eat little bushes?”
+
+“Yes, that is true.”
+
+“Ah! I am glad!”
+
+I did not understand why it was so important that sheep should eat little bushes. But the little
+prince added: “Then it follows that they also eat baobabs?” I pointed out to the little prince that
+baobabs were not little bushes, but, on the contrary, trees as big as castles; and that even if he
+took a whole herd of elephants away with him, the herd would not eat up one single baobab.
+
+The idea of the herd of elephants made the little prince laugh. “We would have to put them one on
+top of the other,” he said. But he made a wise comment:
+
+“Before they grow so big, the baobabs start out by being little.”
+
+“That is strictly correct,” I said. “But why do you want the sheep to eat the little baobabs?”
+
+He answered me at once, “Oh, come, come!”, as if he were speaking of something that was self-
+evident. And I was obliged to make a great mental effort to solve this problem, without any
+assistance.
+
+Indeed, as I learned, there were on the planet where the little prince lived, as on all planets, good
+
+
+
+
+
+plants and bad plants. In consequence, there were good seeds from good plants, and bad seeds
+from bad plants. But seeds are invisible. They sleep deep in the heart of the earth’s darkness,
+until some one among them is seized with the desire to awaken. Then this little seed will stretch
+itself and begin, timidly at first, to push a charming little sprig inoffensively upward toward the
+sun. If it is only a sprout of radish or the sprig of a rose-bush, one would let it grow wherever it
+might wish. But when it is a bad plant, one must destroy it as soon as possible, the very first
+instant that one recognises it.
+
+Now there were some terrible seeds on the planet that was the home of the little prince; and these
+were the seeds of the baobab. The soil of that planet was infested with them. A baobab is
+something you will never, never be able to get rid of if you attend to it too late. It spreads over the
+entire planet. It bores clear through it with its roots. And if the planet is too small, and the
+baobabs are too many, they split it in pieces...
+
+“It is a question of discipline,” the little prince said to me later on.
+
+“When you’ve finished your own toilet in the morning, then it is time to attend to the toilet of your
+planet, just so, with the greatest care. You must see to it that you pull up regularly all the baobabs,
+at the very first moment when they can be distinguished from the rosebushes, which they
+resemble so closely in their earliest youth. It is very tedious work,” the little prince added, “but
+very easy.” And one day he said to me: “You ought to make a beautiful drawing, so that the
+children where you live can see exactly how all this is. That would be very useful to them if they
+were to travel some day.
+
+
+
+
+Sometimes,” he added, “there is no harm in putting off a piece of work until another day. But
+when it is a matter of baobabs, that always means a catastrophe.
+
+I knew a planet that was inhabited by a lazy man. He neglected three little bushes... So, as the
+little prince described it to me, I have made a drawing of that planet. I do not much like to take
+the tone of a moralist. But the danger of the baobabs is so little understood, and such considerable
+risks would be run by anyone who might get lost on an asteroid, that for once I am breaking
+through my reserve. “Children,” I say plainly, “watch out for the baobabs!” My friends, like
+myself, have been skirting this danger for a long time, without ever knowing it; and so it is for
+them that I have worked so hard over this drawing.
+
+The lesson which I pass on by this means is worth all the trouble it has cost me. Perhaps you will
+ask me, “Why are there no other drawing in this book as magnificent and impressive as this
+drawing of the baobabs?” The reply is simple. I have tried. But with the others I have not been
+successful. When I made the drawing of the baobabs I was carried beyond myself by the inspiring
+force of urgent necessity.
+
+Oh, little prince! Bit by bit I came to understand the secrets of your sad little life... For a long time
+you had found your only entertainment in the quiet pleasure of looking at the sunset.
+
+I learned that new detail on the morning of the fourth day, when you said to me:
+
+“I am very fond of sunsets. Come, let us go look at a sunset now.”
+
+“But we must wait,” I said.
+
+“Wait? For what?”
+
+“For the sunset. We must wait until it is time.”
+
+At first you seemed to be very much surprised. And then you laughed to yourself. You said to me:
+“I am always thinking that I am at home!”
+
+Just so. Everybody knows that when it is noon in the United States the sun is setting over France.
+If you could fly to France in one minute, you could go straight into the sunset, right from noon.
+Unfortunately, France is too far away for that. But on your tiny planet, my little prince, all you
+need do is move your chair a few steps. You can see the day end and the twilight falling whenever
+you like...
+
+“One day,” you said to me, “I saw the sunset forty-four times!”
+
+And a little later you added: “You know, one loves the sunset, when one is so sad...” “Were you so
+sad, then?” I asked, “on the day of the forty-four sunsets?”
+
+But the little prince made no reply.
+
+On the fifth day, again, as always, it was thanks to the sheep, the secret of the little prince’s life
+was revealed to me.
+
+Abruptly, without anything to lead up to it, and as if the question had been born of long and silent
+meditation on his problem, he demanded: “A sheep; if it eats little bushes, does it eat flowers,
+too?”
+
+
+
+
+“A sheep,” I answered, “eats anything it finds in its reach.”
+
+
+
+“Even flowers that have thorns?”
+
+“Yes, even flowers that have thorns.”
+
+“Then the thorns, what use are they?” I did not know.
+
+At that moment I was very busy trying to unscrew a bolt that had got stuck in my engine. I was
+very much worried, for it was becoming clear to me that the breakdown of my plane was
+extremely serious. And I had so little drinking water left that I had to fear for the worst.
+
+“The thorns, what use are they?”
+
+The little prince never let go of a question, once he had asked it. As for me, I was upset over that
+bolt. And I answered with the first thing that came into my head: “The thorns are of no use at all.
+Flowers have thorns just for spite!”
+
+“Oh!” There was a moment of complete silence.
+
+Then the little prince flashed back at me, with a kind of resentfulness: “I don’t believe you!
+Flowers are weak creatures. They are naive. They reassure themselves as best they can. They
+believe that their thorns are terrible weapons...”
+
+I did not answer. At that instant I was saying to myself: “If this bolt still won’t turn, I am going to
+knock it out with the hammer.”
+
+Again the little prince disturbed my thoughts. “And you actually believe that the flowers...”
+
+“Oh, no!” I cried. “No, no no! I don’t believe anything. I answered you with the first thing that
+came into my head. Don’t you see, I am very busy with matters of consequence!”
+
+He stared at me, thunderstruck. “Matters of consequence!”
+
+He looked at me there, with my hammer in my hand, my fingers black with engine grease, bending
+down over an object which seemed to him extremely ugly...
+
+“You talk just like the grown-ups!” That made me a little ashamed. But he went on, relentlessly:
+“You mix everything up together... You confuse everything...”
+
+He was really very angry. He tossed his golden curls in the breeze.
+
+“I know a planet where there is a certain red-faced gentleman. He has never smelled a flower. He
+has never looked at a star. He has never loved any one. He has never done anything in his life but
+add up figures. And all day he says over and over, just like you: ‘I am busy with matters of
+consequence!’ And that makes him swell up with pride.
+
+“But he is not a man, he is a mushroom!”
+
+
+
+“A what?”
+
+
+
+“A mushroom!” The little prince was now white with rage. “The flowers have been growing thorns
+for millions of years. For millions of years the sheep have been eating them just the same. And is
+it not a matter of consequence to try to understand why the flowers go to so much trouble to grow
+
+
+
+
+' '
+
+I \
+
+
+
+
+thorns, which are never of any use to them? Is the warfare between the sheep and the flowers not
+important? Is this not of more consequence than a fat red-faced gentleman’s sums? And if I know,
+I, myself, one flower which is unique in the world, which grows nowhere but on my planet, but
+which one little sheep can destroy in a single bite some morning, without even noticing what he is
+doing, Oh! You think that is not important! His face turned from white to red as he continued: “If
+some one loves a flower, of which just one single blossom grows in all the millions and millions of
+stars, it is enough to make him happy just to look at the stars.
+
+He can say to himself, ‘Somewhere, my flower is there...’ But if the sheep eats the flower, in one
+moment all his stars will be darkened... And you think that is not important!”
+
+He could not say anything more. His words were choked by sobbing. The night had fallen. I had
+let my tools drop from my hands. Of what moment now was my hammer, my bolt, or thirst, or
+death? On one star, one planet, my planet, the Earth, there was a little prince to be comforted. I
+took him in my arms, and rocked him. I said to him: “The flower that you love is not in danger. I
+will draw you a muzzle for your sheep. I will draw you a railing to put around your flower. I will...”
+
+I did not know what to say to him. I felt awkward and blundering. I did not know how I could reach
+him, where I could overtake him and go on hand in hand with him once more.
+
+It is such a secret place, the land of tears.
+
+I soon learned to know this flower better. On the little prince’s planet the flowers had always been
+very simple. They had only one ring of petals; they took up no room at all; they were a trouble to
+nobody. One morning they would appear in the grass, and by night they would have faded
+peacefully away. But one day, from a seed blown from no one knew where, a new flower had come
+up; and the little prince had watched very closely over this small sprout which was not like any
+other small sprouts on his planet.
+
+It might, you see, have been a new kind of baobab. The shrub soon stopped growing, and began to
+get ready to produce a flower. The little prince, who was present at the first appearance of a huge
+bud, felt at once that some sort of miraculous apparition must emerge from it. But the flower was
+not satisfied to complete the preparations for her beauty in the shelter of her green chamber. She
+
+
+
+chose her colours with the greatest care. She adjusted her petals one by one. She did not wish to
+go out into the world all rumpled, like the field poppies. It was only in the full radiance of her
+beauty that she wished to appear. Oh, yes! She was a coquettish creature! And her mysterious
+adornment lasted for days and days. Then one morning, exactly at sunrise, she suddenly showed
+herself. And, after working with all this painstaking precision, she yawned and said: “Ah! I am
+scarcely awake. I beg that you will excuse me. My petals are still all disarranged...” But the little
+prince could not restrain his admiration:
+
+“Oh! How beautiful you are!”
+
+“Am I not?” the flower responded, sweetly. “And I was born at the same moment as the sun...”
+
+The little prince could guess easily enough that she was not any too modest, but how moving, and
+exciting she was!
+
+“I think it is time for breakfast,” she added an instant later. “If you would have the kindness to
+think of my needs” And the little prince, completely abashed, went to look for a sprinkling can of
+fresh water.
+
+So, he tended the flower. So, too, she began very quickly to torment him with her vanity, which
+was, if the truth be known, a little difficult to deal with.
+
+One day, for instance, when she was speaking of her four thorns, she said to the little prince: “Let
+the tigers come with their claws!”
+
+“There are no tigers on my planet,” the little prince objected. “And, anyway, tigers do not eat
+weeds.”
+
+“I am not a weed,” the flower replied, sweetly. “Please excuse me...” “I am not at all afraid of
+tigers,” she went on, “but I have a horror of drafts. I suppose you wouldn’t screen for me?"
+
+“A horror of drafts, that is bad luck, for a plant,” remarked the little prince, and added to himself,
+“This flower is a very complex creature...”
+
+“At night I want you to put me under a glass globe. It is very cold where you live. In the place I
+came from...” But she interrupted herself at that point. She had come in the form of a seed. She
+could not have known anything of any other worlds.
+
+Embarrassed over having let herself be caught on the verge of such an untruth, she coughed two
+or three times, in order to put the little prince in the wrong.
+
+“The screen?”
+
+“I was just going to look for it when you spoke to me...”
+
+Then she forced her cough a little more so that he should suffer from remorse just the same. So
+the little prince, in spite of all the good will that was inseparable from his love, had soon come to
+doubt her. He had taken seriously words which were without importance, and it made him very
+unhappy.
+
+“I ought not to have listened to her,” he confided to me one day.
+
+“One never ought to listen to the flowers. One should simply look at them and breathe their
+
+
+
+
+fragrance. Mine perfumed all my planet. But I did not know how to take pleasure in all her grace.
+This tale of claws, which disturbed me so much, should only have filled my heart with tenderness
+and pity.”
+
+And he continued his confidences: “The fact is that I did not know how to understand anything! I
+ought to have judged by deeds and not by words. She cast her fragrance and her radiance over
+me. I ought never to have run away from her... I ought to have guessed all the affection that lay
+behind her poor little stratagems. Flowers are so inconsistent! But I was too young to know how to
+love her...”
+
+I believe that for his escape he took advantage of the migration of a flock of wild birds. On the
+morning of his departure he put his planet in perfect order. He carefully cleaned out his active
+volcanoes. He possessed two active volcanoes; and they were very convenient for heating his
+breakfast in the morning. He also had one volcano that was extinct. But, as he said, “One never
+knows!” So he cleaned out the extinct volcano, too. If they are well cleaned out, volcanoes burn
+slowly and steadily, without any eruptions. Volcanic eruptions are like fires in a chimney.
+
+On our earth we are obviously much too small to clean out our volcanoes. That is why they bring
+no end of trouble upon us. The little prince also pulled up, with a certain sense of dejection, the
+last little shoots of the baobabs. He believed that he would never want to return. But on this last
+morning all these familiar tasks seemed very precious to him. And when he watered the flower for
+the last time, and prepared to place her under the shelter of her glass globe, he realised that he
+was very close to tears. “Goodbye,” he said to the flower. But she made no answer. “Goodbye,”
+he said again. The flower coughed. But it was not because she had a cold.
+
+“I have been silly,” she said to him, at last. “I ask your forgiveness. Try to be happy...” He was
+surprised by this absence of reproaches. He stood there all bewildered, the glass globe held
+arrested in mid-air. He did not understand this quiet sweetness.
+
+“Of course I love you,” the flower said to him. “It is my fault that you have not known it all the
+while. That is of no importance. But you, you have been just as foolish as I. Try to be happy... let
+the glass globe be. I don’t want it any more.”
+
+“But the wind...” “My cold is not so bad as all that... the cool night air will do me good. I am a
+flower.”
+
+“But the animals...” “Well, I must endure the presence of two or three caterpillars if I wish to
+become acquainted with the butterflies. It seems that they are very beautiful. And if not the
+butterflies and the caterpillars who will call upon me? You will be far away... as for the large
+animals, I am not at all afraid of any of them. I have my claws.”
+
+And, naively, she showed her four thorns.
+
+Then she added: “Don’t linger like this. You have decided to go away. Now go!”
+
+For she did not want him to see her crying. She was such a proud flower...
+
+
+
+He found himself in the neighbourhood of the asteroids 325, 326, 327, 328, 329, and 330. He
+began, therefore, by visiting them, in order to add to his knowledge. The first of them was
+inhabited by a king. Clad in royal purple and ermine, he was seated upon a throne, which was at
+
+
+
+
+the same time both simple and majestic.
+
+
+
+“Ah! Here is a subject,” exclaimed the king, when he saw the little prince coming. And the little
+prince asked himself: “How could he recognise me when he had never seen me before?”
+
+He did not know how the world is simplified for kings. To them, all men are subjects. “Approach,
+so that I may see you better,” said the king, who felt consumingly proud of being at last a king
+over somebody.
+
+The little prince looked everywhere to find a place to sit down; but the entire planet was crammed
+and obstructed by the king’s magnificent ermine robe. So he remained standing upright, and, since
+he was tired, he yawned.
+
+“It is contrary to etiquette to yawn in the presence of a king,” the monarch said to him. “I forbid
+you to do so.”
+
+“I can’t help it. I can’t stop myself,” replied the little prince, thoroughly embarrassed.
+
+“I have come on a long journey, and I have had no sleep...”
+
+“Ah, then,” the king said. “I order you to yawn. It is years since I have seen anyone yawning.
+Yawns, to me, are objects of curiosity. Come, now! Yawn again! It is an order.”
+
+“That frightens me... I cannot, any more...” murmured the little prince, now completely abashed.
+
+“Hum! Hum!” replied the king. “Then I... I order you sometimes to yawn and sometimes to” He
+sputtered a little, and seemed vexed. For what the king fundamentally insisted upon was that his
+authority should be respected. He tolerated no disobedience. He was an absolute monarch. But,
+because he was a very good man, he made his orders reasonable.
+
+“If I ordered a general,” he would say, by way of example, “if I ordered a general to change
+himself into a sea bird, and if the general did not obey me, that would not be the fault of the
+general. It would be my fault.”
+
+“May I sit down?” came now a timid inquiry from the little prince. “I order you to do so,” the king
+answered him, and majestically gathered in a fold of his ermine mantle. But the little prince was
+wondering... The planet was tiny. Over what could this king really rule?
+
+“Sire,” he said to him, “I beg that you will excuse my asking you a question”
+
+“I order you to ask me a question,” the king hastened to assure him. “Sire, over what do you
+rule?” “Over everything,” said the king, with magnificent simplicity.
+
+“Over everything?” The king made a gesture, which took in his planet, the other planets, and all
+the stars. “Over all that?” asked the little prince. “Over all that,” the king answered. For his rule
+was not only absolute: it was also universal. “And the stars obey you?” “Certainly they do,” the
+king said. “They obey instantly. I do not permit insubordination.”
+
+Such power was a thing for the little prince to marvel at. If he had been master of such complete
+authority, he would have been able to watch the sunset, not forty-four times in one day, but
+seventy-two, or even a hundred, or even two hundred times, with out ever having to move his
+chair. And because he felt a bit sad as he remembered his little planet, which he had forsaken, he
+plucked up his courage to ask the king a favour:
+
+
+
+
+
+“I should like to see a sunset... do me that kindness... Order the sun to set...”
+
+“If I ordered a general to fly from one flower to another like a butterfly, or to write a tragic
+drama, or to change himself into a sea bird, and if the general did not carry out the order that he
+had received, which one of us would be in the wrong?” the king demanded. “The general, or
+myself?”
+
+“You,” said the little prince firmly.
+
+“Exactly. One much require from each one the duty which each one can perform,” the king went
+on. “Accepted authority rests first of all on reason. If you ordered your people to go and throw
+themselves into the sea, they would rise up in revolution. I have the right to require obedience
+because my orders are reasonable.”
+
+“Then my sunset?” the little prince reminded him: for he never forgot a question once he had
+asked it.
+
+“You shall have your sunset. I shall command it. But, according to my science of government, I
+shall wait until conditions are favourable.”
+
+“When will that be?” inquired the little prince. “Hum! Hum!” replied the king; and before saying
+anything else he consulted a bulky almanac. “Hum! Hum! That will be about... about... that will be
+this evening about twenty minutes to eight. And you will see how well I am obeyed.”
+
+The little prince yawned. He was regretting his lost sunset. And then, too, he was already
+beginning to be a little bored. “I have nothing more to do here,” he said to the king. “So I shall set
+out on my way again.” “Do not go,” said the king, who was very proud of having a subject. “Do
+not go. I will make you a Minister!” “Minister of what?” “Minster of...of Justice!” “But there is
+nobody here to judge!” “We do not know that,” the king said to him. “I have not yet made a
+complete tour of my kingdom. I am very old. There is no room here for a carriage. And it tires me
+to walk.” “Oh, but I have looked already!” said the little prince, turning around to give one more
+glance to the other side of the planet.
+
+On that side, as on this, there was nobody at all... “Then you shall judge yourself,” the king
+answered, “that is the most difficult thing of all. It is much more difficult to j udge oneself than to
+j udge others. If you succeed in j udging yourself rightly, then you are indeed a man of true
+wisdom.”
+
+
+
+“Yes,” said the little prince, “but I can judge myself anywhere. I do not need to live on this planet.
+“Hum! Hum!” said the king. “I have good reason to believe that somewhere on my planet there is
+an old rat. I hear him at night. You can judge this old rat. From time to time you will condemn him
+to death. Thus his life will depend on your j ustice. But you will pardon him on each occasion; for
+he must be treated thriftily. He is the only one we have.”
+
+“I,” replied the little prince, “do not like to condemn anyone to death. And now I think I will go on
+my way.” “No,” said the king. But the little prince, having now completed his preparations for
+departure, had no wish to grieve the old monarch. “If Your Majesty wishes to be promptly
+obeyed,” he said, “he should be able to give me a reasonable order. He should be able, for
+example, to order me to be gone by the end of one minute. It seems to me that conditions are
+favourable...” As the king made no answer, the little prince hesitated a moment.
+
+Then, with a sigh, he took his leave. “I made you my Ambassador,” the king called out, hastily.
+
+He had a magnificent air of authority.
+
+“The grown-ups are very strange,” the little prince said to himself, as he continued on his journey.
+The second planet was inhabited by a conceited man.
+
+
+
+
+
+
+
+
+
+
+“Ah! Ah! I am about to receive a visit from an admirer!” he exclaimed from afar, when he first
+saw the little prince coming. For, to conceited men, all other men are admirers.
+
+“Good morning,” said the little prince. “That is a queer hat you are wearing.”
+
+“It is a hat for salutes,” the conceited man replied. “It is to raise in salute when people acclaim
+me. Unfortunately, nobody at all ever passes this way.”
+
+“Yes?” said the little prince, who did not understand what the conceited man was talking about.
+
+“Clap your hands, one against the other,” the conceited man now directed him. The little prince
+clapped his hands. The conceited man raised his hat in a modest salute. “This is more entertaining
+than the visit to the king,” the little prince said to himself. And he began again to clap his hands,
+one against the other. The conceited man against raised his hat in salute. After five minutes of
+
+
+
+this exercise the little prince grew tired of the game’s monotony. “And what should one do to
+make the hat come down?” he asked. But the conceited man did not hear him. Conceited people
+never hear anything but praise.
+
+“Do you really admire me very much?” he demanded of the little prince. “What does that mean,
+‘admire’?”
+
+“To admire means that you regard me as the handsomest, the best-dressed, the richest, and the
+most intelligent man on this planet.” “But you are the only man on your planet!” “Do me this
+kindness. Admire me just the same.”
+
+“I admire you,” said the little prince, shrugging his shoulders slightly, “but what is there in that to
+interest you so much?”
+
+And the little prince went away. “The grown-ups are certainly very odd,” he said to himself, as he
+continued on his journey.
+
+The next planet was inhabited by a tippler.
+
+
+
+
+This was a very short visit, but it plunged the little prince into deep dejection. “What are you
+doing there?” he said to the tippler, whom he found settled down in silence before a collection of
+empty bottles and also a collection of full bottles.
+
+“I am drinking,” replied the tippler, with a lugubrious air.
+
+“Why are you drinking?” demanded the little prince.
+
+“So that I may forget,” replied the tippler. “Forget what?” inquired the little prince, who already
+was sorry for him.
+
+“Forget that I am ashamed,” the tippler confessed, hanging his head.
+
+“Ashamed of what?” insisted the little prince, who wanted to help him.
+
+“Ashamed of drinking!” The tippler brought his speech to an end, and shut himself up in an
+impregnable silence.
+
+And the little prince went away, puzzled. “The grown-ups are certainly very, very odd,” he said to
+himself, as he continued on his journey.
+
+The fourth planet belonged to a businessman.
+
+This man was so much occupied that he did not even raise his head at the little prince’s arrival.
+
+
+
+“Good morning,” the little prince said to him. “Your cigarette has gone out.”
+
+
+
+“Three and two make five. Five and seven make twelve. Twelve and three make fifteen. Good
+morning. Fifteen and seven make twenty-two. Twenty-two and six make twenty-eight. I haven’t
+time to light it again. Twenty-six and five make thirty-one. Phew ! Then that makes five-hundred-
+and-one-million, six-hundred-twenty-two-thousand, seven-hundred-thirty-one.”
+
+“Five hundred million what?” asked the little prince. “Eh? Are you still there? Five-hundred-and-
+one million, I can’t stop... I have so much to do! I am concerned with matters of consequence. I
+don’t amuse myself with balderdash. Two and five make seven...”
+
+“Five-hundred-and-one million what?” repeated the little prince, who never in his life had let go of
+a question once he had asked it.
+
+The businessman raised his head. “During the fifty-four years that I have inhabited this planet, I
+have been disturbed only three times. The first time was twenty-two years ago, when some giddy
+goose fell from goodness knows where. He made the most frightful noise that resounded all over
+the place, and I made four mistakes in my addition. The second time, eleven years ago, I was
+disturbed by an attack of rheumatism. I don’t get enough exercise. I have no time for loafing. The
+third time, well, this is it! I was saying, then, five -hundred-and-one millions”
+
+“Millions of what?” The businessman suddenly realised that there was no hope of being left in
+peace until he answered this question.
+
+“Millions of those little objects,” he said, “which one sometimes sees in the sky.” “Flies?” “Oh,
+no. Little glittering objects.” “Bees?” “Oh, no. Little golden objects that set lazy men to idle
+dreaming. As for me, I am concerned with matters of consequence. There is no time for idle
+dreaming in my life.” “Ah! You mean the stars?” “Yes, that’s it. The stars.” “And what do you do
+with five-hundred millions of stars?” “Five-hundred-and-one million, six-hundred-twenty-two
+thousand, seven-hundred-thirty-one. I am concerned with matters of consequence: I am
+accurate.”
+
+“And what do you do with these stars?” “What do I do with them?” “Yes.” “Nothing. I own them.”
+“You own the stars?” “Yes.” “But I have already seen a king who...” “Kings do not own, they
+reign over. It is a very different matter.”
+
+“And what good does it do you to own the stars?” “It does me the good of making me rich.”
+
+“And what good does it do you to be rich?”
+
+“It makes it possible for me to buy more stars, if any are ever discovered.”
+
+“This man,” the little prince said to himself, “reasons a little like my poor tippler...” Nevertheless,
+he still had some more questions. “How is it possible for one to own the stars?” “To whom do they
+belong?” the businessman retorted, peevishly. “I don’t know. To nobody.” “Then they belong to
+me, because I was the first person to think of it.” “Is that all that is necessary?” “Certainly.
+
+When you find a diamond that belongs to nobody, it is yours. When you discover an island that
+belongs to nobody, it is yours. When you get an idea before any one else, you take out a patent on
+it: it is yours. So with me: I own the stars, because nobody else before me ever thought of owning
+them.”
+
+“Yes, that is true,” said the little prince. “And what do you do with them?”
+
+
+
+
+“I administer them,” replied the businessman. “I count them and recount them. It is difficult. But I
+am a man who is naturally interested in matters of consequence.”
+
+The little prince was still not satisfied. “If I owned a silk scarf,” he said, “I could put it around my
+neck and take it away with me. If I owned a flower, I could pluck that flower and take it away with
+me. But you cannot pluck the stars from heaven...”
+
+“No. But I can put them in the bank.” “Whatever does that mean?” “That means that I write the
+number of my stars on a little paper. And then I put this paper in a drawer and lock it with a key.”
+
+“And that is all?”
+
+“That is enough,” said the businessman.
+
+“It is entertaining,” thought the little prince. “It is rather poetic. But it is of no great
+consequence.” On matters of consequence, the little prince had ideas, which were very different
+from those of the grown-ups.
+
+“I myself own a flower,” he continued his conversation with the businessman, “which I water
+every day. I own three volcanoes, which I clean out every week (for I also clean out the one that is
+extinct; one never knows). It is of some use to my volcanoes, and it is of some use to my flower,
+that I own them. But you are of no use to the stars...”
+
+The businessman opened his mouth, but he found nothing to say in answer. And the little prince
+went away. “The grown-ups are certainly altogether extraordinary,” he said simply, talking to
+himself as he continued on his journey.
+
+The fifth planet was very strange. It was the smallest of all. There was just enough room on it for
+a street lamp and a lamplighter.
+
+
+
+
+The little prince was not able to reach any explanation of the use of a street lamp and a
+lamplighter, somewhere in the heavens, on a planet, which had no people, and not one house.
+
+But he said to himself, nevertheless: “It may well be that this man is absurd. But he is not so
+absurd as the king, the conceited man, the businessman, and the tippler. For at least his work has
+
+
+
+some meaning. When he lights his street lamp, it is as if he brought one more star to life, or one
+flower. When he puts out his lamp, he sends the flower, or the star, to sleep. That is a beautiful
+occupation. And since it is beautiful, it is truly useful.”
+
+When he arrived on the planet he respectfully saluted the lamplighter.
+
+“Good morning. Why have you just put out your lamp?”
+
+“Those are the orders,” replied the lamplighter. “Good morning.”
+
+“What are the orders?”
+
+“The orders are that I put out my lamp. Good evening.” And he lighted his lamp again. “But why
+have you just lighted it again?”
+
+“Those are the orders,” replied the lamplighter.
+
+“I do not understand,” said the little prince.
+
+“There is nothing to understand,” said the lamplighter. “Orders are orders. Good morning.” And
+he put out his lamp.
+
+Then he mopped his forehead with a handkerchief decorated with red squares.
+
+“I follow a terrible profession. In the old days it was reasonable. I put the lamp out in the morning,
+and in the evening I lighted it again. I had the rest of the day for relaxation and the rest of the
+night for sleep.”
+
+“And the orders have been changed since that time?”
+
+“The orders have not been changed,” said the lamplighter. “That is the tragedy! From year to
+year the planet has turned more rapidly and the orders have not been changed!”
+
+“Then what?” asked the little prince.
+
+“Then the planet now makes a complete turn every minute, and I no longer have a single second
+for repose. Once every minute I have to light my lamp and put it out!”
+
+“That is very funny! A day lasts only one minute, here where you live!”
+
+“It is not funny at all!” said the lamplighter. “While we have been talking together a month has
+gone by.”
+
+“A month?”
+
+
+
+“Yes, a month. Thirty minutes. Thirty days. Good evening.” And he lighted his lamp again. As the
+little prince watched him, he felt that he loved this lamplighter who was so faithful to his orders.
+He remembered the sunsets, which he himself had gone to seek, in other days, merely by pulling
+up his chair; and he wanted to help his friend.
+
+“You know,” he said, “I can tell you a way you can rest whenever you want to...”
+
+“I always want to rest,” said the lamplighter. For it is possible for a man to be faithful and lazy at
+the same time.
+
+
+
+
+The little prince went on with his explanation: “Your planet is so small that three strides will take
+you all the way around it. To be always in the sunshine, you need only walk along rather slowly.
+When you want to rest, you will walk and the day will last as long as you like.”
+
+“That doesn’t do me much good,” said the lamplighter. “The one thing I love in life is to sleep.”
+
+“Then you’re unlucky,” said the little prince.
+
+“I am unlucky,” said the lamplighter. “Good morning.” And he put out his lamp.
+
+“That man,” said the little prince to himself, as he continued farther on his journey, “that man
+would be scorned by all the others: by the king, by the conceited man, by the tippler, by the
+businessman. Nevertheless he is the only one of them all who does not seem to me ridiculous.
+Perhaps that is because he is thinking of something else besides himself.”
+
+He breathed a sigh of regret, and said to himself, again: “That man is the only one of them all
+whom I could have made my friend. But his planet is indeed too small. There is no room on it for
+two people...” What the little prince did not dare confess was that he was sorry most of all to leave
+this planet, because it was blest every day with 1440 sunsets!
+
+The sixth planet was ten times larger than the last one. It was inhabited by an old gentleman who
+wrote voluminous books.
+
+
+
+
+“Oh, look! Here is an explorer!” he exclaimed to himself when he saw the little prince coming.
+
+The little prince sat down on the table and panted a little. He had already travelled so much and
+so far!
+
+“Where do you come from?” the old gentleman said to him.
+
+“What is that big book?” said the little prince. “What are you doing?”
+
+“I am a geographer,” the old gentleman said to him.
+
+“What is a geographer?” asked the little prince. “A geographer is a scholar who knows the
+location of all the seas, rivers, towns, mountains, and deserts.”
+
+“That is very interesting,” said the little prince. “Here at last is a man who has a real profession!”
+And he cast a look around him at the planet of the geographer.
+
+
+
+It was the most magnificent and stately planet that he had ever seen.
+
+“Your planet is very beautiful,” he said. “Has it any oceans?”
+
+“I couldn’t tell you,” said the geographer.
+
+“Ah!” The little prince was disappointed. “Has it any mountains?”
+
+“I couldn’t tell you,” said the geographer.
+
+“And towns, and rivers, and deserts?”
+
+“I couldn’t tell you that, either.”
+
+“But you are a geographer!”
+
+“Exactly,” the geographer said. “But I am not an explorer. I haven’t a single explorer on my
+planet. It is not the geographer who goes out to count the towns, the rivers, the mountains, the
+seas, the oceans, and the deserts. The geographer is much too important to go loafing about. He
+does not leave his desk. But he receives the explorers in his study. He asks them questions, and
+he notes down what they recall of their travels. And if the recollections of any one among them
+seem interesting to him, the geographer orders an inquiry into that explorer’s moral character.”
+
+“Why is that?”
+
+“Because an explorer who told lies would bring disaster on the books of the geographer. So would
+an explorer who drank too much.”
+
+“Why is that?” asked the little prince.
+
+“Because intoxicated men see double. Then the geographer would note down two mountains in a
+place where there was only one.”
+
+“I know some one,” said the little prince, “who would make a bad explorer.”
+
+“That is possible. Then, when the moral character of the explorer is shown to be good, an inquiry
+is ordered into his discovery.”
+
+“One goes to see it?”
+
+“No. That would be too complicated. But one requires the explorer to furnish proofs. For example,
+if the discovery in question is that of a large mountain, one requires that large stones be brought
+back from it.” The geographer was suddenly stirred to excitement. “But you come from far away!
+You are an explorer! You shall describe your planet to me!” And, having opened his big register,
+the geographer sharpened his pencil. The recitals of explorers are put down first in pencil. One
+waits until the explorer has furnished proofs, before putting them down in ink. “Well?” said the
+geographer expectantly.
+
+“Oh, where I live,” said the little prince, “it is not very interesting. It is all so small. I have three
+volcanoes. Two volcanoes are active and the other is extinct. But one never knows.”
+
+“One never knows,” said the geographer.
+
+
+
+“I have also a flower.”
+
+
+
+
+“We do not record flowers,” said the geographer.
+
+“Why is that? The flower is the most beautiful thing on my planet!”
+
+“We do not record them,” said the geographer, “because they are ephemeral.”
+
+“What does that mean ‘ephemeral’?”
+
+“Geographies,” said the geographer, “are the books which, of all books, are most concerned with
+matters of consequence. They never become old-fashioned. It is very rarely that a mountain
+changes its position. It is very rarely that an ocean empties itself of its waters. We write of eternal
+things.”
+
+“But extinct volcanoes may come to life again,” the little prince interrupted.
+
+“What does that mean ‘ephemeral’?”
+
+“Whether volcanoes are extinct or alive, it comes to the same thing for us,” said the geographer.
+“The thing that matters to us is the mountain. It does not change.”
+
+“But what does that mean ‘ephemeral’?” repeated the little prince, who never in his life had let go
+of a question, once he had asked it.
+
+“It means, ‘which is in danger of speedy disappearance.’ “
+
+“Is my flower in danger of speedy disappearance?”
+
+“Certainly it is.”
+
+“My flower is ephemeral,” the little prince said to himself, “and she has only four thorns to
+defend herself against the world. And I have left her on my planet, all alone!”
+
+That was his first moment of regret. But he took courage once more. “What place would you
+advise me to visit now?” he asked. “The planet Earth,” replied the geographer. “It has a good
+reputation.” And the little prince went away, thinking of his flower.
+
+
+
+
+So then the seventh planet was the Earth.
+
+The Earth is not just an ordinary planet!
+
+One can count, there 111 kings (not forgetting, to be sure, the Negro kings among them), 7000
+geographers, 900,000 businessmen, 7,500,000 tipplers, 311,000,000 conceited men, that is to say,
+about 2,000,000,000 grown-ups.
+
+To give you an idea of the size of the Earth, I will tell you that before the invention of electricity it
+was necessary to maintain, over the whole of the six continents, a veritable army of 462,511
+lamplighters for the street lamps. Seen from a slight distance, that would make a splendid
+spectacle.
+
+The movements of this army would be regulated like those of the ballet in the opera. First would
+come the turn of the lamplighters of New Zealand and Australia. Having set their lamps alight,
+these would go off to sleep. Next, the lamplighters of China and Siberia would enter for their steps
+in the dance, and then they too would be waved back into the wings. After that would come the
+turn of the lamplighters of Russia and the Indies; then those of Africa and Europe, then those of
+South America; then those of North America. And never would they make a mistake in the order
+of their entry upon the stage. It would be magnificent.
+
+Only the man who was in charge of the single lamp at the North Pole, and his colleague who was
+responsible for the single lamp at the South Pole, only these two would live free from toil and
+care: they would be busy twice a year.
+
+When one wishes to play the wit, he sometimes wanders a little from the truth.
+
+I have not been altogether honest in what I have told you about the lamplighters. And I realise
+that I run the risk of giving a false idea of our planet to those who do not know it.
+
+Men occupy a very small place upon the Earth. If the two billion inhabitants who people its
+surface were all to stand upright and somewhat crowded together, as they do for some big public
+assembly, they could easily be put into one public square twenty miles long and twenty miles wide.
+All humanity could be piled up on a small Pacific islet.
+
+The grown-ups, to be sure, will not believe you when you tell them that. They imagine that they fill
+a great deal of space. They fancy themselves as important as the baobabs. You should advise
+them, then, to make their own calculations. They adore figures, and that will please them. But do
+not waste your time on this extra task. It is unnecessary. You have, I know, confidence in me.
+
+When the little prince arrived on the Earth, he was very much surprised not to see any people. He
+was beginning to be afraid he had come to the wrong planet, when a coil of gold, the colour of the
+moonlight, flashed across the sand.
+
+“Good evening,” said the little prince courteously.
+
+“Good evening,” said the snake.
+
+“What planet is this on which I have come down?” asked the little prince.
+
+“This is the Earth; this is Africa,” the snake answered.
+
+“Ah! Then there are no people on the Earth?”
+
+
+
+
+“This is the desert. There are no people in the desert. The Earth is large,” said the snake.
+
+The little prince sat down on a stone, and raised his eyes toward the sky.
+
+“I wonder,” he said, “whether the stars are set alight in heaven so that one day each one of us
+may find his own again... Look at my planet. It is right there above us. But how far away it is!”
+
+“It is beautiful,” the snake said. “What has brought you here?”
+
+“I have been having some trouble with a flower,” said the little prince. “Ah!” said the snake. And
+they were both silent.
+
+“Where are the men?” the little prince at last took up the conversation again. “It is a little lonely
+in the desert...”
+
+“It is also lonely among men,” the snake said. The little prince gazed at him for a long time.
+
+“You are a funny animal,” he said at last. “You are no thicker than a finger...”
+
+“But I am more powerful than the finger of a king,” said the snake.
+
+The little prince smiled. “You are not very powerful. You haven’t even any feet. You cannot even
+travel...”
+
+“I can carry you farther than any ship could take you,” said the snake. He twined himself around
+the little prince’s ankle, like a golden bracelet.
+
+“Whomever I touch, I send back to the earth from whence he came,” the snake spoke again. “But
+you are innocent and true, and you come from a star...”
+
+The little prince made no reply. “You move me to pity, you are so weak on this Earth made of
+granite,” the snake said. “I can help you, some day, if you grow too homesick for your own planet.
+I can...”
+
+“Oh! I understand you very well,” said the little prince. “But why do you always speak in
+riddles?”
+
+“I solve them all,” said the snake. And they were both silent.
+
+The little prince crossed the desert and met with only one flower.
+
+It was a flower with three petals, a flower of no account at all.
+
+“Good morning,” said the little prince.
+
+“Good morning,” said the flower.
+
+“Where are the men?” the little prince asked, politely. The flower had once seen a caravan
+passing.
+
+“Men?” she echoed. “I think there are six or seven of them in existence. I saw them, several
+years ago. But one never knows where to find them. The wind blows them away. They have no
+roots, and that makes their life very difficult.”
+
+
+
+“Goodbye,” said the little prince.
+
+
+
+
+“Goodbye,” said the flower.
+
+
+
+After that, the little prince climbed a high mountain. The only mountains he had ever known were
+the three volcanoes, which came up to his knees. And he used the extinct volcano as a footstool.
+
+“From a mountain as high as this one,” he said to himself, “I shall be able to see the whole planet
+at one glance, and all the people...” But he saw nothing, save peaks of rock that were sharpened
+like needles.
+
+
+
+
+“Good morning,” he said courteously.
+
+“Good morning...Good morning...Good morning,” answered the echo.
+
+“Who are you?” said the little prince.
+
+“Who are you...Who are you...Who are you?” answered the echo.
+
+“Be my friends. I am all alone,” he said.
+
+“I am all alone...all alone. ..all alone,” answered the echo.
+
+“What a queer planet!” he thought. “It is altogether dry, and altogether pointed, and altogether
+harsh and forbidding. And the people have no imagination. They repeat whatever one says to
+them... On my planet I had a flower; she always was the first to speak...”
+
+But it happened that after walking for a long time through sand, and rocks, and snow, the little
+prince at last came upon a road. And all roads lead to the abodes of men.
+
+“Good morning,” he said. He was standing before a garden, all a-bloom with roses.
+
+“Good morning,” said the roses.
+
+The little prince gazed at them. They all looked like his flower.
+
+“Who are you?” he demanded, thunderstruck.
+
+“We are roses,” the roses said. And he was overcome with sadness. His flower had told him that
+she was the only one of her kind in all the universe. And here were five thousand of them, all
+alike, in one single garden!
+
+“She would be very much annoyed,” he said to himself, “if she should see that... she would cough
+
+
+
+most dreadfully, and she would pretend that she was dying, to avoid being laughed at. And I
+should be obliged to pretend that I was nursing her back to life, for if I did not do that, to humble
+myself also, she would really allow herself to die...”
+
+Then he went on with his reflections: “I thought that I was rich, with a flower that was unique in all
+the world; and all I had was a common rose. A common rose, and three volcanoes that come up to
+my knees — and one of them perhaps extinct forever... that doesn’t make me a very great
+prince...” And he lay down in the grass and cried.
+
+It was then that the fox appeared.
+
+“Good morning,” said the fox.
+
+“Good morning,” the little prince responded politely, although when he turned around he saw
+nothing.
+
+“I am right here,” the voice said, “under the apple tree.” “
+
+Who are you?” asked the little prince, and added, “You are very pretty to look at.”
+
+“I am a fox,” said the fox.
+
+“Come and play with me,” proposed the little prince.
+
+“I am so unhappy.” “I cannot play with you,” the fox said. “I am not tamed.”
+
+“Ah! Please excuse me,” said the little prince. But, after some thought, he added: “What does
+that mean, ‘tame’?”
+
+
+
+
+“You do not live here,” said the fox. “What is it that you are looking for?”
+
+“I am looking for men,” said the little prince. “What does that mean, ‘tame’?”
+
+“Men,” said the fox. “They have guns, and they hunt. It is very disturbing. They also raise
+chickens. These are their only interests. Are you looking for chickens?”
+
+“No,” said the little prince. “I am looking for friends. What does that mean, ‘tame’?”
+
+“It is an act too often neglected,” said the fox. It means to establish ties.”
+
+
+
+“‘To establish ties’?”
+
+
+
+“Just that,” said the fox. “To me, you are still nothing more than a little boy who is just like a
+hundred thousand other little boys. And I have no need of you. And you, on your part, have no
+need of me. To you, I am nothing more than a fox like a hundred thousand other foxes. But if you
+tame me, then we shall need each other. To me, you will be unique in all the world. To you, I shall
+be unique in all the world...”
+
+“I am beginning to understand,” said the little prince. “There is a flower... I think that she has
+tamed me...”
+
+“It is possible,” said the fox. “On the Earth one sees all sorts of things.”
+
+“Oh, but this is not on the Earth!” said the little prince. The fox seemed perplexed, and very
+curious.
+
+“On another planet?”
+
+“Yes.”
+
+“Are there hunters on this planet?”
+
+“No.”
+
+“Ah, that is interesting! Are there chickens?”
+
+“No.”
+
+“Nothing is perfect,” sighed the fox. But he came back to his idea. “My life is very monotonous,”
+the fox said. “I hunt chickens; men hunt me. All the chickens are just alike, and all the men are
+just alike. And, in consequence, I am a little bored. But if you tame me, it will be as if the sun
+came to shine on my life. I shall know the sound of a step that will be different from all the others.
+Other steps send me hurrying back underneath the ground. Yours will call me, like music, out of
+my burrow. And then look: you see the grain-fields down yonder? I do not eat bread. Wheat is of
+no use to me. The wheat fields have nothing to say to me. And that is sad. But you have hair that
+is the colour of gold. Think how wonderful that will be when you have tamed me! The grain, which
+is also golden, will bring me back the thought of you. And I shall love to listen to the wind in the
+wheat...” The fox gazed at the little prince, for a long time. “Please, tame me!” he said.
+
+“I want to, very much,” the little prince replied. “But I have not much time. I have friends to
+discover, and a great many things to understand.”
+
+“One only understands the things that one tames,” said the fox. “Men have no more time to
+understand anything. They buy things all ready-made at the shops. But there is no shop anywhere
+where one can buy friendship, and so men have no friends any more. If you want a friend, tame
+me...”
+
+“What must I do, to tame you?” asked the little prince.
+
+“You must be very patient,” replied the fox. “First you will sit down at a little distance from me,
+like that, in the grass. I shall look at you out of the corner of my eye, and you will say nothing.
+Words are the source of misunderstandings. But you will sit a little closer to me, every day...”
+
+
+
+
+The next day the little prince came back.
+
+
+
+“It would have been better to come back at the same hour,” said the fox. “If, for example, you
+come at four o’clock in the afternoon, then at three o’clock I shall begin to be happy. I shall feel
+happier and happier as the hour advances. At four o’clock, I shall already be worrying and
+jumping about. I shall show you how happy I am! But if you come at just any time, I shall never
+know at what hour my heart is to be ready to greet you... One must observe the proper rites...”
+
+“What is a rite?” asked the little prince.
+
+“Those also are actions too often neglected,” said the fox. “They are what make one day
+different from other days, one hour from other hours. There is a rite, for example, among my
+hunters. Every Thursday they dance with the village girls. So Thursday is a wonderful day for me!
+I can take a walk as far as the vineyards. But if the hunters danced at just any time, every day
+would be like every other day, and I should never have any vacation at all.”
+
+So the little prince tamed the fox. And when the hour of his departure drew near...
+
+“Ah,” said the fox, “I shall cry.”
+
+“It is your own fault,” said the little prince. “I never wished you any sort of harm; but you wanted
+me to tame you...”
+
+“Yes, that is so,” said the fox.
+
+“But now you are going to cry!” said the little prince.
+
+“Yes, that is so,” said the fox.
+
+“Then it has done you no good at all!”
+
+“It has done me good,” said the fox, “because of the colour of the wheat fields.” And then he
+added: “Go and look again at the roses. You will understand now that yours is unique in all the
+world. Then come back to say goodbye to me, and I will make you a present of a secret.”
+
+The little prince went away, to look again at the roses. “You are not at all like my rose,” he said.
+“As yet you are nothing. No one has tamed you, and you have tamed no one. You are like my fox
+when I first knew him. He was only a fox like a hundred thousand other foxes. But I have made
+him my friend, and now he is unique in all the world.” And the roses were very much embarrassed.
+“You are beautiful, but you are empty,” he went on. “One could not die for you. To be sure, an
+ordinary passer-by would think that my rose looked just like you, the rose that belongs to me. But
+in herself alone she is more important than all the hundreds of you other roses: because it is she
+that I have watered; because it is she that I have put under the glass globe; because it is she that
+I have sheltered behind the screen; because it is for her that I have killed the caterpillars (except
+the two or three that we saved to become butterflies); because it is she that I have listened to,
+when she grumbled, or boasted, or even sometimes when she said nothing. Because she is my
+rose.
+
+And he went back to meet the fox. “Goodbye,” he said.
+
+“Goodbye,” said the fox. “And now here is my secret, a very simple secret: It is only with the
+heart that one can see rightly; what is essential is invisible to the eye.”
+
+
+
+
+“What is essential is invisible to the eye,” the little prince repeated, so that he would be sure to
+remember.
+
+“It is the time you have wasted for your rose that makes your rose so important.”
+
+“It is the time I have wasted for my rose...” said the little prince, so that he would be sure to
+remember.
+
+“Men have forgotten this truth,” said the fox. “But you must not forget it. You become
+responsible, forever, for what you have tamed. You are responsible for your rose...”
+
+“I am responsible for my rose,” the little prince repeated, so that he would be sure to remember.
+
+“Good morning,” said the little prince.
+
+“Good morning,” said the railway switchman.
+
+“What do you do here?” the little prince asked.
+
+“I sort out travellers, in bundles of a thousand,” said the switchman. “I send off the trains that
+carry them; now to the right, now to the left.” And a brilliantly lighted express train shook the
+switchman’s cabin as it rushed by with a roar like thunder.
+
+“They are in a great hurry,” said the little prince. “What are they looking for?”
+
+“Not even the locomotive engineer knows that,” said the switchman. And a second brilliantly
+lighted express thundered by, in the opposite direction.
+
+“Are they coming back already?” demanded the little prince. “These are not the same ones,” said
+the switchman. “It is an exchange.”
+
+“Were they not satisfied where they were?” asked the little prince.
+
+“No one is ever satisfied where he is,” said the switchman. And they heard the roaring thunder of
+a third brilliantly lighted express.
+
+“Are they pursuing the first travellers?” demanded the little prince.
+
+“They are pursuing nothing at all,” said the switchman. “They are asleep in there, or if they are
+not asleep they are yawning. Only the children are flattening their noses against the
+windowpanes.”
+
+“Only the children know what they are looking for,” said the little prince.
+
+“They waste their time over a rag doll and it becomes very important to them; and if anybody
+takes it away from them, they cry...” “They are lucky,” the switchman said.
+
+“Good morning,” said the little prince.
+
+“Good morning,” said the merchant.
+
+This was a merchant who sold pills that had been invented to quench thirst. You need only swallow
+one pill a week, and you would feel no need of anything to drink.
+
+
+
+
+“Why are you selling those?” asked the little prince.
+
+
+
+“Because they save a tremendous amount of time,” said the merchant. “Computations have been
+made by experts. With these pills, you save fifty-three minutes in every week.”
+
+“And what do I do with those fifty-three minutes?”
+
+“Anything you like...”
+
+“As for me,” said the little prince to himself, “if I had fifty-three minutes to spend as I liked, I
+should walk at my leisure toward a spring of fresh water.”
+
+It was now the eighth day since I had had my accident in the desert, and I had listened to the story
+of the merchant as I was drinking the last drop of my water supply.
+
+“Ah,” I said to the little prince, “these memories of yours are very charming; but I have not yet
+succeeded in repairing my plane; I have nothing more to drink; and I, too, should be very happy if
+I could walk at my leisure toward a spring of fresh water!”
+
+“My friend the fox...” the little prince said to me.
+
+“My dear little man, this is no longer a matter that has anything to do with the fox!”
+
+“Why not?”
+
+“Because I am about to die of thirst...”
+
+He did not follow my reasoning, and he answered me: “It is a good thing to have had a friend,
+even if one is about to die. I, for instance, am very glad to have had a fox as a friend...”
+
+“He has no way of guessing the danger,” I said to myself. “He has never been either hungry or
+thirsty. A little sunshine is all he needs...”
+
+But he looked at me steadily, and replied to my thought: “I am thirsty, too. Let us look for a
+well...” I made a gesture of weariness. It is absurd to look for a well, at random, in the immensity
+of the desert. But nevertheless we started walking.
+
+When we had trudged along for several hours, in silence, the darkness fell, and the stars began to
+come out. Thirst had made me a little feverish, and I looked at them as if I were in a dream. The
+little prince’s last words came reeling back into my memory: “Then you are thirsty, too?” I
+demanded. But he did not reply to my question. He merely said to me: “Water may also be good
+for the heart...”
+
+I did not understand this answer, but I said nothing. I knew very well that it was impossible to
+cross-examine him. He was tired. He sat down. I sat down beside him. And, after a little silence,
+he spoke again: “The stars are beautiful, because of a flower that cannot be seen.”
+
+I replied, “Yes, that is so.” And, without saying anything more, I looked across the ridges of sand
+that were stretched out before us in the moonlight.
+
+“The desert is beautiful,” the little prince added.
+
+And that was true. I have always loved the desert. One sits down on a desert sand dune, sees
+
+
+
+
+
+nothing, hears nothing. Yet through the silence something throbs, and gleams...
+
+“What makes the desert beautiful,” said the little prince, “is that somewhere it hides a well...”
+
+I was astonished by a sudden understanding of that mysterious radiation of the sands. When I was
+a little boy I lived in an old house, and legend told us that a treasure was buried there. To be sure,
+no one had ever known how to find it; perhaps no one had ever even looked for it. But it cast an
+enchantment over that house. My home was hiding a secret in the depths of its heart... “Yes,” I
+said to the little prince. “The house, the stars, the desert — what gives them their beauty is
+something that is invisible!”
+
+“I am glad,” he said, “that you agree with my fox.” As the little prince dropped off to sleep, I took
+him in my arms and set out walking once more. I felt deeply moved, and stirred. It seemed to me
+that I was carrying a very fragile treasure. It seemed to me, even, that there was nothing more
+fragile on all Earth. In the moonlight I looked at his pale forehead, his closed eyes, his locks of
+hair that trembled in the wind, and I said to myself:
+
+“What I see here is nothing but a shell. What is most important is invisible...”
+
+As his lips opened slightly with the suspicious of a half-smile, I said to myself, again: “What
+moves me so deeply, about this little prince who is sleeping here, is his loyalty to a flower — the
+image of a rose that shines through his whole being like the flame of a lamp, even when he is
+asleep...”
+
+And I felt him to be more fragile still. I felt the need of protecting him, as if he himself were a
+flame that might be extinguished by a little puff of wind... And, as I walked on so, I found the well,
+at daybreak.
+
+“Men,” said the little prince, “set out on their way in express trains, but they do not know what
+they are looking for. Then they rush about, and get excited, and turn round and round...” And he
+added: “It is not worth the trouble...”
+
+
+
+The well that we had come to was not like the wells of the Sahara. The wells of the Sahara are
+mere holes dug in the sand. This one was like a well in a village. But there was no village here,
+and I thought I must be dreaming...
+
+“It is strange,” I said to the little prince. “Everything is ready for use: the pulley, the bucket, the
+rope...” He laughed, touched the rope, and set the pulley to working. And the pulley moaned, like
+an old weathervane, which the wind has long since forgotten.
+
+“Do you hear?” said the little prince. “We have wakened the well, and it is singing...”
+
+I did not want him to tire himself with the rope.
+
+“Leave it to me,” I said. “It is too heavy for you.” I hoisted the bucket slowly to the edge of the
+well and set it there, happy, tired as I was, over my achievement. The song of the pulley was still
+in my ears, and I could see the sunlight shimmer in the still trembling water.
+
+“I am thirsty for this water,” said the little prince. “Give me some of it to drink...”
+
+And I understood what he had been looking for. I raised the bucket to his lips. He drank, his eyes
+closed. It was as sweet as some special festival treat. This water was indeed a different thing from
+ordinary nourishment. Its sweetness was born of the walk under the stars, the song of the pulley,
+the effort of my arms. It was good for the heart, like a present. When I was a little boy, the lights
+of the Christmas tree, the music of the Midnight Mass, the tenderness of smiling faces, used to
+make up, so, the radiance of the gifts I received.
+
+“The men where you live,” said the little prince, “raise five thousand roses in the same garden
+and they do not find in it what they are looking for.”
+
+“They do not find it,” I replied.
+
+“And yet what they are looking for could be found in one single rose, or in a little water.”
+
+“Yes, that is true,” I said.
+
+And the little prince added: “But the eyes are blind. One must look with the heart...”
+
+I had drunk the water. I breathed easily. At sunrise the sand is the colour of honey. And that
+honey colour was making me happy, too. What brought me, then, this sense of grief?
+
+“You must keep your promise,” said the little prince, softly, as he sat down beside me once more.
+“What promise?” “You know, a muzzle for my sheep... I am responsible for this flower...”
+
+I took my rough drafts of drawings out of my pocket. The little prince looked them over, and
+laughed as he said:
+
+“Your baobabs, they look a little like cabbages.”
+
+“Oh!” I had been so proud of my baobabs! “Your fox, his ears look a little like horns; and they are
+too long.” And he laughed again.
+
+“You are not fair, little prince,” I said. “I don’t know how to draw anything except boa constrictors
+from the outside and boa constrictors from the inside.”
+
+
+
+
+
+“Oh, that will be all right,” he said, “children understand.”
+
+So then I made a pencil sketch of a muzzle. And as I gave it to him my heart was torn.
+
+“You have plans that I do not know about,” I said. But he did not answer me. He said to me,
+instead: “You know, my descent to the earth... Tomorrow will be its anniversary.” Then, after a
+silence, he went on: “I came down very near here.” And he flushed.
+
+And once again, without understanding why, I had a queer sense of sorrow. One question,
+however, occurred to me: “Then it was not by chance that on the morning when I first met you — a
+week ago — you were strolling along like that, all alone, a thousand miles from any inhabited
+region? You were on the your way back to the place where you landed?”
+
+The little prince flushed again. And I added, with some hesitancy: “Perhaps it was because of the
+anniversary?” The little prince flushed once more. He never answered questions, but when one
+flushes does that not mean “Yes”?
+
+“Ah,” I said to him, “I am a little frightened...”
+
+But he interrupted me. “Now you must work. You must return to your engine. I will be waiting for
+you here. Come back tomorrow evening...”
+
+But I was not reassured. I remembered the fox. One runs the risk of weeping a little, if one lets
+himself be tamed...
+
+Beside the well there was the ruin of an old stone wall. When I came back from my work, the next
+evening, I saw from some distance away my little prince sitting on top of a wall, with his feet
+dangling. And I heard him say: “Then you don’t remember. This is not the exact spot.” Another
+voice must have answered him, for he replied to it: “Yes, yes! It is the right day, but this is not the
+place.”
+
+I continued my walk toward the wall. At no time did I see or hear anyone. The little prince,
+however, replied once again: “...Exactly. You will see where my track begins, in the sand. You have
+nothing to do but wait for me there. I shall be there tonight.”
+
+
+
+I was only twenty metres from the wall, and I still saw nothing. After a silence the little prince
+spoke again: “You have good poison? You are sure that it will not make me suffer too long?” I
+stopped in my tracks, my heart torn asunder; but still I did not understand. “Now go away,” said
+the little prince. “I want to get down from the wall.”
+
+I dropped my eyes, then, to the foot of the wall... and I leaped into the air. There before me, facing
+the little prince, was one of those yellow snakes that take just thirty seconds to bring your life to
+an end. Even as I was digging into my pocked to get out my revolver I made a running step back.
+But, at the noise I made, the snake let himself flow easily across the sand like the dying spray of
+a fountain, and, in no apparent hurry, disappeared, with a light metallic sound, among the stones. I
+reached the wall just in time to catch my little man in my arms; his face was white as snow.
+
+“What does this mean?” I demanded. “Why are you talking with snakes?”
+
+I had loosened the golden muffler that he always wore. I had moistened his temples, and had
+given him some water to drink. And now I did not dare ask him any more questions. He looked at
+me very gravely, and put his arms around my neck. I felt his heart beating like the heart of a
+dying bird, shot with someone’s rifle...
+
+“I am glad that you have found what was the matter with your engine,” he said. “Now you can go
+back home”
+
+“How do you know about that?” I was just coming to tell him that my work had been successful,
+beyond anything that I had dared to hope.
+
+He made no answer to my question, but he added: “I, too, am going back home today...” Then,
+sadly, “It is much farther... it is much more difficult...” I realised clearly that something
+extraordinary was happening. I was holding him close in my arms as if he were a little child; and
+yet it seemed to me that he was rushing headlong toward an abyss from which I could do nothing
+to restrain him... His look was very serious, like some one lost far away.
+
+“I have your sheep. And I have the sheep’s box. And I have the muzzle...”
+
+And he gave me a sad smile. I waited a long time. I could see that he was reviving little by little.
+
+“Dear little man,” I said to him, “you are afraid...” He was afraid, there was no doubt about that.
+But he laughed lightly.
+
+“I shall be much more afraid this evening...”
+
+Once again I felt myself frozen by the sense of something irreparable. And I knew that I could not
+bear the thought of never hearing that laughter any more. For me, it was like a spring of fresh
+water in the desert.
+
+“Little man,” I said, “I want to hear you laugh again.” But he said to me: “Tonight, it will be a
+year... my star, then, can be found right above the place where I came to the Earth, a year ago...”
+
+“Little man,” I said, “tell me that it is only a bad dream, this affair of the snake, and the meeting-
+place, and the star...” But he did not answer my plea.
+
+He said to me, instead: “The thing that is important is the thing that is not seen...” “Yes, I
+know...”
+
+
+
+
+“It is just as it is with the flower. If you love a flower that lives on a star, it is sweet to look at the
+sky at night. All the stars are a-bloom with flowers...”
+
+“Yes, I know...”
+
+“It is just as it is with the water. Because of the pulley, and the rope, what you gave me to drink
+was like music. You remember, how good it was.”
+
+“Yes, I know...”
+
+“And at night you will look up at the stars. Where I live everything is so small that I cannot show
+you where my star is to be found. It is better, like that. My star will just be one of the stars, for
+you. And so you will love to watch all the stars in the heavens... they will all be your friends. And,
+besides, I am going to make you a present...” He laughed again.
+
+“Ah, little prince, dear little prince! I love to hear that laughter!”
+
+“That is my present. Just that. It will be as it was when we drank the water...”
+
+“What are you trying to say?”
+
+“All men have the stars,” he answered, “but they are not the same things for different people. For
+some, who are travellers, the stars are guides. For others they are no more than little lights in the
+sky. For others, who are scholars, they are problems. For my businessman they were wealth. But
+all these stars are silent. You, you alone, will have the stars as no one else has them”
+
+“What are you trying to say?”
+
+“In one of the stars I shall be living. In one of them I shall be laughing. And so it will be as if all
+the stars were laughing, when you look at the sky at night... you, only you, will have stars that can
+laugh!”
+
+And he laughed again. “And when your sorrow is comforted (time soothes all sorrows) you will be
+content that you have known me. You will always be my friend. You will want to laugh with me. And
+you will sometimes open your window, so, for that pleasure... and your friends will be properly
+astonished to see you laughing as you look up at the sky! Then you will say to them, ‘Yes, the
+stars always make me laugh!’ And they will think you are crazy. It will be a very shabby trick that
+I shall have played on you...”
+
+And he laughed again. “It will be as if, in place of the stars, I had given you a great number of
+little bells that knew how to laugh...”
+
+And he laughed again. Then he quickly became serious: “Tonight, you know... do not come,” said
+the little prince.
+
+“I shall not leave you,” I said.
+
+“I shall look as if I were suffering. I shall look a little as if I were dying. It is like that. Do not
+come to see that. It is not worth the trouble...”
+
+“I shall not leave you.”
+
+
+
+But he was worried. “I tell you, it is also because of the snake. He must not bite you. Snakes, they
+
+
+
+
+are malicious creatures. This one might bite you just for fun...”
+
+
+
+“I shall not leave you.”
+
+But a thought came to reassure him: “It is true that they have no more poison for a second bite.”
+
+That night I did not see him set out on his way. He got away from me without making a sound.
+When I succeeded in catching up with him he was walking along with a quick and resolute step. He
+said to me merely: “Ah! You are there...” And he took me by the hand. But he was still worrying.
+“It was wrong of you to come. You will suffer. I shall look as if I were dead; and that will not be
+true...”
+
+I said nothing.
+
+“You understand... it is too far. I cannot carry this body with me. It is too heavy.”
+
+I said nothing.
+
+“But it will be like an old abandoned shell. There is nothing sad about old shells...”
+
+I said nothing. He was a little discouraged. But he made one more effort: “You know, it will be
+very nice. I, too, shall look at the stars. All the stars will be wells with a rusty pulley. All the stars
+will pour out fresh water for me to drink...”
+
+I said nothing.
+
+“That will be so amusing! You will have five hundred million little bells, and I shall have five
+hundred million springs of fresh water...” And he too said nothing more, because he was crying...
+
+“Here it is. Let me go on by myself.” And he sat down, because he was afraid. Then he said,
+again: “You know, my flower... I am responsible for her. And she is so weak! She has four thorns,
+of no use at all, to protect herself against all the world...”
+
+I too sat down, because I was not able to stand up any longer. “There now, that is all...”
+
+He still hesitated a little; then he got up. He took one step. I could not move. There was nothing
+but a flash of yellow close to his ankle. He remained motionless for an instant. He did not cry out.
+He fell as gently as a tree falls. There was not even any sound, because of the sand.
+
+And now six years have already gone by... I have never yet told this story.
+
+The companions who met me on my return were well content to see me alive. I was sad, but I told
+them: “I am tired.” Now my sorrow is comforted a little. That is to say, not entirely. But I know
+that he did go back to his planet, because I did not find his body at daybreak. It was not such a
+heavy body... and at night I love to listen to the stars. It is like five hundred million little bells...
+But there is one extraordinary thing... when I drew the muzzle for the little prince, I forgot to add
+the leather strap to it. He will never have been able to fasten it on his sheep.
+
+So now I keep wondering: what is happening on his planet? Perhaps the sheep has eaten the
+flower... At one time I say to myself: “Surely not! The little prince shuts his flower under her glass
+globe every night, and he watches over his sheep very carefully...” Then I am happy. And there is
+sweetness in the laughter of all the stars.
+
+
+
+
+But at another time I say to myself: “At some moment or other one is absent-minded, and that is
+enough! On some one evening he forgot the glass globe, or the sheep got out, without making any
+noise, in the night...” And then the little bells are changed to tears... Here, then, is a great
+mystery.
+
+For you who also love the little prince, and for me, nothing in the universe can be the same if
+somewhere, we do not know where, a sheep that we never saw has eaten a rose... Look up at the
+sky. Ask yourselves: is it yes or no?
+
+Has the sheep eaten the flower? And you will see how everything changes... And no grown-up will
+ever understand that this is a matter of so much importance! This is, to me, the loveliest and
+saddest landscape in the world. It is the same as that on the preceding page, but I have drawn it
+again to impress it on your memory. It is here that the little prince appeared on Earth, and
+disappeared. Look at it carefully so that you will be sure to recognise it in case you travel some
+day to the African desert. And, if you should come upon this spot, please do not hurry on. Wait for
+a time, exactly under the star. Then, if a little man appears who laughs, who has golden hair and
+who refuses to answer questions, you will know who he is. If this should happen, please comfort
+me. Send me word that he has come back.
+
+
+
+END
diff --git a/perf/texts/en-words.txt b/perf/texts/en-words.txt
new file mode 100644
index 0000000..14200fa
--- /dev/null
+++ b/perf/texts/en-words.txt
@@ -0,0 +1,12391 @@
+a
+A
+aa
+AA
+aaa
+AAA
+aaae
+AAAu
+AAB
+AAC
+aacute
+Aacute
+Aacutesmall
+AAD
+aae
+AAE
+aaf
+AAF
+aalt
+aao
+aarch
+Aari
+aat
+AAT
+aatFeatureType
+AAu
+ab
+AB
+Abaza
+abb
+ABBREV
+abc
+ABC
+abcde
+abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+ABD
+ABE
+ABEu
+ABF
+ABFu
+abh
+ABI
+ability
+Abkhazian
+able
+Aboriginal
+ABORIGINAL
+abort
+about
+above
+Above
+ABOVE
+abq
+abs
+absolute
+absolutely
+absorb
+abstraction
+abstractions
+ABu
+abuse
+abv
+ABVF
+abvm
+abvs
+ABVS
+ABx
+ABxCD
+ABxD
+ac
+AC
+acb
+ACBu
+acc
+ACC
+accel
+Accelerate
+accelerator
+ACCELERATOR
+accels
+accent
+ACCENT
+accents
+accept
+acceptable
+accepted
+accepting
+accepts
+access
+Access
+accessed
+accessible
+accessing
+accessors
+accommodate
+Accommodate
+accompanying
+accomplish
+according
+According
+account
+accounting
+ACCu
+accumulate
+Accumulate
+accuracy
+accurate
+AccuT
+ACDu
+acf
+ach
+Achi
+achieve
+Acholi
+achung
+achVendID
+acircumflex
+Acircumflex
+Acircumflexsmall
+ack
+acm
+Acoli
+acom
+acq
+ACQ
+acquire
+ACQUIRE
+acr
+across
+act
+action
+Action
+ACTION
+actionable
+actionClass
+actionData
+actionLength
+actions
+Actions
+ActionSubrecord
+ActionSubrecordHeader
+actionType
+ActionType
+activated
+activates
+active
+acts
+actual
+Actual
+actualGlyphsCount
+actually
+ACu
+acute
+Acutesmall
+acw
+acx
+acy
+ad
+AD
+ada
+Adamawa
+Adangme
+Adap
+adapt
+Adapted
+Adaptors
+aData
+adb
+ADBu
+add
+Add
+addcnt
+added
+AddFontMemResourceEx
+addGlyph
+adding
+Adding
+addition
+Addition
+additional
+Additional
+additionalCount
+additions
+addr
+AddRef
+address
+addressof
+adds
+ADDu
+Adeni
+adequate
+adf
+adieresis
+Adieresis
+Adieresissmall
+Adilabad
+adjacent
+Adjacent
+adjust
+Adjust
+adjusted
+adjustment
+adjustments
+Adjusts
+ADL
+Adlam
+ADLAM
+adobe
+Adobe
+adopt
+Adopted
+adorned
+adp
+ADu
+adv
+advance
+Advance
+Advanced
+advanceMax
+advanceMeasurement
+advanceOffset
+advances
+ADVANCES
+Advancing
+advantage
+ADVISED
+advMap
+ady
+Adyghe
+ae
+AE
+aea
+aeaf
+aeb
+aec
+AEDu
+AEEu
+AEFu
+Aegean
+AEsmall
+AEu
+af
+AF
+afa
+afadd
+Afar
+AFAu
+afb
+AFBAu
+AFBu
+AFDKO
+AFEu
+AFF
+affect
+affected
+affecting
+affects
+affinity
+Afghanistan
+Africa
+Afrikaans
+after
+After
+AFTER
+afterGrowLimit
+afterShrinkLimit
+AFu
+AG
+again
+against
+Agaw
+Agfa
+agnostic
+agrave
+Agrave
+Agravesmall
+agree
+agreement
+ahead
+Aheri
+ahg
+Ahom
+AHOM
+aht
+Ahtena
+ai
+AI
+aii
+AIN
+aio
+Aiton
+aiw
+AIX
+ajp
+ak
+aka
+AKA
+Akan
+AKAT
+AKHN
+alaph
+ALAPH
+alas
+Alaska
+Alaskan
+Albania
+Albanian
+ALBANIAN
+Albay
+alef
+Alef
+ALEF
+Algeria
+Algerian
+algorithm
+Algorithm
+algorithmic
+algorithms
+Algorithms
+algs
+ALGS
+alias
+aliased
+aliases
+aliasing
+align
+aligned
+alignment
+alignof
+aligns
+alive
+all
+All
+ALL
+ALLAH
+AllDirections
+Allison
+alloc
+Alloc
+allocate
+Allocate
+ALLOCATE
+allocated
+allocates
+allocating
+allocation
+Allocation
+allocations
+Allocations
+allocator
+allow
+Allow
+allowed
+allowing
+allows
+almost
+aln
+alone
+along
+alpha
+Alpha
+alphabet
+Alphabet
+alphabetic
+Alphabetic
+alphabetical
+alphabetically
+Alphanumeric
+Alphanumerics
+already
+als
+Alsatian
+also
+Also
+alt
+ALT
+Altai
+alter
+alternate
+Alternate
+ALTERNATE
+alternates
+ALTERNATES
+alternateSet
+AlternateSet
+AlternateSubst
+AlternateSubstFormat
+alternative
+Alternatively
+ALTERNATIVES
+although
+Although
+alts
+always
+Always
+am
+AM
+ambiguity
+ambiguous
+Ambo
+Amend
+American
+Americanist
+amf
+Amharic
+among
+amongst
+amount
+Amoy
+amp
+ampersand
+ampersandsmall
+amw
+an
+An
+AN
+Ana
+analysis
+Analysis
+ANALYSIS
+analyze
+Analyze
+analyzer
+Analyzer
+analyzers
+Analyzes
+AnalyzeScript
+ANATOLIAN
+Ancash
+anchor
+Anchor
+anchorData
+anchored
+AnchorFormat
+AnchorMatrix
+anchorPoint
+anchors
+Ancient
+and
+And
+AND
+android
+Android
+ANDROID
+ang
+angle
+Angle
+ANGLE
+Anglo
+ankr
+ANKR
+ankrActionIndex
+ankrData
+annex
+annotate
+Annotated
+annotation
+ANNOTATION
+annotations
+another
+Another
+Ansi
+Antankarana
+Antillean
+any
+Any
+ANY
+anymore
+anything
+Anything
+anyway
+ap
+Apache
+apc
+apd
+Api
+API
+apis
+APIs
+apj
+apk
+apl
+apm
+APP
+Apparently
+appear
+appearance
+appearing
+append
+Append
+APPEND
+appended
+appending
+Appendix
+AppendixF
+Appends
+Appl
+APPL
+apple
+Apple
+APPLE
+AppleColorEmoji
+applicable
+Applicable
+APPLICABLE
+application
+applications
+Applications
+ApplicationServices
+applied
+applies
+apply
+Apply
+APPLY
+applying
+Applying
+approach
+approaches
+appropriate
+approxequal
+approximate
+appveyor
+April
+apt
+Apurímac
+apw
+AQ
+ar
+Arabia
+ARABIAN
+arabic
+Arabic
+ARABIC
+ArabicShaping
+Aragonese
+Arakanese
+Arakwal
+Aramaic
+ARAMAIC
+arb
+Arbëreshë
+arbitrarily
+arbitrary
+ARC
+Archaic
+architecturally
+archive
+archives
+are
+ARE
+area
+Area
+Arequipa
+arg
+ARG
+Argentina
+Argh
+args
+ARGS
+argStack
+argument
+arguments
+aring
+Aring
+Aringsmall
+ARISING
+arith
+arithmetic
+Ariza
+armcc
+Armenia
+Armenian
+ARMENIAN
+arn
+Aromanian
+around
+arounds
+Arpitan
+arq
+arr
+arranged
+array
+Array
+ARRAY
+ArrayOf
+ArrayOfM
+arrays
+arrayZ
+arrive
+Arrows
+ars
+Arsi
+articles
+Arvanitika
+ary
+arz
+as
+As
+AS
+Asat
+ascender
+ASCENDER
+ascenderOffset
+ascending
+ascent
+ASCENT
+ascii
+ASCII
+asciicircum
+asciitilde
+Asho
+Asian
+aSize
+asked
+Asking
+Asmall
+Asomtavruli
+aspect
+aspects
+aspx
+Assamese
+assembly
+assert
+ASSERT
+assertion
+ASSERTION
+assign
+Assign
+ASSIGN
+assignable
+assigned
+assigns
+assistance
+assisted
+associated
+associates
+associating
+Association
+assume
+Assume
+assumed
+Assumed
+assuming
+Assuming
+assumption
+Assumption
+Assyrian
+ast
+asterisk
+ASTERISK
+Asturian
+asuperior
+at
+At
+atexit
+ATEXIT
+aTextPosition
+ath
+Athapascan
+Athapaskan
+Atikamekw
+atilde
+Atilde
+Atildesmall
+atj
+Atlas
+atleast
+ATLEAST
+atomic
+Atomic
+ATOMIC
+Atomically
+atomics
+atsFont
+ATSFontGetFileReference
+ATSFontRef
+attach
+Attach
+ATTACH
+attached
+ATTACHED
+attaches
+attaching
+attachList
+AttachList
+attachment
+Attachment
+ATTACHMENT
+attachments
+attachPoint
+AttachPoint
+attempt
+attempted
+attempts
+Attempts
+attr
+ATTR
+attractive
+attrib
+attribute
+ATTRIBUTE
+attributed
+attributes
+Attributes
+attrs
+atv
+au
+Au
+AU
+audiences
+augmented
+Australia
+Austria
+Author
+AUTHOR
+authors
+auto
+AUTO
+autoconf
+autogen
+automake
+automatic
+Automatic
+automatically
+auxiliary
+Auxiliary
+auz
+av
+AV
+Avagraha
+AVAGRAHA
+avail
+Availability
+AvailabilityMacros
+available
+avar
+Avar
+AVAR
+Avaric
+AVESTAN
+avl
+avoid
+Avoid
+avoided
+avoiding
+avoids
+aw
+awa
+Awa
+Awadhi
+aware
+away
+awful
+ax
+Ax
+AxCD
+AxD
+axes
+axesZ
+axis
+Axis
+AXIS
+axisCount
+axisIndex
+axisNameID
+AxisRecord
+axisSize
+axisTag
+AxisValue
+axisValueCount
+AxisValueFormat
+AxisValueMap
+AxisValueRecord
+axisValues
+ay
+Ayacucho
+ayc
+ayh
+AYIN
+ayl
+Aymara
+ayn
+ayp
+ayr
+az
+azb
+Azerbaijan
+Azerbaijani
+Azeri
+azj
+b
+B
+ba
+BA
+Babalia
+Babine
+BABu
+Bacanese
+back
+backend
+backends
+background
+Background
+BACKGROUND
+backing
+backslash
+backtrack
+backtrackClassDef
+backtrackCount
+backtracking
+backward
+BACKWARD
+backwards
+Backwards
+bad
+Badaga
+badly
+BADLY
+bae
+BAEu
+BAFu
+Bagheli
+Baghelkhandi
+Bagirmi
+Bagri
+Baharna
+Bahrain
+bai
+bail
+Bakhtiari
+bal
+Balanta
+Balante
+Balinese
+BALINESE
+Balkan
+Balkar
+Balochi
+Balti
+Baltic
+Baluchi
+Bamanankan
+Bambara
+Bamileke
+BAMUM
+ban
+Banda
+Bandjalang
+Bangka
+Bangladesh
+Bangun
+Banjar
+Banna
+Baoulé
+bar
+Bara
+BARREE
+barrier
+Barrier
+bars
+Bas
+base
+Base
+BASE
+baseArray
+BaseArray
+BaseCoord
+BaseCoordFormat
+baseCoords
+baseCoverage
+BaseCoverage
+based
+Based
+BaseFontBlend
+baseFontName
+BaseFontName
+BaseGlyph
+BaseGlyphRecord
+baseGlyphsZ
+BaseLangSysRecord
+baseLangSysRecords
+BaseLangSysRecords
+baseLangSysTag
+baseline
+Baseline
+BASELINE
+baselines
+BaselineTableFormat
+baselinetags
+baselineTags
+bases
+baseScript
+BaseScript
+baseScriptList
+BaseScriptList
+BaseScriptRecord
+baseScriptRecords
+BaseScriptRecords
+baseScriptTag
+baseTagCount
+baseTagList
+BaseTagList
+baseValues
+BaseValues
+Bashkir
+basic
+Basic
+BASIC
+basically
+BASIS
+Basque
+BASSA
+Batak
+BATAK
+batch
+BAu
+Baulé
+Bavarian
+Bawm
+BB
+BBAu
+BBBu
+bbc
+bbee
+BBEu
+BBF
+BBu
+bbz
+bc
+BC
+bca
+BCA
+BCAu
+BCBu
+bcc
+BCCu
+bcd
+BCD
+BCDu
+BCEu
+bci
+bcl
+bcp
+BCP
+bcq
+bcr
+BCu
+bcursor
+bd
+BD
+bdadd
+bdfaab
+bdu
+BDu
+bdy
+be
+Be
+BE
+bea
+BEAM
+bearing
+bearings
+bearingX
+bearingY
+Beaver
+beb
+Bebele
+Bebil
+bec
+because
+Because
+become
+BECOME
+becomes
+bed
+Bedawi
+BEEH
+been
+BEEN
+BEEu
+before
+Before
+BEFORE
+beforeGrowLimit
+beforehand
+beforeShrinkLimit
+BeforeSub
+began
+begin
+BEGIN
+beginning
+Beginning
+BEH
+behave
+behaved
+behaving
+behavior
+behaviors
+behaviour
+Behdad
+BEHEH
+behind
+Bei
+being
+Being
+BEInt
+Belarus
+Belarusian
+Belarussian
+Belgium
+Belize
+belong
+belonging
+belongs
+below
+Below
+BELOW
+bem
+Bemba
+Bench
+bend
+benefits
+BENG
+Bengali
+BENGALI
+ber
+Berau
+Berber
+best
+Bet
+BET
+Beti
+bets
+Betsimisaraka
+better
+between
+BEu
+beyond
+bf
+BF
+bfaeafe
+BFAu
+bfb
+BFF
+bffc
+BFFu
+bfind
+BFIND
+bfq
+bft
+bfu
+BFu
+bfy
+bg
+bgc
+bgn
+bgp
+bgq
+bgr
+BGRAColor
+Bhaiksuki
+BHAIKSUKI
+Bhasha
+bhb
+bhi
+Bhilali
+Bhili
+bhk
+bho
+Bhojpuri
+bhr
+bi
+Bi
+bias
+biased
+biasedSubrs
+Bible
+Bicolano
+bidi
+bidirectional
+BiDirectional
+bidirectionality
+big
+Big
+BIG
+BigGlyphMetrics
+bik
+Bikol
+BILD
+Bilen
+Bilin
+billion
+bimap
+BIMAP
+bin
+binaries
+binary
+Binary
+BINARY
+bindings
+Bindu
+BINDU
+Bindus
+BinSearchArrayOf
+BinSearchHeader
+Bishnupriya
+Bislama
+bit
+Bit
+bitcount
+bitDepth
+bitfield
+bithacks
+Bithacks
+bitmap
+Bitmap
+BITMAP
+bitmaps
+BitmapSizeTable
+bits
+Bits
+BITS
+BitScanForward
+BitScanReverse
+bitset
+bitsize
+bitwise
+bjj
+bjn
+BJN
+bjq
+bjt
+bl
+BL
+bla
+black
+Black
+BLACK
+Blackfoot
+blackhole
+blacklist
+BLACKLIST
+blacklisted
+blacklisting
+Blas
+ble
+blend
+Blend
+BLEND
+blendcs
+blenddict
+blended
+blending
+BlendInterpEnv
+blends
+Blink
+blk
+bln
+blob
+BLOB
+blobs
+Blobs
+block
+Block
+BLOCK
+blocked
+Blocked
+blocks
+Blocks
+Bloom
+blow
+blown
+blue
+Blue
+BlueFuzz
+BlueScale
+BlueShift
+BlueValues
+blwf
+BLWF
+blwm
+blws
+BLWS
+bm
+bmg
+bmm
+bmp
+BMP
+bn
+bo
+Bodo
+body
+bok
+Bokmal
+Bokmål
+bold
+Bold
+BOLD
+bolder
+Bolivia
+Bolivian
+book
+Book
+bookbold
+bookkeeping
+bool
+BOOL
+Boolean
+Booleans
+BOOM
+Bopomofo
+BOPOMOFO
+Borana
+BORDERS
+Borgu
+Borrowed
+Bosnia
+Bosnian
+BOT
+both
+bother
+bottom
+Bottom
+BOTTOM
+bottomSide
+bound
+Bound
+boundaries
+boundary
+Boundary
+bounding
+bounds
+Bounds
+BOUNDS
+Bouyei
+box
+Box
+BOX
+boxed
+BOXED
+boxes
+bpy
+bqi
+br
+BR
+bra
+braceleft
+braceright
+braces
+Bracket
+BRACKET
+bracketleft
+bracketright
+Brahmi
+BRAHMI
+Brahui
+Braille
+BRAILLE
+Braj
+branches
+brand
+Brawer
+Brazil
+break
+BREAK
+breakfast
+breaking
+breakpoint
+BREAKPOINT
+breaks
+bretagne
+Breton
+breve
+Brevesmall
+brew
+brh
+brief
+broken
+Broken
+brokenbar
+Brunei
+Bruno
+bruteforce
+brx
+bs
+bsb
+bsearch
+bsk
+bsln
+BSLN
+Bsmall
+bsuperior
+bswap
+btb
+btj
+bto
+bts
+btt
+BTT
+bu
+Bu
+Bualkhaw
+Bubble
+bucket
+buf
+buff
+buffArray
+buffer
+Buffer
+BUFFER
+buffers
+Buffers
+BUFSIZ
+bug
+BUG
+buggy
+Buginese
+BUGINESE
+Bugis
+bugs
+bugzilla
+Buhi
+Buhid
+BUHID
+build
+builder
+Builder
+building
+Building
+builds
+built
+builtin
+BUILTIN
+builtins
+Bukit
+Bukusu
+Bulgaria
+Bulgarian
+bulk
+bullet
+Bulu
+bum
+Bumthangkha
+bundles
+burden
+Buriat
+Burmese
+Burushaski
+business
+but
+But
+BUT
+BV
+bve
+bvu
+bxk
+bxp
+bxr
+by
+By
+BY
+Byagowi
+Byelorussian
+byes
+byn
+byte
+Byte
+BYTE
+byteArray
+byteOffsetToIndex
+bytes
+Bytes
+BYTES
+bytesArray
+bytesX
+bytesZ
+byv
+Byzantine
+bzc
+c
+C
+ca
+Ca
+CA
+CABu
+caca
+cache
+Cache
+CACHE
+cacheable
+cached
+caches
+caching
+Caching
+cacute
+Cacute
+caf
+cairo
+Cairo
+cairographics
+Cajamarca
+Cajatambo
+Cajun
+cak
+calcOffSize
+CalcTableChecksum
+calculate
+Calculate
+calculated
+calculates
+calculation
+Calderón
+Calibry
+call
+Call
+callback
+Callback
+callbacks
+CALLBACKS
+called
+Called
+caller
+callers
+callgsubr
+calling
+calloc
+calls
+Calls
+callStack
+callsubr
+calt
+Cambodia
+Cameroon
+Campidanese
+can
+Can
+Canada
+Canadian
+CANADIAN
+Cañar
+CANCEL
+candidate
+candidates
+cannot
+Cannot
+canon
+canonical
+Canonical
+CANONICAL
+canonically
+cantarell
+Cantarell
+Cantillation
+CANTILLATION
+cap
+Cap
+CAP
+capabilities
+capable
+capital
+CAPS
+care
+careful
+carefully
+caret
+Caret
+CARET
+caretOffset
+carets
+caretSlopeDenominator
+caretSlopeNumerator
+caretSlopeRise
+caretSlopeRun
+CaretValue
+caretValueFormat
+CaretValueFormat
+caretValuePoint
+Carian
+CARIAN
+Caribbean
+caron
+Caronsmall
+Carpathian
+Carrier
+carry
+cas
+cascade
+cascading
+case
+CASE
+cases
+cast
+Cast
+casting
+casts
+Casts
+cat
+Cat
+CAT
+Catalan
+Catanduanes
+catch
+categories
+Categories
+CATEGORIES
+categorization
+categorize
+categorized
+categorizes
+category
+Category
+CATEGORY
+Cateories
+CAu
+CAUCASIAN
+cause
+caused
+causes
+causing
+cautious
+cb
+CB
+cbb
+CBCu
+cbdt
+CBDT
+CBEu
+CBFu
+cbk
+cbl
+cblc
+CBLC
+CBu
+cc
+Cc
+CC
+ccaron
+Ccaron
+CCAu
+CCBu
+ccc
+CCC
+ccccae
+cccf
+CCCu
+CCD
+CCDu
+ccedilla
+Ccedilla
+Ccedillasmall
+CCEu
+cChars
+ccmp
+cco
+ccq
+CCu
+cd
+CD
+CDATA
+cdd
+cdo
+CDu
+CDx
+CDxA
+CDxAB
+CDxBA
+ce
+CE
+ceb
+Cebuano
+CECu
+cedilla
+Cedillasmall
+CEDu
+CEEu
+ceil
+CEIL
+cent
+center
+Center
+centered
+CENTERED
+centinferior
+centoldstyle
+CentOS
+central
+Central
+centsuperior
+ceparams
+certain
+Certain
+CEu
+cf
+Cf
+CF
+cfar
+CFAR
+CFArrayAppendValue
+CFArrayCreate
+CFArrayCreateMutable
+CFArrayGetCount
+CFArrayGetValueAtIndex
+CFArrayRef
+CFAttributedStringCreateMutable
+CFAttributedStringRemoveAttribute
+CFAttributedStringReplaceString
+CFAttributedStringSetAttribute
+CFComparisonResult
+cfd
+CFData
+CFDataGetBytePtr
+CFDataGetLength
+CFDataRef
+CFDictionaryCreate
+CFDictionaryGetValue
+CFDictionaryRef
+CFDu
+CFEqual
+cff
+CFF
+cfff
+CFFIndex
+CFFIndexOf
+CFFTag
+CFFu
+CFIndex
+cfm
+CFMutableArrayRef
+CFMutableAttributedStringRef
+CFNumberCreate
+CFNumberRef
+CFRange
+CFRangeMake
+CFRelease
+CFRetain
+CFSTR
+CFStringCompare
+CFStringCreateWithCharactersNoCopy
+CFStringCreateWithCStringNoCopy
+CFStringGetCharacterAtIndex
+CFStringHasPrefix
+CFStringHasSuffix
+CFStringRef
+CFu
+CFURLCreateFromFSRef
+CFURLRef
+cg
+CGDataProviderCreateWithData
+CGDataProviderRef
+CGDataProviderRelease
+CGFloat
+CGFont
+CGFontCopyPostScriptName
+CGFontCopyTableForTag
+CGFontCreateWithDataProvider
+CGFontRef
+CGFontRelease
+CGFontRetain
+cgg
+CGGlyph
+cgi
+cgit
+CGJ
+cGlyphs
+CGPoint
+ch
+Chachapoyas
+Chadian
+Chaha
+chain
+Chain
+chainContext
+ChainContext
+ChainContextApplyLookupContext
+ChainContextClosureLookupContext
+ChainContextCollectGlyphsLookupContext
+ChainContextFormat
+ChainContextPos
+ChainContextSubst
+chainCount
+chaining
+Chaining
+ChainRule
+ChainRuleSet
+chains
+Chains
+ChainSubtable
+Chakma
+CHAKMA
+Chaldean
+Cham
+CHAM
+Chamorro
+chance
+chandas
+change
+Change
+changed
+changes
+Changes
+changing
+channel
+channels
+Chap
+chapter
+Chapter
+char
+Char
+CHAR
+character
+Character
+CHARACTER
+characterCode
+characterize
+characters
+Characters
+CHARACTERS
+characterVariants
+charmap
+Charmap
+charMirror
+CHARPROP
+chars
+charset
+Charset
+CHARSET
+CharsetID
+charsetInfo
+CharsetOffset
+charstreing
+charstring
+CharString
+charstrings
+charStrings
+CharStrings
+charStringsInfo
+charStringsOffset
+CharstringType
+charts
+chattawa
+CHATTAWA
+Chattisgarhi
+Chaungtha
+Chavacano
+cheaper
+Chechen
+check
+Check
+CHECK
+checked
+CHECKED
+checking
+Checking
+checks
+Checks
+checksum
+checkSum
+CheckSum
+checkSumAdjustment
+Cherokee
+CHEROKEE
+Chetco
+Chewa
+Cheyenne
+Chhattisgarhi
+Chichewa
+Chiga
+Chiki
+CHIKI
+Chilcotin
+child
+children
+Chile
+Chilean
+Chillus
+Chiltepec
+Chimborazo
+Chin
+China
+Chinantec
+Chinbon
+Chincha
+Chinese
+Chipewyan
+Chippewa
+Chiquián
+Chiricahua
+Chiripá
+Chittagonian
+chj
+chk
+CHL
+cho
+Choctaw
+choice
+choices
+choose
+Choose
+chooses
+choosing
+chop
+Chop
+chosen
+CHOSEONG
+chp
+chq
+chr
+chris
+Chris
+chromium
+Chromium
+Chuanqiandian
+Chukchi
+Chukot
+chunk
+ChunkLen
+chunks
+Church
+Chuukese
+Chuvash
+chy
+chz
+ci
+CI
+CID
+cidCount
+CIDCount
+CIDFontRevision
+CIDFontType
+CIDFontVersion
+CIN
+cInChars
+CIP
+circle
+CIRCLE
+circles
+circuit
+CIRCUIT
+circumflex
+Circumflexsmall
+circumstances
+circumvents
+citer
+CITI
+ciw
+cja
+CJCT
+CJK
+cjm
+cjy
+ck
+CK
+cka
+ckb
+ckt
+cl
+Clamp
+clang
+clarity
+Clasen
+class
+Class
+CLASS
+classArray
+classCount
+classDef
+ClassDef
+ClassDefFormat
+classes
+classFormat
+Classic
+Classical
+classifications
+classified
+classify
+classTable
+ClassTable
+ClassType
+ClassTypeNarrow
+ClassTypeWide
+classValue
+classValueArray
+clc
+cld
+cle
+clean
+Clean
+cleanest
+clear
+Clear
+cleared
+clearing
+clearly
+clears
+Clears
+ClearType
+ClearType™
+client
+Client
+clients
+Clients
+clig
+clipping
+CLIPPING
+clockwise
+close
+Close
+CLOSE
+CloseHandle
+closely
+closer
+closest
+CLOSEST
+closure
+Closure
+CLOSURE
+closures
+cluster
+Cluster
+CLUSTER
+clustering
+clusterMap
+clusters
+Clusters
+CLUSTERS
+clz
+clzl
+clzll
+CM
+CMAbv
+cmake
+cmap
+CMAP
+cmapsubtable
+CmapSubtable
+CmapSubtableFormat
+CmapSubtableLongGroup
+CmapSubtableLongSegmented
+CmapSubtableTrimmed
+cMaxGlyphs
+cMaxItems
+CMBlw
+cmn
+cmp
+cmpexch
+cmplexch
+cmpswap
+cmr
+cn
+Cn
+cnb
+cnh
+cnk
+cnl
+cnt
+cntrmask
+cnw
+co
+Co
+coa
+Cocos
+code
+Code
+CODE
+codebase
+coded
+codepath
+codepoint
+CODEPOINT
+codepoints
+codepont
+codes
+Codethink
+Coeng
+COENG
+coengs
+col
+Col
+collect
+Collect
+COLLECT
+collected
+collection
+Collection
+collections
+Collections
+collects
+Colombia
+colon
+COLON
+colonmonetary
+color
+Color
+COLOR
+colorIdx
+colorLabelsZ
+ColorRecord
+colorRecordIndicesZ
+colorRecordsZ
+colorRef
+colors
+colorType
+Colour
+colr
+COLR
+cols
+COLS
+columnCount
+columnIndexTable
+com
+Comaltepec
+combination
+combinations
+combine
+COMBINE
+combined
+combiner
+combiners
+combining
+Combining
+COMBINING
+come
+comes
+comfortably
+coming
+comma
+COMMA
+commainferior
+command
+Command
+commands
+commas
+commasuperior
+comment
+Commenting
+comments
+commit
+commitcomment
+commits
+common
+Common
+COMMON
+commonly
+Comorian
+comp
+compact
+Compact
+compar
+compare
+Compare
+compared
+compares
+comparing
+Comparing
+comparison
+compat
+compatibility
+Compatibility
+COMPATIBILITY
+compatible
+COMPATIBLE
+compensate
+compilable
+compile
+Compile
+compiled
+compiler
+Compiler
+compilers
+compiles
+COMPILES
+compiling
+complains
+complang
+Complement
+complete
+Complete
+completely
+complex
+Complex
+COMPLEX
+COMPLEXITY
+complicated
+component
+COMPONENT
+componentData
+ComponentGlyph
+components
+Components
+COMPONENTS
+ComponentsArray
+composable
+compose
+composed
+COMPOSED
+composePair
+composes
+Composes
+composing
+composite
+COMPOSITE
+CompositeGlyph
+CompositeGlyphChain
+composites
+composition
+Composition
+COMPOSITION
+COMPOUND
+compressed
+compressionMethod
+comprise
+comprising
+comps
+compute
+Compute
+Computes
+computing
+concepts
+Concepts
+conceptual
+Conceptually
+concern
+concerned
+Conchucos
+cond
+Cond
+condensed
+Condensed
+CONDENSED
+condition
+Condition
+conditional
+conditionalAddGlyphAction
+ConditionalAddGlyphAction
+conditionally
+ConditionFormat
+conditions
+Conditions
+ConditionSet
+config
+CONFIG
+configs
+configuration
+Configuration
+configurations
+configure
+configured
+conflicting
+confused
+confusing
+Congo
+conjunct
+connect
+CONNECT
+connected
+CONNECTED
+connecting
+connection
+CONNECTION
+connector
+CONNECTOR
+Cons
+CONS
+consecutive
+CONSEQUENTIAL
+Consequently
+consider
+Consider
+considerably
+consideration
+considerations
+considered
+consist
+consistent
+consists
+consonant
+Consonant
+CONSONANT
+consonants
+const
+CONST
+constant
+CONSTANT
+constants
+Constants
+constexpr
+constituent
+constitute
+constitutes
+constraints
+CONSTRAINTS
+construct
+constructed
+constructible
+construction
+constructor
+constructors
+Constructors
+constructs
+consult
+consumed
+contain
+contained
+container
+containers
+containing
+contains
+ContainsTextPosition
+contemporary
+content
+CONTENT
+contents
+context
+Context
+CONTEXT
+ContextApplyFuncs
+ContextApplyLookupContext
+ContextClosureFuncs
+ContextClosureLookupContext
+ContextCollectGlyphsFuncs
+ContextCollectGlyphsLookupContext
+ContextFormat
+ContextPos
+contexts
+ContextSubst
+contextual
+Contextual
+CONTEXTUAL
+ContextualSubtable
+contiguous
+continuation
+CONTINUATION
+continuations
+continue
+continues
+contour
+Contour
+contours
+contract
+CONTRACT
+contrary
+contrast
+contributing
+Contributor
+control
+Control
+CONTROL
+controlling
+controls
+convenience
+conveniences
+convenient
+conventions
+Conversely
+conversion
+Conversion
+Conversions
+convert
+Convert
+converted
+Converted
+converters
+convertible
+converting
+Converts
+convoluted
+coord
+coordinate
+Coordinate
+coordinates
+Coordinates
+COORDINATES
+coordinatesZ
+coordPoint
+coords
+coorinates
+cop
+copied
+Copied
+copies
+Copies
+Coptic
+COPTIC
+copy
+Copy
+COPY
+copyable
+copying
+copyright
+Copyright
+COPYRIGHT
+coq
+Coquille
+core
+CoreGraphics
+coretext
+CoreText
+CORETEXT
+corner
+CORNER
+corners
+Cornish
+Corongo
+correct
+correction
+correctionHeight
+correctly
+Correctly
+correctness
+correlate
+correspond
+corresponding
+corresponds
+corrupt
+Corsican
+cost
+Costa
+costs
+costy
+cotfRecords
+could
+Could
+count
+Count
+COUNT
+countChar
+counted
+counter
+counting
+Counting
+CountMask
+countries
+counts
+couple
+Courier
+course
+courtesy
+cover
+coverage
+Coverage
+COVERAGE
+coverageFormat
+CoverageFormat
+coverageZ
+covered
+COVERED
+covering
+covers
+cp
+CP
+cpa
+cpal
+CPAL
+CPALV
+cpe
+cpf
+cplusplus
+cpp
+cppreference
+CPR
+CPrf
+cpx
+cqd
+cqu
+cr
+CRAMPED
+cRanges
+crap
+Crap
+CRAP
+CrapHelper
+CrapOrNull
+CrapOrNullHelper
+CrapPool
+crash
+crashes
+crazy
+crbug
+create
+Create
+CREATE
+CreateCustomFontFileReference
+created
+CreateFile
+CREATEFILE
+CreateFileMapping
+CreateFileMappingFromApp
+CreateFileW
+CreateFontFace
+CreateFontIndirectW
+creates
+Creates
+CreateStreamFromKey
+CreateTextAnalyzer
+creating
+Creating
+creation
+creator
+Cree
+Creek
+Creole
+creoles
+Creoles
+crh
+Crimean
+Crioulo
+criteria
+CRITICAL
+crj
+crk
+crl
+crm
+Croatia
+Croatian
+cross
+Cross
+crossStream
+CrossStream
+crp
+crucial
+crx
+cs
+Cs
+CS
+csa
+csb
+csh
+Csmall
+cso
+csop
+CSOPSET
+CSR
+CSS
+CSType
+csw
+cswh
+csy
+ct
+ctc
+ctd
+cte
+CTFont
+CTFontCopyAttribute
+CTFontCopyGraphicsFont
+CTFontCopyName
+CTFontCopyPostScriptName
+CTFontCreateCopyWithAttributes
+CTFontCreateUIFontForLanguage
+ctfontcreatewithgraphicsfont
+CTFontCreateWithGraphicsFont
+CTFontDescriptorCreateWithAttributes
+CTFontDescriptorCreateWithNameAndSize
+CTFontDescriptorRef
+CTFontGetPlatformFont
+CTFontGetSize
+CTFontRef
+CTFontUIFontType
+ctg
+CTGetCoreTextVersion
+ctl
+CTLineGetGlyphRuns
+CTLineGetTrailingWhitespaceWidth
+CTLineRef
+ctlPoints
+ctor
+CTRunGetAttributes
+CTRunGetGlyphCount
+CTRunGetGlyphs
+CTRunGetGlyphsPtr
+CTRunGetPositions
+CTRunGetPositionsPtr
+CTRunGetStatus
+CTRunGetStringIndices
+CTRunGetStringIndicesPtr
+CTRunGetStringRange
+CTRunGetTypographicBounds
+CTRunRef
+CTRunStatus
+cts
+CTTypesetterCreateLine
+CTTypesetterCreateWithAttributedStringAndOptions
+CTTypesetterRef
+CTYPE
+ctz
+ctzl
+ctzll
+cu
+Cu
+cuc
+cuk
+cumulated
+Cumulative
+Cuneiform
+CUNEIFORM
+cur
+curEntry
+Curiously
+CURISVE
+CURLY
+curr
+curradv
+curradvx
+curradvy
+currAnchor
+currAnchorPoint
+currclus
+currControlPoint
+currency
+Currency
+CURRENCY
+current
+Current
+CurrentCategory
+currentIndex
+currentInsertBefore
+CurrentInsertBefore
+currentInsertCount
+CurrentInsertCount
+currentInsertIndex
+currentInsertList
+CurrentIsKashidaLike
+currently
+Currently
+currX
+currY
+curs
+cursive
+Cursive
+CURSIVE
+CursivePos
+CursivePosFormat
+cursor
+Cursor
+cursoring
+curve
+CURVE
+Cusco
+custom
+Custom
+customization
+customize
+customizing
+Customizing
+CustomRange
+cut
+CUT
+cutting
+cv
+cvn
+CVT
+cvXX
+cwd
+CWS
+cx
+cy
+CYGWIN
+Cypriot
+CYPRIOT
+Cyrillic
+CYRILLIC
+Czech
+czh
+czo
+czt
+d
+D
+da
+DA
+Daai
+DAD
+DAFu
+dagesh
+DAGESH
+dagger
+daggerdbl
+DAHAL
+Dai
+DAL
+DALATH
+DALET
+dam
+DAMAGE
+DAMAGES
+damma
+dammatan
+Dan
+dance
+dangerous
+Dangme
+Danish
+dao
+dap
+dar
+Dargwa
+Dari
+dark
+DARK
+Darkhat
+Darussalam
+Darwazi
+DASH
+data
+Data
+DATA
+dataArray
+dataArrayLen
+Database
+dataLen
+dataLength
+DataMap
+dataMaps
+dataOffset
+dataset
+dataSets
+dataSize
+dataSizeArray
+dataZ
+Date
+DAu
+David
+Daw
+dax
+day
+Dayi
+db
+DB
+DBAu
+DBBu
+DBCu
+DBEu
+DBF
+dbfo
+DBL
+DBu
+dc
+DC
+DCA
+DCAu
+DCBu
+DCFu
+dcroat
+DCu
+DCx
+DCxA
+DCxAB
+DCxBA
+dd
+DD
+DDA
+DDAHAL
+DDAL
+DDAu
+DDCu
+DDD
+DDDu
+dde
+DDEu
+ddf
+DDF
+DDFu
+DDu
+de
+DE
+deabc
+Dead
+DEAD
+deal
+deallocate
+Deallocate
+DEALLOCATE
+deallocation
+dealt
+DEAu
+Debian
+debug
+Debug
+DEBUG
+debugging
+Debugging
+dec
+decay
+decender
+decide
+Decide
+deciding
+DECIMAL
+decipoints
+decision
+decisions
+declaration
+declarations
+declare
+Declare
+DECLARE
+declared
+declaring
+decls
+DECLS
+declspec
+decltype
+declval
+decode
+DECODE
+decomp
+decompose
+Decompose
+DECOMPOSE
+decomposed
+DECOMPOSED
+decomposedglyphs
+decomposes
+decomposing
+decomposition
+DECOMPOSITION
+decompositionAction
+DecompositionAction
+decompositions
+decompressed
+deconstructed
+DECORATIVE
+DecorativeBorders
+decrease
+decreased
+decreases
+Decreases
+decreasing
+deduce
+deduced
+deduces
+deem
+deemed
+deep
+def
+DEF
+defaul
+default
+Default
+DEFAULT
+defaultBaseline
+defaultFlags
+defaultIndex
+DefaultJstfLangSys
+defaultLangSys
+DefaultLangSys
+defaultMinMax
+defaults
+defaultUVS
+DefaultUVS
+defaultValue
+defaultVertOriginY
+defaultWidthX
+define
+DEFINE
+defined
+Defined
+DEFINED
+defines
+Defines
+defining
+Defining
+definition
+Definition
+definitions
+Definitions
+DEFu
+Degexit
+degree
+DEGREE
+degrees
+Dehong
+DejaVu
+del
+delayed
+delete
+DELETE
+DeleteCriticalSection
+deleted
+DELETED
+DeleteObject
+deleting
+delimited
+DELIMITED
+delta
+Delta
+DELTA
+deltaFormat
+deltaGlyphID
+deltas
+DELTAS
+DeltaSetIndexMap
+DeltaValue
+deltaValueZ
+Democratic
+demonstrate
+den
+DENIED
+Denmark
+denom
+DENOM
+DENOMINATOR
+denote
+density
+depend
+dependant
+dependencies
+dependency
+dependent
+Dependent
+DEPENDENT
+depending
+depends
+deprecated
+Deprecated
+DEPRECATED
+depth
+deref
+dereference
+dereferenced
+dereferencing
+derived
+Derived
+DerivedCoreProperties
+desc
+descendent
+descender
+DESCENDER
+descending
+descent
+DESCENT
+describe
+described
+describes
+describing
+description
+Description
+DESCRIPTION
+descriptor
+descriptors
+Deseret
+DESERET
+deserialize
+DESERIALIZE
+design
+Design
+DESIGN
+designated
+designates
+designAxesOffset
+designAxisCount
+designAxisSize
+designed
+designer
+DESIGNER
+designSize
+desirable
+desired
+desktop
+dest
+destroy
+Destroy
+DESTROY
+destroyed
+destroying
+destroys
+Destroys
+destruct
+destructed
+destructible
+destruction
+desubroutinize
+detail
+detailed
+details
+detect
+detected
+determine
+Determine
+determined
+determines
+determining
+Determining
+DEu
+dev
+DEVA
+devanagari
+Devanagari
+DEVANAGARI
+devel
+develop
+developed
+developer
+developers
+developing
+development
+Deviate
+device
+Device
+DeviceHeader
+DeviceRecord
+devices
+deviceTable
+devnet
+df
+DF
+DFAu
+dfde
+DFDu
+dfe
+DFF
+DFFu
+dflt
+DFLT
+dfont
+DFont
+DFontTag
+DFu
+dgo
+dgr
+Dhangu
+dhd
+dhg
+Dhivehi
+Dhofari
+Dhundari
+Dhuwal
+Dhuwaya
+diacritic
+Diacritical
+diacritics
+DIACRITICS
+diagnostic
+DIAGNOSTIC
+DIAGONAL
+DIAMOND
+dib
+dict
+Dict
+DICT
+dictionary
+dicts
+dictsSize
+dictval
+DICTVAL
+did
+didn
+Didn
+didnt
+dieresis
+Dieresissmall
+diff
+DIFF
+differ
+difference
+differences
+different
+Different
+differentiate
+differently
+differing
+differs
+difficult
+difficulty
+digest
+DIGEST
+digests
+digit
+Digit
+DIGIT
+digital
+Digits
+dik
+dimensional
+dimensions
+Dimli
+din
+Dingbats
+DINGBATS
+Dinka
+dip
+DIPHTHONG
+diq
+dir
+DIR
+direct
+DIRECT
+direction
+Direction
+DIRECTION
+directional
+directionality
+directions
+directive
+directly
+directory
+directwrite
+DirectWrite
+DIRECTWRITE
+dirty
+disable
+Disable
+DISABLE
+disabled
+disableFlags
+disables
+disabling
+disallow
+disallows
+disambiguated
+Disc
+discard
+Discarding
+discards
+discern
+DISCLAIMS
+discover
+Discovered
+discretionary
+discussed
+Discussion
+dispatch
+Dispatch
+DISPATCH
+displacement
+display
+Display
+DISPLAY
+displaying
+dist
+distance
+Distance
+DISTANCE
+distances
+distinct
+distinction
+distinguish
+distinguishes
+distinguishing
+distribute
+distribution
+ditto
+div
+DIV
+Divehi
+divert
+divide
+DIVIDE
+divided
+divisible
+diw
+Djambarrpuyngu
+dje
+djr
+dks
+DLBAR
+dlig
+dll
+DLL
+dllexport
+dm
+dng
+dnj
+dnom
+do
+Do
+DO
+DOACHASHMEE
+doc
+Doc
+docbook
+DocBook
+docbookx
+docs
+DOCTYPE
+document
+Document
+documentation
+DOCUMENTATION
+documented
+documents
+Documents
+does
+Does
+doesn
+Doesn
+doesnt
+Dogra
+DOGRA
+Dogri
+Dogrib
+doi
+doing
+dollar
+dollarinferior
+dollaroldstyle
+dollarsuperior
+Domain
+dominant
+Dominican
+Domino
+don
+Don
+DON
+done
+Done
+DONE
+Dong
+dont
+DONT
+DontAdvance
+Dos
+DoS
+dot
+Dot
+DOT
+dotaccent
+Dotaccentsmall
+dotlessi
+dotsection
+dotted
+DOTTED
+dottedcircle
+DOTTEDCIRCLE
+Dotyali
+double
+DOUBLE
+down
+DOWN
+download
+downloaded
+Downloading
+downstream
+downward
+DPI
+DR
+dragons
+drain
+draw
+Draw
+drawing
+Drawing
+DRAWINGS
+drawn
+Drepper
+drh
+drive
+driver
+Driver
+drop
+Drop
+DROP
+dropped
+dropping
+drops
+drw
+ds
+dsb
+Dsmall
+dsohowto
+dst
+dsuperior
+dtd
+DTD
+dtor
+dty
+du
+Du
+dual
+Duano
+duct
+ductile
+ductileGlyphAction
+DuctileGlyphAction
+ductility
+due
+duj
+DUL
+dumb
+dumber
+Dumbest
+dummy
+Dummy
+Dungan
+dup
+dupe
+duplicate
+DUPLICATE
+duplicated
+Duplicated
+duplicates
+duplication
+DUPLOYAN
+dupped
+duration
+during
+During
+Dutch
+dv
+dw
+dwFeatures
+dwFileAttributes
+dwFileFlags
+DWORD
+dwrite
+DWrite
+DWRITE
+DWriteCreateFactory
+dwriteFactory
+DWriteFontFileLoader
+DWriteFontFileStream
+dwSecurityQosFlags
+dwSize
+dwu
+dwy
+dx
+Dx
+DxA
+DxAB
+DxBA
+dy
+DYEH
+dynamic
+dyu
+Dyula
+dz
+Dzongkha
+e
+E
+ea
+EA
+EAAu
+EABu
+each
+Each
+eachother
+EACu
+eacute
+Eacute
+Eacutesmall
+EADu
+eae
+EAEu
+EAFu
+eager
+earlier
+Earlier
+early
+EARLY
+easier
+East
+eastasian
+Eastern
+easy
+EAu
+eb
+EB
+EBAu
+EBBu
+EBCu
+ebdt
+EBDT
+EBDu
+EBEu
+EBFu
+Ebira
+eblc
+Ebrahim
+EBu
+ec
+EC
+ECAu
+ECBu
+ECCu
+ECD
+ecde
+ECDu
+ECE
+ECEu
+ecfb
+ECFu
+ecircumflex
+Ecircumflex
+Ecircumflexsmall
+ECu
+Ecuador
+ed
+ED
+eda
+EDAu
+EDBu
+EDCu
+EDDu
+EDEu
+EDFu
+edge
+edges
+edieresis
+Edieresis
+Edieresissmall
+edit
+edits
+EDITS
+Edo
+EDu
+ee
+EE
+EEAu
+EEBu
+EECu
+EEDu
+EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE
+EEELLLGGGGEEEE
+EEEu
+EEFu
+EEu
+ef
+EF
+EFEu
+EFF
+effect
+effectively
+effects
+efficiency
+efficiently
+effort
+efi
+Efik
+EFu
+eg
+Eg
+egrave
+Egrave
+Egravesmall
+Egypt
+Egyptian
+EGYPTIAN
+eight
+EIGHT
+EIGHTEEN
+eightinferior
+eightoldstyle
+eightsuperior
+EINTR
+either
+Either
+EK
+ekk
+el
+El
+ELBASAN
+ELEM
+element
+ELEMENT
+elements
+Elements
+ELEVEN
+elidable
+ELIDABLE
+elidedFallbackNameID
+elie
+Elie
+elif
+ellipsis
+ELLIPSIS
+else
+Else
+elt
+ELT
+ELYMAIC
+em
+EM
+embed
+embedded
+EmbeddedPeakTuple
+embedding
+EMBEDDING
+emboldening
+EMBOX
+emdash
+emk
+emoji
+Emoji
+EMOJI
+emphasis
+empty
+Empty
+EMPTY
+ems
+en
+EN
+enable
+Enable
+enabled
+ENABLED
+enableFlags
+enables
+enabling
+enb
+enc
+Enclosed
+enclosing
+ENCLOSING
+encode
+ENCODE
+encoded
+Encoded
+encoder
+Encodes
+encoding
+Encoding
+ENCODING
+encodingID
+EncodingID
+encodingOffset
+EncodingOffset
+encodingrec
+EncodingRecIter
+encodingRecord
+EncodingRecord
+encodings
+encounter
+encountered
+end
+End
+END
+endash
+endchar
+endCharCode
+endcode
+endCode
+endConnectorLength
+endCoord
+endCount
+endcp
+ended
+endGlyphID
+endGlyphIndex
+endian
+Endian
+ENDIAN
+endif
+ending
+EndPtr
+endPtsOfContours
+ends
+endSize
+Enets
+enf
+enforce
+engine
+Engine
+engines
+English
+ENGRAVED
+enh
+ENHANCEMENTS
+enlarge
+Enlarge
+enough
+ensure
+Ensure
+ensures
+enter
+EnterCriticalSection
+entire
+entirely
+entirety
+ENTITY
+entries
+Entries
+entry
+Entry
+entryAnchor
+EntryAnchor
+EntryData
+EntryExit
+entryExitRecord
+EntryExitRecord
+entrySelector
+EntryT
+entryTable
+enum
+enumerate
+enumerated
+Enumerates
+enumeration
+enumerations
+enums
+env
+ENV
+environment
+eo
+eof
+EOT
+epsilon
+eq
+equal
+EQUAL
+equality
+equally
+equals
+Equatorial
+equivalent
+Eric
+err
+Err
+Erratic
+erratically
+erring
+errno
+ERRNO
+error
+Error
+ERROR
+errors
+errs
+Erzya
+es
+ESC
+escape
+escapes
+eScript
+Esfahbod
+esg
+esi
+esk
+Esmall
+esp
+especially
+Esperanto
+esque
+essence
+essentially
+Estero
+estimate
+estimated
+estimates
+Estonia
+Estonian
+Estrangela
+Estrangelo
+esu
+esuperior
+et
+etc
+eth
+Eth
+Ethiopia
+Ethiopic
+ETHIOPIC
+Ethsmall
+eto
+Eton
+eu
+Eu
+eval
+evaluate
+evaluating
+eve
+even
+Even
+EVEN
+Evenki
+event
+EVENT
+events
+eventual
+ever
+every
+Every
+everyone
+everything
+evidence
+evident
+evn
+Ewe
+ewo
+Ewondo
+exact
+exactly
+examine
+examines
+examining
+example
+examples
+exceed
+exceeds
+except
+Except
+exception
+exceptional
+exceptions
+excess
+excessive
+exch
+exchange
+exclam
+EXCLAMATION
+exclamdown
+exclamdownsmall
+exclamsmall
+excluded
+exclusion
+exclusive
+Exclusive
+exclusivity
+exe
+executable
+execute
+EXECUTE
+exhaust
+exist
+existence
+existent
+existing
+EXISTING
+exists
+exit
+exitAnchor
+ExitAnchor
+exp
+EXP
+expand
+expanded
+EXPANDED
+ExpansionFactor
+expect
+expected
+expects
+expensive
+experience
+experimental
+experimentally
+expert
+EXPERT
+ExpertCharset
+ExpertEncoding
+ExpertSubsetCharset
+explanation
+explicit
+EXPLICIT
+explicitLevel
+explicitly
+explore
+exponent
+EXPONENTS
+export
+EXPORT
+exported
+exports
+expose
+Expose
+exposed
+exposing
+Exposing
+expr
+EXPR
+express
+Express
+expressed
+expression
+expressions
+extend
+Extend
+extended
+Extended
+EXTENDED
+extendedShapeCoverage
+ExtendedTypes
+Extender
+EXTENDER
+ExtenderGlyph
+extenderGlyphs
+ExtenderGlyphs
+extensibility
+extension
+Extension
+extensionDisableGPOS
+extensionDisableGSUB
+extensionEnableGPOS
+extensionEnableGSUB
+ExtensionFormat
+extensionJstfMax
+extensionLookupType
+extensionOffset
+ExtensionOffset
+ExtensionPos
+extensions
+Extensions
+EXTENSIONS
+ExtensionSubst
+extensively
+extent
+Extent
+extents
+EXTENTS
+extern
+EXTERN
+external
+externally
+externs
+extlang
+extra
+Extra
+EXTRA
+extract
+extracted
+EXTRAS
+extreme
+extremely
+eye
+Eye
+eyelash
+eyo
+f
+F
+fa
+FA
+FAAu
+fabs
+FABu
+FAbv
+faca
+face
+Face
+FACE
+faceBlob
+Facebook
+faces
+FACESIZE
+facet
+faceType
+facilities
+facility
+fact
+factor
+FACTOR
+factors
+factory
+FACTORY
+factoryType
+FACu
+FADu
+FAEu
+FAFu
+fail
+Fail
+FAIL
+failed
+Failed
+FAILED
+failing
+FAILLING
+fails
+Fails
+failure
+FAILURE
+failures
+fairly
+Falam
+fall
+Fall
+fallback
+Fallback
+FALLBACK
+falling
+falls
+fallthrough
+FALLTHROUGH
+false
+FALSE
+family
+Family
+FAMILY
+FamilyBlues
+familyName
+FamilyName
+FamilyOtherBlues
+fan
+Fancy
+Fang
+Fanti
+faq
+far
+Faroe
+Faroese
+Farsi
+FARSI
+fashion
+fast
+faster
+fat
+fatha
+FATHA
+fathatan
+FAu
+faulty
+favor
+fb
+FB
+fba
+FBAu
+FBBu
+FBCu
+FBDu
+fbe
+FBFu
+fbl
+FBlw
+FBu
+fc
+FC
+FCAu
+fcc
+FCCu
+FCDu
+FCEu
+FCFu
+fclose
+fcntl
+FCu
+fd
+FD
+fda
+fdArray
+FDArray
+FDArrayInfo
+FDArrayOffset
+FDAu
+fdcount
+fdCount
+FDDu
+fde
+FDEFs
+FDEu
+FDF
+FDFu
+FDIndex
+fdmap
+fds
+fdsc
+FDSC
+fdselect
+fdSelect
+FDSelect
+FDSELECT
+FDSelectInfo
+FDSelectOffset
+FDu
+fe
+Fe
+FE
+feat
+FEAT
+FeatMinMaxRecord
+featMinMaxRecords
+FeatMinMaxRecords
+feats
+featUILableNameID
+featUITooltipTextNameID
+feature
+Feature
+FEATURE
+featureCount
+featureFlags
+featureIndex
+featureList
+FeatureList
+FeatureName
+featureNameCount
+featureParams
+FeatureParams
+FeatureParamsCharacterVariants
+FeatureParamsSize
+FeatureParamsStylisticSet
+featureRangeLengths
+features
+Features
+FEATURES
+featureSetting
+FeatureTableSubstitution
+FeatureTableSubstitutionRecord
+featureTableTag
+featureType
+featureval
+FeatureVariationRecord
+FeatureVariations
+featureVars
+featureZ
+FEAu
+Feb
+February
+FEBu
+FECu
+Fedora
+FEDu
+fee
+feed
+feel
+fees
+FEFF
+FEH
+fence
+feof
+ferror
+fetch
+Fetch
+fetched
+fetches
+Fetches
+fetching
+FetchNextRun
+FEu
+few
+fewer
+ff
+FF
+FFA
+FFAu
+ffbfea
+ffcdf
+FFCu
+FFEu
+FFF
+FFFD
+FFFF
+FFFFF
+FFFFFF
+FFFFFFF
+FFFFFFFFULL
+FFFFFu
+FFFFu
+FFFFULL
+FFFu
+ffi
+ffl
+ffm
+FFu
+FFULL
+ffuncs
+ffunctions
+fh
+fi
+fi
+fid
+field
+fields
+FIFTEEN
+figure
+FIGURE
+figuredash
+Fijian
+fil
+file
+File
+FILE
+filename
+fileOffset
+files
+fileSize
+fileType
+Filipino
+fill
+Fill
+filled
+FILLER
+filling
+Filling
+filter
+Filter
+filtered
+filtering
+filterMethod
+filterRangeMaxValue
+filterRangeMinValue
+filters
+FIN
+fina
+FINA
+final
+Final
+FINAL
+finalcode
+finalize
+finalizer
+Finalizer
+finally
+Finally
+finaLookup
+finaSubLookup
+find
+Find
+FINDFONT
+finding
+finds
+Finds
+fine
+fini
+finish
+Finish
+finished
+finite
+Finland
+Finnish
+Firefox
+first
+First
+FIRST
+firstAxis
+firstAxisSegmentMaps
+firstChain
+firstDeviceRecord
+firstGlyph
+firstGlyphIndex
+FirstGlyphs
+firstLayerIdx
+firstPairValueRecord
+firstParamUILabelNameID
+firstSubtable
+firstSubTable
+fit
+FITNESS
+fitting
+five
+FIVE
+fiveeighths
+fiveinferior
+fiveoldstyle
+fivesuperior
+fix
+Fix
+fixed
+Fixed
+FIXED
+fixedcs
+FixedType
+FixedVersion
+Fixes
+fixup
+Fixup
+fj
+fl
+flag
+Flag
+FLAG
+flags
+Flags
+FLAGS
+flat
+flatStr
+flatten
+Flatten
+FLATTENED
+flattener
+fLayoutRTL
+Flemish
+Fleurons
+FLEURONS
+flex
+flip
+flm
+float
+floating
+fLogicalOrder
+flooded
+floor
+florin
+flow
+Flowery
+FLT
+flush
+fly
+FM
+FMAbv
+FMBlw
+fMergeNeutralItems
+fmp
+FMPst
+fmt
+fNoGlyphIndex
+fo
+folded
+follow
+followed
+Followed
+following
+Following
+follows
+fon
+Fon
+fonipa
+fonnapa
+font
+Font
+FONT
+FontBBox
+fontconfig
+Fontconfig
+FontConfig
+FontDescriptor
+fontdict
+FontDict
+fontdicts
+fontDicts
+fontDictStr
+fontDirectionHint
+fontEmSize
+fontFace
+fontFile
+fontFileKey
+fontFileLoader
+fontFileReferenceKey
+fontFileReferenceKeySize
+fontFileStream
+FontInfo
+fontlab
+FontMatrix
+fontName
+FontName
+fontRevision
+fonts
+Fonts
+fontSzr
+fonttools
+fontTools
+FontTools
+foo
+fopen
+for
+For
+FOR
+forbid
+Force
+ForceBold
+forced
+foreach
+foreground
+Forest
+forget
+forgives
+fork
+Fork
+form
+Form
+FORM
+format
+Format
+FORMAT
+formatReserved
+formats
+Formats
+formatting
+formed
+former
+Former
+formerly
+forms
+Forms
+FORMS
+FORMULA
+forum
+forw
+forward
+FORWARD
+forwards
+found
+Found
+FOUND
+Foundation
+four
+Four
+FOUR
+fourinferior
+fouroldstyle
+foursuperior
+FOURTEEN
+fourth
+fOverrideDirection
+fp
+fprintf
+FPst
+fr
+frac
+FRACT
+fraction
+FRACTION
+fractional
+fractions
+FRACTIONS
+fragmentContext
+fragmentSize
+fragmentStart
+frame
+framework
+franc
+France
+frc
+fread
+Frédéric
+free
+Free
+FREE
+freed
+freedesktop
+Freedesktop
+freeing
+FreeLibrary
+freelocale
+freely
+freetype
+FreeType
+FREETYPE
+fref
+French
+frequent
+frequently
+fribidi
+friend
+Frisian
+Friulian
+from
+From
+FROM
+fromCoord
+FromGlyphs
+front
+frozen
+frp
+fRTL
+fscale
+Fsmall
+fsref
+FSRef
+fsSelection
+fstat
+fsType
+ft
+FT
+FTStringRange
+fu
+Fu
+fub
+fuc
+fue
+fuf
+fuh
+fui
+Fujian
+Fukien
+Fulah
+fulfilled
+Fulfulde
+full
+Full
+FULL
+fullAdvance
+fullName
+FullName
+fullset
+Fullwidth
+FULLWIDTH
+fully
+Fully
+fun
+func
+Func
+FUNC
+FUNCOBJ
+funcs
+Funcs
+FUNCS
+FUNCSIG
+function
+Function
+FUNCTION
+functionality
+functions
+Functions
+FuncType
+funcZ
+fundamental
+fundamentals
+FUnit
+FUnits
+fuq
+fur
+further
+Furthermore
+Futa
+future
+fuv
+Fuzhou
+fuzz
+fvar
+FVAR
+FVSes
+FWIDTH
+FWORD
+fy
+FYROM
+g
+G
+ga
+Ga
+gaa
+Gade
+Gaelic
+GAF
+gag
+Gagauz
+Gah
+Gahri
+Galice
+Galician
+Galla
+Gallurese
+gan
+Gan
+Ganda
+Ganja
+gap
+GAP
+gaps
+garbage
+Garhwali
+Garo
+Garret
+Garshuni
+gasp
+GASP
+GaspRange
+gaspRanges
+gather
+gaw
+gax
+gaz
+GB
+gbm
+GBoxedCopyFunc
+GBoxedFreeFunc
+gbreve
+Gbreve
+gbytes
+GBytes
+gc
+GC
+gcc
+GCC
+gce
+gchar
+gconstpointer
+gd
+gda
+gdef
+GDEF
+gdi
+GDI
+Ge
+Geez
+Gemination
+GEMINATION
+gen
+Gen
+GEN
+general
+General
+GENERAL
+generally
+Generally
+generate
+generated
+GenerateResults
+generates
+Generates
+Generating
+generic
+Generic
+GENERIC
+geok
+Geok
+Geometric
+Georgia
+Georgian
+GEORGIAN
+German
+germandbls
+Germany
+get
+Get
+GET
+GetCharVariantIndex
+getCombiningClass
+GetDC
+getenv
+GETENV
+GetFileSize
+GetFileSizeEx
+GetFontData
+GetGlyphPlacements
+getglyphs
+GetGlyphs
+getIntPropertyMaxValue
+getIntPropertyValue
+GetJustificationOpportunities
+getjustifiedglyphs
+GetJustifiedGlyphs
+GetLastWriteTime
+GetLocaleName
+GetModuleHandle
+getNFCInstance
+getNFDInstance
+GetNumberSubstitution
+getpagesize
+GETPAGESIZE
+GetParagraphReadingDirection
+GetProcAddress
+getRawDecomposition
+gets
+Gets
+getScript
+GetScriptProperties
+getShortName
+getter
+getters
+GetTextAtPosition
+GetTextBeforePosition
+getting
+Getting
+gez
+gfxShapedWord
+ggo
+GHAIN
+Gheg
+GHUNNA
+gid
+GID
+gidDDD
+gids
+gih
+Gikuyu
+gil
+Gilaki
+Gilbertese
+Gilyak
+GIMEL
+ginfo
+git
+Githabul
+github
+GitHub
+give
+Give
+given
+Given
+gives
+giving
+gju
+gkp
+gl
+Glagolitic
+GLAGOLITIC
+gld
+glib
+GLib
+GLIB
+glibc
+GLIBC
+glk
+global
+Global
+GLOBAL
+GlobalSubr
+globalsubrs
+globalSubrs
+globalSubrsInfo
+glue
+glyf
+GLYF
+glyid
+glyID
+glyph
+Glyph
+GLYPH
+glyphAdvances
+GlyphAnchors
+glyphArray
+glyphAssembly
+GlyphAssembly
+GlyphBitmapDataFormat
+glyphClassDef
+GlyphClasses
+glyphConstruction
+glyphCount
+glyphDataFormat
+glyphDataOffsets
+glyphFormat
+GlyphHeader
+glyphid
+glyphId
+glyphID
+GlyphID
+GLYPHID
+glyphIdArray
+glyphIdArrayLength
+GlyphIDs
+glyphIndex
+glyphIndices
+glyphMetrics
+glyphNameIndex
+glyphOffsets
+GLYPHPROP
+glyphProperties
+glyphs
+Glyphs
+GLYPHS
+glyphset
+GlyphVarData
+GM
+gmappedfile
+GMT
+gn
+gname
+gnn
+gno
+gnome
+gnu
+GNU
+GNUC
+gnw
+go
+goal
+GOAL
+goals
+Goan
+gobject
+GObject
+GOBJECT
+GOFFSET
+gog
+Gogo
+going
+gom
+gon
+Gondi
+GONDI
+gone
+good
+google
+Google
+Goronzy
+got
+Got
+Gothic
+GOTHIC
+goto
+gpos
+GPOS
+GPOSProxy
+gr
+grab
+graduated
+grained
+granted
+GRANTED
+Grantha
+GRANTHA
+granular
+granularly
+graph
+grapheme
+Grapheme
+GRAPHEME
+graphemes
+Graphemes
+GRAPHEMES
+graphic
+graphics
+Graphics
+graphicType
+graphite
+Graphite
+GRAPHITE
+grave
+Gravesmall
+greater
+greaterequal
+Greece
+Greek
+GREEK
+green
+Green
+Greenland
+Greenlandic
+greg
+grep
+grface
+Grid
+GRID
+Grigori
+grigorig
+group
+GROUP
+grouped
+Groupings
+grouprecord
+groups
+grow
+growFlags
+growing
+grows
+growth
+grt
+gru
+gsize
+Gsmall
+gsub
+GSUB
+gsubgpos
+GSUBGPOS
+GSUBProxy
+gsw
+gt
+gtk
+GTK
+gtype
+GType
+gu
+Guarani
+Guaraní
+guarantee
+guaranteed
+guarantees
+guards
+Guatemala
+guc
+GUEH
+guess
+guessing
+guf
+gug
+gui
+Guibei
+Guibian
+guillemotleft
+guillemotright
+guilsinglleft
+guilsinglright
+Guinea
+Guiyang
+Gujarati
+GUJARATI
+Gujari
+Guji
+GUJR
+guk
+Gulf
+Gumatj
+Gumuz
+gun
+GUnicodeScript
+GUnicodeType
+Gunjala
+GUNJALA
+Gupapuyngu
+Gurage
+Gurmukhi
+GURMUKHI
+GURU
+Gusii
+guz
+gv
+gvar
+GVAR
+gwi
+Gwich
+GX
+gxFontDescriptor
+gzip
+h
+H
+ha
+haa
+hack
+HACKMEM
+had
+Hadothi
+Hadrami
+hae
+HAFS
+HAH
+Haible
+HAIR
+Haitian
+Haji
+hak
+Hakha
+Hakka
+Halam
+halant
+Halant
+HALANT
+halants
+half
+Half
+HALF
+Halfwidth
+HALFWIDTH
+Halh
+HALN
+Hamer
+Hammer
+HAMZA
+HAMZAH
+Han
+HAN
+hand
+Hand
+handed
+handing
+handle
+Handle
+HANDLE
+handled
+handler
+handles
+handling
+hang
+hanging
+Hanging
+HANGING
+hangul
+Hangul
+HANGUL
+Hanifi
+HANIFI
+HANJA
+hans
+Hans
+hant
+Hant
+Hanunoo
+HANUNOO
+happen
+happened
+happening
+happens
+Happens
+happier
+happy
+har
+Harari
+Harauti
+hard
+harder
+hardest
+harfbuzz
+HarfBuzz
+HarffBuzz
+Haryanvi
+has
+Has
+HAS
+hash
+hashmap
+Hat
+hataf
+HATRAN
+HAU
+Hausa
+have
+Have
+HAVE
+having
+haw
+Hawaiian
+hAxis
+hay
+Haya
+haz
+Hazaragi
+hb
+HB
+HBASELINE
+HBFixed
+HBGlyphID16
+HBINT
+hbot
+hbotABCD
+hbsc
+hbshape
+hbsubset
+HBUCHAR
+HBUINT
+HBUSHORT
+hbview
+hdc
+HDC
+hdmx
+HDMX
+he
+HE
+hea
+head
+Head
+HEAD
+header
+Header
+HEADER
+headerfile
+headers
+Headers
+headerSize
+HeadlessArrayOf
+heap
+heavier
+heavily
+hebrew
+Hebrew
+HEBREW
+HEH
+height
+HEIGHT
+heightCount
+heights
+help
+helper
+Helper
+helpers
+helpful
+helps
+hence
+Hence
+here
+Here
+hereby
+Herero
+HEREUNDER
+Herzegovina
+HET
+heuristic
+Hexagram
+hflex
+hfont
+HFONT
+hh
+HH
+hhcurveto
+hhea
+HHEA
+hi
+hidden
+HIDDEN
+hide
+HIDE
+hiding
+HIEROGLYPHS
+high
+High
+HIGH
+higher
+highest
+Highland
+HIGHLEVEL
+highlight
+highlighting
+highly
+Hijazi
+hil
+Hiligaynon
+himalaya
+Himalaya
+Hindi
+Hindko
+hinstLib
+hint
+hinted
+hinting
+HINTING
+HintingDevice
+hintmask
+hints
+Hiragana
+HIRAGANA
+Hiri
+hiriq
+HIRIQ
+historical
+HISTORICAL
+history
+hit
+hji
+hk
+HK
+hlineto
+hlt
+hma
+hmc
+hmd
+hme
+hmetrics
+hmg
+hmh
+hmi
+hmj
+hml
+hmm
+hmn
+HMODULE
+Hmong
+HMONG
+hmoveto
+hmp
+hmq
+hms
+hmtx
+HMTX
+hmtxvmtx
+hmw
+hmy
+hmz
+HN
+hnd
+hne
+hnj
+hno
+ho
+Ho
+hoc
+hoi
+hoj
+HOJO
+Hokkien
+Hoklo
+holam
+HOLAM
+hold
+holder
+Holder
+HOLDER
+holding
+holds
+Holikachuk
+home
+Homebrew
+Honduras
+Hong
+Hongshuihe
+hood
+hook
+Hook
+hooks
+horiBearingX
+horiBearingY
+horiz
+HORIZ
+horizData
+horizGlyphCount
+horizGlyphCoverage
+horizontal
+Horizontal
+HORIZONTAL
+horizontally
+Horned
+Hosken
+Hosny
+hosted
+house
+House
+how
+however
+However
+HOWEVER
+HP
+hr
+HRESULT
+hrm
+hsb
+Hsmall
+hsn
+hstem
+hstemhm
+ht
+hTemplateFile
+html
+http
+https
+hu
+Huallaga
+Huamalíes
+Huánuco
+Huaylas
+Huaylla
+huge
+Huishui
+Huizhou
+huj
+human
+Humm
+Hungarian
+HUNGARIAN
+hungarumlaut
+Hungarumlautsmall
+Hungary
+hup
+Hupa
+hvar
+HVAR
+HVARTag
+HVARVVAR
+hvcurveto
+HVM
+hy
+hyphen
+HYPHEN
+hyphenation
+hypheninferior
+HYPHENS
+hyphensuperior
+hyw
+hz
+i
+I
+ia
+iacute
+Iacute
+Iacutesmall
+iba
+Iban
+ibb
+Ibibio
+IBMCPP
+ibmxl
+ibo
+ic
+Iceland
+Icelandic
+iCharPos
+iche
+icircumflex
+Icircumflex
+Icircumflexsmall
+icu
+ICU
+id
+ID
+ida
+Idakho
+idDelta
+idea
+ideal
+Ideally
+ideas
+IDEFs
+idempotent
+identical
+identically
+identification
+identified
+identifier
+identifiers
+identifies
+identify
+identifying
+identity
+IDEO
+Ideograms
+Ideographic
+IDEOGRAPHIC
+Ideographs
+IDEOGRAPHS
+idieresis
+Idieresis
+Idieresissmall
+Ido
+Idotaccent
+idRangeOffset
+ids
+IDs
+IDWriteFactory
+IDWriteFontFace
+IDWriteFontFile
+IDWriteFontFileLoader
+IDWriteFontFileStream
+IDWriteNumberSubstitution
+IDWriteTextAnalysisSink
+IDWriteTextAnalysisSource
+IDWriteTextAnalyzer
+idx
+ie
+Ie
+ietf
+IETF
+if
+If
+IF
+IFACEMETHOD
+IFACEMETHODIMP
+ifdef
+ifelse
+iff
+ifndef
+ig
+Igalia
+igb
+Igbo
+ignorable
+Ignorable
+IGNORABLE
+ignorables
+IGNORABLES
+ignore
+Ignore
+IGNORE
+IgnoreBaseGlyphs
+ignored
+Ignored
+IGNORED
+IgnoreFlags
+IgnoreLigatures
+IgnoreMarks
+ignoring
+igrave
+Igrave
+Igravesmall
+IHDR
+ii
+II
+iid
+IID
+ijc
+ijo
+Ijo
+ik
+ike
+ikt
+ill
+illegal
+ILLUMINATED
+illustrates
+ilo
+Ilokano
+Iloko
+image
+imageDataOffset
+imageFormat
+imageOffsetsZ
+images
+imagine
+Imbabura
+IMC
+immediately
+immutable
+IMPERIAL
+impl
+IMPL
+implement
+Implement
+IMPLEMENT
+implementation
+IMPLEMENTATION
+implementations
+Implementations
+implemented
+IMPLEMENTED
+implementing
+Implementing
+implementor
+implements
+Implements
+implicit
+IMPLICIT
+implied
+IMPLIED
+implies
+important
+Important
+impose
+impossible
+improve
+improved
+iMu
+in
+In
+IN
+inaccuracy
+Inari
+inc
+Inc
+inch
+INCIDENTAL
+Incidentally
+include
+Include
+included
+includes
+Includes
+including
+Including
+INCLUDING
+inclusion
+inclusive
+incoming
+incompatible
+incomplete
+inconsistencies
+incorporating
+incorrect
+incorrectly
+incorrectness
+increase
+Increase
+increased
+increases
+Increases
+increasing
+incrementally
+incurs
+IND
+indeed
+indefinitely
+indented
+independent
+Independent
+INDEPENDENT
+independently
+index
+Index
+INDEX
+IndexArray
+indexed
+Indexed
+indexes
+indexFormat
+indexing
+IndexMask
+IndexOf
+IndexSubtable
+IndexSubtableArray
+indexSubtableArrayOffset
+IndexSubtableFormat
+IndexSubtableHeader
+IndexSubtableRecord
+indexSubtablesZ
+indexTablesSize
+indexToLocFormat
+India
+indic
+Indic
+INDIC
+indicate
+indicated
+indicates
+Indicates
+indicating
+indication
+indices
+indicies
+IndicPositionalCategory
+IndicShapingInvalidCluster
+IndicSMatraCategory
+IndicSyllabicCategory
+IndicSyllableCategory
+INDIRECT
+indirection
+individual
+Individual
+individually
+indivisible
+Indonesia
+Indonesian
+inds
+industry
+IndV
+indx
+indy
+ineffective
+inefficient
+INEQUALITY
+inert
+INERT
+inf
+infer
+Infer
+INFERIORS
+inferred
+infinite
+infinitum
+infinity
+info
+INFO
+informaltable
+informatimago
+information
+Information
+infos
+infrequent
+ing
+Ingush
+inh
+INHERENT
+inherit
+Inherit
+INHERITED
+inherits
+inhibit
+init
+Init
+INIT
+initial
+Initial
+INITIAL
+Initialization
+initialize
+InitializeCriticalSection
+InitializeCriticalSectionEx
+initialized
+initializer
+INITIALIZER
+initializers
+initially
+Initially
+initialRandomSeed
+initiated
+initLookup
+initmediSubLookup
+initpos
+initSubLookup
+InitT
+ink
+inline
+inner
+innerIndex
+inout
+INOUT
+inplace
+input
+Input
+INPUT
+inputClassDef
+inputCount
+inputs
+inputX
+inputZ
+Inremental
+ins
+insane
+INSCRIPTIONAL
+insert
+Insert
+INSERT
+inserted
+insertion
+Insertion
+insertionAction
+insertions
+InsertionSubtable
+inserts
+inside
+Inside
+inspect
+inspecting
+inspects
+install
+Install
+installed
+installing
+Installing
+instance
+INSTANCE
+instanceCoords
+instanceCount
+InstanceRecord
+instances
+Instances
+instanceSize
+INSTANTIATE
+instantiated
+instead
+Instead
+instruct
+instruction
+instructionLength
+instructions
+Instructions
+INSTRUCTIONS
+INSUFFICIENT
+int
+Int
+INT
+integer
+Integer
+INTEGER
+integers
+integral
+integrate
+integrating
+integration
+Integration
+intel
+INTEL
+intended
+intentional
+intentionally
+Intentionally
+Inter
+interact
+InterCharacter
+interest
+interested
+interface
+interfaces
+interfering
+interim
+Interix
+interlaceMethod
+Interlingua
+Interlingue
+InterlockedCompareExchangePointer
+InterlockedExchange
+InterlockedExchangeAdd
+intermediate
+intermediateEndTuple
+IntermediateRegion
+intermediateStartTuple
+intermixed
+intern
+internal
+Internal
+INTERNAL
+internally
+Internally
+internals
+International
+INTERNATIONAL
+InternationalSymbols
+interp
+INTERP
+interpolate
+Interpolate
+interpolation
+interpret
+interpretation
+Interpretation
+interpreter
+interpreting
+INTERROBANG
+intersect
+intersections
+intersects
+INTERSECTS
+interviews
+intl
+into
+intOp
+intptr
+intrin
+intro
+introduced
+Introduced
+introducing
+Introduction
+ints
+IntType
+INTTYPE
+inttypes
+intuition
+Inuinnaqtun
+Inuktitut
+Inupiaq
+Inupiat
+Inupiatun
+invalid
+Invalid
+INVALID
+invert
+INVERTED
+inverts
+investigated
+investigation
+invisible
+Invisible
+INVISIBLE
+invocation
+invoke
+invoked
+invol
+involve
+involved
+involves
+io
+iOS
+iota
+IOTA
+ip
+IPA
+IPHONE
+Iran
+Iranian
+IranNastaliq
+Iraq
+Ireland
+Irish
+irrelevant
+is
+Is
+IS
+Isaac
+ISALNUM
+ISALPHA
+ISC
+isCombinedS
+isCombiningL
+isCombiningT
+isCombiningV
+isEmojiFont
+isFixedPitch
+ish
+isHangulTone
+isiXhosa
+isiZulu
+isL
+Islamic
+Islands
+Ismall
+isn
+iso
+ISO
+ISOAdobeCharset
+ISOL
+ISOLATE
+isolated
+ISOLATED
+Israel
+isRightToLeft
+ISSPACE
+issue
+issuecomment
+issues
+issuetracker
+isSupported
+isT
+Isukha
+isuperior
+isV
+it
+It
+ital
+Italian
+italic
+Italic
+ITALIC
+italicAngle
+ItalicAngle
+italics
+Italics
+italicsCorrection
+Italy
+item
+Item
+ITEM
+itemCount
+itemizedlist
+itemizer
+items
+Items
+ITEMS
+ItemSize
+iter
+Iter
+ITER
+iterable
+Iterable
+iterables
+iterate
+Iterate
+iterated
+iteration
+iterations
+iterator
+Iterator
+IteratorIn
+IteratorOut
+iterators
+iters
+its
+Its
+ITS
+itself
+iu
+IUnknown
+ivs
+iw
+Izon
+izzi
+j
+J
+ja
+jak
+Jakun
+jam
+Jamaica
+Jamaican
+Jambi
+jamo
+Jamo
+January
+Japan
+Japanese
+Jauja
+Javanese
+JAVANESE
+jax
+jbo
+jct
+JEEM
+JEH
+jg
+ji
+Jicarilla
+Jing
+Jinyu
+JIS
+JMO
+job
+join
+joiner
+Joiner
+JOINER
+joiners
+JOINERS
+joining
+Joining
+JOINING
+Jonathan
+Jordan
+jpg
+Jsmall
+json
+JSON
+jstf
+JSTF
+JstfLangSys
+JstfLangSysRecords
+JstfMax
+JstfModList
+JstfPriority
+JstfScript
+JstfScripts
+jt
+Jula
+JUNGSEONG
+Junín
+junk
+just
+Just
+JUST
+justClass
+JustClass
+justClassTable
+justification
+Justification
+JUSTIFICATION
+JustificationCategory
+justificationCharacter
+JustificationHeader
+justificationOpportunities
+justified
+justifiedGlyphAdvances
+justifiedGlyphOffsets
+justify
+JustifyGlyphAdvances
+JustWidthDeltaEntry
+jv
+jw
+jy
+k
+K
+ka
+kaa
+kab
+Kabardian
+Kabras
+Kabuverdianu
+Kabyle
+Kachchi
+Kachhi
+KAF
+Kaithi
+KAITHI
+Kalenjin
+Kalmyk
+Kalo
+Kalpak
+kam
+Kamba
+Kambaata
+kana
+KANA
+Kanaq
+Kanauji
+Kanbun
+Kangri
+Kangxi
+Kanji
+Kannada
+KANNADA
+Kanuri
+Kaqchikel
+kar
+Kara
+Karachay
+Karaim
+Karakalpak
+Karelian
+Karen
+kashida
+Kashida
+KashidaLike
+Kashmiri
+Kashubian
+Kaska
+kasra
+kasratan
+Katakana
+KATAKANA
+Katanga
+Kato
+kau
+Kaur
+Kayah
+KAYAH
+Kazakh
+Kazakhstan
+Kazim
+kb
+kbd
+kby
+kByte
+kca
+kCFAllocatorDefault
+kCFAllocatorNull
+kCFBooleanTrue
+kCFCompareEqualTo
+kCFNumberIntType
+kCFStringEncodingUTF
+kCFTypeArrayCallBacks
+kCFTypeDictionaryKeyCallBacks
+kCFTypeDictionaryValueCallBacks
+kCTFontAttributeName
+kCTFontCascadeListAttribute
+kCTFontEmphasizedSystemFontType
+kCTFontFeatureSelectorIdentifierKey
+kCTFontFeatureSettingsAttribute
+kCTFontFeatureTypeIdentifierKey
+kCTFontPostScriptNameKey
+kCTFontSystemFontType
+kCTFontUIFontEmphasizedSystem
+kCTFontUIFontSystem
+kCTFontURLAttribute
+kCTKernAttributeName
+kCTLanguageAttributeName
+kCTRunStatusNonMonotonic
+kCTRunStatusRightToLeft
+kCTTypesetterOptionForcedEmbeddingLevel
+kCTVersionNumber
+kCTVerticalFormsAttributeName
+kde
+kdr
+kdt
+kea
+Kebena
+Kedah
+keep
+Keep
+keeping
+KEHEH
+Keith
+Keiyo
+kek
+Kekchi
+Kentohe
+Kenya
+kept
+Kerinci
+kern
+KERN
+KernAAT
+KernAATSubTableHeader
+kernAction
+kernActionIndex
+KERNEL
+kernIndex
+kerning
+Kerning
+KERNING
+kerningv
+KernOT
+KernOTSubTableHeader
+KernPair
+kerns
+KernSubTable
+KernSubTableFormat
+KernSubTableHeader
+kernValue
+kernValueCount
+kernValueZ
+kerx
+KERX
+KerxSubTable
+KerxSubTableFormat
+KerxSubTableHeader
+KerxTable
+kerxTupleKern
+Kew
+kex
+key
+Key
+KEY
+keys
+kfa
+KFGQPC
+kfr
+kfx
+kfy
+kg
+kha
+KHAH
+Khakas
+Khakass
+Khaled
+Khamti
+Khanty
+Kharoshthi
+KHAROSHTHI
+Khasi
+Khayo
+khb
+Khengkha
+Khimi
+khk
+khmer
+Khmer
+KHMER
+KhmerUI
+Khojki
+KHOJKI
+Khorasani
+Khowar
+kht
+Khudawadi
+KHUDAWADI
+Khumi
+Khutsuri
+khw
+ki
+kick
+KIKAKUI
+Kikongo
+Kikuyu
+Kildin
+Killer
+KILLER
+Kimbundu
+kind
+kinda
+kinds
+Kingdom
+kinoho
+kINVALID
+Kinyarwanda
+Kiowa
+Kipsigis
+Kirghiz
+KIRGHIZ
+Kiribati
+Kirmanjki
+Kisa
+Kisi
+Kisii
+Kissi
+Kistane
+Kiswahili
+Kita
+Kituba
+kiu
+Kiwai
+kj
+kjd
+kjh
+kjp
+kjz
+kk
+kkz
+kl
+klass
+klasses
+kln
+km
+kMaxCallLimit
+kmb
+kmr
+kmw
+kmz
+kn
+knc
+KNDA
+kng
+knn
+know
+knowing
+Knowing
+knowledge
+known
+Known
+knows
+Knuth
+ko
+Ko
+Kodagu
+Kodava
+koi
+kok
+Kokni
+Kölsch
+Komi
+Komo
+Komso
+Kong
+Kongo
+Konkani
+Konso
+Konyanka
+Koongo
+Koorete
+Korea
+Korean
+Koryak
+kos
+Kosraean
+Kota
+koy
+Koyukon
+kpe
+Kpelle
+kpv
+kpy
+kqs
+kqy
+kr
+krc
+kri
+Krio
+krl
+krt
+kru
+Krymchak
+ks
+ksh
+kShort
+kSizeLimit
+Ksmall
+kss
+ksw
+ktb
+ktu
+ktw
+ku
+Kuanyama
+Kubu
+Kui
+Kukna
+Kullu
+Kulvi
+kum
+Kumaoni
+Kumyk
+Kumzari
+Kuna
+Kurdish
+Kurukh
+Kuskokwim
+Kutai
+kuu
+Kuwait
+Kuy
+kv
+kvb
+kvr
+kw
+KW
+kwy
+kxc
+kxd
+kxu
+ky
+Kyrgyz
+Kyrgyzstan
+kyu
+kZero
+l
+L
+la
+La
+Laari
+label
+LABEL
+labels
+lack
+lad
+Ladakhi
+Ladin
+Ladino
+Lahuli
+laid
+Lak
+Laki
+Lalana
+Lam
+LAM
+lamAlefLigaturesSubLookup
+Lambadi
+Lambani
+Lambayeque
+LAMED
+lamInitLigature
+lamLigatureSet
+Lampung
+lang
+langs
+langsys
+langSys
+LangSys
+LANGSYS
+LangSysRecords
+LangSysTag
+LangTag
+language
+Language
+LANGUAGE
+LanguageGroup
+languageID
+languages
+Languages
+LANGUAGES
+languagetags
+Lanka
+Lao
+LAO
+large
+Large
+LARGE
+larger
+largest
+Largest
+LArrayOf
+lash
+last
+Last
+LAST
+lastCode
+lastGlyphIndex
+LastResort
+lastWriteTime
+LATE
+later
+latest
+latg
+Latg
+Latgalian
+latin
+Latin
+LATIN
+latn
+latter
+Latvia
+Latvian
+Lauricocha
+Lawoi
+lay
+layer
+Layer
+layering
+LayerRecord
+layers
+layersZ
+layout
+Layout
+LAYOUT
+LayoutRTL
+lays
+Laz
+lazily
+lazy
+Lazy
+lb
+LBAR
+LBase
+LBASE
+lbe
+lbj
+lbl
+LC
+lcar
+LCAR
+lcarFormat
+lce
+lcf
+LCount
+LCOUNT
+ld
+ldi
+Le
+LE
+lead
+LEADER
+leading
+Leading
+LEADING
+leadingBearingX
+Lealao
+LEAN
+leans
+least
+leave
+Leave
+LeaveCriticalSection
+leaving
+Lebanon
+Leboa
+left
+Left
+LEFT
+leftC
+leftClass
+leftClassCount
+leftClassTable
+leftSide
+legacy
+Legacy
+LEGACY
+legally
+legit
+Lemberg
+len
+LEN
+LENG
+length
+Length
+LENGTH
+lengthed
+lengths
+lengthy
+lenient
+lenM
+lenP
+LENTICULAR
+LenType
+Leone
+Lepcha
+LEPCHA
+less
+lessequal
+let
+Let
+lets
+Lets
+letter
+Letter
+LETTER
+Letterlike
+letters
+Letters
+Levantine
+level
+Level
+LEVEL
+levels
+leverage
+lexicographic
+lez
+Lezghian
+Lezgi
+lf
+LF
+lfCharSet
+lfFaceName
+lfHeight
+lg
+lhs
+Lhs
+li
+Li
+LI
+LIABLE
+Lianshan
+libc
+libcairo
+Liberia
+libfreetype
+libglib
+libharfbuzz
+libkern
+Libon
+libraries
+Libraries
+library
+Library
+LibreOffice
+libs
+libstdc
+libtool
+Libya
+Libyan
+license
+LICENSE
+lidentity
+Liechtenstein
+lif
+life
+lifecycle
+lifecycles
+lig
+LIG
+liga
+ligAction
+LigActionFlags
+ligActionIndex
+LigActionLast
+LigActionOffset
+LigActionStore
+ligActionTable
+ligate
+ligated
+LIGATED
+ligating
+ligation
+ligature
+Ligature
+LIGATURE
+ligatureArray
+LigatureArray
+LigatureAttach
+ligatureCoverage
+LigatureCoverage
+ligatureData
+LigatureEntry
+LigatureEntryT
+LigatureGlyph
+ligatures
+Ligatures
+LIGATURES
+ligatureSet
+LigatureSet
+LigatureSetOffsets
+LigatureSetOffsetsArray
+LigatureSubst
+LigatureSubstFormat
+LigatureSubtable
+ligbase
+LIGBASE
+LigCaretClassEntry
+ligCaretList
+LigCaretList
+ligGlyph
+LigGlyph
+light
+Light
+LIGHT
+lighter
+lightweight
+ligs
+Ligurian
+lij
+like
+Like
+likely
+Likewise
+Lima
+Limbu
+LIMBU
+Limburgish
+limit
+Limit
+LIMIT
+limitation
+limited
+Limited
+LIMITED
+limiting
+limits
+lindex
+line
+LINE
+linear
+Linear
+LINEAR
+linearly
+Linebreak
+lineBreakpoints
+lineGap
+lines
+lineWidth
+Lingala
+lingo
+linguistic
+LINGUISTIC
+linguistically
+linguistics
+link
+linked
+linkedValue
+linking
+links
+linux
+Linux
+Lipan
+lis
+list
+List
+LIST
+listed
+listinfo
+listitem
+lists
+Lisu
+LISU
+literal
+Literary
+Lithuania
+Lithuanian
+little
+LITTLE
+Liujiang
+Liuqian
+liw
+ljmo
+LJMO
+ljp
+lkb
+lki
+lklug
+lko
+lks
+ll
+Ll
+lld
+LLLEEEEEEEGGGG
+LLONG
+LLVM
+lm
+Lm
+lmn
+lmo
+ln
+LNNOffsetTo
+lo
+Lo
+load
+Load
+LOAD
+loaded
+loader
+loaders
+loading
+LoadLibrary
+loc
+loca
+local
+locale
+Locale
+LOCALE
+localeName
+localized
+localsubr
+LocalSubr
+localsubrs
+localSubrs
+localSubrsInfos
+Locate
+located
+location
+Location
+locations
+lock
+lockable
+Lockable
+locl
+locName
+LOffsetArrayOf
+LOffsetLArrayOf
+LOffsetTo
+log
+LOG
+LOGFONT
+logfontw
+LOGFONTW
+logic
+logical
+Logical
+logicalnot
+LogicalOrder
+Logo
+logograms
+Logooli
+LOGOS
+Logudorese
+Lohar
+lohit
+Lohit
+Loja
+lojban
+Lojban
+lom
+Loma
+Lombard
+Lomwe
+Loncong
+lone
+Lonely
+long
+Long
+LONG
+LONGDATETIME
+longer
+longint
+longintdict
+LongMetric
+longMetricZ
+longword
+look
+Look
+lookahead
+lookaheadClassDef
+lookaheadCount
+lookaheadX
+looked
+looking
+Looking
+looks
+Looks
+lookup
+Lookup
+LOOKUP
+lookupCount
+lookupFlag
+LookupFlag
+LookupFlags
+LookupFormat
+lookupIndex
+lookupList
+LookupList
+lookupListIndex
+lookupOffset
+lookupOrderZ
+lookupRecord
+LookupRecord
+LookupRecords
+lookupRecordX
+lookups
+Lookups
+LOOKUPS
+LookupSegmentArray
+LookupSegmentSingle
+LookupSingle
+lookupTable
+lookupType
+LookupType
+lookupX
+loop
+Loop
+loops
+loose
+loosely
+Lortie
+lose
+LOSS
+lossless
+lost
+lot
+Lots
+low
+Low
+LOW
+lower
+Lower
+LOWER
+lowercase
+LOWERCASE
+lowercased
+lowerLimit
+lowest
+lowestRecPPEM
+Lowland
+LowPart
+lozenge
+lParameter
+lps
+lpSecurityAttributes
+LR
+lrc
+lri
+lrm
+lsb
+lsbMap
+lsearch
+lslash
+Lslash
+Lslashsmall
+lsm
+Lsmall
+lsuperior
+lt
+Lt
+ltag
+LTAG
+ltg
+lto
+ltr
+LTR
+lts
+lu
+Lu
+Lü
+lua
+Luba
+Lubu
+Lucian
+Lue
+LUE
+Lule
+Lulua
+luo
+Luo
+Luopohe
+Luri
+lus
+Lushai
+lux
+Luxembourg
+Luxembourgish
+luy
+Luyia
+luz
+lv
+LV
+lvalue
+lvalues
+lvs
+LVT
+lwg
+lwsync
+lx
+Lycian
+LYCIAN
+Lydian
+LYDIAN
+lzh
+lzz
+m
+M
+ma
+Maasina
+MAbv
+mac
+Mac
+MAC
+Macao
+Macedonia
+Macedonian
+machine
+MACHINE
+machinery
+MACHINERY
+machines
+Macintosh
+macos
+macOS
+MacPorts
+macro
+macrolanguage
+macroman
+MACROMAN
+macron
+Macronsmall
+macros
+Macros
+macStyle
+mad
+MADDA
+MADDAH
+made
+Madura
+Madurese
+mag
+Magahi
+magic
+magicNumber
+Mahafaly
+Mahajani
+MAHAJANI
+Mahjong
+mai
+MAI
+mailing
+mailman
+main
+Main
+MAIN
+mainly
+maintain
+maintained
+MAINTENANCE
+MAITAIKHU
+Maithili
+Majang
+major
+Major
+MAJOR
+mak
+Makasar
+MAKASAR
+make
+Make
+MAKE
+makeotf
+makeOTF
+MakeOTF
+makes
+Makes
+Makhuwa
+making
+Making
+Makonde
+MAKSURA
+Malagasy
+Malay
+Malayalam
+MALAYALAM
+Malaysia
+Maldives
+Maldivian
+Male
+Malinke
+malloc
+Malta
+Maltese
+Malvi
+mam
+Mam
+man
+Manado
+manage
+managed
+management
+manages
+Manchu
+Mandaic
+MANDAIC
+Mandar
+Mandarin
+Mandingo
+Mandinka
+Manga
+Manichaean
+MANICHAEAN
+manifest
+Manifest
+MANIFEST
+manifestData
+ManifestLookup
+Maninka
+Maninkakan
+Manipuri
+manner
+manpage
+Mansi
+manual
+Manual
+MANUAL
+manufacturer
+MANUFACTURER
+Manx
+many
+Many
+Maore
+Maori
+map
+Map
+MAP
+mapCount
+mapDataZ
+mapLen
+mapped
+mapper
+mapping
+Mapping
+mappings
+maps
+Maps
+Mapudungun
+MapViewOfFile
+MapViewOfFileFromApp
+Mara
+Marachi
+Marama
+Marathi
+MARBUTA
+March
+Marchen
+MARCHEN
+margins
+Margos
+Mari
+mark
+Mark
+MARK
+markAnchor
+markAnchorPoint
+markArray
+MarkArray
+markAttachClassDef
+MarkAttachmentType
+markBase
+MarkBase
+MarkBasePos
+MarkBasePosFormat
+MarkCategory
+markControlPoint
+markCoverage
+MarkCoverage
+marked
+markedInsertBefore
+MarkedInsertBefore
+markedInsertCount
+MarkedInsertCount
+markedInsertIndex
+markedInsertList
+MarkedIsKashidaLike
+markers
+markFilteringSet
+markFilteringSetX
+MarkFirst
+MarkGlyph
+MarkGlyphSets
+markGlyphSetsDef
+MarkGlyphSetsFormat
+markIndex
+marking
+MarkLast
+markLig
+MarkLig
+MarkLigPos
+MarkLigPosFormat
+markMark
+MarkMark
+MarkMarkPos
+MarkMarkPosFormat
+MarkRecord
+MarkRecords
+marks
+Marks
+MARKS
+Markweeta
+markX
+markY
+Marma
+Marshallese
+Martin
+Martín
+Marwari
+Masaram
+MASARAM
+Mashan
+Masikoro
+mask
+Mask
+MASK
+masks
+Masks
+master
+Master
+MASTERS
+match
+Match
+MATCH
+matched
+matcher
+matches
+matching
+material
+math
+Math
+MATH
+mathConstants
+MathConstants
+mathematical
+Mathematical
+MATHEMATICAL
+mathematics
+MathGlyphAssembly
+MathGlyphConstruction
+mathGlyphInfo
+MathGlyphInfo
+MathGlyphPartRecord
+mathGlyphVariantRecord
+MathGlyphVariantRecord
+MathGlyphVariantRecords
+mathItalicsCorrectionInfo
+MathItalicsCorrectionInfo
+mathKern
+MathKern
+mathKernCoverage
+mathKernInfo
+MathKernInfo
+MathKernInfoRecord
+mathKernInfoRecords
+MathKernInfoRecords
+MathSymbols
+mathTopAccentAttachment
+MathTopAccentAttachment
+MathValueRecord
+mathValueRecords
+MathValueRecords
+mathValueRecordsZ
+mathVariants
+MathVariants
+matra
+Matra
+MATRA
+matras
+Matras
+matrix
+Matrix
+matrixZ
+matter
+Matthias
+Mattole
+Matu
+max
+Max
+MAX
+maxBeforeBL
+maxComponentDepth
+maxComponentElements
+maxCompositeContours
+maxCompositePoints
+maxContours
+maxCoord
+MaxDebugDepth
+maxExtent
+maxFunctionDefs
+maxGlyphCount
+maximum
+Maximum
+maximumLimit
+maximums
+maxInstructionDefs
+maxMemType
+maxp
+MAXP
+maxPoints
+maxpV
+maxSizeOfInstructions
+maxStackElements
+maxStorage
+maxTwilightPoints
+maxVal
+maxValue
+maxWidth
+maxZones
+may
+May
+MAY
+Mayan
+maybe
+Maybe
+MAYBE
+Mayek
+MAYEK
+Mayo
+Mazanderani
+mb
+MB
+mbarrier
+Mbembe
+mBidiLevel
+MBlw
+mbo
+Mbo
+mbstowcs
+Mbundu
+Mbyá
+Mc
+mcm
+mct
+mCurrentRun
+md
+MD
+mdash
+mData
+mdf
+mdr
+mdy
+me
+Me
+mean
+MEAN
+meaning
+meaningfully
+meanings
+means
+Meanwhile
+measurable
+measure
+MEASURE
+measured
+measuring
+mechanical
+mechanism
+MED
+MEDEFAIDRIN
+medi
+MEDI
+medial
+Medial
+MEDIAL
+median
+medifinaLamAlefSubLookup
+mediLookup
+mediSubLookup
+Medium
+MEDIUM
+Medumba
+MEEM
+Meetei
+MEETEI
+Meh
+MEM
+memaccess
+member
+members
+Members
+memcmp
+memcpy
+memmove
+memoize
+memory
+Memory
+MEMORY
+MemoryBarrier
+memset
+men
+Mende
+MENDE
+Mengisa
+mentioned
+mentions
+menu
+meo
+mer
+MERCHANTABILITY
+merge
+Merge
+merged
+merger
+merges
+merging
+Merging
+MEROITIC
+Meru
+Merwari
+Mescalero
+Mesopotamian
+message
+MESSAGE
+messaging
+messed
+meta
+Meta
+META
+metadata
+Metadata
+metamorphosis
+Metamorphosis
+meteg
+method
+methods
+Methods
+metric
+METRIC
+metricDataFormat
+metrics
+Metrics
+METRICS
+Mewari
+Mewati
+Mexico
+mfa
+mfb
+mfe
+mFontFileStream
+mg
+mGlyphCount
+mGlyphStart
+mh
+MH
+mhr
+mhv
+mi
+Miao
+MIAO
+Michiharu
+micro
+MICRO
+microsoft
+Microsoft
+microsqoft
+MicroType
+mid
+middle
+Middle
+midnight
+might
+Might
+min
+Min
+MIN
+minAdvanceSB
+minAfterBL
+Minangkabau
+minConnectorOverlap
+minCoord
+mind
+mingw
+MinGW
+MINGW
+minHeight
+MINI
+minimal
+minimum
+Minimum
+minimumLimit
+minimums
+Minjangbal
+Minjungbal
+minLeadingBearing
+minlen
+minMax
+MinMax
+minMaxCoord
+minMemType
+Minnan
+minor
+MINOR
+minOriginSB
+minorVersion
+minstd
+minTrailingBearing
+minus
+MINUS
+minVal
+minValue
+minVersion
+Minz
+Mirandese
+Miraya
+mirror
+mirroring
+Mirroring
+misc
+Misc
+Miscellaneous
+MISMATCH
+mIsSideways
+missing
+MIT
+mix
+mixed
+mixin
+Mixin
+Mixing
+mixture
+Mizo
+mk
+mkmk
+mku
+mkw
+ml
+ML
+mLocaleName
+mlq
+MLYM
+mm
+MM
+mman
+MMAN
+mmap
+Mmap
+MMAP
+mmr
+mn
+Mn
+mnc
+mnemonics
+mni
+mnk
+mnp
+mns
+mnw
+mo
+mod
+MOD
+mode
+Mode
+MODE
+model
+models
+Modern
+modes
+Modi
+MODI
+modification
+Modification
+modifications
+MODIFICATIONS
+modified
+Modified
+MODIFIED
+modifiedClusterMap
+modifiedGlyphAdvances
+modifiedGlyphIndices
+modifiedGlyphOffsets
+modifier
+Modifier
+MODIFIER
+modifiers
+modify
+Modify
+modifying
+Modifying
+MODIFYING
+modulo
+moh
+Mohawk
+Moksha
+Moldavian
+Moldova
+Moldovan
+Moluccan
+Mon
+Monaco
+Mongolia
+mongolian
+Mongolian
+MONGOLIAN
+Mono
+monospaced
+MONOSPACED
+monotone
+MONOTONE
+monotonic
+monotonically
+monster
+Months
+Moose
+more
+More
+MORE
+MoreToolbox
+Morisyen
+Moroccan
+Morocco
+morphHeader
+mort
+MORT
+mortmorx
+morx
+MORX
+mos
+Mossi
+most
+Most
+mostly
+Motorola
+Motu
+move
+Move
+moved
+moves
+moveto
+moving
+Moving
+mozilla
+Mozilla
+mpe
+MPre
+mprotect
+MPROTECT
+MPst
+mqg
+mr
+MR
+mReadingDirection
+mrh
+mrj
+Mro
+MRO
+mRunHead
+ms
+MS
+msc
+MSC
+mScript
+msdn
+msg
+MSG
+msgidx
+msgstr
+msh
+msi
+mSize
+Msmall
+msuperior
+MSVC
+mt
+MT
+mText
+mTextLength
+mTextStart
+mtr
+mtx
+mu
+much
+mui
+MUJ
+mul
+MulFix
+Muller
+mult
+Multani
+MULTANI
+multi
+multiple
+Multiple
+MULTIPLE
+MultipleSubst
+MultipleSubstFormat
+multiplication
+multiplicative
+multiplied
+MULTIPLIED
+multiply
+MULTIPLY
+multiplying
+mults
+Mundari
+munmap
+mup
+muq
+mus
+Muscogee
+Musi
+Musical
+MUSICAL
+must
+Must
+MUST
+mutable
+mutex
+MUTEX
+mutually
+mvar
+MVAR
+mvb
+mve
+mvf
+MW
+Mwali
+mwk
+mwl
+mwr
+mww
+my
+MY
+myanmar
+Myanmar
+MYANMAR
+mym
+mymr
+myn
+myq
+myv
+mzn
+n
+N
+na
+NABATAEAN
+Nacional
+nag
+Naga
+Nagari
+Nagri
+NAGRI
+nags
+nah
+Nahuatl
+naive
+Najdi
+nalf
+nalfType
+name
+Name
+NAME
+named
+Named
+nameid
+nameID
+NameID
+nameids
+nameIndex
+NameIndex
+nameIndexOffset
+nameList
+namely
+Namely
+nameOffset
+NameRecord
+nameRecordZ
+names
+Names
+NAMES
+nameSIDs
+namespace
+Namespace
+NAMESPACE
+namesX
+namesZ
+nameTag
+Naming
+nan
+Nan
+Nanai
+Nandi
+Nandinagari
+NANDINAGARI
+nap
+Napo
+NARROW
+narrowing
+nasalization
+Naskapi
+native
+NativeFontResourceDWrite
+natural
+Nauru
+Nauruan
+navajo
+Navajo
+nb
+NC
+nClasses
+nCodes
+NCount
+NCOUNT
+nd
+Nd
+ndash
+Ndau
+ndc
+Ndebele
+NDEBUG
+Ndonga
+nds
+Ndzwani
+ne
+Neapolitan
+necessarily
+necessary
+need
+Need
+needed
+needing
+needs
+Needs
+neg
+NEG
+negation
+negative
+Negative
+NEGATIVE
+Negeri
+NEGLIGENCE
+negotiate
+neighboring
+neither
+nel
+Nenets
+Neo
+Nepal
+Nepali
+nesting
+NESTING
+net
+NetBSD
+Netherlands
+neuter
+neutrals
+never
+Never
+nevertheless
+new
+New
+NEW
+Newa
+NEWA
+Newari
+newBits
+newCount
+newer
+newlocale
+NEWLOCALE
+newly
+newRun
+newState
+next
+Next
+NEXT
+nextRun
+NFC
+NFD
+ng
+NG
+nga
+Ngawn
+Ngazidja
+Ngbaka
+ngl
+ngo
+NGOEH
+Ngoni
+nhd
+nibble
+Nibble
+nibbles
+Nicaragua
+nice
+Niger
+Nigeria
+Nigerian
+nikhahit
+Nikhahit
+NIKHAHIT
+nil
+NIL
+Nimadi
+nindex
+nine
+NINE
+nineinferior
+nineoldstyle
+ninesuperior
+NINETEEN
+niq
+Nirmala
+Nisi
+niu
+Niuean
+niv
+NJ
+Njua
+njz
+NKD
+nko
+NKo
+NKO
+Nkoo
+nl
+Nl
+NLCCHARACTERS
+nle
+nLeft
+nmemb
+nn
+NNOffsetTo
+no
+No
+NO
+nod
+node
+nodes
+noe
+noErr
+nog
+Nogai
+nominal
+NOMINAL
+nominalValue
+nominalWidthX
+non
+Non
+NON
+Nonaka
+NonAlphabetic
+nonbreakingspace
+noncontextual
+Noncontextual
+NoncontextualSubtable
+nonDefault
+nonDefaultUVS
+NonDefaultUVS
+none
+NONE
+nonexistent
+Nong
+nonliteral
+nonmarkingreturn
+nonmonotonic
+nonnull
+nonspacing
+NonStop
+nonzero
+NOON
+NOP
+noporpoise
+nor
+Nor
+NORESERVE
+Norfolk
+normal
+NORMAL
+normalization
+Normalization
+NORMALIZATION
+normalize
+NORMALIZE
+normalized
+normalizer
+normally
+Normally
+North
+NORTH
+Northeastern
+Northern
+Northwest
+Northwestern
+Norway
+Norwegian
+noStretchValue
+not
+Not
+NOT
+notable
+notably
+Notably
+Notation
+notdef
+NOTDEF
+NotDefault
+note
+Note
+NOTE
+noted
+notequal
+notes
+NOTES
+nothing
+Nothing
+notice
+Notice
+noticeably
+notification
+notified
+notifiers
+NOTIMPL
+noting
+notionally
+Noto
+NotoSerif
+nounihan
+nov
+novalidate
+NOVAR
+Novial
+now
+Now
+np
+npi
+nqo
+nr
+nRanges
+nSettings
+nSizes
+nsk
+NSLanguage
+Nsmall
+nso
+nSubrs
+nsuperior
+nSups
+ntilde
+Ntilde
+Ntildesmall
+nTracks
+Nüa
+Nuke
+NUKT
+nukta
+Nukta
+NUKTA
+nul
+NUL
+null
+Null
+NULL
+nullable
+NullHelper
+NullPool
+NullPriority
+nullptr
+num
+Num
+NUM
+numBaseGlyphs
+number
+Number
+NUMBER
+numberOfContours
+numberOfFaces
+numberOfIndexSubtables
+numberOfLongMetrics
+numbers
+Numbers
+NUMBERS
+numbersign
+numberSubstitution
+numBlends
+numColorRecords
+numColors
+numeral
+NUMERAL
+numerals
+Numerals
+numeration
+NUMERATOR
+numeric
+numerical
+Numerical
+numGlyphs
+numLayers
+numNamedParameters
+numOfHMetrics
+numPalettes
+numParameters
+numr
+numRecords
+numScriptCode
+numTables
+numValues
+NUN
+nUnits
+NUSHU
+Nuskhuri
+nv
+ny
+Nyala
+Nyamwezi
+Nyanja
+Nyankole
+nyd
+NYEH
+NYIAKENG
+Nyishi
+nym
+nyn
+Nynorsk
+Nyore
+nza
+o
+O
+oacute
+Oacute
+Oacutesmall
+oasis
+OASIS
+obj
+OBJ
+object
+Object
+OBJECT
+objects
+Objects
+objidx
+OBLIGATION
+oblique
+Oblique
+OBLIQUE
+obliqueing
+obscure
+Obsolete
+obsoleted
+ObsoleteTypes
+obtained
+obvious
+oc
+occasionally
+Occitan
+occupancy
+occupy
+occurrence
+occurrences
+occurring
+occurs
+ocircumflex
+Ocircumflex
+Ocircumflexsmall
+odd
+oddly
+Odia
+odieresis
+Odieresis
+Odieresissmall
+oe
+OE
+OEM
+OEsmall
+of
+Of
+OF
+off
+Off
+OFF
+offer
+offers
+offload
+offs
+OFFS
+offset
+Offset
+OFFSET
+OffsetArrayOf
+offsetArrayZ
+OffsetListOf
+offsetof
+offsets
+Offsets
+OffsetTable
+OffsetTables
+OffsetTo
+offsetToAxisValueOffsets
+offsetToIndex
+offsetToSubtable
+OffsetType
+offsetZ
+offSize
+ofs
+Ofs
+often
+Often
+og
+Ogham
+OGHAM
+ogonek
+Ogoneksmall
+ograve
+Ograve
+Ogravesmall
+Oh
+Oirat
+oj
+ojb
+ojc
+ojg
+Oji
+Ojibwa
+Ojibway
+Ojitlán
+ojs
+ojw
+ok
+Ok
+OK
+oki
+Okiek
+okm
+Ol
+OL
+old
+Old
+OLD
+older
+Older
+OLDER
+om
+Oman
+Omani
+Omega
+omitted
+on
+On
+ON
+once
+Once
+one
+One
+ONE
+OneByteIntFirst
+OneByteIntLast
+onedotenleader
+oneeighth
+onefitted
+onehalf
+oneinferior
+oneoldstyle
+onequarter
+ones
+onesuperior
+onethird
+only
+Only
+ONLY
+onto
+OOP
+op
+Op
+OP
+opaque
+Opaque
+opbd
+OPBD
+opbdFormat
+opcode
+OpCode
+opcodes
+opeator
+open
+Open
+OPEN
+OpenBSD
+opentype
+OpenType
+OPENTYPE
+OpenTypeFontFace
+OpenTypeFontFile
+OpenTypeTable
+operand
+operands
+operate
+operates
+operating
+operation
+operations
+Operations
+operator
+Operator
+OPERATOR
+operators
+Operators
+opportunities
+OPPORTUNITY
+opposite
+ops
+OPS
+opset
+OPSET
+opStart
+opstr
+OPSTR
+opsz
+opszr
+optical
+Optical
+OPTICAL
+OpticalBounds
+OpticalSize
+optimal
+optimally
+optimization
+optimizations
+optimize
+Optimize
+OPTIMIZE
+optimized
+opting
+option
+OPTION
+optional
+Optional
+OPTIONAL
+optionally
+options
+OPTIONS
+opts
+or
+Or
+OR
+oracle
+Orang
+orc
+order
+Order
+ORDER
+ordered
+orderedlist
+ordering
+ordfeminine
+ordinal
+ORDINALS
+ordmasculine
+org
+Organization
+oriented
+orig
+origin
+Origin
+original
+originally
+Originally
+originated
+origins
+origRun
+Oriya
+ORIYA
+Orma
+orn
+ORNAMENT
+ORNAMENTS
+Oromo
+ors
+orthogonal
+orthographic
+Orthographic
+orthographically
+ory
+ORYA
+os
+OS
+OSAGE
+OSAtomic
+OSAtomicAdd
+OSAtomicCompareAndSwap
+OSAtomicCompareAndSwapPtrBarrier
+oslash
+Oslash
+Oslashsmall
+Osmall
+Osmanya
+OSMANYA
+OSMemoryBarrier
+Ossetian
+OSStatus
+osuperior
+ot
+OT
+otf
+otFeatureTag
+OTFontFileVal
+OTHeader
+other
+Other
+OTHER
+OtherBlues
+others
+otherwise
+Otherwise
+OTHERWISE
+otilde
+Otilde
+Otildesmall
+otspec
+Ottawa
+OTTO
+otw
+Ouch
+OUCH
+ought
+our
+Our
+ourself
+ourselves
+out
+Out
+OUT
+outbuffer
+outcome
+outer
+Outer
+outerIndex
+outline
+Outline
+OUTLINE
+OUTLINED
+outlines
+OUTOFMEMORY
+outOfRange
+output
+Output
+OutputArray
+outside
+outward
+over
+OVERBAR
+overflow
+OVERFLOW
+Overflowed
+overflows
+Overflows
+overhead
+overlap
+OVERLAP
+OVERLAPPED
+overlapping
+OVERLAPPING
+OVERLAY
+overloaded
+overloading
+overridden
+override
+Override
+OVERRIDE
+overriden
+overrides
+Overrides
+overriding
+overstrike
+Overstruck
+OVERSTRUCK
+overview
+overwrite
+Owen
+own
+owned
+ownership
+Ozumacín
+p
+P
+pa
+Pa
+PA
+pABC
+Pacaraos
+pack
+package
+packages
+packed
+pad
+padauk
+Padauk
+padded
+padding
+PADMA
+pag
+page
+PAGE
+pages
+pagesize
+PAGESIZE
+Pahari
+PAHAWH
+Pahlavi
+PAHLAVI
+PaintType
+pair
+Pair
+Paired
+pairing
+PairPos
+PairPosFormat
+pairs
+Pairs
+pairSet
+PairSet
+PairValueRecord
+PairValueRecords
+pairwise
+Paite
+Pakistan
+Palantla
+Palauan
+Palaung
+Palestinian
+palette
+Palette
+PALETTE
+paletteFlagsZ
+paletteLabelsZ
+palettes
+Pali
+PALMYRENE
+Palpa
+pam
+Pampanga
+Pampangan
+Panama
+Panao
+Pangasinan
+pango
+Pango
+Panjabi
+panose
+Pao
+pap
+Papiamento
+Papiamentu
+para
+paragraph
+PARAGRAPH
+paragraphs
+Paraguay
+Paraguayan
+parallel
+param
+PARAM
+parameter
+parameters
+Parameters
+PARAMETERS
+params
+PARAMS
+paren
+parenleft
+parenleftinferior
+parenleftsuperior
+parenright
+parenrightinferior
+parenrightsuperior
+parent
+Parent
+parentheses
+PARENTHESIS
+parity
+parse
+parsed
+parser
+PARSER
+parses
+Parses
+parsing
+part
+Part
+PART
+partFlags
+PartFlags
+PARTHIAN
+partial
+Partial
+partialdiff
+PARTIALIZE
+partially
+PARTIALLY
+partically
+participate
+participates
+particular
+PARTICULAR
+particularly
+partRecords
+parts
+Parts
+PARTY
+Pascal
+Pasco
+Pashto
+pass
+Pass
+passed
+PASSED
+passes
+passing
+passthru
+past
+Pastaza
+paste
+PASTE
+patah
+path
+PATH
+Pattani
+pattern
+patterns
+Patterns
+pau
+PAU
+pause
+pauses
+pb
+pbt
+pbu
+Pc
+PC
+pcc
+pcd
+pce
+pcGlyphs
+pCharProps
+pchars
+pcItems
+pck
+pcTable
+pd
+Pd
+pdc
+pdefault
+pdf
+PDF
+pdfs
+pe
+Pe
+PE
+peak
+peakCoord
+peakTuple
+peculiarities
+peculiarity
+pedantic
+Pedi
+peek
+PEH
+PEHEH
+Pekal
+pel
+pend
+Pennsylvania
+people
+People
+per
+Per
+PER
+percent
+Percent
+PERCENT
+percentage
+percentScaleDown
+perfect
+perform
+Perform
+performAction
+PerformAction
+performance
+PERFORMANCE
+performed
+performing
+Performing
+performs
+Performs
+perhaps
+period
+PERIOD
+periodcentered
+periodinferior
+PERIODS
+periodsuperior
+peripheral
+Peripheral
+permanently
+PERMIC
+permissible
+permission
+Permission
+permissions
+permissive
+permitted
+permute
+Permyak
+perpendicular
+Persian
+PERSIAN
+persistent
+person
+perspective
+pertaining
+perthousand
+Peru
+pes
+PETITE
+Pf
+pg
+pga
+pglyph
+pGlyphProps
+pGoffset
+pgwide
+Phags
+PHAGS
+Phaistos
+Phake
+Phalaa
+phantom
+PHANTOM
+phantoms
+phase
+Phase
+phases
+Phases
+phi
+Philippines
+PHINTHU
+phk
+Phoenician
+PHOENICIAN
+PHONE
+Phonetic
+phrase
+PHRASE
+PHRU
+pi
+Pi
+PI
+piAdvance
+Picard
+PiCharacters
+pick
+picks
+pictographic
+Pictographic
+Pictures
+PICTURES
+Pidgin
+pidgins
+piece
+piecemeal
+pieces
+Piemontese
+pih
+pinfo
+pipes
+Pisin
+Pitcairn
+pItems
+pivot
+Pivot
+pivots
+pixel
+Pixel
+pixels
+pixelSize
+pj
+pk
+PK
+pkey
+pkg
+pkgconfig
+pko
+pl
+place
+Place
+placed
+placeholder
+Placeholder
+PLACEHOLDER
+placeholders
+placement
+PLACEMENT
+placements
+plain
+Plains
+plan
+Plan
+PLAN
+plane
+Plane
+planes
+planned
+planner
+planning
+plans
+Plans
+Plateau
+platform
+Platform
+platformID
+platforms
+ple
+please
+plen
+plevel
+pll
+plookups
+plp
+plt
+plus
+PLUS
+plusminus
+pms
+pnb
+png
+PNG
+PNGHeader
+po
+Po
+Pocomchi
+poh
+Pohnpeian
+point
+Point
+POINT
+pointed
+pointer
+Pointer
+pointers
+pointing
+points
+POINTS
+POISON
+Pökoot
+Poland
+Polish
+polyton
+polytonic
+Polytonic
+pon
+pool
+POOL
+pools
+poor
+pop
+popcount
+popcountl
+popcountll
+popped
+pops
+populate
+Populate
+population
+Poqomchi
+port
+Port
+portability
+portal
+Portugal
+Portuguese
+pos
+Pos
+POS
+positinoing
+position
+Position
+POSITION
+Positional
+positioned
+positioning
+Positioning
+positions
+POSITIONS
+positive
+Positive
+POSIX
+PosLookup
+PosLookupSubTable
+possibility
+POSSIBILITY
+possible
+Possible
+possibly
+post
+Post
+POST
+PosTable
+postcompensation
+PostcompensationActionChain
+posted
+postfix
+Postfixed
+POSTFIXED
+postponing
+postprocess
+postscript
+Postscript
+PostScript
+POSTSCRIPT
+postScriptNameIDX
+postV
+potential
+potentially
+potfRecords
+Pournader
+pOutGlyphProps
+pow
+power
+powers
+pp
+ppa
+ppc
+ppem
+PPEM
+ppemX
+ppemY
+PPI
+ppObject
+pPos
+pr
+practical
+practice
+pragma
+PRAGMA
+pragmas
+PRC
+pre
+Pre
+PRE
+precede
+precedence
+preceding
+Preceding
+PRECEDING
+precious
+precision
+precomposed
+Pred
+predef
+predefined
+Predicate
+predicates
+predictable
+pref
+PREF
+prefer
+Prefer
+preferable
+preference
+preferences
+preferred
+Preferred
+prefers
+prefix
+PREFIX
+prefixed
+Prefixed
+PREFIXED
+preloadAll
+prepare
+Prepare
+preparing
+preprocess
+preprocessor
+PREREQ
+pres
+PRES
+presence
+present
+PRESENT
+presentation
+Presentation
+preserve
+PRESERVE
+preserved
+preserving
+presForm
+presidential
+pressure
+PRETTY
+prev
+PREV
+prevent
+PREVENT
+prevented
+preventing
+prevents
+previous
+previously
+Previously
+Pri
+primarily
+primary
+prime
+primitives
+PRIMITIVES
+Principality
+print
+Print
+printed
+printer
+Printer
+printf
+PRINTF
+printing
+prints
+prior
+priorities
+prioritize
+priority
+Priority
+priv
+private
+Private
+PRIVATE
+PrivateDict
+privateDictInfo
+privateDictInfos
+privateDicts
+privateDictsOffset
+privateInfos
+PrivatePointNumbers
+privDictStr
+PRIVDICTVAL
+privInfo
+PRIVOPSET
+privSzr
+pro
+probable
+probably
+Probably
+Probing
+problem
+problems
+Procedure
+proceed
+proceeding
+process
+Process
+processed
+processes
+processing
+procs
+produce
+produced
+Produced
+produces
+product
+Profile
+PROFITS
+program
+programlisting
+programming
+programs
+Programs
+Proj
+project
+projection
+Projection
+promise
+promotion
+propagate
+Propagate
+proper
+properly
+properties
+PROPERTIES
+property
+PROPORTIONAL
+proportionally
+props
+PROPS
+PROT
+protected
+Protection
+prototypes
+provenc
+Provençal
+proves
+provide
+PROVIDE
+provided
+PROVIDED
+provider
+provides
+Provides
+Province
+proxy
+Proxy
+prs
+prune
+ps
+Ps
+PS
+psa
+Psalter
+PSALTER
+psc
+psControl
+pScriptTags
+pse
+pseudo
+Psmall
+psState
+pst
+pstf
+PSTF
+PString
+PSTS
+psva
+pt
+PT
+ptem
+pthread
+PTHREAD
+ptr
+PTR
+ptrdiff
+Pu
+pua
+PUA
+PUACHUE
+public
+Public
+PUBLIC
+publicly
+published
+Puerto
+Pulaar
+Pular
+pull
+Pull
+punctuation
+Punctuation
+PUNCTUATION
+Punjabi
+Puno
+pure
+Pure
+PURE
+purely
+purpose
+PURPOSE
+purposes
+push
+Push
+put
+Put
+puts
+pv
+pval
+pwcChars
+pwcInChars
+pwGlyphs
+pwLogClust
+pwo
+Pwo
+pwOutGlyphs
+px
+py
+Python
+q
+Q
+Qaai
+QAF
+qamats
+QAMATS
+Qatar
+Qiandong
+Qimant
+Qiubei
+QOF
+Qsmall
+qsort
+QSORT
+QType
+qu
+QUAD
+QuadPart
+qualifiers
+quantity
+QUARTER
+qub
+qubuts
+quc
+qud
+Quechua
+queried
+queries
+query
+querying
+QueryInterface
+question
+QUESTION
+questiondown
+questiondownsmall
+questions
+questionsmall
+quf
+qug
+quh
+Quichua
+quick
+quickly
+quicksort
+Quicksort
+Quiotepec
+quite
+quk
+qul
+quot
+quotation
+quotations
+quote
+quotedbl
+quotedblbase
+quotedblleft
+quotedblright
+quoteleft
+quoteright
+QUOTES
+quotesinglbase
+quotesingle
+Quotient
+Quoting
+qup
+qur
+qus
+qut
+quw
+qux
+quy
+quz
+qva
+qvc
+qve
+qvh
+qvi
+qvj
+qvl
+qvm
+qvn
+qvo
+qvp
+qvs
+qvw
+qvz
+qwa
+qwc
+qwh
+qws
+qxa
+qxc
+qxh
+qxl
+qxn
+qxo
+qxp
+qxr
+qxt
+qxu
+qxw
+r
+R
+ra
+Ra
+RA
+race
+races
+radical
+RADICAL
+radicalDegreeBottomRaisePercent
+Radicals
+rafe
+RAFE
+rag
+ragel
+Raise
+RAISE
+raises
+raj
+Rajasthani
+Rakhine
+ran
+rand
+random
+Random
+RANDOM
+randomize
+Randomly
+range
+Range
+RANGE
+rangeCount
+rangeEnd
+rangeGaspBehavior
+rangeMaxPPEM
+rangeMaxValue
+rangeMinValue
+rangeoffset
+rangeOffset
+rangeRecord
+RangeRecord
+ranges
+Ranges
+RANGES
+rangeShift
+RangeShift
+rangeStart
+Ranglong
+rar
+rare
+RARE
+Rarely
+Rarotongan
+rasterizer
+rate
+rather
+ratio
+raw
+rb
+rbb
+rbl
+RC
+rclt
+rcRangeChars
+RCU
+rcurveline
+RD
+RDONLY
+re
+Re
+reach
+reaches
+read
+Read
+READ
+readable
+reader
+ReadFileFragment
+READING
+readingDirection
+readjusting
+readonly
+READONLY
+ready
+real
+Real
+realistic
+reality
+realloc
+reallocate
+Reallocate
+reallocating
+really
+Really
+rearranged
+rearrangement
+Rearrangement
+REARRANGEMENT
+RearrangementSubtable
+reason
+reasons
+reassign
+reassigned
+reassignment
+reassignSIDs
+rebuild
+REBUS
+rec
+recalculated
+recategorize
+receive
+recent
+recently
+Recognition
+recognizable
+recognize
+recognized
+recognizes
+recom
+recommended
+recompose
+recomposed
+recomposing
+recomposition
+reconfiguration
+reconfigured
+reconfiguring
+record
+Record
+RECORD
+RecordArrayOf
+recording
+RecordList
+RecordListOf
+records
+Records
+Recover
+recovery
+recreate
+recurring
+recurse
+recursed
+Recursed
+recursing
+recursion
+recursive
+recursively
+Recursively
+red
+Red
+redefine
+redefined
+redirected
+redone
+Redu
+reduce
+redundant
+reenabling
+ref
+refcount
+refer
+reference
+Reference
+REFERENCE
+referenced
+referenceGlyph
+references
+referred
+referring
+refers
+REFIID
+refine
+refinements
+reflect
+reflecting
+reflects
+Reformed
+refs
+REGARD
+regardless
+Regex
+region
+Region
+regionCount
+regionIndices
+regions
+register
+Register
+REGISTER
+registered
+RegisterFontFileLoader
+registers
+registry
+Registry
+regular
+Regular
+REGULAR
+REH
+reinterpret
+rej
+Rejang
+REJANG
+reject
+Reject
+rejection
+rel
+REL
+related
+relation
+relationship
+relative
+relax
+relaxed
+RELAXED
+release
+Release
+RELEASE
+released
+releasedc
+ReleaseDC
+ReleaseFileFragment
+ReleaseFontTable
+releases
+relevant
+relicensed
+relies
+relocating
+rely
+Rely
+relying
+remain
+remainder
+remained
+remaining
+remains
+remap
+remapping
+remaps
+Remarks
+remember
+Remember
+remembered
+Removable
+removal
+remove
+Remove
+REMOVE
+removed
+RemoveFontMemResourceEx
+removing
+rename
+render
+rendered
+renderer
+rendering
+renders
+renum
+renumber
+Renumber
+renumbering
+renumbers
+reorder
+Reorder
+reordered
+REORDERED
+reordering
+Reordering
+reorders
+Reorders
+Repack
+repeat
+REPEAT
+repeated
+repeatedAddGlyphAction
+RepeatedAddGlyphAction
+repeating
+REPEATING
+reph
+Reph
+REPH
+repha
+Repha
+REPHA
+replace
+Replace
+replaced
+REPLACEME
+replacement
+REPLACEMENT
+replaces
+Replaces
+replacing
+replicate
+report
+Report
+reports
+Reports
+repositioned
+repositioning
+repository
+represent
+representation
+representations
+represented
+representing
+represents
+Represents
+reproduces
+Republic
+reqFeatureIndex
+request
+requested
+requests
+require
+Require
+required
+REQUIRED
+requirement
+requirements
+requires
+Requires
+requiring
+res
+resCountM
+research
+reserved
+Reserved
+RESERVED
+reservedESC
+ReservedESC
+reservedPad
+reset
+Reset
+Resets
+RESH
+reshaping
+reside
+resize
+resizing
+resolution
+resolutions
+resolve
+Resolved
+resolvedLevel
+resolver
+resolves
+resort
+Resort
+resource
+Resource
+ResourceForkHeader
+ResourceMap
+ResourceRecord
+resources
+resourcesZ
+ResourceTypeRecord
+respect
+respective
+respectively
+responsibilities
+responsibility
+responsible
+resreved
+rest
+RESTORE
+restrict
+restructuring
+result
+resulted
+resulting
+RESULTING
+results
+resume
+ret
+Ret
+RET
+retain
+Retain
+retained
+retains
+RETAINS
+retired
+retrieve
+retrieved
+retrieves
+Retrieves
+retry
+return
+Return
+RETURN
+returned
+Returned
+returning
+returns
+Returns
+reuse
+reused
+reusing
+reverse
+REVERSE
+reverseChainContextSingle
+ReverseChainSingle
+ReverseChainSingleSubst
+ReverseChainSingleSubstFormat
+reversed
+Reverses
+reversing
+revert
+revised
+rewind
+Rewind
+rewinding
+Rewinding
+Rewrite
+rfHeader
+RHA
+RHEL
+rhs
+Rhs
+ri
+ria
+Riang
+Rica
+Rico
+ridentity
+Rieger
+rif
+right
+Right
+RIGHT
+rightC
+rightClass
+rightClassCount
+rightClassTable
+rightSide
+RightToLeft
+Rinconada
+ring
+Ringsmall
+Ripuarian
+rise
+RISE
+RISH
+risking
+rit
+Ritarungo
+rki
+RKRF
+rkw
+rl
+rlig
+rligLookup
+rligMarksLookup
+rlinecurve
+rlineto
+rm
+RM
+rmc
+rmf
+rml
+rmn
+rmo
+rmoveto
+rmw
+rmy
+rmz
+rn
+rnl
+RNOON
+ro
+Ro
+RO
+road
+Robatic
+Roberts
+rock
+Rod
+Roderick
+Rohingya
+ROHINGYA
+role
+roll
+rom
+Roman
+ROMAN
+Romani
+Romania
+Romanian
+ROMANIZATION
+Romansh
+Romany
+room
+root
+rooted
+Roozbeh
+ros
+ROS
+rotate
+rotated
+Rotuman
+round
+ROUND
+ROUNDED
+roundf
+ROUNDF
+rounding
+rounds
+routine
+routines
+roux
+Roux
+row
+rowCount
+rowIndexTable
+rows
+rowWidth
+royalty
+RP
+rpc
+rphf
+RPHF
+rpRangeProperties
+RRA
+rrcurveto
+RREH
+RS
+rsb
+rsbMap
+Rsmall
+rsuperior
+Rsv
+rt
+rtl
+RTL
+rtlm
+rtm
+ru
+Ruanda
+RUBY
+Ruching
+rue
+rule
+Rule
+RULE
+rules
+Rules
+ruleSet
+RuleSet
+rulesets
+ruleSets
+Rumai
+run
+Run
+RUN
+Rundi
+runHead
+Runic
+RUNIC
+running
+runs
+runtime
+Runtime
+rup
+rupiah
+Russia
+Russian
+Rusyn
+rvalue
+rvalues
+Rvalues
+rw
+Rwanda
+rwr
+Ryan
+s
+S
+sa
+Saamia
+Sabah
+Sabaot
+Sad
+SAD
+Sadri
+safe
+safely
+safest
+sah
+Saharan
+said
+Saidi
+Saint
+Sakalava
+sake
+Sakha
+sakot
+SAKOT
+sal
+Salasaca
+salt
+Salvador
+sam
+Samaritan
+SAMARITAN
+Sambalpuri
+same
+Same
+SAME
+SAMEKH
+Sami
+Samoan
+Samogitian
+sample
+SAMPLE
+sampleTextNameId
+sampleTextNameID
+San
+Sanaani
+sandboxed
+sane
+Sango
+sanitization
+sanitizations
+sanitize
+Sanitize
+SANITIZE
+sanitized
+sanitizer
+sanitizing
+Sanitizing
+sanity
+Sankaran
+Sans
+Sanskrit
+Santa
+Santali
+Santiago
+santization
+SAR
+sara
+SARA
+Saraiki
+Sardinian
+Sarsi
+sas
+Sasak
+Sascha
+Sassarese
+sat
+Saterfriesisch
+Saterland
+Saudi
+Saurashtra
+SAURASHTRA
+save
+Save
+SAVE
+saved
+savedprops
+Saves
+saw
+Saxon
+say
+Sayisi
+says
+sb
+SBase
+SBASE
+SBitLineMetrics
+sbix
+SBIX
+SBIXGlyph
+SBIXStrike
+sbl
+SBL
+SBLHebrewUserManual
+sc
+Sc
+SC
+Scalable
+scalar
+Scalar
+scalars
+scale
+SCALE
+scaled
+SCALED
+scalef
+scaler
+scaling
+scan
+Scan
+sCapHeight
+scaron
+Scaron
+Scaronsmall
+scedilla
+Scedilla
+scenario
+scenarios
+SCHAR
+sched
+SCHED
+scheme
+Schouten
+science
+SCIENTIFIC
+sck
+scn
+sco
+sconsumed
+scope
+score
+Scots
+Scottish
+scount
+SCount
+SCOUNT
+scratch
+SCRATCH
+screen
+script
+Script
+SCRIPT
+scriptAnalysis
+scriptCode
+ScriptExtensions
+ScriptFreeCache
+ScriptItemize
+ScriptItemizeOpenType
+scriptList
+ScriptList
+ScriptPlace
+ScriptPlaceOpenType
+scriptProperties
+scripts
+Scripts
+SCRIPTS
+ScriptShape
+ScriptShapeOpenType
+ScriptTag
+scripttags
+scs
+scursor
+sd
+SD
+sDageshForms
+sdc
+sdh
+SDL
+sdn
+se
+seac
+search
+Search
+SEARCH
+searched
+searching
+searchRange
+Sebat
+sec
+second
+Second
+secondGlyph
+seconds
+sect
+section
+SECTION
+sections
+security
+sed
+see
+See
+seeing
+seek
+seem
+seems
+Seems
+seen
+SEEN
+seenCrossStream
+seequence
+sees
+seg
+segcount
+segCount
+segCountX
+segment
+Segment
+SEGMENT
+segmented
+segmenting
+SegmentMaps
+segments
+segol
+seh
+Seigo
+sek
+Sekani
+Sekota
+sel
+select
+Select
+selected
+selecting
+selection
+selections
+selectively
+SelectObject
+selector
+Selector
+SELECTOR
+selectors
+Selectors
+SELECTORs
+selectorToDisable
+selectorToEnable
+selects
+Seletar
+self
+Selkup
+semantic
+semantical
+SEMANTICS
+Sembilan
+semi
+SEMI
+Semibold
+semicolon
+SEMICOLON
+Sena
+send
+sending
+Senegal
+sense
+sensible
+sensitive
+SENSITIVE
+sensitivity
+sent
+sentence
+Senthang
+sentinel
+SENTINEL
+separate
+separated
+separately
+separation
+Separator
+SEPARATOR
+seq
+sequence
+Sequence
+sequenceIndex
+sequences
+SEQUENCES
+sequential
+sequentially
+Serbia
+Serbian
+Serer
+serial
+serialization
+serialize
+Serialize
+SERIALIZE
+serialized
+serializer
+SERIALIZER
+Serializes
+series
+Serif
+serve
+servers
+serves
+Sesotho
+set
+Set
+SET
+SetBidiLevel
+SetComponent
+SetCurrentRun
+SetLineBreakpoints
+setlocale
+SETLOCALE
+SetMark
+SetNumberSubstitution
+sets
+Sets
+SETS
+SetScriptAnalysis
+Setswana
+setter
+setters
+setting
+Setting
+SettingName
+settings
+settingTableZ
+setup
+Setup
+seven
+SEVEN
+seveneighths
+seveninferior
+sevenoldstyle
+sevensuperior
+SEVENTEEN
+several
+severely
+Severn
+sez
+sFamilyClass
+sfinae
+SFINAE
+sfm
+SFNSDisplay
+SFNSText
+sfnt
+Sfnt
+SFNT
+sfntVersion
+sg
+sga
+sgc
+sgi
+sgs
+sgw
+sh
+sha
+shadda
+Shadda
+SHADDA
+shaddaLigature
+shaddaLigatureSet
+shaddaLigaturesSubLookup
+Shadow
+SHADOW
+shall
+SHALL
+shallow
+Shan
+shape
+Shape
+SHAPE
+shaped
+shaper
+Shaper
+SHAPER
+shaperprefs
+shapers
+Shapers
+SHAPERS
+shapes
+Shapes
+SHAPES
+shaping
+Shaping
+SHAPING
+Sharada
+SHARADA
+share
+SHARE
+shared
+Shared
+SHARED
+SharedPointNumbers
+sharedTupleCount
+sharedTuples
+Shavian
+SHAVIAN
+SHEEN
+Sheeter
+Shekhawati
+shell
+SHELL
+sheva
+shi
+shift
+Shift
+SHIFT
+shifted
+Shifter
+SHIFTER
+shifting
+Shifting
+Shihhi
+shin
+SHIN
+ship
+shipped
+shn
+Shona
+short
+Short
+SHORT
+shortCount
+shortcut
+shortcuts
+shortest
+shortfall
+Shorthand
+SHORTHAND
+shortint
+shoudln
+should
+Should
+shouldn
+Shouldn
+show
+SHOW
+showing
+shows
+shrink
+Shrinkage
+shrinkageDisableGPOS
+shrinkageDisableGSUB
+shrinkageEnableGPOS
+shrinkageEnableGSUB
+shrinkageJstfMax
+shrinkFlags
+SHRT
+shu
+Shua
+shuffle
+Shurishkar
+shut
+Shut
+Shwe
+si
+Sibe
+SIBLING
+Sichuan
+Sicilian
+sid
+SID
+Sidamo
+Siddham
+SIDDHAM
+side
+sidebearing
+sides
+sidmap
+sids
+SIDs
+Sierra
+sign
+Sign
+signature
+signed
+Signed
+SIGNED
+signedness
+significance
+significant
+significantly
+signifying
+signs
+SIGNWRITING
+Sihuas
+Siksika
+sil
+SIL
+silently
+Silesian
+silf
+Silf
+SILF
+Silt
+Silte
+Simalungun
+similar
+Similar
+similarly
+Similarly
+SIMP
+simple
+Simple
+SIMPLE
+SimpleGlyph
+simpler
+simplest
+simplicity
+simplification
+simplified
+Simplified
+SIMPLIFIED
+simplifies
+Simplifies
+simplify
+simply
+SIMULATIONS
+sin
+SIN
+since
+Since
+Sindhi
+Singapore
+single
+Single
+SINGLE
+SinglePos
+SinglePosFormat
+SingleSubst
+SingleSubstFormat
+singleton
+singletons
+singular
+SINH
+sinhala
+Sinhala
+SINHALA
+Sinhalese
+sink
+Sink
+sinks
+Sinte
+SIOT
+Sit
+site
+sites
+situations
+six
+SIX
+sixinferior
+sixoldstyle
+sixsuperior
+sixteen
+SIXTEEN
+Siyin
+size
+Size
+SIZE
+sized
+SIZED
+sizeDeviceRecord
+sizeof
+sizes
+sizeTable
+sizeTables
+sizing
+sjd
+sjo
+sk
+Sk
+SKEWED
+skg
+skip
+Skip
+SKIP
+skippable
+skipped
+skipping
+Skipping
+skippy
+Skolt
+skr
+sl
+SL
+slant
+Slant
+SLANT
+slanted
+slash
+SLASH
+SLASHED
+Slave
+Slavey
+Slavonic
+slen
+slightly
+slim
+slnt
+slope
+slot
+slots
+Slovak
+Slovakia
+Slovenia
+Slovenian
+slower
+sm
+Sm
+SM
+sma
+SMAbv
+small
+Small
+SMALL
+smaller
+smallest
+Smallest
+SmallGlyphMetrics
+smart
+SMART
+SMBlw
+smj
+smn
+smoking
+sms
+SMVD
+sn
+snap
+snapshot
+sniff
+snk
+snprintf
+so
+So
+Sochiapam
+Sodo
+SOFT
+software
+Software
+SOFTWARE
+Soga
+Sogdian
+SOGDIAN
+Solaris
+SOLARIS
+solely
+solution
+Somali
+some
+Some
+Somebody
+somefunc
+somehow
+Somehow
+someone
+something
+sometime
+sometimes
+somewhat
+SOMPENG
+Songe
+Soninke
+soon
+sop
+SORA
+Sorbian
+sort
+Sort
+SORT
+sorted
+Sorted
+SORTED
+SortedArrayOf
+sortedness
+SortedUnsizedArrayOf
+sorting
+SORTING
+Sotho
+SOUND
+sounds
+source
+Source
+SOURCE
+sourceware
+South
+SOUTH
+Southeast
+Southeastern
+Southern
+Southwestern
+Soyombo
+SOYOMBO
+spac
+space
+Space
+SPACE
+spaced
+spaces
+Spaces
+spacing
+Spacing
+SPACING
+Spain
+Spanish
+spans
+speaking
+spec
+Spec
+special
+Special
+SPECIAL
+Specialization
+specializations
+Specializations
+Specialize
+specially
+Specials
+specific
+specifically
+SPECIFICALLY
+specification
+specifications
+specificed
+specifics
+specified
+specifies
+specify
+specifying
+specs
+speculative
+speed
+Speed
+speeds
+split
+Split
+SplitCurrentRun
+splitPoint
+splitPosition
+Spoon
+SPOT
+Spread
+spreadsheets
+Spring
+spv
+spy
+sq
+sqrt
+Square
+SQUARE
+SQUARED
+squeezing
+sr
+src
+Sri
+sro
+srr
+srs
+ss
+ssh
+Ssmall
+SSOT
+ssuperior
+ssxx
+ssXX
+st
+stable
+stack
+Stack
+STACK
+Stacker
+STACKER
+stacking
+stackoverflow
+stage
+stages
+STAGES
+stale
+standalone
+standard
+Standard
+StandardEncoding
+standardheaderfiles
+standards
+stands
+start
+Start
+START
+startCharCode
+startcode
+startCode
+startConnectorLength
+startCoord
+startCount
+started
+Started
+starter
+Starter
+startGlyph
+startGlyphID
+startGlyphIndex
+starting
+Starting
+StartOfText
+starts
+startSize
+startUnicodeValue
+stat
+STAT
+StatAxisRecord
+state
+State
+STATE
+stateArrayTable
+stateHeader
+statement
+states
+States
+STATES
+StateTable
+StateTableDriver
+stateTableOffset
+static
+Static
+STATIC
+status
+stay
+stays
+stch
+STCH
+std
+STD
+stdarg
+stddef
+stderr
+stdGlyph
+StdHW
+stdint
+stdio
+stdlib
+STDMETHODCALLTYPE
+STDMETHODIMP
+StdVW
+stem
+StemSnapH
+StemSnapV
+step
+STEP
+stepping
+steps
+sterling
+stHeader
+still
+Still
+stmt
+STMT
+stop
+Stop
+STOP
+stopped
+stops
+storage
+Storage
+store
+Store
+STORE
+stored
+Stored
+storing
+stq
+str
+STR
+straight
+Straight
+straightforward
+strategic
+strategy
+Strategy
+strbuf
+strchr
+strcmp
+strcpy
+strdup
+stream
+streams
+strerror
+stretch
+Stretch
+STRETCH
+stretchable
+stretched
+stretchGlyphAction
+StretchGlyphAction
+stretching
+Stribley
+Strict
+STRICT
+strictly
+stride
+strike
+strikeout
+STRIKEOUT
+strikes
+string
+String
+STRING
+stringIndex
+StringIndex
+stringIndexInfo
+stringOffset
+strings
+strlen
+strncmp
+strncpy
+stroke
+Strokes
+StrokeWidth
+strong
+strongly
+strstr
+strtod
+STRTOD
+strtol
+strtoul
+struct
+StructAfter
+StructAtOffset
+StructAtOffsetOrNull
+StructAtOffsetUnaligned
+structs
+STRUCTS
+structure
+Structure
+structures
+Studio
+stuff
+stupid
+stv
+style
+Style
+STYLE
+stylistic
+Stylistic
+STYLISTIC
+stylisticSet
+sTypoAscender
+sTypoDescender
+sTypoLineGap
+su
+sub
+SUB
+subarray
+subclass
+Subclass
+subclasses
+subdivided
+subdivision
+subfamily
+SUBFAMILY
+subfamilyID
+subfamilyNameID
+subFeatureFlags
+subfonts
+SubFormat
+subject
+subjoined
+Subjoined
+SUBJOINED
+subjoining
+sublookup
+SUBLOOKUP
+SubLookupOffsets
+SubLookupOffsetsArray
+submerged
+subpixel
+subr
+subrecord
+subroffset
+subroutine
+Subroutine
+subroutines
+subrs
+Subrs
+SUBRS
+subrsOffset
+subs
+subscript
+Subscript
+SUBSCRIPT
+subscripts
+Subscripts
+subsequence
+subsequences
+subsequent
+subset
+Subset
+SUBSET
+SubsetGlyph
+Subsets
+subsetted
+subsetter
+SUBSETTER
+subsetting
+subst
+SUBST
+substantially
+substGlyph
+substitued
+substitute
+Substitute
+SUBSTITUTE
+substituted
+SUBSTITUTED
+substitutes
+substituteX
+substitution
+Substitution
+SUBSTITUTION
+substitutions
+substitutionTables
+SubstLookup
+SubstLookupSubTable
+substr
+substring
+substThreshold
+subsystem
+subtable
+subTable
+Subtable
+SubTable
+subtableCount
+SubTableFlags
+subtableGlyphCoverageArray
+SubTableHeader
+subtables
+Subtables
+SubTables
+SUBTABLES
+SubtableType
+subtag
+SUBTAG
+subtags
+subtending
+subtract
+subtracting
+subtraction
+succeed
+succeeded
+SUCCEEDED
+Succeeding
+SUCCEEDING
+succeeds
+success
+successful
+successfully
+successive
+such
+SUCH
+sucks
+Sudanese
+sudo
+sufficient
+SUFFICIENT
+suggest
+suggested
+Suggested
+suggests
+suit
+suitable
+suite
+Suite
+suk
+Sukuma
+sukun
+SUKUN
+sum
+Sum
+summation
+Summer
+sun
+Sundanese
+SUNDANESE
+SUNPRO
+SUPER
+superimposing
+SUPERIORS
+superscript
+SUPERSCRIPT
+superscripts
+Superscripts
+supp
+suppData
+suppEncData
+SuppEncData
+SuppEncoding
+supplement
+Supplement
+Supplemental
+supplied
+supply
+supplying
+support
+Support
+SUPPORT
+supported
+Supported
+SUPPORTED
+supporting
+supports
+Supports
+supposed
+supposedly
+suppress
+supps
+suq
+sure
+Suri
+surprise
+surprises
+surrogate
+SURROGATE
+Surrogates
+surrounding
+survive
+survived
+survives
+sutable
+Sutu
+sv
+sva
+Svan
+svg
+SVG
+svgDoc
+svgDocEntries
+svgDocLength
+SVGDocumentIndexEntry
+SVR
+sw
+Swadaya
+Swahili
+Swampy
+swap
+Swap
+SWAP
+swaplp
+swapped
+swaps
+SWASH
+SWASHES
+Swati
+swb
+swc
+Sweden
+Swedish
+Sweep
+swh
+switch
+Switch
+switched
+switches
+Switzerland
+swv
+sxHeight
+sxu
+syc
+syl
+Sylheti
+Syllabary
+syllabic
+Syllabic
+SYLLABIC
+Syllabics
+SYLLABICS
+syllable
+Syllable
+SYLLABLE
+syllables
+Syllables
+Syloti
+SYLOTI
+SYM
+symbol
+Symbol
+SYMBOL
+symbolic
+symbols
+Symbols
+SYMBOLS
+symmetric
+sync
+synchronize
+syntatically
+syntax
+Syntax
+synthesize
+synthesizes
+synthesizing
+SyntheticBase
+syr
+Syrc
+syre
+Syre
+Syria
+syriac
+Syriac
+SYRIAC
+syrj
+Syrj
+syrn
+Syrn
+sys
+SYS
+sysconf
+SYSCONF
+system
+System
+SYSTEM
+systems
+sz
+szl
+t
+T
+ta
+Ta
+taa
+tab
+Tabasaran
+Tabassaran
+table
+Table
+TABLE
+tableCount
+tablelist
+TableRecord
+TableRecords
+tables
+Tables
+TABLES
+tableTag
+TableType
+Tachelhit
+Tachoni
+tag
+Tag
+TAG
+Tagalog
+TAGALOG
+Tagbanwa
+TAGBANWA
+tagFeature
+tagged
+Tagin
+Tagish
+tagLangSys
+tagRanges
+tags
+Tags
+TAGS
+tagScript
+TAH
+Tahaggart
+Tahitian
+Tahltan
+tahoma
+Tahoma
+tahomabd
+Tai
+TAI
+tail
+Tail
+tailored
+Taiwan
+Taiwanese
+Tajik
+Tajiki
+Tajikistan
+take
+Take
+taken
+takes
+taking
+Takri
+TAKRI
+TALL
+Tamahaq
+Tamajaq
+Tamajeq
+Tamashek
+Tamasheq
+Tamazight
+Tamil
+TAMIL
+TAML
+Tanacross
+Tanaina
+Tanana
+TANDEM
+Tandroy
+Tangshewi
+TANGUT
+Tanosy
+Tanzania
+taq
+tarball
+Tarball
+target
+TARGET
+TargetConditionals
+targs
+Tarifit
+tasks
+Tatar
+tator
+tau
+TAV
+Tawallammat
+Tawr
+Tày
+Tayart
+Taylor
+TB
+TBase
+TBASE
+tbl
+tbody
+TBR
+tcb
+tce
+TCHEH
+TCHEHEH
+TCodepoint
+TCount
+TCOUNT
+tcp
+tcy
+tcz
+tdd
+tdx
+te
+tec
+technetwork
+Technical
+technicalities
+Technically
+Tedim
+TEH
+TEHEH
+telecom
+tell
+tells
+TELU
+Telugu
+TELUGU
+tem
+Temne
+temp
+templ
+template
+Template
+templates
+temporarily
+temporary
+tempting
+Temuan
+TEN
+Tena
+Tenggarong
+Tepetotutla
+Tepinapa
+Terik
+term
+terminal
+Terminal
+terminate
+terminated
+terminates
+terminating
+termination
+Termination
+TerminationWordCount
+terminator
+terminology
+Terminology
+terms
+Tesaka
+test
+Test
+TEST
+tested
+testing
+Testing
+tests
+Tests
+tet
+TET
+Tetum
+text
+Text
+TEXT
+TextAnalysis
+textAnalyzer
+textLength
+textPosition
+textProperties
+TEXTRANGE
+textString
+textual
+tfn
+tg
+tgj
+tgroup
+tgx
+th
+TH
+tha
+Thaana
+THAANA
+Thado
+thai
+Thai
+THAI
+Thailand
+THAL
+Tham
+THAM
+than
+THAN
+THANTHAKHAT
+that
+That
+the
+The
+THE
+thead
+THEH
+their
+them
+themed
+themselves
+then
+Then
+theory
+thep
+there
+There
+therefore
+Therefore
+these
+These
+they
+They
+thickness
+THICKNESS
+THIN
+thing
+things
+Things
+thingy
+think
+third
+Third
+THIRD
+THIRTEEN
+this
+This
+THIS
+thiz
+THO
+thorn
+Thorn
+Thornsmall
+those
+though
+thread
+Thread
+threading
+threads
+threadsafe
+threadsafely
+three
+Three
+THREE
+threeeighths
+threeinferior
+threeoldstyle
+threequarters
+threequartersemdash
+threesuperior
+through
+throughout
+throw
+tht
+thus
+thv
+thz
+ti
+Tibetan
+TIBETAN
+Tidy
+tiff
+Tifinagh
+TIFINAGH
+tig
+tight
+Tigon
+Tigre
+Tigrinya
+tilde
+Tildesmall
+tile
+tiles
+Tiles
+time
+timeouts
+times
+Times
+timesbi
+timesi
+Timne
+tindex
+Tiny
+TINY
+Tirhuta
+TIRHUTA
+Tiriki
+title
+TITLECASE
+TITLING
+tiv
+Tiv
+tjmo
+TJMO
+tk
+tkg
+tl
+TL
+Tlacoatzintepec
+tlen
+tlist
+TLookup
+TLookupList
+TLR
+TM
+tmh
+tmp
+tmw
+tn
+tnf
+to
+To
+TO
+Toba
+Tobago
+TObject
+toCoord
+tod
+today
+Todo
+TODO
+toe
+together
+ToGlyphs
+toi
+tok
+Tok
+tol
+Tolowa
+TOLOWER
+Toma
+tombstone
+tombstones
+tone
+Tone
+TONE
+tones
+Tonga
+Tongan
+too
+took
+toolkit
+tools
+tooltip
+top
+Top
+TOP
+topAccentAttachment
+topAccentCoverage
+topdict
+topDict
+TopDict
+topDictIndex
+TopDictIndex
+topDictInfo
+topDictModSIDs
+topDictSize
+topDictStr
+toplevel
+topographical
+Topographical
+topologically
+topSide
+topSzr
+Torki
+TORTIOUS
+TORTOISE
+Tosk
+total
+Total
+totalDataSize
+totally
+touch
+TOUCH
+touches
+TOUPPER
+towards
+tpi
+tr
+TR
+trace
+Trace
+TRACE
+tracing
+track
+Track
+trackData
+TrackData
+tracking
+Tracking
+trackNameID
+tracks
+trackTable
+trackTableEntry
+TrackTableEntry
+TRAD
+trade
+trademark
+TRADEMARK
+trademarks
+Traditional
+TRADITIONAL
+trailed
+trailing
+trak
+TRAK
+trampoline
+trans
+TRANSCODING
+transcription
+transfer
+Transfer
+transform
+Transform
+transformation
+transformed
+transforming
+transient
+Transient
+transition
+transitioning
+transitive
+translatation
+translate
+translating
+translation
+TRANSLITERATION
+transparent
+traversal
+treat
+treated
+treatment
+treats
+tree
+trees
+TRI
+trick
+trickiest
+tricky
+Tricky
+tried
+tries
+Tries
+trigger
+triggered
+triggers
+trim
+trimmable
+trimmed
+Trimming
+Trinidad
+trivial
+Trivial
+trivially
+trouble
+troubleshooting
+tru
+true
+TRUE
+TrueTag
+TrueType
+TRUETYPE
+TrueTypeTag
+truly
+truncate
+truncated
+try
+Try
+TryGetFontTable
+trying
+Trying
+ts
+Ts
+TSA
+TSADI
+tsb
+tsere
+Tsetsaut
+Tshangla
+Tsimihety
+tsj
+Tsmall
+Tsonga
+Tsotso
+TSubTable
+tsuperior
+Tswana
+tt
+TTA
+ttb
+TTB
+ttc
+TTC
+ttcf
+ttcHeader
+TTCHeader
+TTCHeaderVersion
+ttcTag
+TTCTag
+TTEH
+TTEHEH
+ttf
+ttm
+ttq
+Tugen
+Tulu
+tum
+Tumari
+Tumbuka
+Tundra
+Tunisia
+Tunisian
+tuple
+Tuple
+tupleCount
+tupleIndex
+TupleIndexMask
+tuples
+tupleVarCount
+TupleVarCount
+TupleVarHeader
+tupleVarHeaders
+Tupple
+TuppleIndex
+Turkey
+Turkic
+TURKIC
+Turkish
+Turkmen
+Turkmenistan
+turn
+Turn
+Turner
+turning
+turns
+Turns
+Turoyo
+Tusi
+Tutchone
+Tututni
+tuu
+Tuvalu
+Tuvin
+Tuvinian
+tuy
+tvalue
+tvl
+tw
+tweaks
+TWELVE
+TWENTY
+Twi
+twice
+twilight
+two
+Two
+TWO
+TwoByteNegInt
+TwoBytePosInt
+twodotenleader
+twoinferior
+twooldstyle
+twosuperior
+twothirds
+tx
+txc
+txt
+txy
+ty
+tying
+Typ
+type
+Type
+TYPE
+typed
+typedef
+typedefs
+typeface
+typefaces
+typeList
+typename
+TypeName
+types
+Types
+TYPES
+typesetter
+typesetting
+typical
+typically
+typo
+TYPO
+typographic
+Typographic
+TYPOGRAPHIC
+typographical
+typography
+Typography
+typos
+tyv
+tyz
+tze
+tzm
+tzo
+Tzotzil
+u
+U
+uacute
+Uacute
+Uacutesmall
+UARRAY
+ub
+uBidiLevel
+ubl
+Ubuntu
+ubyte
+ubytes
+ucd
+UCD
+ucdn
+UCDN
+uchar
+UChar
+UCHAR
+ucircumflex
+Ucircumflex
+Ucircumflexsmall
+ucs
+udieresis
+Udieresis
+Udieresissmall
+udm
+Udmurt
+ue
+UE
+UEE
+UErrorCode
+ufuncs
+ufunctions
+UFWORD
+ug
+Ugaritic
+UGARITIC
+UGC
+Ugh
+ugly
+Ugly
+UGLY
+ugrave
+Ugrave
+Ugravesmall
+UHEADLESSARRAY
+UI
+UIDBase
+Uighur
+uiLabelNameId
+uiNameID
+uint
+UINT
+uintptr
+UIPC
+UISC
+uk
+Ukraine
+Ukrainian
+ULBAR
+ulCodePageRange
+ulink
+ULL
+ULLONG
+ULong
+ULONG
+Ulrich
+ultimately
+ULTRA
+ulUnicodeOS
+ulUnicodeRange
+umb
+Umbundu
+Umm
+un
+unassigned
+UNASSIGNED
+unbounded
+UNBOUNDED
+unchanged
+UNCLASSIFIED
+UnclassifiedGlyph
+unclear
+unconditionalAddGlyphAction
+UnconditionalAddGlyphAction
+unconditionally
+UNCONNECTED
+unconst
+und
+undef
+UNDEF
+undefined
+UNDEFINED
+under
+Under
+UNDERBAR
+underflow
+undergone
+underline
+Underline
+UNDERLINE
+underlinePosition
+UnderlinePosition
+underlineThickness
+UnderlineThickness
+underlining
+underlying
+underneath
+underscore
+UNDERSCORE
+understand
+understandable
+understood
+undertake
+Undetermined
+undo
+undocumented
+Undocumented
+unequal
+UNFITTED
+unforced
+unformed
+unfortunate
+unfortunately
+Unfortunately
+unhide
+uni
+unichar
+UniChar
+unicode
+Unicode
+UNICODE
+UnicodeData
+unicodes
+UNICODES
+unicodeValue
+UnicodeValueRange
+Unified
+uniform
+uninitialized
+union
+UNION
+Unión
+unions
+unique
+UNIQUE
+UniqueID
+uniscribe
+Uniscribe
+UNISCRIBE
+unistd
+UNISTD
+unit
+United
+units
+Units
+unitSize
+unitsPerEm
+uniUUUU
+Universal
+unix
+unknown
+Unknown
+UNKNOWN
+unless
+Unless
+unlike
+unlikely
+unlimited
+UnlimiteGap
+unloaded
+unlock
+Unmake
+unmap
+UnmapViewOfFile
+unmarked
+unnecessary
+unnormalize
+unoffset
+unorm
+UNormalizer
+unpack
+unpadded
+unpop
+unprocessed
+unr
+unrecognized
+unref
+unreferenced
+UnregisterFontFileLoader
+unsafe
+Unsafe
+UNSAFE
+UNSCALED
+unset
+unsigned
+Unsized
+UnsizedArrayOf
+UnsizedByteStr
+UnsizedOffsetArrayOf
+UnsizedOffsetListOf
+unsorted
+UNSUCCESSFUL
+unsupported
+UNSUPPORTED
+unsure
+UNTAG
+until
+untouched
+unused
+Unused
+UNUSED
+unusual
+unwanted
+unwise
+unzip
+uoffset
+up
+UP
+update
+updated
+UPDATES
+upem
+UPEM
+upon
+upper
+Upper
+UPPER
+uppercase
+UPPERCASE
+upperLimit
+upright
+UPROPS
+upward
+ur
+Urak
+Urdu
+urk
+url
+URL
+Uruguay
+us
+USABLE
+usage
+usBreakChar
+uscript
+USCRIPT
+UScriptCode
+usDefaultChar
+use
+Use
+USE
+used
+Used
+useful
+Useful
+useless
+UseMarkFilteringSet
+user
+User
+USER
+userfeatures
+users
+uses
+Uses
+usFirstCharIndex
+USHRT
+Usila
+using
+Using
+USING
+usLastCharIndex
+usLowerOpticalPointSize
+Usmall
+usMaxContext
+usp
+USP
+ustr
+ustring
+usually
+Usually
+usUpperOpticalPointSize
+usWeightClass
+usWidthClass
+usWinAscent
+usWinDescent
+utf
+UTF
+Uthmanic
+util
+utilities
+Utilities
+utility
+utilize
+UTS
+uu
+UU
+UUID
+UuidCreate
+uuidof
+UVCRDOypOtijlMDLNNyyLk
+uversion
+uvs
+UVS
+UVSMapping
+Uyghur
+uz
+Uzbek
+Uzbeki
+Uzbekistan
+uzn
+uzs
+v
+V
+va
+VA
+VAbv
+VAH
+Vai
+VAI
+Vakhi
+val
+Val
+VAL
+ValCount
+valFormat
+valid
+Valid
+VALID
+validate
+validated
+Validator
+validity
+Valle
+valuable
+value
+Value
+VALUE
+valueArrayZ
+valueCount
+valueFormat
+ValueFormat
+valueFormats
+valueIndex
+valueNameID
+ValueRecord
+valueRecordCount
+ValueRecords
+valueRecordSize
+values
+Values
+VALUES
+ValuesAreLong
+valueSize
+valuesZ
+valueTag
+ValueType
+var
+Var
+VAR
+vararg
+varation
+VarData
+varDataSize
+variable
+Variable
+variablelist
+variables
+variant
+Variant
+VARIANT
+variantGlyph
+variants
+Variants
+variation
+Variation
+VARIATION
+variationAxis
+VariationAxisRecord
+VariationDevice
+variations
+Variations
+VARIATIONS
+VariationSelectorRecord
+variationsTag
+VariationStore
+VariationValueRecord
+varidx
+varIdx
+varies
+variety
+varika
+variour
+various
+Various
+varlistentry
+varname
+varRecords
+VarRegionAxis
+VarRegionList
+vars
+varSelector
+VarSizedBinSearchArrayOf
+VarSizedBinSearchHeader
+varStore
+varStoreOffset
+vary
+vattu
+vatu
+Vatu
+VATU
+VAV
+vAxis
+VBAR
+VBase
+VBASE
+VBlw
+VCount
+VCOUNT
+vcpkg
+VD
+ve
+VE
+vec
+vector
+Vector
+VECTOR
+vectorization
+vectorized
+vedic
+Vedic
+VEH
+ven
+Venda
+VENDOR
+Venetian
+Venezuela
+VER
+Verb
+verbatim
+verify
+versa
+version
+Version
+VERSION
+versions
+versionZ
+vert
+VERT
+vertAdvance
+vertBearingX
+vertBearingY
+vertData
+vertGlyphCount
+vertGlyphCoverage
+vertical
+Vertical
+VERTICAL
+vertically
+VertOriginMetric
+vertOriginY
+vertYOrigins
+very
+vfprintf
+vhcurveto
+vhea
+vi
+VI
+via
+vice
+Viet
+VIET
+Vietnam
+Vietnamese
+view
+vindex
+vINVALID
+violation
+virama
+Virama
+VIRAMA
+viramas
+virtual
+Virtualizing
+vis
+Visarga
+VISARGA
+VISATTR
+visibility
+VISIBILITY
+visible
+visibly
+visit
+visited
+visitLangSys
+visitScript
+vista
+Vista
+visual
+Visual
+VISUAL
+vjmo
+VJMO
+vkk
+vkt
+Vlaams
+Vlax
+vlineto
+vls
+VM
+VMAbv
+VMBlw
+vmoveto
+VMPre
+VMPst
+vmtx
+vmw
+vo
+Vo
+VOICED
+VOICING
+void
+Void
+VOID
+VOL
+Volapük
+volatile
+volt
+vorg
+VORG
+vorgMap
+Võro
+vowel
+Vowel
+VOWEL
+vowels
+Vowels
+vp
+VPre
+VPst
+VRBAR
+vrinda
+vro
+Vs
+VS
+vsindex
+vsindexcs
+vsindexdict
+Vsmall
+vsnprintf
+vstem
+vstemhm
+vstore
+vstoreOffset
+vtable
+vv
+vvar
+VVAR
+VVARTag
+vvcurveto
+w
+W
+wa
+Wa
+Wagdi
+Wailaki
+walk
+Walk
+walks
+Wall
+Walloon
+Wanca
+WANCHO
+Wang
+Wanga
+want
+wanted
+wants
+war
+WARANG
+Waray
+warn
+warning
+Warning
+WARNING
+warnings
+Warnings
+WARRANTIES
+was
+Was
+WASLA
+wasn
+waste
+Watch
+watchout
+Watchout
+WAVY
+WAW
+way
+ways
+Wayuu
+wbm
+wbr
+Wbuiltin
+Wc
+Wcast
+WCE
+wchar
+WCHAR
+Wclass
+Wconversion
+wdcTable
+Wdelete
+Wdeprecated
+Wdisabled
+Wdouble
+wdRecord
+wdth
+we
+We
+WE
+weak
+weight
+Weight
+WEIGHT
+weights
+weird
+welcome
+well
+Welsh
+Wembedded
+went
+were
+Werner
+West
+Western
+Weverything
+Wextra
+Wformat
+wght
+what
+What
+WHAT
+whatever
+Whatever
+whatsoever
+WHATSOEVER
+when
+When
+whenever
+Whenever
+where
+whereas
+Whereas
+WheresData
+WheresFace
+wherever
+whether
+Whether
+WHETHER
+which
+Which
+while
+While
+white
+WHITE
+Whitelist
+whitespace
+Whitespace
+who
+whole
+whose
+why
+Why
+wide
+widely
+width
+Width
+WIDTH
+WidthDeltaCluster
+WidthDeltaPair
+widthMax
+widths
+widthsZ
+Wignored
+wiki
+wikipedia
+wild
+will
+Will
+willing
+willis
+wilson
+Wilson
+Wimplicit
+win
+Win
+WIN
+WINAPI
+windows
+Windows
+Winit
+Winjected
+WINNT
+Winter
+Wipe
+wish
+wishes
+with
+With
+WITH
+within
+Within
+without
+Without
+WJ
+wlc
+wle
+wlk
+Wlogical
+Wmaybe
+Wmissing
+Wnested
+wni
+wo
+Wolane
+Wold
+Wolof
+won
+Woods
+word
+Word
+WORD
+wording
+wordOffsetToIndex
+words
+WORDS
+work
+Work
+worked
+working
+Working
+works
+Works
+world
+worry
+worrying
+worth
+would
+Would
+WOULD
+wouldbn
+wouldn
+Wow
+Wpacked
+Wpointer
+Wpragmas
+wrap
+wrapper
+wrappers
+wrapping
+Wredundant
+Wreorder
+writable
+Writable
+WRITABLE
+write
+Write
+WRITE
+writer
+writing
+written
+Written
+wrong
+wrote
+wry
+Ws
+wsg
+Wshadow
+Wsign
+Wsmall
+Wstrict
+Wstring
+Wswitch
+Wtautological
+wtm
+Wtype
+Wu
+Wundef
+Wunknown
+Wunneeded
+Wunsafe
+Wunused
+wuu
+Wvla
+ww
+Wwrite
+WWS
+www
+x
+X
+xa
+xA
+xaa
+xAA
+xAAF
+xAB
+xabc
+xABC
+xABFFu
+xAC
+xAdvance
+xAdvDevice
+xAFF
+xal
+XALLOCATE
+Xamtanga
+xan
+xAu
+xAvgCharWidth
+xb
+xB
+xBA
+xBB
+xBFF
+xBytes
+xc
+xC
+xCD
+xCFF
+Xconstructor
+xCoordinate
+xCULL
+xD
+xDBFFu
+xDC
+xDE
+xDeviceTable
+xDFDFDFDF
+xDFDFDFDFu
+xDFF
+xDFFF
+xDFFFu
+xDFu
+xe
+xE
+xEFF
+xEFu
+xF
+xFAFF
+xFB
+xFBA
+xFBAAu
+xFBABu
+xFBACu
+xFBADu
+xFBAEu
+xFBAFu
+xFBB
+xFBD
+xFBDAu
+xFBDBu
+xFBDCu
+xFBDDu
+xFBDEu
+xFBDFu
+xFBE
+xFBFCu
+xFBFDu
+xFBFEu
+xFBFFu
+xFDFF
+xfe
+xFE
+xFEA
+xFEAAu
+xFEABu
+xFEACu
+xFEADu
+xFEAEu
+xFEAFu
+xFEB
+xFEBAu
+xFEBBu
+xFEBCu
+xFEBDu
+xFEBEu
+xFEBFu
+xFEC
+xFECAu
+xFECBu
+xFECCu
+xFECDu
+xFECEu
+xFECFu
+xFED
+xFEDAu
+xFEDBu
+xFEDCu
+xFEDDu
+xFEDEu
+xFEDFu
+xFEE
+xFEEAu
+xFEEBu
+xFEECu
+xFEEDu
+xFEEEu
+xFEEFu
+xFEF
+xFEFAu
+xFEFBu
+xFEFCu
+xFEFF
+xFEFFu
+xff
+xFF
+xFFEF
+xFFF
+xFFFC
+xFFFD
+xFFFDu
+xFFFE
+xFFFF
+xFFFFD
+xFFFFF
+xFFFFFF
+xFFFFFFFF
+xFFFFFFFFFFFFFull
+xFFFFFFFFu
+xFFFFu
+xFFu
+xFu
+Xgroup
+xh
+Xhb
+Xhosa
+xi
+Xian
+Xiang
+Xiangxi
+Xibe
+XInclude
+xjb
+xkf
+xlocale
+XLOCALE
+xMax
+xMin
+xml
+XML
+xmlns
+xmm
+xmv
+xmw
+xnr
+xOffset
+xog
+xor
+XP
+xpe
+xPlacement
+xPlaDevice
+xscale
+xsl
+Xsmall
+xst
+Xuan
+XUID
+xwo
+xx
+XXX
+XY
+y
+Y
+Ya
+yacute
+Yacute
+Yacutesmall
+yAdvance
+yAdvDevice
+Yakut
+Yanahuanca
+Yang
+Yangbye
+yao
+Yao
+yap
+Yapese
+Yarowilca
+Yauyos
+Yay
+yb
+ybd
+yBytes
+yCoordinate
+ydd
+yDeviceTable
+ydieresis
+Ydieresis
+Ydieresissmall
+YEH
+Yemen
+yen
+yes
+Yes
+YES
+yet
+Ygroup
+yi
+Yi
+YI
+Yiddish
+YIDDISH
+yield
+YIELD
+yields
+yih
+Yijing
+YING
+yMax
+yMin
+yml
+yo
+YO
+YOD
+yOffset
+Yongbei
+Yongnan
+Yoruba
+yos
+Yos
+Yosemite
+you
+You
+Youjiang
+your
+yourinputtext
+yourself
+yPlacement
+yPlaDevice
+yrk
+yscale
+Ysmall
+yStrikeoutPosition
+yStrikeoutSize
+ySubscriptXOffset
+ySubscriptXSize
+ySubscriptYOffset
+ySubscriptYSize
+ySuperscriptXOffset
+ySuperscriptXSize
+ySuperscriptYOffset
+ySuperscriptYSize
+YU
+yue
+Yue
+Yugoslav
+yum
+Yupik
+z
+Z
+za
+ZAH
+ZAIN
+Zambia
+Zamboanga
+Zanabazar
+ZANABAZAR
+Zande
+Zarma
+zawgyi
+Zawgyi
+ZAWGYI
+ZAYIN
+Zazaki
+zcaron
+Zcaron
+Zcaronsmall
+zch
+zdj
+zea
+Zealand
+Zealandic
+Zeeuws
+zeh
+zero
+Zero
+ZERO
+zeroed
+zeroinferior
+zeroing
+zeroint
+zerooldstyle
+zeros
+zerosuperior
+zgb
+zgh
+zgm
+zgn
+zh
+zhd
+zhe
+zhn
+Zhong
+Zhuang
+Zimbabwe
+zip
+zipped
+zk
+Zl
+zlj
+zlm
+zln
+zlq
+zmi
+zne
+zo
+zom
+zone
+Zotung
+Zou
+Zp
+zqe
+Zs
+zsm
+Zsmall
+zu
+Zulu
+zum
+Zuojiang
+zwj
+ZWJ
+zwnj
+ZWNJ
+zyb
+zyg
+zyj
+zyn
+Zyrian
+zza
+zzj
diff --git a/perf/texts/fa-monologue.txt b/perf/texts/fa-monologue.txt
new file mode 100644
index 0000000..c41257c
--- /dev/null
+++ b/perf/texts/fa-monologue.txt
@@ -0,0 +1 @@
+من اسمم کاظمه. ما توی یه کوچه بن بست خونه داریم. کوچه‌مون خاکیه. اونوقت خیلی پایئن تر از خونه ما - زیاد پایین نه - اینور می‌پیچی یه نونواس. از اونجا صاف می‌ریم اینجا. یه خیابونه اینجا. اونوقت خیلی پایین‌ترش یه حمومه. بعداً یه بقالی هم دم خونمونه. یه خرده انور خرابه، یه قصابیه. قصابه با بابام رفیقه. پشت خونمون یه دباغیه. اینقده بچه گوسفند توشه! خونه‌مون ساس داره. ساس کوچیک و سیاس. هر جا بزنه جاش باد می‌کنه. وقتی داره از دیوار اتاق می‌ره بالا، نمی‌تونه خودشو نگه داره، می‌افته رو تن ما، می‌گیره خونمونو می‌مکه. یه دفعه همه اثاث مثاثامونو ریختیم بیرون، یه عالمه دوا خریدیم زدیم همه جا: به رختخوابا،‌ زیر زیلو، سوراخ سنبه‌ها. ولی ساسها بیشتر شدن، کمتر نشدن. بابام توی حموم کار می‌کنه. دوتا برادر داریم، یه خواهر: من و مصطفی و زهرا کوچولو. بابا وقتی داره شب می‌شه برمی‌گرده خونه. همیشه استخوناش درد می‌کنه. سر هیچی به هیچی می‌گیره می‌زنه‌مون، بازهم طلبکاره. مثلاً وسط سال، صبح ساعت شیش می‌آد می‌گه، «پاشو برو سیگار بفروش، پول دربیار لباس بخر!» من هم می‌گم: «لباس می‌خوام چی‌ کار؟» اون هم می‌گیره با کمربند حالمونو جا می‌آره. باز خوبه سه ماه تعطیلی خودمون می‌ریم کار می‌کنیم. یه کارخونه هست. می‌ریم اونجا قابلمه درست می‌کنیم، کاسه درست می‌کنیم، عصر که شونصد تا کاسه درست کردیم، دستگارو تمیز می‌کنیم برمی‌گردیم خونه. پارسال هفته‌ای پنجاه تومن مزد می‌دادن. امسال دیگه خدا می‌دونه. با همه این حرفا، بمیریم بهتره آقا! هر روز هر روز کتک.  بابام دیشب بیخودی مصطفی رو گرفت زد. گرفت زدش گفت: «چرا وقتی می‌ری دست به آب، سر پا می‌شاشی؟ بشی بشاش!» مصطفی‌مون هیچی حالیش نمی‌شه. قد زهرامون بوده که از بالا پشت بوم افتاده، رگ کله‌اش تکون خرده. حالا سیزده سالشه. نه چارده،‌ چارده سالشه. داداش بزرگ‌ مونه. الان مدرسه عقب افتاده‌ها درس می‌خونه. آب، بابا، بار میخونه یاد بگیره، بیاد جلو. دو سه کلمه بلده حرف بزنه ولی چیزه... نمیتونه قشنگ حرف بزنه. بابام می‌خواد از مدرسه ورش داره، بذاره یه جا که کار یاد بگیره. بابا زهرا را از همه بیشتر می‌خواد. اون هم هر کاری دلش بخواد می‌کنه. هرچی می‌گیم گوش نمی‌کنه، می‌ره تو جوب محل کثافت‌کاری می‌کنه. اون روزی حواسم نبود، رفت یه مشت دیگ مونده سر کوچه بود ورداشت خورد. شب دلش درد گرفت نزدیک بود بمیره. اونوقت بابام اومد گرفت منو با شیلنگ کشت. آقا مگه شهر هرته؟ خر کتک می‌خوره. دیگه چرا ما رو می‌زنن؟ برن به خر بزنن! آخه من که نمی‌تونم همه‌ش مواظب زهرا باشم. راستی یه صاحب حیاط داریم، خیلی بد اخلاقه آقا! اسمش عباس آقاس. صبح می‌ره ظهر می‌آد. سپور شهرداریه. بیست و چار ساعت می‌آد بند میکنه به ما، میگه: «آب زیاد مصرف نکنین، چاه پر میشه.» زهرامون که گاهی گریه می‌کنه، دادش بلند می‌شه می‌گه: «صدای این تخم‌سگو خفه کنین!» اونوقت که مادرمون زنده بود، یه دفعه می‌خواست از دست عباس آقا نفت بریزه سرش، خودشو آتیش بزنه. عباس آقا اصلاً رحم حالیش نمی‌شه؛ پسر سیزده ساله‌شو گرفته از خونه انداخته بیرون. اون هم رفته توی کوچه‌ پس ‌کوچه‌‌ها ول شده. حالا خدا می‌دونه کجاس، چه کار می‌کنه،‌ از کجا می‌آره می‌خوره. بچه‌ها می‌گن: «شب‌ها می‌ره توی پارک‌ها پیش سگها می‌خوابه.» که رفته دهات خونهٔ باباش، می‌گه دیگه نمی‌آم تهران. آقا، ما هم دلمون می‌خواد میرفتیم دهمون با گوسفندها بازی می‌کردیم؛ با بابا بزرگ‌مون می‌رفتیم دشت بز می‌چروندیم،‌ بادوم پاک می‌کردیم، انگور می‌چیدیم. دهمون ولی خیلی دوره آخه! زن عباس آقا حق داره، آقا! محله‌مون خیلی بده. هر روز اونجا دعواس، دعوا، چاقو کشی. توی خرابه هم پر معتاده، بگی دوهزار تا هم بیشتر. می‌رن اونجا قمار می‌کنن، شیره می‌کشن، آمپول می‌زنن تو رگشون. ماهم از ترس معتادها جرأت نمی‌کنیم از خونه بریم کوچه، یه ذره بازی کنیم. از کمیته‌م نمی‌ترسن، میگیرن بچه‌های مردمو می‌دزدن، میبرن توی کوره‌ها،‌ توی دلاشون چیز قایم می‌کنن؛ هروئین قایم میکنن. یه امیر ریزه هست تریاکیه، اون روزی اومد خرم کنه، گفت: «بیا سوار ماشین بشیم، بریم یه جائی.» من هم از ترسم خر نشدم. یه چیز خنده دار بگم بخندی، آقا: اینورمون یه همسایه داریم، اسمش ربابه. انوقت توپ،‌ لنگه کفش، تنکه، هرچی بیفته خونشون،‌ شوهرش ور می‌داره می‌اندازه توی آب انبارشون. هروقت هم کوچه شلوغ بشه، شوهر رباب می‌آد بیرون می‌گه: «واق، عو!» اون هم مث مصطفی‌ ما لقوه‌ایه‌؛ دستش می‌لزره، همه جاش می‌لرزه. اون روز اومد دم دکون، رفت اونور جوب نشت. این یکی همسایه‌مون رفت یه کتاب دربارهٔ خدا و فرشته‌ها آورد براش خوند. رباب خانم خودش خونه یه اعیونه کار می‌کنه؛ چیزاشونو می‌شوره، باغ‌شونو آب می‌ده؛ کلفتی می‌کنه. بعد همه‌ش می‌آد پز اربابشو می‌ده. الان دیگه همه اهل محل می‌دونن باغ خونهٔ ارباب رباب خانوم اندازه پارک شهره. استخرش از مال پارک شهر هم گنده‌تره. هروقت هم که ارباب می‌خواد‌ آبتنی کنه،‌ اول یه قطره دوای مخصوص هست، می‌ریزه توی استخر که آب‌شو می‌کنه مث اشک چشم. بعد می‌ره زیر دوش، با عطر و گلاب خودشو می‌شوره. بعد می‌پره توی استخر، می‌گیره شوخی شوخی آب می‌پاشه به رباب خانوم. زن اربابش هم خارجیه. مال همون کشوریه که شیش ماه شبه، شیش ماه روز. رباب یه چاخان‌هایی می‌کنه که کلهٔ آدم سوت می‌کشه! می‌گه ارباب یه سگ پشمالو داره،‌ اسمش مونیکاس. قسم می‌خوره می‌گه مونیکا غذاشو با کارد و چنگال می‌خوره. اللَه اکبر به این دروغ. یه پیرزنه هم هست سر کوچمونه. با خودش تنهایی زندگی می‌کنه. اسمش ننه غلامه. هشتاد نود سالشه ولی خجالت نمی‌کشه،‌ از امریکا خوشش می‌آد. همه ازش می‌ترسن؛ هر وفت بیاد بیرون، فحش می‌ده، جیغ و ویغ می‌زنه. مثلا من اذیتش کردم، می‌آد سر فحش‌رو می‌کشه به تو. وقتی بچه‌ها بخوان لج‌شو در‌بیارن، می‌گن: «مرگ بر امریکا!» اونوقت اون هم حرصش می‌گیره، هزار تا فحش بی‌ناموسی و خوار و مادر می‌کشه به جون همه. ننه غلام دیونه‌س. بعضی وقتا هم با‌ آدم خوبه. یه روز من و زهرا رو گرفت به زور برد خونه‌ش، کله پاچه داد، گفت «بخورین!» ما هم خوردیم. ته کاسه یه لقمه موند که روش یه عالمه مو بود. گفت: «اگه نخورین با همین چاقو سرتونو می‌برم.» ما هم از ترس جونمون خوردیم. ننه غلام وقتی سر حاله، چیز می‌آره می‌ده آدم. مثلا یکی زخمه،‌ دوا می‌آره بهش می‌ده. مثلا کسی چیزی نداره، چیز می‌آره بهش می‌ده، وسط کوچه‌مون یه خونه‌س که دخترهاش خرابن، آقا. اونوقت شیره‌ای‌ها و چاقوکش‌ها می‌رن خونه‌شون، کار بد می‌کنن. بعضی وقتا هم دختر‌هاش لباس سرخ و زرد تن می‌کنن و کفش پاشنه بلند تق‌تقی می‌پوشن، می‌رن واسه بالاشهری‌ها قر می‌دن. یه دفعه هم داشتم می‌رفتم پیش بچه‌ها «لیس پس لیس» بازی کنم که دختر کوچیکه‌ش امیر ریزه رو صدا کرد و بهش گفت: «تو چقدر پاهات لاغره!» بعد امیر ریزه هم نامردی نکرد. گفت:«خودت چرا لمبه‌هات چاقه؟» بعد دوتایی کرکر خندیدن. خودم با همین دو تا چشمام دیدم، آقا! اونوقت ما هم که می‌بینیم محله‌مون پر از بی‌تربیتی‌یه، زدیم با هفت‌تا از بچه محلامون قهر کردیم. با اون هفت‌تا هم بمیرم آشتی نمی‌کنم، آقا. با یکی‌شون یه ساله قهریم، اسمش محمده. یه روز سر کوچه‌مون عروسی بود، ما هم داشتیم بازی می‌کردیم. من دراومدم به محمد گفتم: «محمد امشب چه خبره؟ آبجی‌ت می‌ره حجله؟» ناراحت شد، گفت: «باهات قهرم.» من هم گفتم: «چه بهتر! می‌رم درسامو می‌خونم.» به خدا ما چه می‌دونستیم، به خیالمون عروسی آبجیشه، آقا! فقط با دو نفر دوستیم: مهدی ملخ و حسن گامبو. مهدی از بس مردنیه، همه ملخ صداش می‌کنن. باباش قوری بست می‌زنه. وسط بازی یهو پیداش می‌شه، می‌آد می‌گه: «اگه منو بازی ندین، بازی‌تونو بهم می‌زنم.» اونوقت تا که دس بهش می‌خوره، جیغش می‌ره هوا، میگه: «گه خوردم، گه خوردم.» اونوقت می‌ره از حرصش با میخ یه شکل‌هایی می‌کشه روی دیوار، می‌گه: «این عکس کاظمه.» فسقلی فوتش کنی، قل می‌خوره، ها. آقا، ما دوچرخه خیلی دوست داریم، بعضی وقتا می‌ریم یه تومن می‌دیم چرخ کرایه می‌کنیم. حسن گامبو زورش می‌آد، با سنگ می‌زنه، می‌گه: «منو باید سوار کنی.» من هم می‌بینم داره دلش می‌شکنه، می‌گم: «بیا تو هم سوار شو!» داداش حسن گامبو پنج ماهه رفته لب مرز با خارجیا بجنگه. حسن می‌گه: «رفته امریکا رو نابود کنه، برگرده.» بابای حسن آهنکاره؛ یعنی قالب می‌سازه، پشقاب می‌سازه، همه‌چی می‌سازه. نه که حسن خیکیه، بچه‌ها صداش می‌کنن: «حسن گامبو، سرت تو شامپو!» می‌خواییم با این دو نفر هم قهر کنیم بره. هی می‌آن در خونمون داد می‌زنن: «کاظم، بیا بازی، بیا بازی!» بازی چیه، آقا؟ بده بچه بازی کنه. رفوزه بشیم چه کار؟ دلم می‌خواد دکتر، مهندس، بازنشست، نیرو هوایی، هرچی شد بشیم، بریم پی کارمون بره. ولی تو خونه ما نمی‌شه درس خوند. تا می‌آم بشینم، باید پاشم برم نون بخرم، جارو کنم، خشتک زهرامونو بشورم. پارسال که رفوزه شدم، همه‌ش نیم نمره می‌خواستم قبول بشم. مدرسه‌مونم خیلی هردمبیه، آقا! بچه‌هاش دزدن، می‌آن دفترامونو می‌دزدن. سر کلاس یکی گچ پرت می‌کنه، یکی رو نیمکت ضرب می‌گیره، یکی پا می‌شه می‌رقصه. ما هم که می‌بینیم خر تو خره، حوصله‌مون سر می‌ره، از مدرسه جیم می‌شیم، می‌ریم فروشگاه بزرگ. اونجا پله‌برقی داره. می‌ریم می‌ایستیم خودمونو می‌زینم به اون راه. الکی نگاه می‌کنیم به جنس منس‌ها؛ یعنی مثلا ما هم اومدیم چیز بخریم. بعد می‌ریم سوار پله‌برقی می‌شیم، می‌ریم سواری می‌خوریم، عشق می‌کنیم. آقا، اجازه؟ سه تا دایی هم دارم، آقا! یکی‌شون دایی ضامن، یکی‌شونم دایی مرتضی. اونی که وضعش خوبه اسمش دایی رضوانه. یه وانت داره با یه اتوشویی. تا پامونو می‌ذاریم در دکونش، نامرد یه لگد می‌زنه در اونجامون، می‌گه: «بزن به چاک! باز اومدی از دخل کف ببری» به خدا تهمت می‌زنه، آقا! آقا، به خدا هیچکی به اندازه ما از دزدی بدش نمی‌آد. آقا، دایی مرتضی‌مون اولها کارگر بلورسازی بود، ولی وقتی من هنوز تو دل مادرم بودم، افتاد زندان. یه شب هفت نفر ریختن سرش، اون هم چاقو کشید، زد یکی‌شونو کشت. بعد دادگاه هم اومد بیخودی تقصیر رو گذاشت گردن دایی ما. قبل انقلاب از زندان اومد بیرون، رفت معتاد شد. حالا هم همیشه با زنش دعوا مرافعه داره. گاهی می‌ذاره از خونه‌ش می‌ره، می‌ره می‌ره پیداش نمی‌شه. بعد که برمی‌گرده، الکی به زنش می‌گه، رفته بودم بیمارستان ترک کنم. دایی مرتضی یه بچه کوچولو داره، هروقت می‌آد خونمون، می‌خواد از پله‌هامون بره بالا، بیاد پایین. ما هم می‌ریم دنبالش که نیفته سرش بشکنه. می‌ریم بغلش می‌کنیم. اونوقت می‌ترسه، سفت آدمو می‌گیره. دایی ضامن‌مون توی دولت آباد نفتیه، بعضی روزها که می‌ره نفت پخش کنه منو هم با خودش می‌بره. اون تا می‌ره نفت بده به خونه‌ها، بچه‌ها می‌گیرن مسخره‌م می‌کنن، می‌گن: «ای عرب پا نفتی، کی اومدی، کی رفتی؟» سنگ می‌زنن تو کله‌ام. من هم که زورم نمی‌رسه، گریه‌م می‌گیره. یه روز رفتیم در یه خونه نفت بدیم، اونوقت یه پسره بود - لال بود - دنبالمون کرد تا سر کوچه‌شون. فحش مادر داد، گفت: «دیگه در خونه ما نیا!» لال بود، آقا! نمی‌دونیم چی می‌گفت... آقا، هر وقت از مادرمون حرف می‌زنیم، بغض می‌آد گلومونو می‌گیره، ول‌مون نمی‌کنه... مادرمون سر بچه مرد، آقا! شب درد بچه گرفتش. رفتیم نبات خانومو آوردیم. نبات خانوم مامای محله‌س، شله، یه چشمش هم چپه. صبح که بچه اومد دنیا، مادرمون گذاشت از دنیا رفت. بچه‌ هم پشت سرش مرد، آقا!... مادرمون اون وقت که زنده بود، توی کارخونهٔ استارلایت کار می‌کرد. جوراب شلواری می‌بافت. وقتی شکمش اومد بالا، از اونجا بیرونش کردن. مادرمون اینقده سختی کشیده که خدا بگه، بس! همیشه مریض بود، بعضی وقتا هم غش می‌کرد. پاهاش قد یه متکا باد کرده بود، آقا!... آقا، باور کن، آقا... وقتی مادرمون مرد ما صد برابر الان بغض کردیم. من و زهرا و مصطفی شب تا صبح خوابمون نبرد. بابام اون شب هزار تا سیگار کشید،‌ ولی صبحش مادرمون مرد. وقتی رفتیم خاکش کنیم، ننه غلام نمی‌خواست بذاره ما بریم تماشا، می‌گفت، ما بچه‌ایم، گناه داریم. ولی من دزدکی توی مرده‌شور خونه هم رفتم. بوی بدی می‌ده مرده‌شور خونه، بوی گربهٔ مرده. آدم می‌خواد دل و روده‌شو بالا بیاره. وقتی مادرمونو اوردن گذاشتن توی سالن مرده‌شور خونه، هفت تا مرده زودتر مرده بودن. مادرمون نفر هشتم بود. مرده‌ها منتظر بودن دوش خالی بشه، سر نوبت برن تو، غسل کنن. جنازه یه دختر مدرسه هم بود. نمی‌دونی فک و فامیل دختره چی‌کار می‌کردن؛ یکی سرشو می‌زد به دیوار، یکی کفش‌شو دراورده بود می‌زد تو سر خودش. مادرمونو که اوردن بذارن توی قبر، سروکله‌ٔ مصطفی هم پیداش شد. مادرمون با مصطفی خوب بود. خدا بیامرز که رفت توی قبر، نمی‌دونم از کجا یه مگس اومد نشست روی کفنش. تا مصطفی کیش‌اش کرد، مگسه گذاشت در رفت. بعد شروع کردن با بیل خاک ریختن روی سر مادرمون. رباب خانم با ناخن صورتشو می‌کند. بابام داشت توی دل خودش گریه می‌کرد. اگه مصطفی نمی‌زد زیر گریه و توی خاک و خل غلت نمی‌خورد، من هم گریه نمی‌کردم... مادرمونو که خاک کردیم، دم قبرستان حلوای نذری پخش می‌کردن. واسه اینکه بوی گربهٔ مرده از دماغم بره، یه قاشق حلوا گذاشتم دهنم. ولی صاحب عذا که روشو برگردوند، تفش کردم. آقا، هیچی نمی‌تونستیم بخوریم. آقا، ما دلمون خیلی تنگه، هیشکی نیست ما را زفت کنه. دل‌مون می‌خواد از این دنیا می‌رفتیم. آقا، باورتون نمی‌شه، توی محله ما ملت تند تند می‌میرن، آقا! زهرامون یه همبازی داره، همقد خودشه. اسمش الهامه، پنج سالشه. ده بیست روز پیش باباش از داربست افتاد زمین عکس برگردون شد، مرد. دیروز الهام اومده بود خونه‌مون، یه عکس از باباش هم اورده بود، می‌گفت، هر شب خواب باباشو می‌بینه که اون دنیا آتیش درست کرده، می‌خواد بیاد  بگیره اونو کباب کنه بخوره. یه حرفهایی می‌زد که مو به تن آدم سیخ می‌شد. اونوقت شب که خوابم برد، خوابیدم، خواب دیدم عزرائیل و شمر با آتیش اومدن بالای سرم، هی می‌چرخن و چه‌چه می‌خندن. عزرائیل نصفه‌س، آقا! یعنی پا نداره. من هم اومدم از دست‌شون در برم که دیدم یه خرگوشه داره با مامانش قایم موشک بازی می‌کنه. رفتم بگم، من هم بازی که گذاشتن در رفتن. من هم دنبالشون کردم. خسته که شدم دیدم سوار یه قایقم، یه سگ هم داشتم. داشتم با سگ بازی می‌کردم که یهو امیر ریزه پشت پا انداخت، افتادم توی آب. من هم رفتم سوار دوچرخه شدم، زدم به چاک. سگ هم از توی قایق پرید، اومد دنبالم. بعدش دیدم یه هلی‌کوپتر بالای سرمه، می‌خواد باید بستنی لیوانی‌مو قاپ بزنه. من هم با سنگ زدم شیشه‌شو شکوندم. اون هم ترسید در رفت، توی کوچه دباغ‌ها غیب شد. بعدش دیدم عباس آقا گرگ شده، می‌خواد بیاد زهرامونو بگیره لقمه‌ٔ چپش کنه. از ترسم دویدم توی پارک و رفتم سوار تاب شدم. اینقده تاب بازی کردم تا حسابی سرم گیج رفت. اومدم از تاب بپرم پایین، دیدیم زیر پام یه چاهه، یه چاه به این گندگی. داشتم ول می‌شدم ته چاه که از خواب پریدم. نشستم گریه کردم. اونوقت بابام بیدار شد، پرسید: «باز چی شده؟ شاشیدی؟» گفتم: «می‌ترسم.» گفت: «بگیر بخواب بابا تو هم دلت خوشه!» من هم لحافو که کشیدم روی سرم، همه‌ش خدا خدا می‌کردم ایم دفعه که خوابم برد، شانسم بگه، بزنه خواب خوشبختی ببینم، دلم خوش بشه. ولی اگه ما شانس داشتیم، آقا، اسم‌مونو می‌ذاشتن شانسعلی.
diff --git a/perf/texts/fa-thelittleprince.txt b/perf/texts/fa-thelittleprince.txt
new file mode 100644
index 0000000..3c56869
--- /dev/null
+++ b/perf/texts/fa-thelittleprince.txt
@@ -0,0 +1,923 @@
+شازده کوچولو
+اثر آنتوان دو سن‌تگزوپه‌ری
+برگردان احمد شاملو
+
+
+اهدانام‌چه
+به لئون ورث Leon Werth
+از بچه‌ها عذر می‌خواهم که این کتاب را به یکی از بزرگ‌ترها هدیه کرده‌ام. برای این کار یک دلیل حسابی دارم: این «بزرگ‌تر» به‌ترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگ‌تر» همه چیز را می‌تواند بفهمد حتا کتاب‌هایی را که برای بچه‌ها نوشته باشند. عذر سومم این است که این «بزرگ‌تر» تو فرانسه زندگی می‌کند و آن‌جا گشنگی و تشنگی می‌کشد و سخت محتاج دلجویی است. اگر همه‌ی این عذرها کافی نباشد اجازه می‌خواهم این کتاب را تقدیم آن بچه‌ای کنم که این آدم‌بزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچه‌ای بوده (گیرم کم‌تر کسی از آن‌ها این را به یاد می‌آورد). پس من هم اهدانام‌چه‌ام را به این شکل تصحیح می‌کنم:
+
+به لئون ورث
+موقعی که پسربچه بود
+آنتوان دو سن‌تگزوپه‌ری
+
+من هم برگردان فارسی این شعر بزرگ را به دو بچه‌ی دوست‌داشتنی دیگر تقدیم می‌کنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن
+
+احمد شاملو
+

+یک بار شش سالم که بود تو کتابی به اسم قصه‌های واقعی -که درباره‌ی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را می‌بلعید. آن تصویر یک چنین چیزی بود:
+
+یک مار بوآ که دارد حیوانی را می‌بلعد
+تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت می‌دهند. بی این که بجوندش. بعد دیگر نمی‌توانند از جا بجنبند و تمام شش ماهی را که هضمش طول می‌کشد می‌گیرند می‌خوابند».
+
+این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق می‌افتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شماره‌ی یکم را که این جوری بود:
+
+نقاشی شماره‌ی یکم — مار شبیه به کلاه
+شاهکارم را نشان بزرگ‌تر ها دادم و پرسیدم از دیدنش ترس‌تان بر می‌دارد؟
+جوابم دادند: -چرا کلاه باید آدم را بترساند؟
+
+نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم می‌کرد. آن وقت برای فهم بزرگ‌ترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آن‌ها توضیحات داد. نقاشی دومم این جوری بود:
+
+نقاشی دوم — مار و فیل درونش
+بزرگ‌ترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیش‌تر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شماره‌ی یک و نقاشی شماره‌ی دو ام یخ‌شان نگرفت دلسرد شده بودم. بزرگ‌ترها اگر به خودشان باشد هیچ وقت نمی‌توانند از چیزی سر درآرند. برای بچه‌ها هم خسته کننده است که همین جور مدام هر چیزی را به آن‌ها توضیح بدهند.
+
+ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. می‌توانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش می‌رسد.
+
+از این راه است که من تو زندگیم با گروه گروه آدم‌های حسابی برخورد داشته‌ام. پیش خیلی از بزرگ‌ترها زندگی کرده‌ام و آن‌ها را از خیلی نزدیک دیده‌ام گیرم این موضوع باعث نشده در باره‌ی آن‌ها عقیده‌ی بهتری پیدا کنم.
+
+هر وقت یکی‌شان را گیر آورده‌ام که یک خرده روشن بین به نظرم آمده با نقاشی شماره‌ی یکم که هنوز هم دارمش محکش زده‌ام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کرده‌ام نه از جنگل‌های بکر دست نخورده نه از ستاره‌ها. خودم را تا حد او آورده‌ام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زده‌ام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوش‌وقت شده.
+

+این جوری بود که روزگارم تو تنهایی می‌گذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثه‌یی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مساله‌ی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف می‌داد.
+
+شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسه‌ها به روز آوردم پرت افتاده‌تر از هر کشتی شکسته‌یی که وسط اقیانوس به تخته پاره‌یی چسبیده باشد. پس لابد می‌توانید حدس بزنید چه جور هاج و واج ماندم وقتی کله‌ی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم.
+-ها؟
+-یک برّه برام بکش...
+
+چنان از جا جستم که انگار صاعقه بم زده. خوب که چشم‌هام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این به‌ترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آن‌چه من کشیده‌ام کجا و خود او کجا! تقصیر من چیست؟ بزرگ‌تر ها تو شش سالگی از نقاشی دل‌سردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم.
+
+با چشم‌هایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیک‌ترین آبادی مسکونی هزار میل فاصله داشتم و این آدمی‌زاد کوچولوی من هم اصلا به نظر نمی‌آمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچه‌یی نمی‌بُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد.
+
+این بهترین شکلی است که بعدها از او در آوردم.
+وقتی بالاخره صدام در آمد، گفتم:
+-آخه... تو این جا چه می‌کنی؟
+و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که:
+-بی زحمت واسه‌ی من یک برّه بکش.
+آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمی‌کند. گرچه تو آن نقطه‌ی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آن‌چه من یاد گرفته‌ام بیش‌تر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم.
+بم جواب داد: -عیب ندارد، یک بَرّه برام بکش.
+
+از آن‌جایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشی‌ای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکه‌ای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمی‌خواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانه‌ی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.بره‌ی مریض
+-خب، کشیدم.
+با دقت نگاهش کرد و گفت:
+-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ
+-کشیدم.
+لبخند با نمکی زد و در نهایت گذشت گفت:
+-خودت که می‌بینی... این بره نیست، قوچ است. شاخ دارد نه...بره‌ی پیر
+باز نقاشی را عوض کردم.
+آن را هم مثل قبلی ها رد کرد:
+-این یکی خیلی پیر است... من یک بره می‌خواهم که مدت ها عمر کند...
+
+باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبه‌ای کشیدم که دیواره‌اش سه تا سوراخ داشت، و از دهنم پرید که:جعبه
+-این یک جعبه است. بره‌ای که می‌خواهی این تو است.
+
+و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافه‌اش از هم باز شد و گفت:
+-آها... این درست همان چیزی است که می‌خواستم! فکر می‌کنی این بره خیلی علف بخواهد؟
+-چطور مگر؟
+-آخر جای من خیلی تنگ است...
+-هر چه باشد حتماً بسش است. بره‌یی که بت داده‌ام خیلی کوچولوست.
+-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده...
+
+و این جوری بود که من با شهریار کوچولو آشنا شدم.
+

+خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ می‌کرد خودش انگار هیچ وقت سوال‌های مرا نمی‌شنید. فقط چیزهایی که جسته گریخته از دهنش می‌پرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمی‌کنم، سختم است.) ازم پرسید:
+-این چیز چیه؟
+-این «چیز» نیست: این پرواز می‌کند. هواپیماست. هواپیمای من است.
+
+و از این که به‌اش می‌فهماندم من کسی‌ام که پرواز می‌کنم به خود می‌بالیدم.
+حیرت زده گفت: -چی؟ تو از آسمان افتاده‌ای؟
+با فروتنی گفتم: -آره.
+گفت: -اوه، این دیگر خیلی عجیب است!
+و چنان قهقهه‌ی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم می‌خواهد دیگران گرفتاری‌هایم را جدی بگیرند.
+خنده‌هایش را که کرد گفت: -خب، پس تو هم از آسمان می‌آیی! اهل کدام سیاره‌ای؟...
+
+بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم:
+-پس تو از یک سیاره‌ی دیگر آمده‌ای؟
+آرام سرش را تکان داد بی این که چشم از هواپیما بردارد.
+
+اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان می‌داد.
+گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی...
+
+مدت درازی تو خیال فرو رفت، بعد بره‌اش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین
+فکر می‌کنید از این نیمچه اعتراف «سیاره‌ی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم:
+-تو از کجا می‌آیی آقا کوچولوی من؟ خانه‌ات کجاست؟ بره‌ی مرا می‌خواهی کجا ببری؟
+مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت:
+-حسن جعبه‌ای که بم داده‌ای این است که شب‌ها می‌تواند خانه‌اش بشود.
+-معلوم است... اما اگر بچه‌ی خوبی باشی یک ریسمان هم بِت می‌دهم که روزها ببندیش. یک ریسمان با یک میخ طویله...
+انگار از پیش‌نهادم جا خورد، چون که گفت:
+-ببندمش؟ چه فکر ها!
+-آخر اگر نبندیش راه می‌افتد می‌رود گم می‌شود.
+
+دوست کوچولوی من دوباره غش غش خنده را سر داد:
+-مگر کجا می‌تواند برود؟
+-خدا می‌داند. راستِ شکمش را می‌گیرد و می‌رود...
+-بگذار برود...اوه، خانه‌ی من آن‌قدر کوچک است!
+و شاید با یک خرده اندوه در آمد که:
+-یک‌راست هم که بگیرد برود جای دوری نمی‌رود...
+

+به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیاره‌ی او کمی از یک خانه‌ی معمولی بزرگ‌تر بود.این نکته آن‌قدرها به حیرتم نینداخت. می‌دانستم گذشته از سیاره‌های بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیاره‌ی دیگر هم هست که بعضی‌شان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده می‌شوند و هرگاه اخترشناسی یکی‌شان را کشف کند به جای اسم شماره‌ای به‌اش می‌دهد. مثلا اسمش را می‌گذارد «اخترک ۳۲۵۱».
+
+دلایل قاطعی دارم که ثابت می‌کند شهریار کوچولو از اخترک ب۶۱۲ آمده‌بود.
+
+شهریار کوچولو بر اخترکِ ب۶۱۲
+این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگره‌ی بین‌المللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس قدیمیآدم بزرگ‌ها این جوری‌اند!
+
+بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپایی‌ها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائه‌ی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس جدید
+به خاطر آدم بزرگ‌هاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برای‌تان نقل می‌کنم یا شماره‌اش را می‌گویم چون که آن‌ها عاشق عدد و رقم‌اند. وقتی با آن‌ها از یک دوست تازه‌تان حرف بزنید هیچ وقت ازتان درباره‌ی چیزهای اساسی‌اش سوال نمی‌کنند که هیج وقت نمی‌پرسند «آهنگ صداش چه‌طور است؟ چه بازی‌هایی را بیشتر دوست دارد؟ پروانه جمع می‌کند یا نه؟» -می‌پرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چه‌قدر است؟ پدرش چه‌قدر حقوق می‌گیرد؟» و تازه بعد از این سوال‌ها است که خیال می‌کنند طرف را شناخته‌اند.
+
+اگر به آدم بزرگ‌ها بگویید یک خانه‌ی قشنگ دیدم از آجر قرمز که جلو پنجره‌هاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً به‌شان گفت یک خانه‌ی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ!
+
+یا مثلا اگر به‌شان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودل‌برو بود و می‌خندید و دلش یک بره می‌خواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا می‌اندازند و باتان مثل بچ‌ه‌ها رفتار می‌کنند! اما اگر به‌شان بگویید «سیاره‌ای که ازش آمده‌بود اخترک ب۶۱۲ است» بی‌معطلی قبول می‌کنند و دیگر هزار جور چیز ازتان نمی‌پرسند. این جوری‌اند دیگر. نباید ازشان دل‌خور شد. بچه‌ها باید نسبت به آدم بزرگ‌ها گذشت داشته باشند.
+
+اما البته ماها که مفهوم حقیقی زندگی را درک می‌کنیم می‌خندیم به ریش هرچه عدد و رقم است! چیزی که من دلم می‌خواست این بود که این ماجرا را مثل قصه‌ی پریا نقل کنم. دلم می‌خواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی می‌کرد همه‌اش یه خورده از خودش بزرگ‌تر و واسه خودش پیِ دوستِ هم‌زبونی می‌گشت...»، آن هایی که مفهوم حقیقی زندگی را درک کرده‌اند واقعیت قضیه را با این لحن بیشتر حس می‌کنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا می‌داند با نقل این خاطرات چه بار غمی روی دلم می‌نشیند. شش سالی می‌شود که دوستم با بَرّه‌اش رفته. این که این جا می‌کوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غم‌انگیز است. همه کس که دوستی ندارد. من هم می‌توانم مثل آدم بزرگ‌ها بشوم که فقط اعداد و ارقام چشم‌شان را می‌گیرد. و باز به همین دلیل است که رفته‌ام یک جعبه رنگ و چند تا مداد خریده‌ام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرف‌هاست! البته تا آن‌جا که بتوانم سعی می‌کنم چیزهایی که می‌کشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در می‌آید یکیش نه. سرِ قدّ و قواره‌اش هم حرف است. یک جا زیادی بلند درش آورده‌ام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفته‌ام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهم‌ترش هم دچار اشتباه شده‌ام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمی‌رفت. شاید مرا هم مثل خودش می‌پنداشت. اما از بختِ بد، دیدن بره‌ها از پشتِ جعبه از من بر نمی‌آید. نکند من هم یک خرده به آدم بزرگ‌ها رفته‌ام؟ «باید پیر شده باشم».
+

+هر روزی که می‌گذشت از اخترک و از فکرِ عزیمت و از سفر و این حرف‌ها چیزهای تازه‌ای دست‌گیرم می‌شد که همه‌اش معلولِ بازتاب‌هایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم.
+
+این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل مانده‌بود ناگهان ازم پرسید:
+-بَرّه‌ها بته‌ها را هم می‌خورند دیگر، مگر نه؟
+-آره. همین جور است.
+-آخ! چه خوشحال شدم!
+
+نتوانستم بفهمم این موضوع که بَرّه‌ها بوته‌ها را هم می‌خورند اهمیتش کجاست اما شهریار کوچولو درآمد که:
+-پس لابد بائوباب ها را هم می‌خورند دیگر؟
+
+یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شده‌اندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گنده‌تر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمی‌توانند بخورند.
+از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم.
+اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع می‌کند به بزرگ شدن.
+-درست است. اما نگفتی چرا دلت می‌خواهد بره‌هایت نهال‌های بائوباب را بخورند؟
+گفت: -دِ! معلوم است!
+
+و این را چنان گفت که انگار موضوع از آفتاب هم روشن‌تر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم.
+
+راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم می‌رسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاه‌های خوب به هم می‌رسید، هم تخمِ بدِ گیاه‌هایِ بد. اما تخم گیاه‌ها نامریی‌اند. آن‌ها تو حرمِ تاریک خاک به خواب می‌روند تا یکی‌شان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی می‌آید و اول با کم رویی شاخکِ باریکِ خوشگل و بی‌آزاری به طرف خورشید می‌دواند. اگر این شاخک شاخکِ تربچه‌ای گلِ سرخی چیزی باشد می‌شود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشه‌کنش کند.
+
+باری، تو سیاره‌ی شهریار کوچولو گیاه تخمه‌های وحشتناکی به هم می‌رسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر به‌اش برسند دیگر هیچ جور نمی‌شود حریفش شد: تمام سیاره را می‌گیرد و با ریشه‌هایش سوراخ سوراخش می‌کند و اگر سیاره خیلی کوچولو باشد و بائوباب‌ها خیلی زیاد باشند پاک از هم متلاشیش می‌کنند.
+
+شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوباب‌ها از بته‌های گلِ سرخ که تا کوچولواَند عین هم‌اَند با دقت ریشه‌کن‌شان بکند. کار کسل‌کننده‌ای هست اما هیچ مشکل نیست.»
+
+یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچه‌های سیاره‌ی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پاره‌ای وقت‌ها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم می‌زاید. اخترکی را سراغ دارم که یک تنبل‌باشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...».
+
+آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم.
+
+اخترکِ تنبل‌باشی با سه درختِ بائوباب
+هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوباب‌ها آن‌قدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویه‌ی همیشگی خودم دست بر می‌دارم و می‌گویم: «بچه‌ها! هوای بائوباب‌ها را داشته باشید!»
+
+اگر من سرِ این نقاشی این همه به خودم فشار آورده‌ام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدت‌ها پیش بیخ گوش‌شان بوده و مثلِ خودِ من ازش غافل بوده‌اند. درسی که با این نقاشی داده‌ام به زحمتش می‌ارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیه‌ی نقاشی‌های این کتاب هیبتِ تصویرِ بائوباب‌ها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زده‌ام اما نتوانسته‌ام از کار درشان بیاورم. اما عکس بائوباب‌ها را که می‌کشیدم احساس می‌کردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود.
+

+آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دل‌گیر تو سر درآوردم. تا مدت‌ها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکته‌ی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی:
+-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب
+-هوم، حالاها باید صبر کنی...
+-واسه چی صبر کنم؟
+-صبر کنی که آفتاب غروب کند.
+
+اول سخت حیرت کردی بعد از خودت خنده‌ات گرفت و برگشتی به من گفتی:
+-همه‌اش خیال می‌کنم تو اخترکِ خودمم!
+-راستش موقعی که تو آمریکا ظهر باشد همه می‌دانند تو فرانسه تازه آفتاب دارد غروب می‌کند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا این‌جا کجا! اما رو اخترک تو که به آن کوچکی است همین‌قدر که چند قدمی صندلیت را جلو بکشی می‌توانی هرقدر دلت خواست غروب تماشا کنی.
+-یک روز چهل و سه بار غروب آفتاب را تماشا کردم!
+و کمی بعد گفت:
+-خودت که می‌دانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت می‌برد.
+-پس خدا می‌داند آن روز چهل و سه غروبه چه‌قدر دلت گرفته بوده.
+
+اما مسافر کوچولو جوابم را نداد.
+

+روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدت‌ه‌ا تو دلش به‌اش فکر کرده باشد یک‌هو بی مقدمه از من پرسید:
+-گوسفندی که بُتّه ها را بخورد گل ها را هم می‌خورد؟
+-گوسفند هرچه گیرش بیاید می‌خورد.
+-حتا گل‌هایی را هم که خار دارند؟
+-آره، حتا گل‌هایی را هم که خار دارند.
+-پس خارها فایده‌شان چیست؟
+
+من چه می‌دانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهره‌ی سفتِ موتور بودم. از این که یواش یواش بو می‌بردم خرابیِ کار به آن سادگی‌ها هم که خیال می‌کردم نیست برج زهرمار شده‌بودم و ذخیره‌ی آبم هم که داشت ته می‌کشید بیش‌تر به وحشتم می‌انداخت.
+-پس خارها فایده‌شان چسیت؟
+
+شهریار کوچولو وقتی سوالی را می‌کشید وسط دیگر به این مفتی‌ها دست بر نمی‌داشت. مهره پاک کلافه‌ام کرده بود. همین جور سرسری پراندم که:
+-خارها به درد هیچ کوفتی نمی‌خورند. آن‌ها فقط نشانه‌ی بدجنسی گل‌ها هستند.
+-دِ!
+و پس از لحظه‌یی سکوت با یک جور کینه درآمد که:
+-حرفت را باور نمی‌کنم! گل‌ها ضعیفند. بی شیله‌پیله‌اند. سعی می‌کنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال می‌کنند با آن خارها چیزِ ترسناکِ وحشت‌آوری می‌شوند...
+
+لام تا کام به‌اش جواب ندادم. در آن لحظه داشتم تو دلم می‌گفتم: «اگر این مهره‌ی لعنتی همین جور بخواهد لج کند با یک ضربه‌ی چکش حسابش را می‌رسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت:
+-تو فکر می‌کنی گل‌ها...
+من باز همان جور بی‌توجه گفتم:
+-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمی‌کنم! آخر من گرفتار هزار مساله‌ی مهم‌تر از آنم!
+هاج و واج نگاهم کرد و گفت:
+-مساله‌ی مهم!
+
+مرا می‌دید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت می‌آمد خم شده‌ام.
+-مثل آدم بزرگ‌ها حرف می‌زنی!
+از شنیدنِ این حرف خجل شدم اما او همین جور بی‌رحمانه می‌گفت:
+-تو همه چیز را به هم می‌ریزی... همه چیز را قاتی می‌کنی!
+حسابی از کوره در رفته‌بود.
+
+موهای طلایی طلائیش تو باد می‌جنبید.
+-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی می‌کند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستاره‌را تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است!
+-یک چی؟
+-یک قارچ!گلِ سرخ
+حالا دیگر رنگش از فرط خشم مثل گچ سفید شده‌بود:
+-کرورها سال است که گل‌ها خار می‌سازند و با وجود این کرورها سال است که برّه‌ها گل‌ها را می‌خورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گل‌ها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمی‌خورند این قدر به خودشان زحمت می‌دهند؟ جنگ میان برّه‌ها و گل‌ها هیچ مهم نیست؟ این موضوع از آن جمع زدن‌های آقا سرخ‌روئه‌یِ شکم‌گنده مهم‌تر و جدی‌تر نیست؟ اگر من گلی را بشناسم که تو همه‌ی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چه‌کار دارد می‌کند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستاره‌هاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستاره‌ها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟
+دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه.
+
+حالا دیگر شب شده‌بود. اسباب و ابزارم را کنار انداخته‌بودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک می‌آمد. رو ستاره‌ای، رو سیاره‌ای، رو سیاره‌ی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم به‌اش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزه‌بند می‌کشم... خودم واسه گفت یک تجیر می‌کشم... خودم...» بیش از این نمی‌دانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس می‌کردم. نمی‌دانستم چه‌طور باید خودم را به‌اش برسانم یا به‌اش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک!
+

+راه شناختن آن گل را خیلی زود پیدا کردم:
+تو اخترکِ شهریار کوچولو همیشه یک مشت گل‌های خیلی ساده در می‌آمده. گل‌هایی با یک ردیف گلبرگ که جای چندانی نمی‌گرفته، دست و پاگیرِ کسی نمی‌شده. صبحی سر و کله‌شان میان علف‌ها پیدا می‌شده شب از میان می‌رفته‌اند. اما این یکی یک روز از دانه‌ای جوانه زده بود که خدا می‌دانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخک‌های دیگر نمی‌رفت مواظبت کرده‌بود. بعید بنود که این هم نوعِ تازه‌ای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دست‌به‌کارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچه‌ی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزه‌آسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوه‌کند. رنگ‌هایش را با وسواس تمام انتخاب می‌کرد سر صبر لباس می‌پوشید و گلبرگ‌ها را یکی یکی به خودش می‌بست. دلش نمی‌خواست مثل شقایق‌ها با جامه‌ی مچاله و پر چروک بیرون بیاید.
+
+شهریار کوچولو و گلِ سرخنمی‌خواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!...
+
+هوه، بله عشوه‌گری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازه‌کشان گفت:
+-اوه، تازه همین حالا از خواب پا شده‌ام... عذر می‌خواهم که موهام این جور آشفته‌است...
+
+شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند:
+-وای چه‌قدر زیبائید!
+گل به نرمی گفت:
+-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم...
+شهریار کوچولو شستش خبردار شد که طرف آن‌قدرها هم اهل شکسته‌نفسی نیست اما راستی که چه‌قدر هیجان انگیز بود!
+-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید.
+و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل داده‌بود.شهریار کوچولو در حالِ تماشای گلِ سرخ
+با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمی‌نفهمی از ضعفش آب می‌خورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف می‌زد یک‌هو در آمده بود که:ببر و گلِ سرخ
+-نکند ببرها با آن چنگال‌های تیزشان بیایند سراغم!
+شهریار کوچولو ازش ایراد گرفته‌بود که:
+-تو اخترک من ببر به هم نمی‌رسد. تازه ببرها که علف‌خوار نیستند.
+گل به گلایه جواب داده بود:
+-من که علف نیستم.
+و شهریار کوچولو گفته بود:
+-عذر می‌خواهم...
+-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت می‌کنم. تو دستگاه‌تان تجیر به هم نمی‌رسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ
+شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!»
+-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ
+اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانسته‌باشد دنیاهای دیگری را بشناسد. شرم‌سار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را به‌اش یادآور شود:
+-تجیر کو پس؟
+-داشتم می‌رفتم اما شما داشتید صحبت می‌کردید!
+و با وجود این زورکی بنا کرده‌بود به سرفه کردن تا او احساس پشیمانی کند.
+
+به این ترتیب شهریار کوچولو با همه‌ی حسن نیّتی که از عشقش آب می‌خورد همان اول کار به او بد گمان شده‌بود. حرف‌های بی سر و تهش را جدی گرفته‌بود و سخت احساس شوربختی می‌کرد.
+
+یک روز دردِدل کنان به من گفت: -حقش بود به حرف‌هاش گوش نمی‌دادم. هیچ وقت نباید به حرف گل‌ها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر می‌کرد گیرم من بلد نبودم چه‌جوری از آن لذت ببرم. قضیه‌ی چنگال‌های ببر که آن جور دَمَغم کرده‌بود می‌بایست دلم را نرم کرده باشد...»
+
+یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در باره‌اش قضاوت می‌کردم نه روی گفتارش... عطرآگینم می‌کرد. دلم را روشن می‌کرد. نمی‌بایست ازش بگریزم. می‌بایست به مهر و محبتی که پشتِ آن کلک‌های معصومانه‌اش پنهان بود پی می‌بردم. گل‌ها پُرَند از این جور تضادها. اما خب دیگر، من خام‌تر از آن بودم که راهِ دوست داشتنش را بدانم!».
+

+گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد.
+
+گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد.
+صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتش‌فشان‌های فعالش را با دقت پاک و دوده‌گیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتش‌فشان.دو تا آتش‌فشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتش‌فشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتش‌فشان خاموش را هم پاک کرد. آتش‌فشان که پاک باشد مرتب و یک هوا می‌سوزد و یک‌هو گُر نمی‌زند. آتش‌فشان هم عین‌هو بخاری یک‌هو اَلُو می‌زند. البته ما رو سیاره‌مان زمین کوچک‌تر از آن هستیم که آتش‌فشان‌هامان را پاک و دوده‌گیری کنیم و برای همین است که گاهی آن جور اسباب زحمت‌مان می‌شوند.
+
+شهریار کوچولو با دل‌ِگرفته آخرین نهال‌های بائوباب را هم ریشه‌کن کرد. فکر می‌کرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نمانده‌بود که اشکش سرازیر شود.
+به گل گفت: -خدا نگهدار!
+اما او جوابش را نداد.
+دوباره گفت: -خدا نگهدار!
+گل سرفه‌کرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت:
+-من سبک مغز بودم. ازت عذر می‌خواهم. سعی کن خوشبخت باشی.
+از این که به سرکوفت و سرزنش‌های همیشگی برنخورد حیرت کرد و سرپوش به دست هاج‌وواج ماند. از این محبتِ آرام سر در نمی‌آورد.
+گل به‌اش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بی‌عقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمی‌خورد.
+-آخر، باد...
+-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر.
+-آخر حیوانات...
+-اگر خواسته‌باشم با شب‌پره‌ها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چاره‌ای ندارم. شب‌پره باید خیلی قشنگ باشد. جز آن کی به دیدنم می‌آید؟ تو که می‌روی به آن دور دورها. از بابتِ درنده‌ها هم هیچ کَکَم نمی‌گزد: «من هم برای خودم چنگ و پنجه‌ای دارم».
+و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت:
+-دست‌دست نکن دیگر! این کارت خلق آدم را تنگ می‌کند. حالا که تصمیم گرفته‌ای بروی برو!
+
+و این را گفت، چون که نمی‌خواست شهریار کوچولو گریه‌اش را ببیند. گلی بود تا این حد خودپسند...
+
+۱۰
+خودش را در منطقه‌ی اخترک‌های ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکی‌یکی‌شان را سیاحت کردن.
+
+اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد:
+-خب، این هم رعیت!
+شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری می‌تواند بشناسدم؟
+دیگر اینش را نخوانده‌بود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب می‌آیند.
+
+پادشاه در سیاره‌اش
+پادشاه که می‌دید بالاخره شاهِ کسی شده و از این بابت کبکش خروس می‌خواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفته‌بود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهن‌دره افتاد.
+شاه به‌اش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن می‌کنم. شهریار کوچولو که سخت خجل شده‌بود در آمد که:
+-نمی‌توانم جلوِ خودم را بگیرم. راه درازی طی‌کرده‌ام و هیچ هم نخوابیده‌ام...
+پادشاه گفت: -خب خب، پس بِت امر می‌کنم خمیازه بکشی. سال‌هاست خمیازه‌کشیدن کسی را ندیده‌ام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است.
+شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم می‌کنم... دیگر نمی‌توانم.
+شاه گفت: -هوم! هوم! خب، پس من به‌ات امر می‌کنم که گاهی خمیازه بکشی گاهی نه.
+تند و نامفهوم حرف می‌زد و انگار خلقش حسابی تنگ بود.
+
+پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانی‌ها هم هیچ نرمشی از خودش نشان نمی‌داد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر می‌کرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغ‌های دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است».
+شهریار کوچولو در نهایت ادب پرسید: -اجازه می‌فرمایید بنشینم؟
+پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع می‌کرد گفت: -به‌ات امر می‌کنیم بنشینی.
+
+منتها شهریار کوچولو مانده‌بود حیران: آخر آن اخترک کوچک‌تر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت می‌کرد؟ گفت: -قربان عفو می‌فرمایید که ازتان سوال می‌کنم...
+پادشاه با عجله گفت: -به‌ات امر می‌کنیم از ما سوال کنی.
+-شما قربان به چی سلطنت می‌فرمایید؟
+پادشاه خیلی ساده گفت: -به همه چی.
+-به همه‌چی؟
+پادشاه با حرکتی قاطع به اخترک خودش و اخترک‌های دیگر و باقی ستاره‌ها اشاره کرد.
+شهریار کوچولو پرسید: -یعنی به همه‌ی این ها؟
+شاه جواب داد: -به همه‌ی این ها.
+آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود.
+-آن وقت ستاره‌ها هم سربه‌فرمان‌تانند؟
+پادشاه گفت: -البته که هستند. همه‌شان بی‌درنگ هر فرمانی را اطاعت می‌کنند. ما نافرمانی را مطلقا تحمل نمی‌کنیم.
+
+یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی می‌داشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویست‌بار غروب آفتاب را تماشا می‌کرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ول‌کرده‌بود غصه‌اش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند:
+-دلم می‌خواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند.
+-اگر ما به یک سردار امر کنیم مثل شب‌پره از این گل به آن گل بپرد یا قصه‌ی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکی‌مان مقصریم، ما یا او؟
+شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما.
+پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب می‌کنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است.
+شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمی‌کرد گفت: -غروب آفتاب من چی؟
+-تو هم به غروب آفتابت می‌رسی. امریه‌اش را صادر می‌کنیم. منتها با شَمِّ حکمرانی‌مان منتظریم زمینه‌اش فراهم بشود.
+شهریار کوچولو پرسید: -کِی فراهم می‌شود؟
+پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد:
+-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشم‌های خودت می‌بینی که چه‌طور فرمان ما اجرا می‌شود!
+
+شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسه‌اش رفته‌بود تاسف می‌خورد. از آن گذشته دلش هم کمی گرفته‌بود. این بود که به پادشاه گفت:
+-من دیگر این‌جا کاری ندارم. می‌خواهم بروم.
+شاه که دلش برای داشتن یک رعیت غنج می‌زد گفت:
+-نرو! نرو! وزیرت می‌کنیم.
+-وزیرِ چی؟
+-وزیرِ دادگستری!
+-آخر این جا کسی نیست که محاکمه بشود.
+پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزده‌ایم. خیلی پیر شده‌ایم، برای کالسکه جا نداریم. پیاده‌روی هم خسته‌مان می‌کند.
+شهریار کوچولو که خم شده‌بود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کرده‌ام، آن طرف هم دیارالبشری نیست.
+پادشاه به‌اش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکل‌تر هم هست. محاکمه کردن خود از محاکمه‌کردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم می‌شود یک فرزانه‌ی تمام عیاری.
+شهریار کوچولو گفت: -من هر جا باشم می‌توانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر می‌کنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها می‌شنویم. می‌توانی او را به محاکمه بکشی و گاه‌گاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا می‌کند. گیرم تو هر دفعه عفوش می‌کنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیش‌تر نیست که.
+شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمی‌آید. فکر می‌کنم دیگر باید بروم.
+پادشاه گفت: -نه!
+
+اما شهریار کوچولو که آماده‌ی حرکت شده بود و ضمنا هم هیچ دلش نمی‌خواست اسباب ناراحتی سلطان پیر بشود گفت:
+-اگر اعلی‌حضرت مایلند اوامرشان دقیقا اجرا بشود می‌توانند فرمان خردمندانه‌ای در مورد بنده صادر بفرمایند. مثلا می‌توانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور می‌کنم زمینه‌اش هم آماده باشد...
+چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد.
+آن‌وقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت!
+حالت بسیار شکوهمندی داشت.
+
+شهریار کوچولو همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
+
+۱۱
+اخترک دوم مسکن آدم خود پسندی بود.
+خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -به‌به! این هم یک ستایشگر که دارد می‌آید مرا ببیند!
+
+خودپسند در سیاره‌اش
+آخر برای خودپسندها دیگران فقط یک مشت ستایش‌گرند.
+شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشته‌اید!
+خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهله‌ی ستایشگرهایم بلند می‌شود. گیرم متاسفانه تنابنده‌ای گذارش به این طرف‌ها نمی‌افتد.
+شهریار کوچولو که چیزی حالیش نشده بود گفت:
+-چی؟
+خودپسند گفت: -دست‌هایت را بزن به هم دیگر.
+شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد.
+شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیش‌تر از دیدنِ پادشاه‌است». و دوباره بنا کرد دست‌زدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن.
+
+پس از پنج دقیقه‌ای شهریار کوچولو که از این بازی یک‌نواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟
+اما خودپسند حرفش را نشنید. آخر آن‌ها جز ستایش خودشان چیزی را نمی‌شنوند.
+از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه می‌کنی؟
+-ستایش و تحسین یعنی چه؟
+-یعنی قبول این که من خوش‌قیافه‌ترین و خوش‌پوش‌ترین و ثروت‌مندترین و باهوش‌ترین مرد این اخترکم.
+-آخر روی این اخترک که فقط خودتی و کلاهت.
+-با وجود این ستایشم کن. این لطف را در حق من بکن.
+شهریار کوچولو نیم‌چه شانه‌ای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟
+
+شهریار کوچولو به راه افتاد و همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
+
+۱۲
+تو اخترک بعدی می‌خواره‌ای می‌نشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد.
+
+می‌خواره در سیاره‌اش
+
+به می‌خواره که صُم‌بُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری می‌کنی؟
+می‌خواره با لحن غم‌زده‌ای جواب داد: -مِی می‌زنم.
+شهریار کوچولو پرسید: -مِی می‌زنی که چی؟
+می‌خواره جواب داد: -که فراموش کنم.
+شهریار کوچولو که حالا دیگر دلش برای او می‌سوخت پرسید: -چی را فراموش کنی؟
+می‌خواره همان طور که سرش را می‌انداخت پایین گفت: -سر شکستگیم را.
+شهریار کوچولو که دلش می‌خواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟
+می‌خواره جواب داد: -سرشکستگیِ می‌خواره بودنم را.
+این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی‌راستی چه‌قدر عجیبند!
+
+۱۳
+اخترک چهارم اخترک مرد تجارت‌پیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد.
+
+مردِ تجارت‌پیشه در سیاره‌اش
+شهریار کوچولو گفت: -سلام. آتش‌سیگارتان خاموش شده.
+-سه و دو می‌کند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش می‌کند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک.
+-پانصد میلیون چی؟
+-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه می‌دانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرف‌های هشت‌من‌نه‌شاهی سر و کار ندارم!... دو و پنج هفت...
+شهریار کوچولو که وقتی چیزی می‌پرسید دیگر تا جوابش را نمی‌گرفت دست بردار نبود دوباره پرسید:
+-پانصد و یک میلیون چی؟
+تاجر پیشه سرش را بلند کرد:
+-تو این پنجاه و چهار سالی که ساکن این اخترکم همه‌اش سه بار گرفتار مودماغ شده‌ام. اولیش بیست و دو سال پیش یک سوسک بود که خدا می‌داند از کدام جهنم پیدایش شد. صدای وحشت‌ناکی از خودش در می‌آورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعه‌ی دوم یازده سال پیش بود که استخوان درد بی‌چاره‌ام کرد. من ورزش نمی‌کنم. وقت یللی‌تللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و...
+-این همه میلیون چی؟
+تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیون‌ها از این چیزهای کوچولویی که پاره‌ای وقت‌ها تو هوا دیده می‌شود.
+-مگس؟
+-نه بابا. این چیزهای کوچولوی براق.
+-زنبور عسل؟
+-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت می‌برد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیال‌بافی نمی‌کنم.
+-آها، ستاره؟
+-خودش است: ستاره.
+-خب پانصد میلیون ستاره به چه دردت می‌خورد؟
+-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق.
+-خب، به چه دردت می‌خورند؟
+-به چه دردم می‌خورند؟
+-ها.
+-هیچی تصاحب‌شان می‌کنم.
+-ستاره‌ها را؟
+-آره خب.
+-آخر من به یک پادشاهی برخوردم که...
+-پادشاه‌ها تصاحب نمی‌کنند بل‌که به‌اش «سلطنت» می‌کنند. این دو تا با هم خیلی فرق دارد.
+-خب، حالا تو آن‌ها را تصاحب می‌کنی که چی بشود؟
+-که دارا بشوم.
+-خب دارا شدن به چه کارت می‌خورد؟
+-به این کار که، اگر کسی ستاره‌ای پیدا کرد من ازش بخرم.
+شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائم‌الخمره می‌بَرَد.» با وجود این باز ازش پرسید:
+-چه جوری می‌شود یک ستاره را صاحب شد؟
+تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستاره‌ها مال کی‌اند؟
+-چه می‌دانم؟ مال هیچ کس.
+-پس مال منند، چون من اول به این فکر افتادم.
+-همین کافی است؟
+-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد می‌شود مال تو. اگر جزیره‌ای کشف کنی که مال هیچ کس نباشد می‌شود مال تو. اگر فکری به کله‌ات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش می‌کنی و می‌شود مال تو. من هم ستاره‌ها را برای این صاحب شده‌ام که پیش از من هیچ کس به فکر نیفتاده بود آن‌ها را مالک بشود.
+شهریار کوچولو گفت: -این ها همه‌اش درست. منتها چه کارشان می‌کنی؟
+تاجر پیشه گفت: -اداره‌شان می‌کنم، همین جور می‌شمارم‌شان و می‌شمارم‌شان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی.
+شهریار کوچولو که هنوز این حرف تو کَتَش نرفته‌بود گفت:
+-اگر من یک شال گردن ابریشمی داشته باشم می‌توانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم می‌توانم بچینم با خودم ببرمش. اما تو که نمی‌توانی ستاره‌ها را بچینی!
+-نه. اما می‌توانم بگذارم‌شان تو بانک.
+-اینی که گفتی یعنی چه؟
+-یعنی این که تعداد ستاره‌هایم را رو یک تکه کاغذ می‌نویسم می‌گذارم تو کشو درش را قفل می‌کنم.
+-همه‌اش همین؟
+-آره همین کافی است.
+
+شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدم‌های بزرگ فرق می‌کرد.
+باز گفت: -من یک گل دارم که هر روز آبش می‌دهم. سه تا هم آتش‌فشان دارم که هفته‌ای یک بار پاک و دوده‌گیری‌شان می‌کنم. آخر آتش‌فشان خاموشه را هم پاک می‌کنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتش‌فشان‌ها و هم برای گل این که من صاحب‌شان باشم فایده دارد. تو چه فایده‌ای به حال ستاره‌ها داری؟
+
+تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
+
+۱۴
+اخترکِ پنجم چیز غریبی بود. از همه‌ی اخترک‌های دیگر کوچک‌تر بود، یعنی فقط به اندازه‌ی یک فانوس پایه‌دار و یک فانوس‌بان جا داشت.
+
+فانوس‌بان در حالِ روشن کردنِ فانوس در سیاره‌اش
+شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانه‌ای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوس‌بان چه می‌تواند باشد. با وجود این تو دلش گفت:
+-خیلی احتمال دارد که این بابا عقلش پاره‌سنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقل‌تر نیست. دست کم کاری که می‌کند یک معنایی دارد. فانوسش را که روشن می‌کند عین‌هو مثل این است که یک ستاره‌ی دیگر یا یک گل به دنیا می‌آورد و خاموشش که می‌کند پنداری گل یا ستاره‌ای را می‌خواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفت‌وگو مفید هم هست.
+
+وقتی رو اخترک پایین آمد با ادب فراوان به فانوس‌بان سلام کرد:
+-سلام. واسه چی فانوس را خاموش کردی؟
+-دستور است. صبح به خیر!
+-دستور چیه؟
+-این است که فانوسم را خاموش کنم. شب خوش!
+و دوباره فانوس را روشن کرد.
+-پس چرا روشنش کردی باز؟
+فانوس‌بان جواب داد: -خب دستور است دیگر.
+شهریار کوچولو گفت: -اصلا سر در نمیارم.
+فانوس‌بان گفت: -چیز سر در آوردنی‌یی توش نیست که. دستور دستور است. روز بخیر!
+و باز فانوس را خاموش کرد.
+بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت:
+-کار جان‌فرسایی دارم. پیش‌تر ها معقول بود: صبح خاموشش می‌کردم و شب که می‌شد روشنش می‌کردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم می‌توانستم بگیرم بخوابم...
+-بعدش دستور عوض شد؟
+فانوس‌بان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است.
+-خب؟
+-حالا که سیاره دقیقه‌ای یک بار دور خودش می‌گردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقه‌ای یک بار فانوس را روشن می‌کنم یک بار خاموش.
+-چه عجیب است! تو اخترک تو شبانه روز همه‌اش یک دقیقه طول می‌کشد!
+فانوس‌بان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط می‌کنیم.
+-یک ماه؟
+-آره. سی دقیقه. سی روز! شب خوش!
+و دوباره فانوس را روشن کرد.
+
+شهریار کوچولو به فانوس‌بان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست می‌دارد. یادِ آفتاب‌غروب‌هایی افتاد که آن وقت‌ها خودش با جابه‌جا کردن صندلیش دنبال می‌کرد. برای این که دستی زیر بال دوستش کرده باشد گفت:
+-می‌دانی؟ یک راهی بلدم که می‌توانی هر وقت دلت بخواهد استراحت کنی.
+فانوس‌بان گفت: -آرزوش را دارم.
+آخر آدم می‌تواند هم به دستور وفادار بماند هم تنبلی کند.
+شهریار کوچولو دنبال حرفش را گرفت و گفت:
+-تو، اخترکت آن‌قدر کوچولوست که با سه تا شلنگ برداشتن می‌توانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی می‌توانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع می‌کنی به راه‌رفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش می‌آید.
+فانوس‌بان گفت: -این کار گرهی از بدبختی من وا نمی‌کند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است.
+شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه.
+فانوس‌بان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر!
+و فانوس را خاموش کرد.
+
+شهریار کوچولو میان راه با خودش گفت: گرچه آن‌های دیگر، یعنی خودپسنده و تاجره اگر این را می‌دیدند دستش می‌انداختند و تحقیرش می‌کردند، هر چه نباشد کار این یکی به نظر من کم‌تر از کار آن‌ها بی‌معنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است.
+
+از حسرت آهی کشید و همان طور با خودش گفت:
+-این تنها کسی بود که من می‌توانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمی‌گیرند.
+
+چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود.
+
+۱۵
+اخترک ششم اخترکی بود ده بار فراخ‌تر، و آقاپیره‌ای توش بود که کتاب‌های کَت‌وکلفت می‌نوشت.
+
+جغرافی‌دان در سیاره‌اش
+همین که چشمش به شهریار کوچولو افتاد با خودش گفت:
+-خب، این هم یک کاشف!
+شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟
+آقا پیره به‌اش گفت: -از کجا می‌آیی؟
+شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما این‌جا چه‌کار می‌کنید؟
+آقا پیره گفت: -من جغرافی‌دانم.
+-جغرافی‌دان چه باشد؟
+-جغرافی‌دان به دانشمندی می‌گویند که جای دریاها و رودخانه‌ها و شهرها و کوه‌ها و بیابان‌ها را می‌داند.
+شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است.
+و به اخترک جغرافی‌دان، این سو و آن‌سو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیده‌بود.
+-اخترک‌تان خیلی قشنگ است. اقیانوس هم دارد؟
+جغرافی‌دان گفت: -از کجا بدانم؟
+شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چه‌طور؟
+جغرافی‌دان گفت: -از کجا بدانم؟
+-شهر، رودخانه، بیابان؟
+جغرافی‌دان گفت: از این‌ها هم خبری ندارم.
+-آخر شما جغرافی‌دانید؟
+جغرافی‌دان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافی‌دان نیست که دوره‌بیفتد برود شهرها و رودخانه‌ها و کوه‌ها و دریاها و اقیانوس‌ها و بیابان‌ها را بشمرد. مقام جغرافی‌دان برتر از آن است که دوره بیفتد و ول‌بگردد. اصلا از اتاق کارش پا بیرون نمی‌گذارد بلکه کاشف‌ها را آن تو می‌پذیرد ازشان سوالات می‌کند و از خاطرات‌شان یادداشت بر می‌دارد و اگر خاطرات یکی از آن‌ها به نظرش جالب آمد دستور می‌دهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد.
+-برای چه؟
+-برای این که اگر کاشفی گنده‌گو باشد کار کتاب‌های جغرافیا را به فاجعه می‌کشاند. هکذا کاشفی که اهل پیاله باشد.
+-آن دیگر چرا؟
+b-چون آدم‌های دائم‌الخمر همه چیز را دوتا می‌بینند. آن وقت جغرافی‌دان برمی‌دارد جایی که یک کوه
+بیشتر نیست می‌نویسد دو کوه.
+شهریار کوچولو گفت: -پس من یک بابایی را می‌شناسم که کاشف هجوی از آب در می‌آید.
+-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام می‌گیرد.
+-یعنی می‌روند می‌بینند؟
+-نه، این کار گرفتاریش زیاد است. از خود کاشف می‌خواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش می‌خواهند سنگ‌های گنده‌ای از آن کوه رو کند.
+جغرافی‌دان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری می‌آیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی.
+و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشف‌ها را اول بامداد یادداشت می‌کنند و دست نگه می‌دارند تا دلیل اقامه کند، آن وقت با جوهر می‌نویسند.
+گفت: -خب؟
+شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتش‌فشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده.
+جغرافی‌دان هم گفت: -آدم چه می‌داند چه پیش می‌آید.
+-یک گل هم دارم.
+-نه، نه، ما دیگر گل ها را یادداشت نمی‌کنیم.
+-چرا؟ گل که زیباتر است.
+-برای این که گل‌ها فانی‌اند.
+-فانی یعنی چی؟
+جغرافی‌دان گفت: -کتاب‌های جغرافیا از کتاب‌های دیگر گران‌بهاترست و هیچ وقت هم از اعتبار نمی‌افتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را می‌نویسیم.
+شهریار کوچولو تو حرف او دوید و گفت: -اما آتش‌فشان‌های خاموش می‌توانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟
+جغرافی‌دان گفت: -آتش‌فشان چه روشن باشد چه خاموش برای ما فرقی نمی‌کند. آن‌چه به حساب می‌آید خود کوه است که تغییر پیدا نمی‌کند.
+شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی می‌پرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟
+-یعنی چیزی که در آینده تهدید به نابودی شود.
+-گل من هم در آینده نابود می‌شود؟
+-البته که می‌شود.
+شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کرده‌ام!»
+این اولین باری بود که دچار پریشانی و اندوه می‌شد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه می‌کنید؟
+جغرافی‌دان به‌اش جواب داد: -سیاره‌ی زمین. شهرت خوبی دارد...
+
+و شهریار کوچولو هم چنان که به گلش فکر می‌کرد به راه افتاد.
+
+۱۶
+لاجرم، زمین، سیاره‌ی هفتم شد.
+
+زمین، فلان و بهمان سیاره نیست. رو پهنه‌ی زمین یک‌صد و یازده پادشاه (البته بامحاسبه‌ی پادشاهان سیاه‌پوست)، هفت هزار جغرافی‌دان، نه‌صد هزار تاجرپیشه، پانزده کرور می‌خواره و شش‌صد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی می‌کند. برای آن‌که از حجم زمین مقیاسی به دست‌تان بدهم بگذارید به‌تان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قاره‌ی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوس‌بان را تامین کنند.
+
+روشن شدن فانوس‌ها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک باله‌ی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوس‌بان‌های زلاندنو و استرالیا بود. این‌ها که فانوس‌هاشان را روشن می‌کردند، می‌رفتند می‌گرفتند می‌خوابیدند آن وقت نوبت فانوس‌بان‌های چین و سیبری می‌رسید که به رقص درآیند. بعد، این‌ها با تردستی تمام به پشت صحنه می‌خزیدند و جا را برای فانوس‌بان‌های ترکیه و هفت پَرکَنِه‌ی هند خالی می کردند. بعد نوبت به فانوس‌بان‌های آمریکای‌جنوبی می‌شد. و آخر سر هم نوبت فانوس‌بان‌های افریقا و اروپا می‌رسد و بعد نوبت فانوس‌بان‌های آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچ‌کدام این‌ها در ترتیب ورودشان به صحنه دچار اشتباه نمی‌شدند. چه شکوهی داشت! میان این جمع عظیم فقط نگه‌بانِ تنها فانوسِ قطب شمال و همکارش نگه‌بانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بی‌هودگی می‌گذراندند: آخر آن‌ها سالی به سالی همه‌اش دو بار کار می‌کردند.
+
+۱۷
+آدمی که اهل اظهار لحیه باشد بفهمی نفهمی می‌افتد به چاخان کردن. من هم تو تعریف قضیه‌ی فانوس‌بان‌ها برای شما آن‌قدرهاروراست نبودم. می‌ترسم به آن‌هایی که زمین ما را نمی‌سناسند تصور نادرستی داده باشم. انسان‌ها رو پهنه‌ی زمین جای خیلی کمی را اشغال می‌کنند. اگر همه‌ی دو میلیارد نفری که رو کره‌ی زمین زندگی می‌کنند بلند بشوند و مثل موقعی که به تظاهرات می‌روند یک خورده جمع و جور بایستند راحت و بی‌درپسر تو میدانی به مساحت بیست میل در بیست میل جا می‌گیرند. همه‌ی جامعه‌ی بشری را می‌شود یک‌جا روی کوچک‌ترین جزیره‌ی اقیانوس آرام کُپه کرد.
+
+البته گفت‌وگو ندارد که آدم بزرگ‌ها حرف‌تان را باور نمی‌کنند. آخر تصور آن‌ها این است که کلی جا اشغال کرده‌اند، نه این‌که مثل بائوباب‌ها خودشان را خیلی مهم می‌بینند؟ بنابراین به‌شان پیش‌نهاد می‌کنید که بنشینند حساب کنند. آن‌ها هم که عاشق اعداد و ارقامند، پس این پیش‌نهاد حسابی کیفورشان می‌کند. اما شما را به خدا بی‌خودی وقت خودتان را سر این جریمه‌ی مدرسه به هدر ندهید. این کار دو قاز هم نمی‌ارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمی‌شد سخت هاج و واج ماند.
+
+شهریار کوچولو وسطِ کویر
+تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر می‌داشت که چنبره‌ی مهتابی رنگی رو ماسه‌ها جابه‌جا شد.شهریار کوچولو و مار
+شهریار کوچولو همین‌جوری سلام کرد.
+مار گفت: -سلام.
+شهریار کوچولو پرسید: -رو چه سیاره‌ای پایین آمده‌ام؟
+مار جواب داد: -رو زمین تو قاره‌ی آفریقا.
+-عجب! پس رو زمین انسان به هم نمی‌رسد؟
+مار گفت: -این‌جا کویر است. تو کویر کسی زندگی نمی‌کند. زمین بسیار وسیع است.
+شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم می‌گویم ستاره‌ها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چه‌قدر دور است!
+مار گفت: -قشنگ است. این‌جا آمده‌ای چه کار؟
+شهریار کوچولو گفت: -با یک گل بگومگویم شده.
+مار گفت: -عجب!
+و هر دوشان خاموش ماندند.
+دست آخر شهریار کوچولو درآمد که: -آدم‌ها کجاند؟ آدم تو کویر یک خرده احساس تنهایی می‌کند.
+مار گفت: -پیش آدم‌ها هم احساس تنهایی می‌کنی.
+شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر به‌اش گفت: -تو چه جانور بامزه‌ای هستی! مثل یک انگشت، باریکی.
+مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم.
+شهریار کوچولو لب‌خندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمی‌تونی بری...
+-من می‌تونم تو را به چنان جای دوری ببرم که با هیچ کشتی‌یی هم نتونی بری.
+مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر می‌گردانم اما تو پاکی و از یک سیّاره‌ی دیگر آمده‌ای...
+شهریار کوچولو جوابی بش نداد.
+-تو رو این زمین خارایی آن‌قدر ضعیفی که به حالت رحمم می‌آید. روزی‌روزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من می‌توانم...
+شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همه‌ی حرف‌هایت را به صورت معما درمی‌آری؟
+
+مار گفت: -حلّال همه‌ی معماهام من.
+و هر دوشان خاموش شدند.
+
+۱۸
+شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گل‌برگه. یک گلِ ناچیز.
+
+یک گُل وسطِ کویر
+
+شهریار کوچولو گفت: -سلام.
+گل گفت: -سلام.
+شهریار کوچولو با ادب پرسید: -آدم‌ها کجاند؟
+گل روزی روزگاری عبور کاروانی را دیده‌بود. این بود که گفت: -آدم‌ها؟ گمان کنم ازشان شش هفت تایی باشد. سال‌ها پیش دیدم‌شان. منتها خدا می‌داند کجا می‌شود پیداشان کرد. باد این‌ور و آن‌ور می‌بَرَدشان؛ نه این که ریشه ندارند؟ بی‌ریشگی هم حسابی اسباب دردسرشان شده.
+شهریار کوچولو گفت: -خداحافظ.
+گل گفت: -خداحافظ.
+
+۱۹
+از کوه بلندی بالا رفت.
+
+شهریار کوچولو بر قله‌ی کوهِ بلند
+تنها کوه‌هایی که به عمرش دیده بود سه تا آتش‌فشان‌های اخترک خودش بود که تا سر زانویش می‌رسید و از آن یکی که خاموش بود جای چارپایه استفاده می‌کرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی می‌توانم به یک نظر همه‌ی سیاره و همه‌ی آدم‌ها را ببینم...» اما جز نوکِ تیزِ صخره‌های نوک‌تیز چیزی ندید.
+همین جوری گفت: -سلام.
+طنین به‌اش جواب داد: -سلام... سلام... سلام...
+شهریار کوچولو گفت: -کی هستید شما؟
+طنین به‌اش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما...
+گفت: -با من دوست بشوید. من تک و تنهام.
+طنین به‌اش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام...
+آن‌وقت با خودش فکر کرد: «چه سیاره‌ی عجیبی! خشک‌ِخشک و تیزِتیز و شورِشور. این آدم‌هاش که یک ذره قوه‌ی تخیل ندارند و هر چه را بشنوند عینا تکرار می‌کنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف می‌زد...»
+
+۲۰
+اما سرانجام، بعد از مدت‌ها راه رفتن از میان ریگ‌ها و صخره‌ها و برف‌ها به جاده‌ای برخورد. و هر جاده‌ای یک‌راست می‌رود سراغ آدم‌ها.
+گفت: -سلام.
+و مخاطبش گلستان پرگلی بود.
+
+شهریار کوچولو در گلستانِ پرگل
+
+گل‌ها گفتند: -سلام.
+شهریار کوچولو رفت تو بحرشان. همه‌شان عین گل خودش بودند. حیرت‌زده ازشان پرسید: -شماها کی هستید؟
+گفتند: -ما گل سرخیم.
+
+آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنج‌هزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را می‌دید بدجور از رو می‌رفت. پشت سر هم بنا می‌کرد سرفه‌کردن و، برای این‌که از هُوشدن نجات پیدا کند خودش را به مردن می‌زد و من هم مجبور می‌شدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی می‌مرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولت‌مندِ عالم خیال می‌کردم در صورتی‌که آن‌چه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتش‌فشان که تا سرِ زانومَند و شاید هم یکی‌شان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمی‌آیم.»
+
+شهریار کوچولو در حالِ احساسِ شوربختی
+رو سبزه‌ها دراز شد و حالا گریه نکن کی گریه‌کن.
+
+۲۱
+آن وقت بود که سر و کله‌ی روباه پیدا شد.
+
+شهریار کوچولو و روباه
+
+روباه گفت: -سلام.
+شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام.
+صداگفت: -من این‌جام، زیر درخت سیب...
+شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی!
+روباه گفت: -یک روباهم من.
+شهریار کوچولو گفت: -بیا با من بازی کن. نمی‌دانی چه قدر دلم گرفته...
+روباه گفت: -نمی‌توانم بات بازی کنم. هنوز اهلیم نکرده‌اند آخر.
+شهریار کوچولو آهی کشید و گفت: -معذرت می‌خواهم.
+اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟
+روباه گفت: -تو اهل این‌جا نیستی. پی چی می‌گردی؟
+شهریار کوچولو گفت: -پی آدم‌ها می‌گردم. نگفتی اهلی کردن یعنی چه؟
+روباه گفت: -آدم‌ها تفنگ دارند و شکار می‌کنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش می‌دهند و خیرشان فقط همین است. تو پی مرغ می‌کردی؟
+شهریار کوچولو گفت: -نَه، پیِ دوست می‌گردم. اهلی کردن یعنی چی؟
+روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است.
+-ایجاد علاقه کردن؟
+روباه گفت: -معلوم است. تو الان واسه من یک پسر بچه‌ای مثل صد هزار پسر بچه‌ی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا می‌کنیم. تو واسه من میان همه‌ی عالم موجود یگانه‌ای می‌شوی من واسه تو.
+شهریار کوچولو گفت: -کم‌کم دارد دستگیرم می‌شود. یک گلی هست که گمانم مرا اهلی کرده باشد.
+روباه گفت: -بعید نیست. رو این کره‌ی زمین هزار جور چیز می‌شود دید.
+شهریار کوچولو گفت: -اوه نه! آن رو کره‌ی زمین نیست.
+روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیاره‌ی دیگر است؟
+-آره.
+شکارچی-تو آن سیاره شکارچی هم هست؟
+-نه.
+-محشر است! مرغ و ماکیان چه‌طور؟
+-نه.
+روباه آه‌کشان گفت: -همیشه‌ی خدا یک پای بساط لنگ است!
+اما پی حرفش را گرفت و گفت: -زندگی یک‌نواختی دارم. من مرغ‌ها را شکار می‌کنم آدم‌ها مرا. همه‌ی مرغ‌ها عین همند همه‌ی آدم‌ها هم عین همند. این وضع یک خرده خلقم را تنگ می‌کند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را می‌شناسم که باهر صدای پای دیگر فرق می‌کند: صدای پای دیگران مرا وادار می‌کند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمه‌ای مرا از سوراخم می‌کشد بیرون. تازه، نگاه کن آن‌جا آن گندم‌زار را می‌بینی؟ برای من که نان بخور نیستم گندم چیز بی‌فایده‌ای است. پس گندم‌زار هم مرا به یاد چیزی نمی‌اندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر می‌شود! گندم که طلایی رنگ است مرا به یاد تو می‌اندازد و صدای باد را هم که تو گندم‌زار می‌پیچد دوست خواهم داشت...
+خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت می‌خواهد منو اهلی کن!
+شهریار کوچولو جواب داد: -دلم که خیلی می‌خواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم.
+روباه گفت: -آدم فقط از چیزهایی که اهلی کند می‌تواند سر در آرد. انسان‌ها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکان‌ها می‌خرند. اما چون دکانی نیست که دوست معامله کند آدم‌ها مانده‌اند بی‌دوست... تو اگر دوست می‌خواهی خب منو اهلی کن!
+شهریار کوچولو پرسید: -راهش چیست؟
+روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من می‌گیری این جوری میان علف‌ها می‌نشینی. من زیر چشمی نگاهت می‌کنم و تو لام‌تاکام هیچی نمی‌گویی، چون تقصیر همه‌ی سؤِتفاهم‌ها زیر سر زبان است. عوضش می‌توانی هر روز یک خرده نزدیک‌تر بنشینی.
+
+روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد.
+روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب می‌شود و هر چه ساعت جلوتر برود بیش‌تر احساس شادی و خوشبختی می‌کنم. ساعت چهار که شد دلم بنا می‌کند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را می‌فهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعده‌ای دارد.
+شهریار کوچولو گفت: -قاعده یعنی چه؟
+روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث می‌شود فلان روز با باقی روزها و فلان ساعت با باقی ساعت‌ها فرق کند. مثلا شکارچی‌های ما میان خودشان رسمی دارند و آن این است که پنج‌شنبه‌ها را با دخترهای ده می‌روند رقص. پس پنج‌شنبه‌ها بَرّه‌کشانِ من است: برای خودم گردش‌کنان می‌روم تا دم مُوِستان. حالا اگر شکارچی‌ها وقت و بی وقت می‌رقصیدند همه‌ی روزها شبیه هم می‌شد و منِ بیچاره دیگر فرصت و فراغتی نداشتم.
+
+به این ترتیب شهریار کوچولو روباه را اهلی کرد.
+لحظه‌ی جدایی که نزدیک شد روباه گفت: -آخ! نمی‌توانم جلو اشکم را بگیرم.
+شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمی‌خواستم، خودت خواستی اهلیت کنم.
+روباه گفت: -همین طور است.
+شهریار کوچولو گفت: -آخر اشکت دارد سرازیر می‌شود!
+روباه گفت: -همین طور است.
+-پس این ماجرا فایده‌ای به حال تو نداشته.
+روباه گفت: -چرا، واسه خاطرِ رنگ گندم.
+بعد گفت: -برو یک بار دیگر گل‌ها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع می‌کنیم و من به عنوان هدیه رازی را به‌ات می‌گویم.
+شهریار کوچولو بار دیگر به تماشای گل‌ها رفت و به آن‌ها گفت: -شما سرِ سوزنی به گل من نمی‌مانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همه‌ی عالم تک است.
+گل‌ها حسابی از رو رفتند.
+شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برای‌تان نمی‌شود مُرد. گفت‌وگو ندارد که گلِ مرا هم فلان ره‌گذر می‌بیند مثل شما. اما او به تنهایی از همه‌ی شما سر است چون فقط اوست که آبش داده‌ام، چون فقط اوست که زیر حبابش گذاشته‌ام، چون فقط اوست که با تجیر برایش حفاظ درست کرده‌ام، چون فقط اوست که حشراتش را کشته‌ام (جز دو سه‌تایی که می‌بایست شب‌پره بشوند)، چون فقط اوست که پای گِلِه‌گزاری‌ها یا خودنمایی‌ها و حتا گاهی پای بُغ کردن و هیچی نگفتن‌هاش نشسته‌ام، چون او گلِ من است.
+و برگشت پیش روباه.
+گفت: -خدانگه‌دار!
+روباه گفت: -خدانگه‌دار!... و اما رازی که گفتم خیلی ساده است:
+جز با دل هیچی را چنان که باید نمی‌شود دید. نهاد و گوهر را چشمِ سَر نمی‌بیند.
+شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمی‌بیند.
+-ارزش گل تو به قدرِ عمری است که به پاش صرف کرده‌ای.
+شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کرده‌ام.
+روباه گفت: -انسان‌ها این حقیقت را فراموش کرده‌اند اما تو نباید فراموشش کنی. تو تا زنده‌ای نسبت به چیزی که اهلی کرده‌ای مسئولی. تو مسئول گُلِتی...
+
+شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم.
+
+۲۲
+شهریار کوچولو گفت: -سلام.
+سوزن‌بان گفت: -سلام.
+شهریار کوچولو گفت: -تو چه کار می‌کنی این‌جا؟
+سوزن‌بان گفت: -مسافرها را به دسته‌های هزارتایی تقسیم می‌کنم و قطارهایی را که می‌بَرَدشان گاهی به سمت راست می‌فرستم گاهی به سمت چپ. و همان دم سریع‌السیری با چراغ‌های روشن و غرّشی رعدوار اتاقک سوزن‌بانی را به لرزه انداخت.
+-عجب عجله‌ای دارند! پیِ چی می‌روند؟
+سوزن‌بان گفت: -از خودِ آتش‌کارِ لکوموتیف هم بپرسی نمی‌داند!
+سریع‌السیر دیگری با چراغ‌های روشن غرّید و در جهت مخالف گذشت .
+شهریار کوچولو پرسید: -برگشتند که؟
+سوزن‌بان گفت: -این‌ها اولی‌ها نیستند. آن‌ها رفتند این‌ها برمی‌گردند.
+-جایی را که بودند خوش نداشتند؟
+سوزن‌بان گفت: -آدمی‌زاد هیچ وقت جایی را که هست خوش ندارد.
+و رعدِ سریع‌السیرِ نورانیِ ثالثی غرّید.
+شهریار کوچولو پرسید: -این‌ها دارند مسافرهای اولی را دنبال می‌کنند؟
+سوزن‌بان گفت: -این‌ها هیچ چیزی را دنبال نمی‌کنند. آن تو یا خواب‌شان می‌بَرَد یا دهن‌دره می‌کنند. فقط بچه‌هاند که دماغ‌شان را فشار می‌دهند به شیشه‌ها.
+شهریار کوچولو گفت: -فقط بچه‌هاند که می‌دانند پیِ چی می‌گردند. بچه‌هاند که کُلّی وقت صرف یک عروسک پارچه‌ای می‌کنند و عروسک برای‌شان آن قدر اهمیت به هم می‌رساند که اگر یکی آن را ازشان کِش برود می‌زنند زیر گریه...
+سوزن‌بان گفت: -بخت، یارِ بچه‌هاست.
+
+۲۳
+شهریار کوچولو گفت: -سلام!
+پیله‌ور گفت: -سلام.
+این بابا فروشنده‌ی حَب‌های ضد تشنگی بود. خریدار هفته‌ای یک حب می‌انداخت بالا و دیگر تشنگی بی تشنگی.
+شهریار کوچولو پرسید: -این‌ها را می‌فروشی که چی؟
+پیله‌ور گفت: -باعث صرفه‌جویی کُلّی وقت است. کارشناس‌های خبره نشسته‌اند دقیقا حساب کرده‌اند که با خوردن این حب‌ها هفته‌ای پنجاه و سه دقیقه وقت صرفه‌جویی می‌شود.
+-خب، آن وقت آن پنجاه و سه دقیقه را چه کار می‌کنند؟
+ـ هر چی دل‌شان خواست...
+
+چشمه
+شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوش‌خوشک به طرفِ یک چشمه می‌روم...»
+
+۲۴
+هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چک‌ّه‌ی ذخیره‌ی آبم به قضیه‌ی پیله‌وره گوش داده بودم. به شهریار کوچولو گفتم:
+-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامده‌ام، یک چکه آب هم ندارم. و راستی که من هم اگر می‌توانستم خوش‌خوشک به طرف چشمه‌ای بروم سعادتی احساس می‌کردم که نگو!
+درآمد که: -دوستم روباه...
+گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر!
+-واسه چی؟
+-واسه این که تشنگی کارمان را می سازد. واسه این!
+از استدلال من چیزی حالیش نشد و در جوابم گفت:
+-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم...
+به خودم گفتم نمی‌تواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنه‌اش می‌شود نه گشنه‌اش. یه ذره آفتاب بسش است...
+اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنه‌م است... بگردیم یک چاه پیدا کنیم...
+از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است.
+و با وجود این به راه افتادیم.
+
+پس از ساعت‌ها که در سکوت راه رفتیم شب شد و ستاره‌ها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آن‌ها را خواب می‌دیدم. حرف‌های شهریار کوچولو تو ذهنم می‌رقصید.
+ازش پرسیدم: -پس تو هم تشنه‌ات هست، ها؟
+اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد...
+از حرفش چیزی دستگیرم نشد اما ساکت ماندم. می‌دانستم از او نباید حرف کشید.
+خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت:
+-قشنگیِ ستاره‌ها واسه خاطرِ گلی است که ما نمی‌بینیمش...
+گفتم: -همین طور است
+و بدون حرف در مهتاب غرق تماشای چین و شکن‌های شن شدم.
+باز گفت: -کویر زیباست.
+
+و حق با او بود. من همیشه عاشق کویر بوده‌ام. آدم بالای توده‌ای شن لغزان می‌نشیند، هیچی نمی‌بیند و هیچی نمی‌شنود اما با وجود این چیزی توی سکوت برق‌برق می‌زند.
+شهریار کوچولو گفت: -چیزی که کویر را زیبا می‌کند این است که یک جایی یک چاه قایم کرده...
+از این‌که ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرت‌زده شدم. بچگی‌هام تو خانه‌ی کهنه‌سازی می‌نشستیم که معروف بود تو آن گنجی چال کرده‌اند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همه‌ی اهل خانه را تردماغ می‌کرد: «خانه‌ی ما تهِ دلش رازی پنهان کرده بود...»
+گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیبایی‌اش می‌شود نامریی است!
+گفت: -خوشحالم که با روباه من توافق داری.
+
+چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم می‌لرزید.انگار چیز شکستنیِ بسیار گران‌بهایی را روی دست می‌بردم. حتا به نظرم می‌آمد که تو تمام عالم چیزی شکستنی‌تر از آن هم به نظر نمی‌رسد. تو روشنی مهتاب به آن پیشانی رنگ‌پریده و آن چشم‌های بسته و آن طُرّه‌های مو که باد می‌جنباند نگاه کردم و تو دلم گفتم: «آن چه می‌بینم صورت ظاهری بیش‌تر نیست. مهم‌ترش را با چشم نمی‌شود دید...»
+باز، چون دهان نیمه‌بازش طرح کم‌رنگِ نیمه‌لبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر می‌کند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعله‌ی چراغی حتا در خوابِ ناز هم که هست تو وجودش می‌درخشد...» و آن وقت او را باز هم شکننده‌تر دیدم. حس کردم باید خیلی مواظبش باشم: به شعله‌ی چراغی می‌مانست که یک وزش باد هم می‌توانست خاموشش کند.
+و همان طور در حال راه رفتن بود که دمدمه‌ی سحر چاه را پیداکردم.
+
+۲۵
+شهریار کوچولو درآمد که: -آدم‌ها!... می‌چپند تو قطارهای تندرو اما نمی‌دانند دنبال چی می‌گردند. این است که بنامی‌کنند دور خودشان چرخک‌زدن.
+و بعد گفت: -این هم کار نشد...
+چاهی که به‌اش رسیده‌بودیم اصلا به چاه‌های کویری نمی‌مانست. چاه کویری یک چاله‌ی ساده است وسط شن‌ها. این یکی به چاه‌های واحه‌ای می‌مانست اما آن دوروبر واحه‌ای نبود و من فکر کردم دارم خواب می‌بینم.
+گفتم: -عجیب است! قرقره و سطل و تناب، همه‌چیز روبه‌راه است.
+خندید تناب را گرفت و قرقره را به کار انداخت
+
+شهریار کوچولو در حالِ کشیدنِ آب از چاه
+و قرقره مثل بادنمای کهنه‌ای که تا مدت‌ها پس از خوابیدنِ باد می‌نالد به ناله‌درآمد.
+گفت: -می‌شنوی؟ ما داریم این چاه را از خواب بیدار می‌کنیم و او دارد برای‌مان آواز می‌خواند...
+دلم نمی‌خواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است.
+سطل را آرام تا طوقه‌ی چاه آوردم بالا و آن‌جا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همان‌طور تو گوشم داشتم و تو آب که هنوز می‌لرزید لرزش خورشید را می‌دیدم.
+گفت: -بده من، که تشنه‌ی این آبم.
+ومن تازه توانستم بفهمم پی چه چیز می‌گشته!
+
+سطل را تا لب‌هایش بالا بردم. با چشم‌های بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییده‌ی راه رفتنِ زیر ستاره‌ها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمه‌شب عید کریسمس و لطف لب‌خنده‌ها عیدیی را که بم می‌دادند درست به همین شکل آن همه جلا و جلوه می‌بخشید.
+گفت: -مردم سیاره‌ی تو ور می‌دارند پنج هزار تا گل را تو یک گلستان می‌کارند، و آن یک دانه‌ای را که پِیَش می‌گردند آن وسط پیدا نمی‌کنند...
+گفتم: -پیدایش نمی‌کنند.
+-با وجود این، چیزی که پیَش می‌گردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود...
+جواب دادم: -گفت‌وگو ندارد.
+باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پی‌اش گشت.
+من هم سیراب شده بودم. راحت نفس می‌کشیدم. وقتی آفتاب درمی‌آید شن به رنگ عسل است. من هم از این رنگ عسلی لذت می‌بردم. چرا می‌بایست در زحمت باشم...
+شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها!
+-کدام قول؟
+-یادت است؟ یک پوزه‌بند برای بَرّه‌ام... آخر من مسئول گلمَم!
+طرح‌های اولیه‌ام را از جیب درآوردم. نگاه‌شان کرد و خندان‌خندان گفت: -بائوباب‌هات یک خرده شبیه کلم شده.
+ای وای! مرا بگو که آن‌قدر به بائوباب‌هام می‌نازیدم.
+-روباهت... گوش‌هاش بیش‌تر به شاخ می‌ماند... زیادی درازند!
+و باز زد زیر خنده.
+-آقا کوچولو داری بی‌انصافی می‌کنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که.
+گفت: -خب، مهم نیست. عوضش بچه‌ها سرشان تو حساب است.
+با مداد یک پوزه‌بند کشیدم دادم دستش و با دلِ فشرده گفتم:
+-تو خیالاتی به سر داری که من ازشان بی‌خبرم...
+اما جواب مرا نداد. بم گفت: -می‌دانی؟ فردا سالِ به زمین آمدنِ من است.
+بعد پس از لحظه‌ای سکوت دوباره گفت: -همین نزدیکی‌ها پایین آمدم.
+و سرخ شد.
+
+و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمی‌گشتی به همان جایی که پایین‌آمدی...
+دوباره سرخ شد
+و من با دودلی به دنبال حرفم گفتم:
+-شاید به مناسبت همین سال‌گرد؟...
+باز سرخ شد. او هیچ وقت به سوآل‌هایی که ازش می‌شد جواب نمی‌داد اما وقتی کسی سرخ می‌شود معنیش این است که «بله»، مگر نه؟
+به‌اش گفتم: -آخر، من ترسم برداشته...
+اما او حرفم را برید:
+-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همین‌جا منتظرت می‌مانم. فردا عصر برگرد...
+
+منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمی‌نفهمی خودش را به این خطر انداخته که کارش به گریه‌کردن بکشد.
+
+۲۶
+کنار چاه دیوارِ سنگی مخروبه‌ای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده،
+
+شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن
+و شنیدم که می‌گوید:
+-پس یادت نمی‌آید؟ درست این نقطه نبود ها!
+لابد صدای دیگری به‌اش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت:
+-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست...
+راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که:
+-... آره، معلوم است. خودت می‌توانی ببینی رَدِّ پاهایم روی شن از کجا شروع می‌شود.
+همان جا منتظرم باش، تاریک که شد می‌آیم.
+بیست متری دیوار بودم و هنوز چیزی نمی‌دیدم. پس از مختصر مکثی دوباره گفت:
+-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمی‌دهد؟
+با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم.
+گفت: -خب، حالا دیگر برو. دِ برو. می‌خواهم بیایم پایین!
+
+آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را می‌کنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم می‌بردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فواره‌ای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجله‌ای از خودش نشان دهد باصدای خفیف فلزی لای سنگ‌ها خزید.
+من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم.
+-این دیگر چه حکایتی است! حالا دیگر با مارها حرف می‌زنی؟
+شال زردش را که مدام به گردن داشت باز کردم به شقیقه‌هایش آب زدم و جرعه‌ای به‌اش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرنده‌ای می‌زند که تیر خورده‌است و دارد می‌میرد.
+گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوش‌حالم. حالا می‌توانی برگردی خانه‌ات...
+-تو از کجا فهمیدی؟
+درست همان دم لب‌واکرده‌بودم بش خبر بدهم که علی‌رغم همه‌ی نومیدی‌ها تو کارم موفق شده‌ام!
+به سوآل‌های من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر می‌گردم خانه‌ام...
+و بعد غم‌زده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سخت‌تر است...
+
+حس می‌کردم اتفاق فوق‌العاده‌ای دارد می‌افتد. گرفتمش تو بغلم. عین یک بچه‌ی کوچولو. با وجود این به نظرم می‌آمد که او دارد به گردابی فرو می‌رود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردست‌های دور راه کشیده بود.
+گفت: بَرِّه‌ات را دارم. جعبه‌هه را هم واسه بره‌هه دارم. پوزه‌بنده را هم دارم.
+و با دلِ گرفته لبخندی زد.
+مدت درازی صبر کردم. حس کردم کم‌کمَک تنش دوباره دارد گرم می‌شود.
+-عزیز کوچولوی من، وحشت کردی...
+-امشب وحشت خیلی بیش‌تری چشم به‌راهم است.
+
+دوباره از احساسِ واقعه‌ای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غش‌غش خنده‌ی او را نخواهم شنید برایم سخت تحمل‌ناپذیر بود. خنده‌ی او برای من به چشمه‌ای در دلِ کویر می‌مانست.
+-کوچولوئَکِ من، دلم می‌خواهد باز هم غش‌غشِ خنده‌ات را بشنوم.
+اما به‌ام گفت: -امشب درست می‌شود یک سال و اخترَکَم درست بالای همان نقطه‌ای می‌رسد که پارسال به زمین آمدم.
+-کوچولوئک، این قضیه‌ی مار و میعاد و ستاره یک خواب آشفته بیش‌تر نیست. مگر نه؟
+به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمی‌شود.
+-مسلم است.
+-در مورد گل هم همین‌طور است: اگر گلی را دوست داشته باشی که تو یک ستاره‌ی دیگر است، شب تماشای آسمان چه لطفی پیدا می‌کند: همه‌ی ستاره‌ها غرق گل می‌شوند!
+-مسلم است...
+-در مورد آب هم همین‌طور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی می‌مانست... یادت که هست... چه خوب بود.
+-مسلم است...
+-شب‌به‌شب ستاره‌ها را نگاه می‌کنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو می‌شود یکی از ستاره‌ها؛ و آن وقت تو دوست داری همه‌ی ستاره‌ها را تماشا کنی... همه‌شان می‌شوند دوست‌های تو... راستی می‌خواهم هدیه‌ای بت بدهم...
+و غش غش خندید.
+-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خنده‌ام!
+-هدیه‌ی من هم درست همین است... درست مثل مورد آب.
+-چی می‌خواهی بگویی؟
+-همه‌ی مردم ستاره دارند اما همه‌ی ستاره‌ها یک‌جور نیست: واسه آن‌هایی که به سفر می‌روند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزن‌اند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستاره‌ها همه‌شان زبان به کام کشیده و خاموشند. فقط تو یکی ستاره‌هایی خواهی داشت که تنابنده‌ای مِثلش را ندارد.
+-چی می‌خواهی بگویی؟
+-نه این که من تو یکی از ستاره‌هام؟ نه این که من تو یکی از آن‌ها می‌خندم؟... خب، پس هر شب که به آسمان نگاه می‌کنی برایت مثل این خواهد بود که همه‌ی ستاره‌ها می‌خندند. پس تو ستاره‌هایی خواهی داشت که بلدند بخندند!
+و باز خندید.
+-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمی‌زاد یک جوری تسلا پیدا می‌کند دیگر) از آشنایی با من خوش‌حال می‌شوی. دوست همیشگی من باقی می‌مانی و دلت می‌خواهد با من بخندی و پاره‌ای وقت‌هام واسه تفریح پنجره‌ی اتاقت را وا می‌کنی... دوستانت از این‌که می‌بینند تو به آسمان نگاه می‌کنی و می‌خندی حسابی تعجب می‌کنند آن وقت تو به‌شان می‌گویی: «آره، ستاره‌ها همیشه مرا خنده می‌اندازند!» و آن‌وقت آن‌ها یقین‌شان می‌شود که تو پاک عقلت را از دست داده‌ای. جان! می‌بینی چه کَلَکی به‌ات زده‌ام...
+و باز زد زیر خنده.
+-به آن می‌ماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند...
+دوباره خندید و بعد حالتی جدی به خودش گرفت:
+-نه، من تنهات نمی‌گذارم.
+
+شهریار کوچولو تنها
+
+-ظاهر آدمی را پیدا می‌کنم که دارد درد می‌کشد... یک خرده هم مثل آدمی می‌شوم که دارد جان می‌کند. رو هم رفته این جوری‌ها است. نیا که این را نبینی. چه زحمتی است بی‌خود؟
+-تنهات نمی‌گذارم.
+اندوه‌زده بود.
+-این را بیش‌تر از بابت ماره می‌گویم که، نکند یک‌هو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند.
+-تنهات نمی‌گذارم.
+منتها یک چیز باعث خاطر جمعیش شد:
+-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند.
+شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت.
+وقتی خودم را به‌اش رساندم با قیافه‌ی مصمم و قدم‌های محکم پیش می‌رفت. همین قدر گفت: -اِ! این‌جایی؟
+و دستم را گرفت.
+اما باز بی‌قرار شد وگفت: -اشتباه کردی آمدی. رنج می‌بری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا می‌کنم.
+من ساکت ماندم.
+-خودت درک می‌کنی. راه خیلی دور است. نمی‌توانم این جسم را با خودم ببرم. خیلی سنگین است.
+من ساکت ماندم.
+-گیرم عینِ پوستِ کهنه‌ای می‌شود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟
+من ساکت ماندم.
+کمی دل‌سرد شد اما باز هم سعی کرد:
+-خیلی با مزه می‌شود، نه؟ من هم به ستاره‌ها نگاه می‌کنم. هم‌شان به صورت چاه‌هایی در می‌آیند با قرقره‌های زنگ زده. همه‌ی ستاره‌ها بم آب می‌دهند بخورم...
+من ساکت ماندم.
+-خیلی با مزه می‌شود. نه؟ تو صاحب هزار کرور زنگوله می‌شوی من صاحب هزار کرور فواره...
+او هم ساکت شد، چرا که داشت گریه می‌کرد...
+-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم.
+و گرفت نشست، چرا که می‌ترسید.
+
+شهریار کوچولو نشسته
+
+می‌دانی؟... گلم را می‌گویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بی‌شیله‌پیله. برای آن که جلو همه‌ی عالم از خودش دفاع کند همه‌اش چی دارد مگر؟ چهارتا خار پِرپِرَک!
+
+من هم گرفتم نشستم. دیگر نمی‌توانستم سر پا بند بشوم.
+گفت: -همین... همه‌اش همین و بس...
+باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم.
+
+کنار قوزکِ پایش جرقه‌ی زردی جست و... فقط همین! یک دم بی‌حرکت ماند. فریادی نزد. مثل درختی که بیفتد آرام‌آرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد.
+
+شهریار کوچولو در حالی که آرام‌آرام به زمین می‌افتد
+۲۷
+شش سال گذشته است و من هنوز بابت این قضیه جایی لب‌ترنکرده‌ام. دوستانم از این که مرا دوباره زنده می‌دیدند سخت شاد شدند. من غم‌زده بودم اما به آن‌ها می‌گفتم اثر خستگی است.
+حالا کمی تسلای خاطر پیدا کرده‌ام. یعنی نه کاملا... اما این را خوب می‌دانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شب‌ها دوست دارم به ستاره‌ها گوش بدهم. عین هزار زنگوله‌اند.
+اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزه‌بندی که برای شهریار کوچولو کشیدم تسمه‌ی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزه‌ی بَرّه ببندد. این است که از خودم می‌پرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند بره‌هه گل را چریده باشد؟...»
+گاه به خودم می‌گویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشه‌ای می‌گذارد و هوای بره‌اش را هم دارد...» آن وقت است که خیالم راحت می‌شود و ستاره‌ها همه به شیرینی می‌خندند.
+گاه به خودم می‌گویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصف‌شبی بی‌سروصدا از جعبه زد بیرون...» آن وقت است که زنگوله‌ها همه تبدیل به اشک می‌شوند!...
+
+یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهم‌تر از دانستن این نیست که تو فلان نقطه‌ای که نمی‌دانیم، فلان بره‌ای که نمی‌شماسیم گل سرخی را چریده یا نچریده...
+
+خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشم‌های خودتان تفاوتش را ببینید...
+
+و محال است آدم بزرگ‌ها روح‌شان خبردار بشود که این موضوع چه قدر مهم است!
+
+بدونِ شهریار کوچولو
+در نظر من این زیباترین و حزن‌انگیزترین منظره‌ی عالم است. این همان منظره‌ی دو صفحه پیش است گیرم آن را دوباره کشیده‌ام که به‌تر نشان‌تان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد».
+
+آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان می‌خواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظه‌ای توقف کنید. آن وقت اگر بچه‌ای به طرف‌تان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس می‌زنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم:
+بی درنگ بردارید به من بنویسید که او برگشته.
+
diff --git a/src/HBIndicVowelConstraints.txt b/src/HBIndicVowelConstraints.txt
deleted file mode 100644
index 146ae1c..0000000
--- a/src/HBIndicVowelConstraints.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-# Copied from https://docs.microsoft.com/en-us/typography/script-development/use
-# On October 23, 2018; with documentd dated 02/07/2018.
-
-  0905 0946       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E
-  0905 093E       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA
-  0930 094D 0907  ; # DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I
-  0909 0941       ; # DEVANAGARI LETTER U, DEVANAGARI VOWEL SIGN U
-  090F 0945       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN CANDRA E
-  090F 0946       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E
-  090F 0947       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN E
-  0905 0949       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA O
-  0906 0945       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN CANDRA E
-  0905 094A       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT O
-  0906 0946       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN SHORT E
-  0905 094B       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN O
-  0906 0947       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN E
-  0905 094C       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AU
-  0906 0948       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN AI
-  0905 0945       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA E
-  0905 093A       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE
-  0905 093B       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OOE
-  0906 093A       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN OE
-  0905 094F       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW
-  0905 0956       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UE
-  0905 0957       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UUE
-  0985 09BE       ; # BENGALI LETTER A, BENGALI VOWEL SIGN AA
-  098B 09C3       ; # BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R
-  098C 09E2       ; # BENGALI LETTER VOCALIC L, BENGALI VOWEL SIGN VOCALIC L
-  0A05 0A3E       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA
-  0A72 0A3F       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN I
-  0A72 0A40       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN II
-  0A73 0A41       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN U
-  0A73 0A42       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN UU
-  0A72 0A47       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN EE
-  0A05 0A48       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AI
-  0A73 0A4B       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN OO
-  0A05 0A4C       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU
-  0A85 0ABE       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA
-  0A85 0AC5       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E
-  0A85 0AC7       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN E
-  0A85 0AC8       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AI
-  0A85 0AC9       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA O
-  0A85 0ACB       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN O
-  0A85 0ABE 0AC5  ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E
-  0A85 0ACC       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AU
-  0A85 0ABE 0AC8  ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI
-  0AC5 0ABE       ; # GUJARATI VOWEL SIGN CANDRA E, GUJARATI VOWEL SIGN AA
-  0B05 0B3E       ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA
-  0B0F 0B57       ; # ORIYA LETTER E, ORIYA AU LENGTH MARK
-  0B13 0B57       ; # ORIYA LETTER O, ORIYA AU LENGTH MARK
-  0C12 0C55       ; # TELUGU LETTER O, TELUGU LENGTH MARK
-  0C12 0C4C       ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU
-  0C3F 0C55       ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK
-  0C46 0C55       ; # TELUGU VOWEL SIGN E, TELUGU LENGTH MARK
-  0C4A 0C55       ; # TELUGU VOWEL SIGN O, TELUGU LENGTH MARK
-  0C89 0CBE       ; # KANNADA LETTER U, KANNADA VOWEL SIGN AA
-  0C92 0CCC       ; # KANNADA LETTER O, KANNADA VOWEL SIGN AU
-  0C8B 0CBE       ; # KANNADA LETTER VOCALIC R, KANNADA VOWEL SIGN AA
-  0D07 0D57       ; # MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK
-  0D09 0D57       ; # MALAYALAM LETTER U, MALAYALAM AU LENGTH MARK
-  0D0E 0D46       ; # MALAYALAM LETTER E, MALAYALAM VOWEL SIGN E
-  0D12 0D3E       ; # MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA
-  0D12 0D57       ; # MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK
-  0D85 0DCF       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN AELA-PILLA
-  0D85 0DD0       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN KETTI AEDA-PILLA
-  0D85 0DD1       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN DIGA AEDA-PILLA
-  0D8B 0DDF       ; # SINHALA LETTER UYANNA, SINHALA VOWEL SIGN GAYANUKITTA
-  0D8D 0DD8       ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA
-  0D8F 0DDF       ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA
-  0D91 0DCA       ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA
-  0D91 0DD9       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA
-  0D91 0DDA       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA
-  0D91 0DDC       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA
-  0D91 0DDD       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
-  0D91 0DDD       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
-  0D94 0DDF       ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA
-  11005 11038     ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA
-  1100B 1103E     ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R
-  1100F 11042     ; # BRAHMI LETTER E, BRAHMI VOWEL SIGN E
-  11680 116AD     ; # TAKRI LETTER A, TAKRI VOWEL SIGN AA
-  11686 116B2     ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
-  11680 116B4     ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
-  11680 116B5     ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
-  112B0 112E0     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
-  112B0 112E5     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
-  112B0 112E6     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
-  112B0 112E7     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN O
-  112B0 112E8     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AU
-  11481 114B0     ; # TIRHUTA LETTER A, TIRHUTA VOWEL SIGN AA
-  114AA 114B5     ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC R
-  114AA 114B6     ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC RR
-  1148B 114BA     ; # TIRHUTA LETTER E, TIRHUTA VOWEL SIGN SHORT E
-  1148D 114BA     ; # TIRHUTA LETTER O, TIRHUTA VOWEL SIGN SHORT E
-  11600 11639     ; # MODI LETTER A, MODI VOWEL SIGN E
-  11600 1163A     ; # MODI LETTER A, MODI VOWEL SIGN AI
-  11601 11639     ; # MODI LETTER AA, MODI VOWEL SIGN E
-  11601 1163A     ; # MODI LETTER AA, MODI VOWEL SIGN AI
diff --git a/src/Makefile.am b/src/Makefile.am
index a76d968..c0c7705 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,8 @@
 check_PROGRAMS =
 
 EXTRA_DIST += harfbuzz.cc
+EXTRA_DIST += meson.build
+EXTRA_DIST += fix_get_types.py
 
 # Convenience targets:
 lib: $(BUILT_SOURCES) libharfbuzz.la
@@ -50,12 +52,7 @@
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
-# XXX
-# The following creates a recursive dependency on FreeType if FreeType is
-# built with HarfBuzz support enabled.  Newer pkg-config handles that just
-# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes.  Remove
-# in a year or two, or otherwise work around it...
-#HBDEPS   += $(FREETYPE_DEPS)
+HBDEPS   += $(FREETYPE_DEPS)
 HBSOURCES += $(HB_FT_sources)
 HBHEADERS += $(HB_FT_headers)
 endif
@@ -153,6 +150,7 @@
 EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
 
 lib_LTLIBRARIES += libharfbuzz-subset.la
+libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
 libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
 libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
 libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS)
@@ -237,7 +235,8 @@
 endif
 check: $(DEF_FILES) # For check-symbols.sh
 CLEANFILES += $(DEF_FILES)
-harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
+harfbuzz.def: $(top_builddir)/config.status
+harfbuzz.def: $(HBHEADERS)
 	$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
 harfbuzz-subset.def: $(HB_SUBSET_headers)
 	$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
@@ -250,11 +249,15 @@
 
 
 GENERATORS = \
+	gen-arabic-joining-list.py \
 	gen-arabic-table.py \
 	gen-def.py \
 	gen-emoji-table.py \
+	gen-harfbuzzcc.py \
+	gen-hb-version.py \
 	gen-indic-table.py \
 	gen-os2-unicode-ranges.py \
+	gen-ragel-artifacts.py \
 	gen-tag-table.py \
 	gen-ucd-table.py \
 	gen-use-table.py \
@@ -262,42 +265,9 @@
 	$(NULL)
 EXTRA_DIST += $(GENERATORS)
 
-unicode-tables: \
-	arabic-table \
-	emoji-table \
-	indic-table \
-	tag-table \
-	ucd-table \
-	use-table \
-	emoji-table \
-	$(NULL)
-
-arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
-	|| ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false)
-emoji-table: gen-emoji-table.py emoji-data.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
-	|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
-indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
-	|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
-tag-table: gen-tag-table.py languagetags language-subtag-registry
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
-	|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
-ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \
-	|| ($(RM) $(srcdir)/hb-ucd-table.hh; false)
-use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
-	|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
-vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
-	|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
-
-
 built-sources: $(BUILT_SOURCES)
 
-.PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-table built-sources
+.PHONY: built-sources
 
 RAGEL_GENERATED = \
 	$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
@@ -334,6 +304,7 @@
 	test-buffer-serialize \
 	test-ot-meta \
 	test-ot-name \
+	test-ot-glyphname \
 	test-gpos-size-params \
 	test-gsub-would-substitute \
 	$(NULL)
@@ -359,6 +330,10 @@
 test_ot_name_CPPFLAGS = $(HBCFLAGS)
 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_gpos_size_params_SOURCES = test-gpos-size-params.cc
 test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
 test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
@@ -367,51 +342,20 @@
 test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
 test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
 
-if HAVE_FREETYPE
-if HAVE_CAIRO_FT
-noinst_PROGRAMS += test-ot-color
-test_ot_color_SOURCES = test-ot-color.cc
-test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
-test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
-endif # HAVE_CAIRO_FT
-endif # HAVE_FREETYPE
-
-dist_check_SCRIPTS = \
-	check-c-linkage-decls.sh \
-	check-externs.sh \
-	check-header-guards.sh \
-	check-includes.sh \
-	check-static-inits.sh \
-	check-symbols.sh \
+COMPILED_TESTS = \
+	test-algs \
+	test-array \
+	test-iter \
+	test-map \
+	test-number \
+	test-ot-tag \
+	test-priority-queue \
+	test-set \
+	test-unicode-ranges \
+	test-vector \
+	test-bimap \
+	test-repacker \
 	$(NULL)
-TESTS += $(dist_check_SCRIPTS)
-
-if !WITH_LIBSTDCXX
-dist_check_SCRIPTS += \
-	check-libstdc++.sh \
-	$(NULL)
-endif
-
-check_PROGRAMS += \
-	dump-indic-data \
-	dump-khmer-data \
-	dump-myanmar-data \
-	dump-use-data \
-	$(NULL)
-dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
-dump_indic_data_CPPFLAGS = $(HBCFLAGS)
-dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
-dump_khmer_data_SOURCES = dump-khmer-data.cc hb-ot-shape-complex-indic-table.cc
-dump_khmer_data_CPPFLAGS = $(HBCFLAGS)
-dump_khmer_data_LDADD = libharfbuzz.la $(HBLIBS)
-dump_myanmar_data_SOURCES = dump-myanmar-data.cc hb-ot-shape-complex-indic-table.cc
-dump_myanmar_data_CPPFLAGS = $(HBCFLAGS)
-dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS)
-dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
-dump_use_data_CPPFLAGS = $(HBCFLAGS)
-dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
-
-COMPILED_TESTS = test-algs test-iter test-meta test-number test-ot-tag test-unicode-ranges test-bimap
 COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
 COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
 check_PROGRAMS += $(COMPILED_TESTS)
@@ -421,13 +365,25 @@
 test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_algs_LDADD = $(COMPILED_TESTS_LDADD)
 
+test_array_SOURCES = test-array.cc
+test_array_CPPFLAGS = $(HBCFLAGS)
+test_array_LDADD = libharfbuzz.la $(HBLIBS)
+
+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_CPPFLAGS = $(HBCFLAGS)
+test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
+
 test_iter_SOURCES = test-iter.cc hb-static.cc
 test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_iter_LDADD = $(COMPILED_TESTS_LDADD)
 
-test_meta_SOURCES = test-meta.cc hb-static.cc
-test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
-test_meta_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_number_SOURCES = test-number.cc hb-number.cc
 test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
@@ -437,26 +393,64 @@
 test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
 
+test_set_SOURCES = test-set.cc hb-static.cc
+test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_set_LDADD = $(COMPILED_TESTS_LDADD)
+
 test_unicode_ranges_SOURCES = test-unicode-ranges.cc
 test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 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_bimap_SOURCES = test-bimap.cc hb-static.cc
 test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
 test_bimap_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)
+TESTS += $(dist_check_SCRIPTS)
+
+if !WITH_LIBSTDCXX
+dist_check_SCRIPTS += \
+	check-libstdc++.py \
+	$(NULL)
+endif
+
 TESTS_ENVIRONMENT = \
 	srcdir="$(srcdir)" \
+	builddir="$(builddir)" \
 	MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
 	HBSOURCES="$(HBSOURCES)" \
 	HBHEADERS="$(HBHEADERS)" \
+	LDD="$(LDD)" \
+	NM="$(NM)" \
+	OBJDUMP="$(OBJDUMP)" \
+	OTOOL="$(OTOOL)" \
 	$(NULL)
 
 if HAVE_INTROSPECTION
 
 -include $(INTROSPECTION_MAKEFILE)
 INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
-INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
+INTROSPECTION_SCANNER_ARGS = \
+	-I$(srcdir) \
+	--warn-all --verbose \
+	--namespace=HarfBuzz \
+	--nsversion=0.0 \
+	--symbol-prefix=hb \
+	--symbol-prefix=hb_gobject \
+	--identifier-prefix=hb_ \
+	--pkg-export=harfbuzz-gobject \
+	--c-include=hb-gobject.h
 INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 INTROSPECTION_SCANNER_ENV = CC="$(CC)"
 
@@ -465,14 +459,7 @@
 HarfBuzz_0_0_gir_CFLAGS = \
 	$(INCLUDES) \
 	$(HBCFLAGS) \
-	-DHB_H \
-	-DHB_H_IN \
-	-DHB_OT_H \
-	-DHB_OT_H_IN \
-	-DHB_AAT_H \
-	-DHB_AAT_H_IN \
-	-DHB_GOBJECT_H \
-	-DHB_GOBJECT_H_IN \
+	-DHB_NO_SINGLE_HEADER_ERROR \
 	-DHAVE_GOBJECT \
 	-DHB_EXTERN= \
 	$(NULL)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index cbbad90..699dfdc 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -1,14 +1,12 @@
 # Base and default-included sources and headers
 
 HB_BASE_sources = \
-	hb-aat-fdsc-table.hh \
 	hb-aat-layout-ankr-table.hh \
 	hb-aat-layout-bsln-table.hh \
 	hb-aat-layout-common.hh \
 	hb-aat-layout-feat-table.hh \
 	hb-aat-layout-just-table.hh \
 	hb-aat-layout-kerx-table.hh \
-	hb-aat-layout-lcar-table.hh \
 	hb-aat-layout-morx-table.hh \
 	hb-aat-layout-opbd-table.hh \
 	hb-aat-layout-trak-table.hh \
@@ -20,6 +18,10 @@
 	hb-algs.hh \
 	hb-array.hh \
 	hb-atomic.hh \
+	hb-bimap.hh \
+	hb-bit-page.hh \
+	hb-bit-set.hh \
+	hb-bit-set-invertible.hh \
 	hb-blob.cc \
 	hb-blob.hh \
 	hb-buffer-serialize.cc \
@@ -35,6 +37,8 @@
 	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 \
@@ -45,8 +49,9 @@
 	hb-machinery.hh \
 	hb-map.cc \
 	hb-map.hh \
-	hb-bimap.hh \
 	hb-meta.hh \
+	hb-ms-feature-ranges.cc \
+	hb-ms-feature-ranges.hh \
 	hb-mutex.hh \
 	hb-null.hh \
 	hb-number.cc \
@@ -55,6 +60,7 @@
 	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 \
@@ -66,9 +72,9 @@
 	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 \
 	hb-ot-face.hh \
-	hb-ot-face-table-list.hh \
 	hb-ot-font.cc \
 	hb-ot-gasp-table.hh \
 	hb-ot-glyf-table.hh \
@@ -104,6 +110,7 @@
 	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 \
@@ -118,10 +125,11 @@
 	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.cc \
+	hb-ot-shape-complex-use-table.hh \
 	hb-ot-shape-complex-use.cc \
-	hb-ot-shape-complex-use.hh \
 	hb-ot-shape-complex-vowel-constraints.cc \
 	hb-ot-shape-complex-vowel-constraints.hh \
 	hb-ot-shape-complex.hh \
@@ -135,6 +143,7 @@
 	hb-ot-tag-table.hh \
 	hb-ot-tag.cc \
 	hb-ot-var-avar-table.hh \
+	hb-ot-var-common.hh \
 	hb-ot-var-fvar-table.hh \
 	hb-ot-var-gvar-table.hh \
 	hb-ot-var-hvar-table.hh \
@@ -156,6 +165,7 @@
 	hb-shaper.hh \
 	hb-static.cc \
 	hb-string-array.hh \
+	hb-style.cc \
 	hb-ucd-table.hh \
 	hb-ucd.cc \
 	hb-unicode-emoji-table.hh \
@@ -163,6 +173,7 @@
 	hb-unicode.hh \
 	hb-utf.hh \
 	hb-vector.hh \
+	hb-priority-queue.hh \
 	hb.hh \
 	$(NULL)
 
@@ -192,6 +203,7 @@
 	hb-buffer.h \
 	hb-common.h \
 	hb-deprecated.h \
+	hb-draw.h \
 	hb-face.h \
 	hb-font.h \
 	hb-map.h \
@@ -209,6 +221,7 @@
 	hb-set.h \
 	hb-shape-plan.h \
 	hb-shape.h \
+	hb-style.h \
 	hb-unicode.h \
 	hb-version.h \
 	hb.h \
@@ -249,6 +262,8 @@
 	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 \
@@ -260,10 +275,9 @@
 	hb-subset-input.hh \
 	hb-subset-plan.cc \
 	hb-subset-plan.hh \
-	hb-subset-plan.hh \
 	hb-subset.cc \
 	hb-subset.hh \
-	hb-subset.hh \
+	hb-repacker.hh \
 	$(NULL)
 
 HB_SUBSET_headers = \
diff --git a/src/check-c-linkage-decls.py b/src/check-c-linkage-decls.py
new file mode 100755
index 0000000..b7532a7
--- /dev/null
+++ b/src/check-c-linkage-decls.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import sys, os
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+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'))]
+
+stat = 0
+
+for x in HBHEADERS:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if ('HB_BEGIN_DECLS' not in content) or ('HB_END_DECLS' not in content):
+		print ('Ouch, file %s does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should' % x)
+		stat = 1
+
+for x in HBSOURCES:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if ('HB_BEGIN_DECLS' in content) or ('HB_END_DECLS' in content):
+		print ('Ouch, file %s has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn\'t' % x)
+		stat = 1
+
+sys.exit (stat)
diff --git a/src/check-c-linkage-decls.sh b/src/check-c-linkage-decls.sh
deleted file mode 100755
index 8234abc..0000000
--- a/src/check-c-linkage-decls.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.cc'`
-
-for x in $HBHEADERS; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
-		echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
-		stat=1
-	fi
-done
-for x in $HBSOURCES; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
-		echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
-		stat=1
-	fi
-done
-
-exit $stat
diff --git a/src/check-externs.py b/src/check-externs.py
new file mode 100755
index 0000000..a64d2e5
--- /dev/null
+++ b/src/check-externs.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+import sys, os, re
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+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')]
+
+stat = 0
+
+print ('Checking that all public symbols are exported with HB_EXTERN')
+for x in HBHEADERS:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	for s in re.findall (r'\n.+\nhb_.+\n', content):
+		if not s.startswith ('\nHB_EXTERN '):
+			print ('failure on:', s)
+			stat = 1
+
+sys.exit (stat)
diff --git a/src/check-externs.sh b/src/check-externs.sh
deleted file mode 100755
index a6de375..0000000
--- a/src/check-externs.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
-test "x$EGREP" = x && EGREP='grep -E'
-
-
-echo 'Checking that all public symbols are exported with HB_EXTERN'
-
-for x in $HBHEADERS; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	$EGREP -B1 -n '^hb_' /dev/null "$x" |
-	$EGREP -v '(^--|:hb_|-HB_EXTERN )' -A1
-done |
-grep . >&2 && stat=1
-
-exit $stat
diff --git a/src/check-header-guards.py b/src/check-header-guards.py
new file mode 100755
index 0000000..0ad42cd
--- /dev/null
+++ b/src/check-header-guards.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+
+import sys, os, re
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+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'))]
+
+stat = 0
+
+for x in HBHEADERS + HBSOURCES:
+	if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
+	tag = x.upper ().replace ('.', '_').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)
+		stat = 1
+
+sys.exit (stat)
diff --git a/src/check-header-guards.sh b/src/check-header-guards.sh
deleted file mode 100755
index b67640f..0000000
--- a/src/check-header-guards.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h' ! -name 'hb-gobject-structs.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
-
-for x in $HBHEADERS $HBSOURCES; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	echo "$x" | grep -q '[^h]$' && continue;
-	xx=`echo "$x" | sed 's@.*/@@'`
-	tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
-	lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ 	]*//g'`
-	if test "x$lines" != x3; then
-		echo "Ouch, header file $x does not have correct preprocessor guards"
-		stat=1
-	fi
-done
-
-exit $stat
diff --git a/src/check-includes.py b/src/check-includes.py
new file mode 100755
index 0000000..88eaa2e
--- /dev/null
+++ b/src/check-includes.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+import sys, os, re
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+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'))]
+
+stat = 0
+
+print ('Checking that public header files #include "hb-common.h" or "hb.h" first (or none)')
+for x in HBHEADERS:
+	if x == 'hb.h' or x == 'hb-common.h': continue
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	first = re.findall (r'#.*include.*', content)[0]
+	if first not in ['#include "hb.h"', '#include "hb-common.h"']:
+		print ('failure on %s' % x)
+		stat = 1
+
+print ('Checking that source files #include a private header first (or none)')
+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])):
+			print ('failure on %s' % x)
+			stat = 1
+
+print ('Checking that there is no #include <hb-*.h>')
+for x in HBHEADERS + HBSOURCES:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if re.findall ('#.*include.*<.*hb', content):
+		print ('failure on %s' % x)
+		stat = 1
+
+sys.exit (stat)
diff --git a/src/check-includes.sh b/src/check-includes.sh
deleted file mode 100755
index f938f70..0000000
--- a/src/check-includes.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
-
-
-echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
-
-for x in $HBHEADERS; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	grep '#.*\<include\>' "$x" /dev/null | head -n 1
-done |
-grep -v '"hb-common[.]h"' |
-grep -v '"hb[.]h"' |
-grep -v 'hb-common[.]h:' |
-grep -v 'hb[.]h:' |
-grep . >&2 && stat=1
-
-
-echo 'Checking that source files #include a private header first (or none)'
-
-for x in $HBSOURCES; do
-	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
-	grep '#.*\<include\>' "$x" /dev/null | head -n 1
-done |
-grep -v '"hb-.*[.]hh"' |
-grep -v 'hb[.]hh' |
-grep . >&2 && stat=1
-
-
-echo 'Checking that there is no #include <hb-*.h>'
-for x in $HBHEADERS $HBSOURCES; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
-	grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1
-done
-
-
-exit $stat
diff --git a/src/check-libstdc++.py b/src/check-libstdc++.py
new file mode 100755
index 0000000..85b7265
--- /dev/null
+++ b/src/check-libstdc++.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+import sys, os, shutil, subprocess
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+libs = os.getenv ('libs', '.libs')
+
+ldd = os.getenv ('LDD', shutil.which ('ldd'))
+if not ldd:
+	otool = os.getenv ('OTOOL', shutil.which ('otool'))
+	if otool:
+		ldd = otool + ' -L'
+	else:
+		print ('check-libstdc++.py: \'ldd\' not found; skipping test')
+		sys.exit (77)
+
+stat = 0
+tested = False
+
+# harfbuzz-icu links to libstdc++ because icu does.
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']:
+	for suffix in ['so', 'dylib']:
+		so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
+		if not os.path.exists (so): continue
+
+		print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so)
+		ldd_result = subprocess.check_output (ldd.split() + [so])
+		if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
+			print ('Ouch, %s is linked to libstdc++ or libc++' % so)
+			stat = 1
+
+		tested = True
+
+if not tested:
+	print ('check-libstdc++.py: libharfbuzz shared library not found; skipping test')
+	sys.exit (77)
+
+sys.exit (stat)
diff --git a/src/check-libstdc++.sh b/src/check-libstdc++.sh
deleted file mode 100755
index ce0bdab..0000000
--- a/src/check-libstdc++.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-test -z "$libs" && libs=.libs
-stat=0
-
-
-if which ldd 2>/dev/null >/dev/null; then
-	LDD=ldd
-else
-	# macOS specific tool
-	if which otool 2>/dev/null >/dev/null; then
-		LDD="otool -L"
-	else
-		echo "check-libstdc++.sh: 'ldd' not found; skipping test"
-		exit 77
-	fi
-fi
-
-tested=false
-# harfbuzz-icu links to libstdc++ because icu does.
-# harfbuzz-subset uses libstdc++.
-for soname in harfbuzz harfbuzz-gobject; do
-	for suffix in so dylib; do
-		so=$libs/lib$soname.$suffix
-		if ! test -f "$so"; then continue; fi
-
-		echo "Checking that we are not linking to libstdc++ or libc++ in $so"
-		if $LDD $so | grep 'libstdc[+][+]\|libc[+][+]'; then
-			echo "Ouch, linked to libstdc++ or libc++"
-			stat=1
-		fi
-		tested=true
-	done
-done
-if ! $tested; then
-	echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
-	exit 77
-fi
-
-exit $stat
diff --git a/src/check-static-inits.py b/src/check-static-inits.py
new file mode 100755
index 0000000..37e0590
--- /dev/null
+++ b/src/check-static-inits.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+import sys, os, shutil, subprocess, glob, re
+
+builddir = os.getenv ('builddir', os.path.dirname (__file__))
+libs = os.getenv ('libs', '.libs')
+
+objdump = os.getenv ('OBJDUMP', shutil.which ('objdump'))
+if not objdump:
+	print ('check-static-inits.py: \'ldd\' not found; skipping test')
+	sys.exit (77)
+
+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, '**', '*.o'), recursive=True)
+if not OBJS:
+	print ('check-static-inits.py: object files not found; skipping test')
+	sys.exit (77)
+
+stat = 0
+tested = 0
+
+for obj in OBJS:
+	result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+	if result.returncode:
+		if result.stderr.find (b'not recognized') != -1:
+			# https://github.com/harfbuzz/harfbuzz/issues/3019
+			print ('objdump %s returned "not recognized", skipping' % obj)
+			continue
+		print ('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8')))
+		stat = 2
+
+	result = result.stdout.decode ('utf-8')
+
+	# Checking that no object file has static initializers
+	for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
+		if not re.match (r'.*\b0+\b', l):
+			print ('Ouch, %s has static initializers/finalizers' % obj)
+			stat = 1
+
+	# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
+	if ('__cxa_' in result) and ('__ubsan_handle' not in result):
+		print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
+		stat = 1
+
+	tested += 1
+
+sys.exit (stat if tested else 77)
diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh
deleted file mode 100755
index def25c7..0000000
--- a/src/check-static-inits.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-test -z "$libs" && libs=.libs
-stat=0
-
-if which objdump 2>/dev/null >/dev/null; then
-	:
-else
-	echo "check-static-inits.sh: 'objdump' not found; skipping test"
-	exit 77
-fi
-
-OBJS=$libs/*.o
-if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
-	echo "check-static-inits.sh: object files not found; skipping test"
-	exit 77
-fi
-
-echo "Checking that no object file has static initializers"
-for obj in $OBJS; do
-	if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
-		echo "Ouch, $obj has static initializers/finalizers"
-		stat=1
-	fi
-done
-
-echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
-for obj in $OBJS; do
-	if objdump -t "$obj" | grep -q '__cxa_' && ! objdump -t "$obj" | grep -q __ubsan_handle; then
-		objdump -t "$obj" | grep '__cxa_'
-		echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
-		stat=1
-	fi
-done
-
-exit $stat
diff --git a/src/check-symbols.py b/src/check-symbols.py
new file mode 100755
index 0000000..385959b
--- /dev/null
+++ b/src/check-symbols.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+import sys, os, shutil, subprocess, re, difflib
+
+os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
+
+builddir = os.getenv ('builddir', os.path.dirname (__file__))
+libs = os.getenv ('libs', '.libs')
+
+IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
+	'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
+	'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
+	'lprofDirMode', 'reset_fn_list'])
+
+nm = os.getenv ('NM', shutil.which ('nm'))
+if not nm:
+	print ('check-symbols.py: \'nm\' not found; skipping test')
+	sys.exit (77)
+
+cxxflit = shutil.which ('c++filt')
+
+tested = False
+stat = 0
+
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']:
+	for suffix in ['so', 'dylib']:
+		so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
+		if not os.path.exists (so): continue
+
+		# On macOS, C symbols are prefixed with _
+		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)
+				    if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
+
+		# run again c++flit also if is available
+		if cxxflit:
+			EXPORTED_SYMBOLS = subprocess.check_output (
+				[cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode ()
+			).decode ('utf-8').splitlines ()
+
+		prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
+
+		print ('Checking that %s does not expose internal symbols' % so)
+		suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)]
+		if suspicious_symbols:
+			print ('Ouch, internal symbols exposed:', suspicious_symbols)
+			stat = 1
+
+		def_path = os.path.join (builddir, soname + '.def')
+		if not os.path.exists (def_path):
+			print ('\'%s\' not found; skipping' % def_path)
+		else:
+			print ('Checking that %s has the same symbol list as %s' % (so, def_path))
+			with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read ()
+			diff_result = list (difflib.context_diff (
+				def_file.splitlines (),
+				['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] +
+					# cheat: copy the last line from the def file!
+					[def_file.splitlines ()[-1]]
+			))
+
+			if diff_result:
+				print ('\n'.join (diff_result))
+				stat = 1
+
+			tested = True
+
+if not tested:
+	print ('check-symbols.py: no shared libraries found; skipping test')
+	sys.exit (77)
+
+sys.exit (stat)
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
deleted file mode 100755
index f181b63..0000000
--- a/src/check-symbols.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-test -z "$libs" && libs=.libs
-stat=0
-
-IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*'
-
-if which nm 2>/dev/null >/dev/null; then
-	:
-else
-	echo "check-symbols.sh: 'nm' not found; skipping test"
-	exit 77
-fi
-
-tested=false
-for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
-	for suffix in so dylib; do
-		so=$libs/lib$soname.$suffix
-		if ! test -f "$so"; then continue; fi
-
-		# On macOS, C symbols are prefixed with _
-		symprefix=
-		if test $suffix = dylib; then symprefix=_; fi
-
-		EXPORTED_SYMBOLS=`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`
-
-		prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
-
-		echo "Checking that $so does not expose internal symbols"
-		if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}\(_\|$\)"; then
-			echo "Ouch, internal symbols exposed"
-			stat=1
-		fi
-
-		def=$soname.def
-		if ! test -f "$def"; then
-			echo "'$def' not found; skipping"
-		else
-			echo "Checking that $so has the same symbol list as $def"
-			{
-				echo EXPORTS
-				echo "$EXPORTED_SYMBOLS" | sed -e "s/^${symprefix}hb/hb/g"
-				# cheat: copy the last line from the def file!
-				tail -n1 "$def"
-			} | c++filt | diff "$def" - >&2 || stat=1
-		fi
-
-		tested=true
-	done
-done
-if ! $tested; then
-	echo "check-symbols.sh: no shared libraries found; skipping test"
-	exit 77
-fi
-
-exit $stat
diff --git a/src/dump-indic-data.cc b/src/dump-indic-data.cc
deleted file mode 100644
index 8ddc9d5..0000000
--- a/src/dump-indic-data.cc
+++ /dev/null
@@ -1,43 +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
- */
-
-#include "hb-ot-shape-complex-indic.hh"
-
-int
-main ()
-{
-  for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
-  {
-    hb_glyph_info_t info;
-    info.codepoint = u;
-    set_indic_properties (info);
-    if (info.indic_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
-	info.indic_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
-      printf("U+%04X	%u	%u\n", u,
-	     info.indic_category(),
-	     info.indic_position());
-  }
-}
diff --git a/src/dump-khmer-data.cc b/src/dump-khmer-data.cc
deleted file mode 100644
index cffbb92..0000000
--- a/src/dump-khmer-data.cc
+++ /dev/null
@@ -1,41 +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
- */
-
-#include "hb-ot-shape-complex-khmer.hh"
-
-int
-main ()
-{
-  for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
-  {
-    hb_glyph_info_t info;
-    info.codepoint = u;
-    set_khmer_properties (info);
-    if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER)
-      printf("U+%04X	%u\n", u,
-	     info.khmer_category());
-  }
-}
diff --git a/src/dump-myanmar-data.cc b/src/dump-myanmar-data.cc
deleted file mode 100644
index c1a303f..0000000
--- a/src/dump-myanmar-data.cc
+++ /dev/null
@@ -1,43 +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
- */
-
-#include "hb-ot-shape-complex-myanmar.hh"
-
-int
-main ()
-{
-  for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
-  {
-    hb_glyph_info_t info;
-    info.codepoint = u;
-    set_myanmar_properties (info);
-    if (info.myanmar_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
-	info.myanmar_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
-      printf("U+%04X	%u	%u\n", u,
-	     info.myanmar_category(),
-	     info.myanmar_position());
-  }
-}
diff --git a/src/dump-use-data.cc b/src/dump-use-data.cc
deleted file mode 100644
index d639426..0000000
--- a/src/dump-use-data.cc
+++ /dev/null
@@ -1,38 +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
- */
-
-#include "hb-ot-shape-complex-use.hh"
-
-int
-main ()
-{
-  for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
-  {
-    unsigned int category = hb_use_get_category (u);
-    if (category != USE_O)
-      printf("U+%04X	%u\n", u, category);
-  }
-}
diff --git a/src/failing-alloc.c b/src/failing-alloc.c
new file mode 100644
index 0000000..1bf18cd
--- /dev/null
+++ b/src/failing-alloc.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int alloc_state = 0;
+
+__attribute__((no_sanitize("integer")))
+static int fastrand ()
+{
+  if (!alloc_state) return 1;
+  /* Based on https://software.intel.com/content/www/us/en/develop/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor.html */
+  alloc_state = (214013 * alloc_state + 2531011);
+  return (alloc_state >> 16) & 0x7FFF;
+}
+
+void* hb_malloc_impl (size_t size)
+{
+  return (fastrand () % 16) ? malloc (size) : NULL;
+}
+
+void* hb_calloc_impl (size_t nmemb, size_t size)
+{
+  return (fastrand () % 16) ? calloc (nmemb, size) : NULL;
+}
+
+void* hb_realloc_impl (void *ptr, size_t size)
+{
+  return (fastrand () % 16) ? realloc (ptr, size) : NULL;
+}
+
+void  hb_free_impl (void *ptr)
+{
+  return free (ptr);
+}
diff --git a/src/fix_get_types.py b/src/fix_get_types.py
new file mode 100644
index 0000000..208b9df
--- /dev/null
+++ b/src/fix_get_types.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+import re
+import argparse
+
+parser = argparse.ArgumentParser ()
+parser.add_argument ('input')
+parser.add_argument ('output')
+args = parser.parse_args ()
+
+with open (args.input, 'r') as inp, open (args.output, 'w') as out:
+    for l in inp.readlines ():
+        l = re.sub ('_t_get_type', '_get_type', l)
+        l = re.sub ('_T \(', ' (', l)
+        out.write (l)
diff --git a/src/gen-arabic-joining-list.py b/src/gen-arabic-joining-list.py
new file mode 100755
index 0000000..8162a4a
--- /dev/null
+++ b/src/gen-arabic-joining-list.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+
+"""usage: ./gen-arabic-joining-table.py ArabicShaping.txt Scripts.txt
+
+Input files:
+* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
+* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
+"""
+
+import os.path, sys
+
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
+
+files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
+
+headers = [[f.readline (), f.readline ()] for f in files]
+while files[0].readline ().find ('##################') < 0:
+	pass
+
+def read (f):
+	mapping = {}
+	for line in f:
+
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+
+		uu = fields[0].split ('..')
+		start = int (uu[0], 16)
+		if len (uu) == 1:
+			end = start
+		else:
+			end = int (uu[1], 16)
+
+		t = fields[1]
+
+		for u in range (start, end + 1):
+			mapping[u] = t
+
+	return mapping
+
+def read_joining_uu (f):
+	values = set ()
+	for line in f:
+
+		if line[0] == '#':
+			continue
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+		if fields[2] in {'T', 'U'}:
+			continue
+
+		values.add (int (fields[0], 16))
+
+	return sorted (values)
+
+def print_has_arabic_joining (scripts, joining_uu):
+
+	print ("static bool")
+	print ("has_arabic_joining (hb_script_t script)")
+	print ("{")
+	print ("  /* List of scripts that have data in arabic-table. */")
+	print ("  switch ((int) script)")
+	print ("  {")
+
+	for script in sorted ({scripts[u] for u in joining_uu if scripts[u] not in {'Common', 'Inherited'}}):
+		print ("    case HB_SCRIPT_{}:".format (script.upper ()))
+
+	print ("      return true;")
+	print ()
+	print ("    default:")
+	print ("      return false;")
+	print ("  }")
+	print ("}")
+	print ()
+
+print ("/* == Start of generated function == */")
+print ("/*")
+print (" * The following function is generated by running:")
+print (" *")
+print (" *   ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt")
+print (" *")
+print (" * on files with these headers:")
+print (" *")
+for h in headers:
+	for l in h:
+		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 ()
+
+print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
+
+print ()
+print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */")
+print ()
+print ("/* == End of generated function == */")
diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py
index ccecb40..621d5b6 100755
--- a/src/gen-arabic-table.py
+++ b/src/gen-arabic-table.py
@@ -1,14 +1,19 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
+"""usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
 
-import io, os.path, sys
+Input files:
+* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
+* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
+* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt
+"""
+
+import os.path, sys
 
 if len (sys.argv) != 4:
-	print ("usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
-	sys.exit (1)
+	sys.exit (__doc__)
 
-files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
+files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
 
 headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
 headers.append (["UnicodeData.txt does not have a header."])
@@ -61,7 +66,7 @@
 		values[u] = value
 
 	short_value = {}
-	for value in set([v for v in values.values()] + ['JOINING_TYPE_X']):
+	for value in sorted (set ([v for v in values.values ()] + ['JOINING_TYPE_X'])):
 		short = ''.join(x[0] for x in value.split('_')[2:])
 		assert short not in short_value.values()
 		short_value[value] = short
@@ -122,7 +127,7 @@
 	print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
 	print ()
 
-	page_bits = 12;
+	page_bits = 12
 	print ()
 	print ("static unsigned int")
 	print ("joining_type (hb_codepoint_t u)")
@@ -176,7 +181,6 @@
 			if items not in ligatures:
 				ligatures[items] = {}
 			ligatures[items][shape] = c
-			pass
 		else:
 			# Save shape
 			if items[0] not in names:
diff --git a/src/gen-def.py b/src/gen-def.py
index 9111c69..33aa4df 100755
--- a/src/gen-def.py
+++ b/src/gen-def.py
@@ -1,11 +1,11 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
+"usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]"
 
-import io, os, re, sys
+import os, re, sys
 
 if len (sys.argv) < 3:
-	sys.exit("usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]")
+	sys.exit(__doc__)
 
 output_file = sys.argv[1]
 header_paths = sys.argv[2:]
@@ -13,12 +13,35 @@
 headers_content = []
 for h in header_paths:
 	if h.endswith (".h"):
-		with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
+		with open (h, encoding='utf-8') as f: headers_content.append (f.read ())
 
-symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M)))
+symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))
+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
+hb_font_get_var_coords_design""".splitlines ()
+	symbols = [x for x in symbols if x not in experimental_symbols]
+symbols = "\n".join (symbols)
 
-result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS
+result = symbols if os.getenv ('PLAIN_LIST', '') else """EXPORTS
 %s
-LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', ''))
+LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', ''))
 
 with open (output_file, "w") as f: f.write (result)
diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py
index 49770d4..0ee8fec 100755
--- a/src/gen-emoji-table.py
+++ b/src/gen-emoji-table.py
@@ -1,14 +1,18 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
+"""usage: ./gen-emoji-table.py emoji-data.txt emoji-test.txt
+
+Input file:
+* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
+* https://www.unicode.org/Public/emoji/latest/emoji-test.txt
+"""
+
 import sys
-import os.path
 from collections import OrderedDict
 import packTab
 
-if len (sys.argv) != 2:
-	print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
-	sys.exit (1)
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
 
 f = open(sys.argv[1])
 header = [f.readline () for _ in range(10)]
@@ -58,7 +62,7 @@
 
 	arr = dict()
 	for start,end in s:
-		for i in range(start,end):
+		for i in range(start, end + 1):
 			arr[i] = 1
 
 	sol = packTab.pack_table(arr, 0, compression=3)
@@ -71,3 +75,24 @@
 print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
 print ()
 print ("/* == End of generated table == */")
+
+
+# Generate test file.
+sequences = []
+with open(sys.argv[2]) as f:
+    for line in f.readlines():
+        if "#" in line:
+            line = line[:line.index("#")]
+        if ";" in line:
+            line = line[:line.index(";")]
+        line = line.strip()
+        line = line.split(" ")
+        if len(line) < 2:
+            continue
+        sequences.append(line)
+
+with open("../test/shaping/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")
diff --git a/src/gen-harfbuzzcc.py b/src/gen-harfbuzzcc.py
new file mode 100755
index 0000000..b25bcc7
--- /dev/null
+++ b/src/gen-harfbuzzcc.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, sys, shutil
+
+if len (sys.argv) < 3:
+	sys.exit (__doc__)
+
+OUTPUT = sys.argv[1]
+CURRENT_SOURCE_DIR = sys.argv[2]
+sources = 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 ())
+
+# copy it also to src/
+shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
diff --git a/src/gen-hb-version.py b/src/gen-hb-version.py
new file mode 100755
index 0000000..4fac0a0
--- /dev/null
+++ b/src/gen-hb-version.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, sys, shutil, re
+
+if len (sys.argv) < 4:
+	sys.exit(__doc__)
+
+version = sys.argv[1]
+major, minor, micro = version.split (".")
+
+OUTPUT = sys.argv[2]
+INPUT = sys.argv[3]
+CURRENT_SOURCE_DIR = os.path.dirname(INPUT)
+
+try:
+	with open (OUTPUT, "r", encoding='utf-8') as old_output:
+		for line in old_output:
+			old_version = re.match (r"#define HB_VERSION_STRING \"(\d.\d.\d)\"", line)
+			if old_version and old_version[1] == version:
+				sys.exit ()
+except IOError:
+	pass
+
+with open (INPUT, "r", encoding='utf-8') as template:
+	with open (OUTPUT, "wb") as output:
+		output.write (template.read ()
+			.replace ("@HB_VERSION_MAJOR@", major)
+			.replace ("@HB_VERSION_MINOR@", minor)
+			.replace ("@HB_VERSION_MICRO@", micro)
+			.replace ("@HB_VERSION@", version)
+			.encode ())
+
+# copy it also to src/
+shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT)))
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index 912b1d7..367e55e 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -1,12 +1,17 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
+"""usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
 
-import io, sys
+Input files:
+* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt
+* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt
+* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt
+"""
+
+import sys
 
 if len (sys.argv) != 4:
-	print ("usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt", file=sys.stderr)
-	sys.exit (1)
+	sys.exit (__doc__)
 
 ALLOWED_SINGLES = [0x00A0, 0x25CC]
 ALLOWED_BLOCKS = [
@@ -32,12 +37,12 @@
 	'Myanmar Extended-A',
 ]
 
-files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
+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 f in files]
-values = [{} for f in files]
+data = [{} for _ in files]
+values = [{} for _ in files]
 for i, f in enumerate (files):
 	for line in f:
 
@@ -77,7 +82,6 @@
 combined = {k:v for k,v in combined.items() if k in ALLOWED_SINGLES or v[2] in ALLOWED_BLOCKS}
 data = combined
 del combined
-num = len (data)
 
 # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
 singles = {}
@@ -196,7 +200,7 @@
 offset = 0
 starts = []
 ends = []
-print ("static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {")
+print ("static const uint16_t indic_table[] = {")
 for u in uu:
 	if u <= last:
 		continue
@@ -211,7 +215,6 @@
 	if start != last + 1:
 		if start - last <= 1+16*3:
 			print_block (None, last+1, start-1, data)
-			last = start-1
 		else:
 			if last >= 0:
 				ends.append (last + 1)
@@ -231,7 +234,7 @@
 page_bits = 12
 print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
 print ()
-print ("INDIC_TABLE_ELEMENT_TYPE")
+print ("uint16_t")
 print ("hb_indic_get_categories (hb_codepoint_t u)")
 print ("{")
 print ("  switch (u >> %d)" % page_bits)
diff --git a/src/gen-os2-unicode-ranges.py b/src/gen-os2-unicode-ranges.py
index 515f4ca..21aa1b9 100755
--- a/src/gen-os2-unicode-ranges.py
+++ b/src/gen-os2-unicode-ranges.py
@@ -1,22 +1,13 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 
-# -*- coding: utf-8 -*-
+"""Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
+Input is a tab seperated list of unicode ranges from the otspec
+(https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
+"""
 
-# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
-# Input is a tab seperated list of unicode ranges from the otspec
-# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
-
-from __future__ import print_function, division, absolute_import
-
-import io
 import re
 import sys
 
-try:
-  reload(sys)
-  sys.setdefaultencoding('utf-8')
-except NameError:
-  pass  # Python 3
 
 print ("""static OS2Range _hb_os2_unicode_ranges[] =
 {""")
@@ -24,9 +15,9 @@
 args = sys.argv[1:]
 input_file = args[0]
 
-with io.open(input_file, mode="r", encoding="utf-8") as f:
+with open (input_file, mode="r", encoding="utf-8") as f:
 
-  all_ranges = [];
+  all_ranges = []
   current_bit = 0
   while True:
     line = f.readline().strip()
diff --git a/src/gen-ragel-artifacts.py b/src/gen-ragel-artifacts.py
new file mode 100755
index 0000000..8bbb375
--- /dev/null
+++ b/src/gen-ragel-artifacts.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, os.path, sys, subprocess, shutil
+
+ragel = sys.argv[1]
+if not ragel:
+	sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself')
+
+if len (sys.argv) < 4:
+	sys.exit (__doc__)
+
+OUTPUT = sys.argv[2]
+CURRENT_SOURCE_DIR = sys.argv[3]
+INPUT = sys.argv[4]
+
+outdir = os.path.dirname (OUTPUT)
+shutil.copy (INPUT, outdir)
+rl = os.path.basename (INPUT)
+hh = rl.replace ('.rl', '.hh')
+subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
+
+# copy it also to src/
+shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py
index 49f5b30..d1b5d43 100755
--- a/src/gen-tag-table.py
+++ b/src/gen-tag-table.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 
 """Generator of the mapping from OpenType tags to BCP 47 tags and vice
 versa.
@@ -16,37 +16,24 @@
 multiple BCP 47 tags) are listed here, except when the alphabetically
 first BCP 47 tag happens to be the chosen disambiguated tag. In that
 case, the fallback behavior will choose the right tag anyway.
+
+usage: ./gen-tag-table.py languagetags language-subtag-registry
+
+Input files:
+* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
+* https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
 """
 
-from __future__ import absolute_import, division, print_function, unicode_literals
-
 import collections
-try:
-	from HTMLParser import HTMLParser
-	def write (s):
-		print (s.encode ('utf-8'), end='')
-except ImportError:
-	from html.parser import HTMLParser
-	def write (s):
-		sys.stdout.flush ()
-		sys.stdout.buffer.write (s.encode ('utf-8'))
-import io
+import html
+from html.parser import HTMLParser
 import itertools
 import re
 import sys
 import unicodedata
 
 if len (sys.argv) != 3:
-	print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr)
-	sys.exit (1)
-
-try:
-	from html import unescape
-	def html_unescape (parser, entity):
-		return unescape (entity)
-except ImportError:
-	def html_unescape (parser, entity):
-		return parser.unescape (entity)
+	sys.exit (__doc__)
 
 def expect (condition, message=None):
 	if not condition:
@@ -54,7 +41,13 @@
 			raise AssertionError
 		raise AssertionError (message)
 
-# from http://www-01.sil.org/iso639-3/iso-639-3.tab
+def write (s):
+	sys.stdout.flush ()
+	sys.stdout.buffer.write (s.encode ('utf-8'))
+
+DEFAULT_LANGUAGE_SYSTEM = ''
+
+# from https://www-01.sil.org/iso639-3/iso-639-3.tab
 ISO_639_3_TO_1 = {
 	'aar': 'aa',
 	'abk': 'ab',
@@ -388,10 +381,10 @@
 			self._current_tr[-1] += data
 
 	def handle_charref (self, name):
-		self.handle_data (html_unescape (self, '&#%s;' % name))
+		self.handle_data (html.unescape ('&#%s;' % name))
 
 	def handle_entityref (self, name):
-		self.handle_data (html_unescape (self, '&%s;' % name))
+		self.handle_data (html.unescape ('&%s;' % name))
 
 	def parse (self, filename):
 		"""Parse the OpenType language system tag registry.
@@ -399,7 +392,7 @@
 		Args:
 			filename (str): The file name of the registry.
 		"""
-		with io.open (filename, encoding='utf-8') as f:
+		with open (filename, encoding='utf-8') as f:
 			self.feed (f.read ())
 		expect (self.header)
 		for tag, iso_codes in self.to_bcp_47.items ():
@@ -475,11 +468,8 @@
 			if ot_macrolanguages:
 				for ot_macrolanguage in ot_macrolanguages:
 					for language in languages:
-						# Remove the following condition if e.g. nn should map to NYN,NOR
-						# instead of just NYN.
-						if language not in original_ot_from_bcp_47:
-							self.add_language (language, ot_macrolanguage)
-							self.ranks[ot_macrolanguage] += 1
+						self.add_language (language, ot_macrolanguage)
+						self.ranks[ot_macrolanguage] += 1
 			else:
 				for language in languages:
 					if language in original_ot_from_bcp_47:
@@ -541,7 +531,7 @@
 		Args:
 			filename (str): The file name of the registry.
 		"""
-		with io.open (filename, encoding='utf-8') as f:
+		with open (filename, encoding='utf-8') as f:
 			subtag_type = None
 			subtag = None
 			deprecated = False
@@ -563,7 +553,7 @@
 						self.grandfathered.add (subtag.lower ())
 				elif line.startswith ('Description: '):
 					description = line.split (' ', 1)[1].replace (' (individual language)', '')
-					description = re.sub (' (\((individual |macro)language\)|languages)$', '',
+					description = re.sub (' (\(family\)|\((individual |macro)language\)|languages)$', '',
 							description)
 					if subtag in self.names:
 						self.names[subtag] += '\n' + description
@@ -598,7 +588,9 @@
 					elif not has_preferred_value and line.startswith ('Macrolanguage: '):
 						self._add_macrolanguage (line.split (' ')[1], subtag)
 				elif subtag_type == 'variant':
-					if line.startswith ('Prefix: '):
+					if line.startswith ('Deprecated: '):
+						self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
+					elif line.startswith ('Prefix: '):
 						self.prefixes[subtag].add (line.split (' ')[1])
 				elif line.startswith ('File-Date: '):
 					self.header = line
@@ -629,6 +621,17 @@
 				for macrolanguage in macrolanguages:
 					self._add_macrolanguage (biggest_macrolanguage, macrolanguage)
 
+	def _get_name_piece (self, subtag):
+		"""Return the first name of a subtag plus its scope suffix.
+
+		Args:
+			subtag (str): A BCP 47 subtag.
+
+		Returns:
+			The name form of ``subtag``.
+		"""
+		return self.names[subtag].split ('\n')[0] + self.scopes.get (subtag, '')
+
 	def get_name (self, lt):
 		"""Return the names of the subtags in a language tag.
 
@@ -638,13 +641,13 @@
 		Returns:
 			The name form of ``lt``.
 		"""
-		name = self.names[lt.language].split ('\n')[0]
+		name = self._get_name_piece (lt.language)
 		if lt.script:
-			name += '; ' + self.names[lt.script.title ()].split ('\n')[0]
+			name += '; ' + self._get_name_piece (lt.script.title ())
 		if lt.region:
-			name += '; ' + self.names[lt.region.upper ()].split ('\n')[0]
+			name += '; ' + self._get_name_piece (lt.region.upper ())
 		if lt.variant:
-			name += '; ' + self.names[lt.variant].split ('\n')[0]
+			name += '; ' + self._get_name_piece (lt.variant)
 		return name
 
 bcp_47 = BCP47Parser ()
@@ -680,22 +683,18 @@
 ot.remove_language_ot ('IRT')
 ot.add_language ('ga-Latg', 'IRT')
 
+ot.add_language ('hy-arevmda', 'HYE')
+
 ot.remove_language_ot ('KGE')
 ot.add_language ('und-Geok', 'KGE')
 
-ot.add_language ('guk', 'GUK')
-ot.names['GUK'] = 'Gumuz (SIL fonts)'
-ot.ranks['GUK'] = ot.ranks['GMZ'] + 1
-
 bcp_47.macrolanguages['id'] = {'in'}
 
 bcp_47.macrolanguages['ijo'] = {'ijc'}
 
 ot.add_language ('kht', 'KHN')
 ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)'
-ot.names['KHT'] = ot.names['KHT'] + ' (OpenType spec and SIL fonts)'
-ot.ranks['KHN'] = ot.ranks['KHT']
-ot.ranks['KHT'] += 1
+ot.ranks['KHN'] = ot.ranks['KHT'] + 1
 
 ot.ranks['LCR'] = ot.ranks['MCR'] + 1
 
@@ -713,6 +712,7 @@
 ot.add_language ('qub', 'QWH')
 ot.add_language ('qud', 'QVI')
 ot.add_language ('qug', 'QVI')
+ot.add_language ('qul', 'QUH')
 ot.add_language ('qup', 'QVI')
 ot.add_language ('qur', 'QWH')
 ot.add_language ('qus', 'QUH')
@@ -743,10 +743,6 @@
 bcp_47.macrolanguages['ro'].remove ('mo')
 bcp_47.macrolanguages['ro-MD'].add ('mo')
 
-ot.add_language ('sgw', 'SGW')
-ot.names['SGW'] = ot.names['CHG'] + ' (SIL fonts)'
-ot.ranks['SGW'] = ot.ranks['CHG'] + 1
-
 ot.remove_language_ot ('SYRE')
 ot.remove_language_ot ('SYRJ')
 ot.remove_language_ot ('SYRN')
@@ -754,7 +750,7 @@
 ot.add_language ('und-Syrj', 'SYRJ')
 ot.add_language ('und-Syrn', 'SYRN')
 
-bcp_47.names['xst'] = u"Silt'e"
+bcp_47.names['xst'] = "Silt'e"
 bcp_47.scopes['xst'] = ' (retired code)'
 bcp_47.macrolanguages['xst'] = {'stv', 'wle'}
 
@@ -763,14 +759,17 @@
 ot.remove_language_ot ('ZHH')
 ot.remove_language_ot ('ZHP')
 ot.remove_language_ot ('ZHT')
+ot.remove_language_ot ('ZHTM')
 bcp_47.macrolanguages['zh'].remove ('lzh')
 bcp_47.macrolanguages['zh'].remove ('yue')
 ot.add_language ('zh-Hant-MO', 'ZHH')
+ot.add_language ('zh-Hant-MO', 'ZHTM')
 ot.add_language ('zh-Hant-HK', 'ZHH')
 ot.add_language ('zh-Hans', 'ZHS')
 ot.add_language ('zh-Hant', 'ZHT')
 ot.add_language ('zh-HK', 'ZHH')
 ot.add_language ('zh-MO', 'ZHH')
+ot.add_language ('zh-MO', 'ZHTM')
 ot.add_language ('zh-TW', 'ZHT')
 ot.add_language ('lzh', 'ZHT')
 ot.add_language ('lzh-Hans', 'ZHS')
@@ -802,6 +801,7 @@
 disambiguation = {
 	'ALT': 'alt',
 	'ARK': 'rki',
+	'ATH': 'ath',
 	'BHI': 'bhb',
 	'BLN': 'bjt',
 	'BTI': 'beb',
@@ -813,7 +813,9 @@
 	'ECR': 'crj',
 	'HAL': 'cfm',
 	'HND': 'hnd',
+	'HYE': 'hyw',
 	'KIS': 'kqs',
+	'KUI': 'uki',
 	'LRC': 'bqi',
 	'NDB': 'nd',
 	'NIS': 'njz',
@@ -824,15 +826,24 @@
 	'QVI': 'qvi',
 	'QWH': 'qwh',
 	'SIG': 'stv',
-	'TNE': 'yrk',
+	'SRB': 'sr',
+	'SXT': 'xnj',
 	'ZHH': 'zh-HK',
 	'ZHS': 'zh-Hans',
 	'ZHT': 'zh-Hant',
+	'ZHTM': 'zh-MO',
 }
 
 ot.inherit_from_macrolanguages ()
 bcp_47.remove_extra_macrolanguages ()
 ot.inherit_from_macrolanguages ()
+ot.names[DEFAULT_LANGUAGE_SYSTEM] = '*/'
+ot.ranks[DEFAULT_LANGUAGE_SYSTEM] = max (ot.ranks.values ()) + 1
+for tricky_ot_tag in filter (lambda tag: re.match ('[A-Z]{3}$', tag), ot.names):
+	possible_bcp_47_tag = tricky_ot_tag.lower ()
+	if possible_bcp_47_tag in bcp_47.names and not ot.from_bcp_47[possible_bcp_47_tag]:
+		ot.add_language (possible_bcp_47_tag, DEFAULT_LANGUAGE_SYSTEM)
+		bcp_47.macrolanguages[possible_bcp_47_tag] = set ()
 ot.sort_languages ()
 
 print ('/* == Start of generated table == */')
@@ -861,7 +872,9 @@
 	Returns:
 		A snippet of C++ representing ``tag``.
 	"""
-	return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
+	if tag == DEFAULT_LANGUAGE_SYSTEM:
+		return 'HB_TAG_NONE\t       '
+	return "HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
 
 def get_variant_set (name):
 	"""Return a set of variant language names from a name.
@@ -873,7 +886,7 @@
 	Returns:
 		A set of normalized language names.
 	"""
-	return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'"))
+	return set (unicodedata.normalize ('NFD', n.replace ('\u2019', "'"))
 			.encode ('ASCII', 'ignore')
 			.strip ()
 			for n in re.split ('[\n(),]', name) if n)
@@ -909,14 +922,18 @@
 		print ('\t/* ', end='')
 		bcp_47_name = bcp_47.names.get (language, '')
 		bcp_47_name_candidates = bcp_47_name.split ('\n')
-		intersection = language_name_intersection (bcp_47_name, ot.names[tag])
+		ot_name = ot.names[tag]
 		scope = bcp_47.scopes.get (language, '')
-		if not intersection:
-			write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot.names[tag]))
+		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.names[tag]) else ot.names[tag], scope))
+			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 ('};')
@@ -998,22 +1015,24 @@
 	print ("  case '%s':" % initial)
 	for lt, tags in items:
 		print ('    if (', end='')
+		script = lt.script
+		region = lt.region
 		if lt.grandfathered:
 			print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='')
 		else:
 			string_literal = lt.language[1:] + '-'
-			if lt.script:
-				string_literal += lt.script
-				lt.script = None
-				if lt.region:
-					string_literal += '-' + lt.region
-					lt.region = None
+			if script:
+				string_literal += script
+				script = None
+				if region:
+					string_literal += '-' + region
+					region = None
 			if string_literal[-1] == '-':
 				print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='')
 			else:
 				print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='')
-		print_subtag_matches (lt.script, True)
-		print_subtag_matches (lt.region, True)
+		print_subtag_matches (script, True)
+		print_subtag_matches (region, True)
 		print_subtag_matches (lt.variant, True)
 		print (')')
 		print ('    {')
@@ -1080,11 +1099,18 @@
 	global disambiguation
 	global ot
 	for ot_tag, bcp_47_tags in ot.to_bcp_47.items ():
-		primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag)
+		if ot_tag == DEFAULT_LANGUAGE_SYSTEM:
+			primary_tags = []
+		else:
+			primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag)
 		if len (primary_tags) == 1:
 			expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag)
 			if '-' in primary_tags[0]:
 				disambiguation[ot_tag] = primary_tags[0]
+			else:
+				first_tag = sorted (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t))[0]
+				if primary_tags[0] != first_tag:
+					disambiguation[ot_tag] = primary_tags[0]
 		elif len (primary_tags) == 0:
 			expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag)
 		else:
@@ -1099,8 +1125,8 @@
 						'%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
 			elif ot_tag not in disambiguation:
 				disambiguation[ot_tag] = macrolanguages[0]
-			different_primary_tags = sorted (t for t in primary_tags if not same_tag (t, ot.from_bcp_47.get (t)))
-			if different_primary_tags and disambiguation[ot_tag] == different_primary_tags[0] and '-' not in disambiguation[ot_tag]:
+			different_bcp_47_tags = sorted (t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t)))
+			if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0] and '-' not in disambiguation[ot_tag]:
 				del disambiguation[ot_tag]
 	for ot_tag in disambiguation.keys ():
 		expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
diff --git a/src/gen-ucd-table.py b/src/gen-ucd-table.py
index 552c3c6..35fba2d 100755
--- a/src/gen-ucd-table.py
+++ b/src/gen-ucd-table.py
@@ -1,14 +1,17 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
+"""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]
 
-import io, os.path, sys, re
+Input file:
+* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip
+"""
+
+import sys, re
 import logging
 logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
 
 if len (sys.argv) not in (2, 3):
-	print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]", file=sys.stderr)
-	sys.exit(1)
+	sys.exit (__doc__)
 
 # https://github.com/harfbuzz/packtab
 import packTab
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index 4523fb8..34540ca 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -1,24 +1,46 @@
-#!/usr/bin/env python
-# flake8: noqa
+#!/usr/bin/env python3
+# flake8: noqa: F821
 
-from __future__ import print_function, division, absolute_import
+"""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
 
-import io
+Input files:
+* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt
+* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt
+* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
+* https://unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
+* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
+* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt
+* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
+* ms-use/IndicSyllabicCategory-Additional.txt
+* ms-use/IndicPositionalCategory-Additional.txt
+"""
+
 import sys
 
-if len (sys.argv) != 5:
-	print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
-	sys.exit (1)
+if len (sys.argv) != 10:
+	sys.exit (__doc__)
 
-BLACKLISTED_BLOCKS = ["Thai", "Lao"]
+DISABLED_SCRIPTS = {
+	'Arabic',
+	'Lao',
+	'Samaritan',
+	'Syriac',
+	'Thai',
+}
 
-files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
+files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
 
-headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 2]
+headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 4]
+for j in range(7, 9):
+	for line in files[j]:
+		line = line.rstrip()
+		if not line:
+			break
+		headers[j - 1].append(line)
 headers.append (["UnicodeData.txt does not have a header."])
 
-data = [{} for f in files]
-values = [{} for f in files]
+data = [{} for _ in files]
+values = [{} for _ in files]
 for i, f in enumerate (files):
 	for line in f:
 
@@ -37,16 +59,26 @@
 		else:
 			end = int (uu[1], 16)
 
-		t = fields[1 if i != 2 else 2]
+		t = fields[1 if i not in [2, 4] else 2]
 
+		if i == 2:
+			t = 'jt_' + t
+		elif i == 3 and t != 'Default_Ignorable_Code_Point':
+			continue
+		elif i == 7 and t == 'Consonant_Final_Modifier':
+			# TODO: https://github.com/MicrosoftDocs/typography-issues/issues/336
+			t = 'Syllable_Modifier'
+		elif i == 8 and t == 'NA':
+			t = 'Not_Applicable'
+
+		i0 = i if i < 7 else i - 7
 		for u in range (start, end + 1):
-			data[i][u] = t
-		values[i][t] = values[i].get (t, 0) + end - start + 1
+			data[i0][u] = t
+		values[i0][t] = values[i0].get (t, 0) + end - start + 1
 
-defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
+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][0x034F] = defaults[0]
 data[0][0x1B61] = defaults[0]
 data[0][0x1B63] = defaults[0]
 data[0][0x1B64] = defaults[0]
@@ -67,8 +99,6 @@
 data[0][0x11C45] = 'Consonant_Placeholder'
 # TODO https://github.com/harfbuzz/harfbuzz/pull/1399
 data[0][0x111C8] = 'Consonant_Placeholder'
-for u in range (0xFE00, 0xFE0F + 1):
-	data[0][u] = defaults[0]
 
 # Merge data into one dict:
 for i,v in enumerate (defaults):
@@ -76,15 +106,14 @@
 combined = {}
 for i,d in enumerate (data):
 	for u,v in d.items ():
-		if i >= 2 and not u in combined:
-			continue
 		if not u in combined:
+			if i >= 4:
+				continue
 			combined[u] = list (defaults)
 		combined[u][i] = v
-combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS}
+combined = {k: v for k, v in combined.items() if v[6] not in DISABLED_SCRIPTS}
 data = combined
 del combined
-num = len (data)
 
 
 property_names = [
@@ -129,6 +158,10 @@
 	'Number_Joiner',
 	'Number',
 	'Brahmi_Joining_Number',
+	'Hieroglyph',
+	'Hieroglyph_Joiner',
+	'Hieroglyph_Segment_Begin',
+	'Hieroglyph_Segment_End',
 	# Indic_Positional_Category
 	'Not_Applicable',
 	'Right',
@@ -138,6 +171,7 @@
 	'Top',
 	'Bottom',
 	'Top_And_Bottom',
+	'Top_And_Bottom_And_Left',
 	'Top_And_Right',
 	'Top_And_Left',
 	'Top_And_Left_And_Right',
@@ -145,20 +179,23 @@
 	'Bottom_And_Right',
 	'Top_And_Bottom_And_Right',
 	'Overstruck',
+	# Joining_Type
+	'jt_C',
+	'jt_D',
+	'jt_L',
+	'jt_R',
+	'jt_T',
+	'jt_U',
+	'jt_X',
 ]
 
-try:
-	basestring
-except NameError:
-	basestring = str
-
 class PropertyValue(object):
 	def __init__(self, name_):
 		self.name = name_
 	def __str__(self):
 		return self.name
 	def __eq__(self, other):
-		return self.name == (other if isinstance(other, basestring) else other.name)
+		return self.name == (other if isinstance(other, str) else other.name)
 	def __ne__(self, other):
 		return not (self == other)
 	def __hash__(self):
@@ -174,96 +211,85 @@
 globals().update(property_values)
 
 
-def is_BASE(U, UISC, UGC):
+def is_BASE(U, UISC, UDI, UGC, AJT):
 	return (UISC in [Number, Consonant, Consonant_Head_Letter,
-			#SPEC-DRAFT Consonant_Placeholder,
 			Tone_Letter,
-			Vowel_Independent #SPEC-DRAFT
+			Vowel_Independent,
 			] or
+		# TODO: https://github.com/MicrosoftDocs/typography-issues/issues/484
+		AJT in [jt_C, jt_D, jt_L, jt_R] and UISC != Joiner or
 		(UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial,
 					Consonant_Subjoined, Vowel, Vowel_Dependent]))
-def is_BASE_IND(U, UISC, UGC):
-	#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
-	return (UISC in [Consonant_Dead, Modifying_Letter] or
-		(UGC == Po and not U in [0x104B, 0x104E, 0x1B5B, 0x1B5C, 0x1B5F, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
-		False # SPEC-DRAFT-OUTDATED! U == 0x002D
-		)
-def is_BASE_NUM(U, UISC, UGC):
+def is_BASE_NUM(U, UISC, UDI, UGC, AJT):
 	return UISC == Brahmi_Joining_Number
-def is_BASE_OTHER(U, UISC, UGC):
-	if UISC == Consonant_Placeholder: return True #SPEC-DRAFT
-	#SPEC-DRAFT return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
+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, UGC):
-	return U == 0x034F
-def is_CONS_FINAL(U, UISC, UGC):
+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]
+def is_CONS_FINAL(U, UISC, UDI, UGC, AJT):
 	return ((UISC == Consonant_Final and UGC != Lo) or
 		UISC == Consonant_Succeeding_Repha)
-def is_CONS_FINAL_MOD(U, UISC, UGC):
-	#SPEC-DRAFT return  UISC in [Consonant_Final_Modifier, Syllable_Modifier]
-	return  UISC == Syllable_Modifier
-def is_CONS_MED(U, UISC, UGC):
+def is_CONS_FINAL_MOD(U, UISC, UDI, UGC, AJT):
+	return UISC == Syllable_Modifier
+def is_CONS_MED(U, UISC, UDI, UGC, AJT):
 	# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
 	return (UISC == Consonant_Medial and UGC != Lo or
 		UISC == Consonant_Initial_Postfixed)
-def is_CONS_MOD(U, UISC, UGC):
-	return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
-def is_CONS_SUB(U, UISC, UGC):
-	#SPEC-DRAFT return UISC == Consonant_Subjoined
+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))
+def is_CONS_SUB(U, UISC, UDI, UGC, AJT):
 	return UISC == Consonant_Subjoined and UGC != Lo
-def is_CONS_WITH_STACKER(U, UISC, UGC):
+def is_CONS_WITH_STACKER(U, UISC, UDI, UGC, AJT):
 	return UISC == Consonant_With_Stacker
-def is_HALANT(U, UISC, UGC):
+def is_HALANT(U, UISC, UDI, UGC, AJT):
 	return (UISC in [Virama, Invisible_Stacker]
-		and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
-		and not is_SAKOT(U, UISC, UGC))
-def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
-	# https://github.com/harfbuzz/harfbuzz/issues/1102
+		and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UDI, UGC, AJT)
+		and not is_SAKOT(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 in [0x11046, 0x1134D]
-def is_HALANT_NUM(U, UISC, UGC):
+	return U == 0x1134D
+def is_HALANT_NUM(U, UISC, UDI, UGC, AJT):
 	return UISC == Number_Joiner
-def is_ZWNJ(U, UISC, UGC):
+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_SEGMENT_BEGIN(U, UISC, UDI, UGC, AJT):
+	return UISC == Hieroglyph_Segment_Begin
+def is_HIEROGLYPH_SEGMENT_END(U, UISC, UDI, UGC, AJT):
+	return UISC == Hieroglyph_Segment_End
+def is_ZWNJ(U, UISC, UDI, UGC, AJT):
 	return UISC == Non_Joiner
-def is_ZWJ(U, UISC, UGC):
-	return UISC == Joiner
-def is_Word_Joiner(U, UISC, UGC):
-	return U == 0x2060
-def is_OTHER(U, UISC, UGC):
-	#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
-	return (UISC == Other
-		and not is_SYM(U, UISC, UGC)
-		and not is_SYM_MOD(U, UISC, UGC)
-		and not is_CGJ(U, UISC, UGC)
-		and not is_Word_Joiner(U, UISC, UGC)
-		and not is_VARIATION_SELECTOR(U, UISC, UGC)
+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])
+		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)
 	)
-def is_Reserved(U, UISC, UGC):
-	return UGC == 'Cn'
-def is_REPHA(U, UISC, UGC):
+def is_REPHA(U, UISC, UDI, UGC, AJT):
 	return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
-def is_SAKOT(U, UISC, UGC):
+def is_SAKOT(U, UISC, UDI, UGC, AJT):
+	# Split off of HALANT
 	return U == 0x1A60
-def is_SYM(U, UISC, UGC):
-	if U == 0x25CC: return False #SPEC-DRAFT
-	#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
-	return UGC in [So, Sc] and U not in [0x1B62, 0x1B68]
-def is_SYM_MOD(U, UISC, UGC):
+def is_SYM_MOD(U, UISC, UDI, UGC, AJT):
 	return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
-def is_VARIATION_SELECTOR(U, UISC, UGC):
-	return 0xFE00 <= U <= 0xFE0F
-def is_VOWEL(U, UISC, UGC):
+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]))
-def is_VOWEL_MOD(U, UISC, UGC):
+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])))
 
 use_mapping = {
 	'B':	is_BASE,
-	'IND':	is_BASE_IND,
 	'N':	is_BASE_NUM,
 	'GB':	is_BASE_OTHER,
 	'CGJ':	is_CGJ,
@@ -276,16 +302,15 @@
 	'H':	is_HALANT,
 	'HVM':	is_HALANT_OR_VOWEL_MODIFIER,
 	'HN':	is_HALANT_NUM,
+	'G':	is_HIEROGLYPH,
+	'J':	is_HIEROGLYPH_JOINER,
+	'SB':	is_HIEROGLYPH_SEGMENT_BEGIN,
+	'SE':	is_HIEROGLYPH_SEGMENT_END,
 	'ZWNJ':	is_ZWNJ,
-	'ZWJ':	is_ZWJ,
-	'WJ':	is_Word_Joiner,
 	'O':	is_OTHER,
-	'Rsv':	is_Reserved,
 	'R':	is_REPHA,
-	'S':	is_SYM,
 	'Sk':	is_SAKOT,
 	'SM':	is_SYM_MOD,
-	'VS':	is_VARIATION_SELECTOR,
 	'V':	is_VOWEL,
 	'VM':	is_VOWEL_MOD,
 }
@@ -298,19 +323,19 @@
 	},
 	'M': {
 		'Abv': [Top],
-		'Blw': [Bottom, Bottom_And_Left],
+		'Blw': [Bottom, Bottom_And_Left, Bottom_And_Right],
 		'Pst': [Right],
-		'Pre': [Left],
+		'Pre': [Left, Top_And_Bottom_And_Left],
 	},
 	'CM': {
 		'Abv': [Top],
-		'Blw': [Bottom],
+		'Blw': [Bottom, Overstruck],
 	},
 	'V': {
 		'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
 		'Blw': [Bottom, Overstruck, Bottom_And_Right],
-		'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
-		'Pre': [Left],
+		'Pst': [Right],
+		'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
 	},
 	'VM': {
 		'Abv': [Top],
@@ -330,36 +355,23 @@
 		'Blw': [Bottom],
 		'Pst': [Not_Applicable],
 	},
+	'R': None,
 	'SUB': None,
 }
 
 def map_to_use(data):
 	out = {}
 	items = use_mapping.items()
-	for U,(UISC,UIPC,UGC,UBlock) in data.items():
+	for U, (UISC, UIPC, AJT, UDI, UGC, UBlock, _) in data.items():
 
 		# Resolve Indic_Syllabic_Category
 
-		# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
+		# TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC
 		if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
 
 		# Tibetan:
-		# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
+		# 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
-		if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark
-		# Overrides to allow NFC order matching syllable
-		# https://github.com/harfbuzz/harfbuzz/issues/1012
-		if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC):
-			if UIPC == Top:
-				UIPC = Bottom
-
-		# TODO: https://github.com/harfbuzz/harfbuzz/pull/982
-		# also  https://github.com/harfbuzz/harfbuzz/issues/1012
-		if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
-			if UIPC == Top:
-				UIPC = Bottom
-			elif UIPC == Bottom:
-				UIPC = Top
 
 		# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
 		if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
@@ -368,39 +380,37 @@
 		# the nasalization marks, maybe only for U+1CE9..U+1CF1.
 		if U == 0x1CED: UISC = Tone_Mark
 
-		# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
-		if U == 0x11134: UISC = Gemination_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,UGC)]
-		assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
+		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 12.0
+		# TODO: These should die, but have UIPC in Unicode 13.0.0
 		if U in [0x953, 0x954]: UIPC = Not_Applicable
 
-		# TODO: In USE's override list but not in Unicode 12.0
-		if U == 0x103C: UIPC = Left
-
-		# TODO: https://github.com/harfbuzz/harfbuzz/pull/2012
-		if U == 0x1C29: UIPC = Left
-
-		# TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0
+		# 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 U == 0x1171E: UIPC = Left
 		if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
 
-		assert (UIPC in [Not_Applicable, Visual_Order_Left] or
-			USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
+		# 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)
 
 		pos_mapping = use_positions.get(USE, None)
 		if pos_mapping:
 			values = [k for k,v in pos_mapping.items() if v and UIPC in v]
-			assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values)
+			assert len(values) == 1, "%s %s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT, values)
 			USE = USE + values[0]
 
 		out[U] = (USE, UBlock)
@@ -413,7 +423,7 @@
 print ("/*")
 print (" * The following table is generated by running:")
 print (" *")
-print (" *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt")
+print (" *   {} IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt".format (sys.argv[0]))
 print (" *")
 print (" * on files with these headers:")
 print (" *")
@@ -422,11 +432,12 @@
 		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 ()
 print ('#include "hb.hh"')
 print ()
-print ('#ifndef HB_NO_OT_SHAPE')
-print ()
-print ('#include "hb-ot-shape-complex-use.hh"')
+print ('#include "hb-ot-shape-complex-use-machine.hh"')
 print ()
 
 total = 0
@@ -468,18 +479,20 @@
 print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
 for k,v in sorted(use_mapping.items()):
 	if k in use_positions and use_positions[k]: continue
-	print ("#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:]))
+	print ("#define %s	USE(%s)	/* %s */" % (k, k, v.__name__[3:]))
 for k,v in sorted(use_positions.items()):
 	if not v: continue
 	for suf in v.keys():
 		tag = k + suf
-		print ("#define %s	USE_%s" % (tag, tag))
+		print ("#define %s	USE(%s)" % (tag, tag))
 print ('#pragma GCC diagnostic pop')
 print ("")
-print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
+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
@@ -491,7 +504,6 @@
 	if start != last + 1:
 		if start - last <= 1+16*3:
 			print_block (None, last+1, start-1, data)
-			last = start-1
 		else:
 			if last >= 0:
 				ends.append (last + 1)
@@ -511,7 +523,7 @@
 page_bits = 12
 print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
 print ()
-print ("USE_TABLE_ELEMENT_TYPE")
+print ("static inline uint8_t")
 print ("hb_use_get_category (hb_codepoint_t u)")
 print ("{")
 print ("  switch (u >> %d)" % page_bits)
@@ -528,7 +540,7 @@
 print ("    default:")
 print ("      break;")
 print ("  }")
-print ("  return USE_O;")
+print ("  return USE(O);")
 print ("}")
 print ()
 for k in sorted(use_mapping.keys()):
@@ -541,7 +553,7 @@
 		print ("#undef %s" % tag)
 print ()
 print ()
-print ('#endif')
+print ("#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */")
 print ("/* == End of generated table == */")
 
 # Maintain at least 50% occupancy in the table */
diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py
index 8ca90c8..184ec29 100755
--- a/src/gen-vowel-constraints.py
+++ b/src/gen-vowel-constraints.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 
 """Generator of the function to prohibit certain vowel sequences.
 
@@ -6,29 +6,23 @@
 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``.
+
+usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
+
+Input file:
+* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
 """
 
-from __future__ import absolute_import, division, print_function, unicode_literals
-
 import collections
-try:
-	from HTMLParser import HTMLParser
-	def write (s):
-		print (s.encode ('utf-8'), end='')
-except ImportError:
-	from html.parser import HTMLParser
-	def write (s):
-		sys.stdout.flush ()
-		sys.stdout.buffer.write (s.encode ('utf-8'))
-import itertools
-import io
+def write (s):
+	sys.stdout.flush ()
+	sys.stdout.buffer.write (s.encode ('utf-8'))
 import sys
 
 if len (sys.argv) != 3:
-	print ('usage: ./gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt', file=sys.stderr)
-	sys.exit (1)
+	sys.exit (__doc__)
 
-with io.open (sys.argv[2], encoding='utf-8') as f:
+with open (sys.argv[2], encoding='utf-8') as f:
 	scripts_header = [f.readline () for i in range (2)]
 	scripts = {}
 	script_order = {}
@@ -84,7 +78,8 @@
 			else:
 				self._c[first] = ConstraintSet (rest)
 
-	def _indent (self, depth):
+	@staticmethod
+	def _indent (depth):
 		return ('  ' * depth).replace ('        ', '\t')
 
 	def __str__ (self, index=0, depth=4):
@@ -92,19 +87,22 @@
 		indent = self._indent (depth)
 		if isinstance (self._c, list):
 			if len (self._c) == 0:
+				assert index == 2, 'Cannot use `matched` for this constraint; the general case has not been implemented'
 				s.append ('{}matched = true;\n'.format (indent))
 			elif len (self._c) == 1:
+				assert index == 1, 'Cannot use `matched` for this constraint; the general case has not been implemented'
 				s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
 			else:
-				s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index))
-				s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c)))
+				s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index or ''))
+				if index:
+					s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), index + 1))
 				for i, cp in enumerate (self._c[1:], start=1):
 					s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
 						self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
 				s.append ('{}{{\n'.format (indent))
-				for i in range (len (self._c)):
-					s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
-				s.append ('{}_output_dotted_circle (buffer);\n'.format (self._indent (depth + 1)))
+				for i in range (index):
+					s.append ('{}(void) buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
+				s.append ('{}matched = true;\n'.format (self._indent (depth + 1)))
 				s.append ('{}}}\n'.format (indent))
 		else:
 			s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or ''))
@@ -127,8 +125,13 @@
 		return ''.join (s)
 
 constraints = {}
-with io.open (sys.argv[1], encoding='utf-8') as f:
-	constraints_header = [f.readline ().strip () for i in range (2)]
+with open (sys.argv[1], encoding='utf-8') as f:
+	constraints_header = []
+	while True:
+		line = f.readline ().strip ()
+		if line == '#':
+			break
+		constraints_header.append(line)
 	for line in f:
 		j = line.find ('#')
 		if j >= 0:
@@ -147,7 +150,7 @@
 print ('/*')
 print (' * The following functions are generated by running:')
 print (' *')
-print (' *   %s use Scripts.txt' % sys.argv[0])
+print (' *   %s ms-use/IndicShapingInvalidCluster.txt Scripts.txt' % sys.argv[0])
 print (' *')
 print (' * on files with these headers:')
 print (' *')
@@ -168,15 +171,15 @@
 print ('static void')
 print ('_output_dotted_circle (hb_buffer_t *buffer)')
 print ('{')
-print ('  hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);')
-print ('  _hb_glyph_info_reset_continuation (&dottedcircle);')
+print ('  (void) buffer->output_glyph (0x25CCu);')
+print ('  _hb_glyph_info_reset_continuation (&buffer->prev());')
 print ('}')
 print ()
 print ('static void')
 print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
 print ('{')
 print ('  _output_dotted_circle (buffer);')
-print ('  buffer->next_glyph ();')
+print ('  (void) buffer->next_glyph ();')
 print ('}')
 print ()
 
@@ -185,7 +188,7 @@
 print ('\t\t\t\t       hb_buffer_t              *buffer,')
 print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
 print ('{')
-print ('#if defined(HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS)')
+print ('#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS')
 print ('  return;')
 print ('#endif')
 print ('  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
@@ -197,7 +200,6 @@
 print ('   *')
 print ('   * https://github.com/harfbuzz/harfbuzz/issues/1019')
 print ('   */')
-print ('  bool processed = false;')
 print ('  buffer->clear_output ();')
 print ('  unsigned int count = buffer->len;')
 print ('  switch ((unsigned) buffer->props.script)')
@@ -209,22 +211,16 @@
 	print ('      {')
 	print ('\tbool matched = false;')
 	write (str (constraints))
-	print ('\tbuffer->next_glyph ();')
+	print ('\t(void) buffer->next_glyph ();')
 	print ('\tif (matched) _output_with_dotted_circle (buffer);')
 	print ('      }')
-	print ('      processed = true;')
 	print ('      break;')
 	print ()
 
 print ('    default:')
 print ('      break;')
 print ('  }')
-print ('  if (processed)')
-print ('  {')
-print ('    if (buffer->idx < count)')
-print ('      buffer->next_glyph ();')
-print ('    buffer->swap_buffers ();')
-print ('  }')
+print ('  buffer->swap_buffers ();')
 print ('}')
 
 print ()
diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc
index 251a065..14ee6f5 100644
--- a/src/harfbuzz.cc
+++ b/src/harfbuzz.cc
@@ -4,10 +4,12 @@
 #include "hb-buffer-serialize.cc"
 #include "hb-buffer.cc"
 #include "hb-common.cc"
+#include "hb-draw.cc"
 #include "hb-face.cc"
 #include "hb-fallback-shape.cc"
 #include "hb-font.cc"
 #include "hb-map.cc"
+#include "hb-ms-feature-ranges.cc"
 #include "hb-number.cc"
 #include "hb-ot-cff1-table.cc"
 #include "hb-ot-cff2-table.cc"
@@ -28,8 +30,8 @@
 #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-table.cc"
 #include "hb-ot-shape-complex-use.cc"
 #include "hb-ot-shape-complex-vowel-constraints.cc"
 #include "hb-ot-shape-fallback.cc"
@@ -42,6 +44,7 @@
 #include "hb-shape.cc"
 #include "hb-shaper.cc"
 #include "hb-static.cc"
+#include "hb-style.cc"
 #include "hb-ucd.cc"
 #include "hb-unicode.cc"
 #include "hb-glib.cc"
diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh
deleted file mode 100644
index 604d5bc..0000000
--- a/src/hb-aat-fdsc-table.hh
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright © 2018  Ebrahim Byagowi
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#ifndef HB_AAT_FDSC_TABLE_HH
-#define HB_AAT_FDSC_TABLE_HH
-
-#include "hb-aat-layout-common.hh"
-#include "hb-open-type.hh"
-
-/*
- * fdsc -- Font descriptors
- * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
- */
-#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
-
-
-namespace AAT {
-
-
-struct FontDescriptor
-{
-  bool has_data () const { return tag; }
-
-  int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
-  float get_value () const { return u.value.to_float (); }
-
-  enum non_alphabetic_value_t {
-    Alphabetic		= 0,
-    Dingbats		= 1,
-    PiCharacters	= 2,
-    Fleurons		= 3,
-    DecorativeBorders	= 4,
-    InternationalSymbols= 5,
-    MathSymbols		= 6
-  };
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  protected:
-  Tag		tag;		/* The 4-byte table tag name. */
-  union {
-  HBFixed		value;		/* The value for the descriptor tag. */
-  HBUINT32	nalfType;	/* If the tag is `nalf`, see non_alphabetic_value_t */
-  } u;
-  public:
-  DEFINE_SIZE_STATIC (8);
-};
-
-struct fdsc
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
-
-  enum {
-    Weight	 = HB_TAG ('w','g','h','t'),
-				/* Percent weight relative to regular weight.
-				 * (defaul value: 1.0) */
-    Width 	 = HB_TAG ('w','d','t','h'),
-				/* Percent width relative to regular width.
-				 * (default value: 1.0) */
-    Slant 	 = HB_TAG ('s','l','n','t'),
-				/* Angle of slant in degrees, where positive
-				 * is clockwise from straight up.
-				 * (default value: 0.0) */
-    OpticalSize  = HB_TAG ('o','p','s','z'),
-				/* Point size the font was designed for.
-				 * (default value: 12.0) */
-    NonAlphabetic= HB_TAG ('n','a','l','f')
-				/* These values are treated as integers,
-				 * not fixed32s. 0 means alphabetic, and greater
-				 * integers mean the font is non-alphabetic (e.g. symbols).
-				 * (default value: 0) */
-  };
-
-  const FontDescriptor &get_descriptor (hb_tag_t style) const
-  { return descriptors.lsearch (style); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  descriptors.sanitize (c));
-  }
-
-  protected:
-  HBFixed		version;	/* Version number of the font descriptors
-				 * table (0x00010000 for the current version). */
-  LArrayOf<FontDescriptor>
-		descriptors;	/* List of tagged-coordinate pairs style descriptors
-				 * that will be included to characterize this font.
-				 * Each descriptor consists of a <tag, value> pair.
-				 * These pairs are located in the gxFontDescriptor
-				 * array that follows. */
-  public:
-  DEFINE_SIZE_ARRAY (8, descriptors);
-};
-
-} /* namespace AAT */
-
-
-#endif /* HB_AAT_FDSC_TABLE_HH */
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index ef98884..63fac84 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -54,7 +54,7 @@
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef LArrayOf<Anchor> GlyphAnchors;
+typedef Array32Of<Anchor> GlyphAnchors;
 
 struct ankr
 {
@@ -64,9 +64,9 @@
 			    unsigned int i,
 			    unsigned int num_glyphs) const
   {
-    const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
+    const NNOffset16To<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
     if (!offset)
-      return Null(Anchor);
+      return Null (Anchor);
     const GlyphAnchors &anchors = &(this+anchorData) + *offset;
     return anchors[i];
   }
@@ -81,11 +81,11 @@
   }
 
   protected:
-  HBUINT16	version; 	/* Version number (set to zero) */
+  HBUINT16	version;	/* Version number (set to zero) */
   HBUINT16	flags;		/* Flags (currently unused; set to zero) */
-  LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
+  Offset32To<Lookup<NNOffset16To<GlyphAnchors>>>
 		lookupTable;	/* Offset to the table's lookup table */
-  LNNOffsetTo<HBUINT8>
+  NNOffset32To<HBUINT8>
 		anchorData;	/* Offset to the glyph data table */
 
   public:
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index 15ef2da..b52844e 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -82,7 +82,7 @@
   }
 
   protected:
-  HBGlyphID	stdGlyph;	/* The specific glyph index number in this
+  HBGlyphID16	stdGlyph;	/* The specific glyph index number in this
 				 * font that is used to set the baseline values.
 				 * This is the standard glyph.
 				 * This glyph must contain a set of control points
@@ -101,11 +101,11 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && lookupTable.sanitize (c));
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c)));
   }
 
   protected:
-  HBGlyphID	stdGlyph;	/* ditto */
+  HBGlyphID16	stdGlyph;	/* ditto */
   HBUINT16	ctlPoints[32];	/* ditto */
   Lookup<HBUINT16>
 		lookupTable;	/* Lookup table that maps glyphs to their
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 473f2cd..1dcbe92 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -30,6 +30,9 @@
 #include "hb-aat-layout.hh"
 #include "hb-open-type.hh"
 
+namespace OT {
+struct GDEF;
+};
 
 namespace AAT {
 
@@ -93,8 +96,8 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  HBGlyphID	last;		/* Last GlyphID in this segment */
-  HBGlyphID	first;		/* First GlyphID in this segment */
+  HBGlyphID16	last;		/* Last GlyphID in this segment */
+  HBGlyphID16	first;		/* First GlyphID in this segment */
   T		value;		/* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (4 + T::static_size);
@@ -159,12 +162,12 @@
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  first <= last &&
-		  valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
+		  valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
   }
 
-  HBGlyphID	last;		/* Last GlyphID in this segment */
-  HBGlyphID	first;		/* First GlyphID in this segment */
-  NNOffsetTo<UnsizedArrayOf<T>>
+  HBGlyphID16	last;		/* Last GlyphID in this segment */
+  HBGlyphID16	first;		/* First GlyphID in this segment */
+  NNOffset16To<UnsizedArrayOf<T>>
 		valuesZ;	/* A 16-bit offset from the start of
 				 * the table to the data. */
   public:
@@ -222,7 +225,7 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  HBGlyphID	glyph;		/* Last GlyphID */
+  HBGlyphID16	glyph;		/* Last GlyphID */
   T		value;		/* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (2 + T::static_size);
@@ -284,7 +287,7 @@
 
   protected:
   HBUINT16	format;		/* Format identifier--format = 8 */
-  HBGlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
 				 * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<T>
@@ -303,7 +306,7 @@
   const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
   {
     if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
-      return Null(T);
+      return Null (T);
 
     const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
 
@@ -326,7 +329,7 @@
   protected:
   HBUINT16	format;		/* Format identifier--format = 8 */
   HBUINT16	valueSize;	/* Byte size of each value. */
-  HBGlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
 				 * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<HBUINT8>
@@ -358,7 +361,7 @@
       case 10: return u.format10.get_value_or_null (glyph_id);
       default:
       const T *v = get_value (glyph_id, num_glyphs);
-      return v ? *v : Null(T);
+      return v ? *v : Null (T);
     }
   }
 
@@ -510,7 +513,7 @@
   const Entry<Extra> &get_entry (int state, unsigned int klass) const
   {
     if (unlikely (klass >= nClasses))
-      klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
+      klass = StateTable::CLASS_OUT_OF_BOUNDS;
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -576,7 +579,7 @@
 	  if (unlikely (stop > states))
 	    return_trace (false);
 	  for (const HBUSHORT *p = states; stop < p; p--)
-	    num_entries = hb_max (num_entries, *(p - 1) + 1);
+	    num_entries = hb_max (num_entries, *(p - 1) + 1u);
 	  state_neg = min_state;
 	}
       }
@@ -597,7 +600,7 @@
 	  if (unlikely (stop < states))
 	    return_trace (false);
 	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
-	    num_entries = hb_max (num_entries, *p + 1);
+	    num_entries = hb_max (num_entries, *p + 1u);
 	  state_pos = max_state + 1;
 	}
       }
@@ -658,8 +661,8 @@
     return_trace (c->check_struct (this) && classArray.sanitize (c));
   }
   protected:
-  HBGlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
-  ArrayOf<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
+  HBGlyphID16		firstGlyph;	/* First glyph index included in the trimmed array. */
+  Array16Of<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
 					 * firstGlyph). */
   public:
   DEFINE_SIZE_ARRAY (4, classArray);
@@ -678,7 +681,8 @@
 				     const void *base,
 				     const T *array)
   {
-    return (offset - ((const char *) array - (const char *) base)) / T::static_size;
+    /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
+    return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
   }
   template <typename T>
   static unsigned int byteOffsetToIndex (unsigned int offset,
@@ -729,7 +733,10 @@
 template <typename Types, typename EntryData>
 struct StateTableDriver
 {
-  StateTableDriver (const StateTable<Types, EntryData> &machine_,
+  using StateTableT = StateTable<Types, EntryData>;
+  using EntryT = Entry<EntryData>;
+
+  StateTableDriver (const StateTableT &machine_,
 		    hb_buffer_t *buffer_,
 		    hb_face_t *face_) :
 	      machine (machine_),
@@ -742,59 +749,101 @@
     if (!c->in_place)
       buffer->clear_output ();
 
-    int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
+    int state = StateTableT::STATE_START_OF_TEXT;
     for (buffer->idx = 0; buffer->successful;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
-			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
+			   (unsigned) StateTableT::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
-      const Entry<EntryData> &entry = machine.get_entry (state, klass);
+      const EntryT &entry = machine.get_entry (state, klass);
+      const int next_state = machine.new_state (entry.newState);
 
-      /* Unsafe-to-break before this if not in state 0, as things might
-       * go differently if we start from state 0 here.
+      /* Conditions under which it's guaranteed safe-to-break before current glyph:
        *
-       * Ugh.  The indexing here is ugly... */
-      if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
-      {
-	/* If there's no action and we're just epsilon-transitioning to state 0,
-	 * safe to break. */
-	if (c->is_actionable (this, entry) ||
-	    !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
-	      entry.flags == context_t::DontAdvance))
-	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
-      }
+       * 1. There was no action in this transition; and
+       *
+       * 2. If we break before current glyph, the results will be the same. That
+       *    is guaranteed if:
+       *
+       *    2a. We were already in start-of-text state; or
+       *
+       *    2b. We are epsilon-transitioning to start-of-text state; or
+       *
+       *    2c. Starting from start-of-text state seeing current glyph:
+       *
+       *        2c'. There won't be any actions; and
+       *
+       *        2c". We would end up in the same state that we were going to end up
+       *             in now, including whether epsilon-transitioning.
+       *
+       *    and
+       *
+       * 3. If we break before current glyph, there won't be any end-of-text action
+       *    after previous glyph.
+       *
+       * This triples the transitions we need to look up, but is worth returning
+       * granular unsafe-to-break results. See eg.:
+       *
+       *   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))
+      ;
 
-      /* Unsafe-to-break if end-of-text would kick in here. */
-      if (buffer->idx + 2 <= buffer->len)
-      {
-	const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
-	if (c->is_actionable (this, end_entry))
-	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
-      }
+      if (!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);
 
-      state = machine.new_state (entry.newState);
+      state = next_state;
       DEBUG_MSG (APPLY, nullptr, "s%d", state);
 
-      if (buffer->idx == buffer->len)
+      if (buffer->idx == buffer->len || unlikely (!buffer->successful))
 	break;
 
       if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
     }
 
     if (!c->in_place)
-    {
-      for (; buffer->successful && buffer->idx < buffer->len;)
-	buffer->next_glyph ();
       buffer->swap_buffers ();
-    }
   }
 
   public:
-  const StateTable<Types, EntryData> &machine;
+  const StateTableT &machine;
   hb_buffer_t *buffer;
   unsigned int num_glyphs;
 };
@@ -817,15 +866,15 @@
   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;
-  unsigned int debug_depth;
 
   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
 				      hb_font_t *font_,
 				      hb_buffer_t *buffer_,
-				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
+				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
 
   HB_INTERNAL ~hb_aat_apply_context_t ();
 
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index 788d408..573f0cf 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -129,6 +129,11 @@
 
   hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
 
+  bool is_exclusive () const { return featureFlags & Exclusive; }
+
+  /* A FeatureName with no settings is meaningless */
+  bool has_data () const { return nSettings; }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -139,7 +144,7 @@
   protected:
   HBUINT16	feature;	/* Feature type. */
   HBUINT16	nSettings;	/* The number of records in the setting name array. */
-  LOffsetTo<UnsizedArrayOf<SettingName>, false>
+  NNOffset32To<UnsizedArrayOf<SettingName>>
 		settingTableZ;	/* Offset in bytes from the beginning of this table to
 				 * this feature's setting name array. The actual type of
 				 * record this offset refers to will depend on the
@@ -172,6 +177,9 @@
     return featureNameCount;
   }
 
+  bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
+  { return get_feature (feature_type).has_data (); }
+
   const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
   { return namesZ.bsearch (featureNameCount, feature_type); }
 
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index e1787d1..d745c11 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -51,10 +51,10 @@
     return_trace (likely (c->check_struct (this)));
   }
 
-  HBUINT16 	actionClass; 	/* The JustClass value associated with this
+  HBUINT16	actionClass;	/* The JustClass value associated with this
 				 * ActionSubrecord. */
-  HBUINT16 	actionType; 	/* The type of postcompensation action. */
-  HBUINT16 	actionLength;	/* Length of this ActionSubrecord record, which
+  HBUINT16	actionType;	/* The type of postcompensation action. */
+  HBUINT16	actionLength;	/* Length of this ActionSubrecord record, which
 				 * must be a multiple of 4. */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -70,16 +70,16 @@
 
   ActionSubrecordHeader
 		header;
-  HBFixed		lowerLimit; 	/* If the distance factor is less than this value,
+  HBFixed	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,
+  HBFixed	upperLimit;	/* If the distance factor is greater than this value,
 				 * then the ligature is decomposed. */
-  HBUINT16 	order;		/* Numerical order in which this ligature will
+  HBUINT16	order;		/* Numerical order in which this ligature will
 				 * be decomposed; you may want infrequent ligatures
 				 * to decompose before more frequent ones. The ligatures
 				 * on the line of text will decompose in increasing
 				 * value of this field. */
-  ArrayOf<HBUINT16>
+  Array16Of<HBUINT16>
 		decomposedglyphs;
 				/* Number of 16-bit glyph indexes that follow;
 				 * the ligature will be decomposed into these glyphs.
@@ -100,7 +100,7 @@
   protected:
   ActionSubrecordHeader
 		header;
-  HBGlyphID	addGlyph;	/* Glyph that should be added if the distance factor
+  HBGlyphID16	addGlyph;	/* Glyph that should be added if the distance factor
 				 * is growing. */
 
   public:
@@ -118,14 +118,14 @@
   protected:
   ActionSubrecordHeader
 		header;
-  HBFixed 	substThreshold; /* Distance growth factor (in ems) at which
+  HBFixed	substThreshold; /* Distance growth factor (in ems) at which
 				 * this glyph is replaced and the growth factor
 				 * recalculated. */
-  HBGlyphID 	addGlyph; 	/* Glyph to be added as kashida. If this value is
+  HBGlyphID16	addGlyph;	/* Glyph to be added as kashida. If this value is
 				 * 0xFFFF, no extra glyph will be added. Note that
 				 * generally when a glyph is added, justification
 				 * will need to be redone. */
-  HBGlyphID 	substGlyph; 	/* Glyph to be substituted for this glyph if the
+  HBGlyphID16	substGlyph;	/* Glyph to be substituted for this glyph if the
 				 * growth factor equals or exceeds the value of
 				 * substThreshold. */
   public:
@@ -143,16 +143,16 @@
   protected:
   ActionSubrecordHeader
 		header;
-  HBUINT32 	variationAxis;	/* The 4-byte tag identifying the ductile axis.
+  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 tha
+  HBFixed	minimumLimit;	/* The lowest value for the ductility axis tha
 				 * still yields an acceptable appearance. Normally
 				 * this will be 1.0. */
-  HBFixed 	noStretchValue; /* This is the default value that corresponds to
+  HBFixed	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
+  HBFixed	maximumLimit;	/* The highest value for the ductility axis that
 				 * still yields an acceptable appearance. */
   public:
   DEFINE_SIZE_STATIC (22);
@@ -169,8 +169,8 @@
   protected:
   ActionSubrecordHeader
 		header;
-  HBUINT16 	flags;		/* Currently unused; set to 0. */
-  HBGlyphID 	glyph;		/* Glyph that should be added if the distance factor
+  HBUINT16	flags;		/* Currently unused; set to 0. */
+  HBGlyphID16	glyph;		/* Glyph that should be added if the distance factor
 				 * is growing. */
   public:
   DEFINE_SIZE_STATIC (10);
@@ -271,14 +271,14 @@
   };
 
   protected:
-  HBFixed		beforeGrowLimit;/* The ratio by which the advance width of the
+  HBFixed	beforeGrowLimit;/* The ratio by which the advance width of the
 				 * glyph is permitted to grow on the left or top side. */
-  HBFixed		beforeShrinkLimit;
+  HBFixed	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
+  HBFixed	afterGrowLimit;	/* The ratio by which the advance width of the glyph
 				 * is permitted to shrink on the left or top side. */
-  HBFixed		afterShrinkLimit;
+  HBFixed	afterShrinkLimit;
 				/* The ratio by which the advance width of the glyph
 				 * is at most permitted to shrink on the right or
 				 * bottom side. */
@@ -310,7 +310,7 @@
   DEFINE_SIZE_STATIC (24);
 };
 
-typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
+typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster;
 
 struct JustificationCategory
 {
@@ -358,21 +358,21 @@
   }
 
   protected:
-  OffsetTo<JustificationCategory>
+  Offset16To<JustificationCategory>
 		justClassTable;	/* Offset to the justification category state table. */
-  OffsetTo<WidthDeltaCluster>
-  		wdcTable;	/* Offset from start of justification table to start
+  Offset16To<WidthDeltaCluster>
+		wdcTable;	/* Offset from start of justification table to start
 				 * of the subtable containing the width delta factors
 				 * for the glyphs in your font.
 				 *
 				 * The width delta clusters table. */
-  OffsetTo<PostcompensationActionChain>
+  Offset16To<PostcompensationActionChain>
 		pcTable;	/* Offset from start of justification table to start
 				 * of postcompensation subtable (set to zero if none).
 				 *
 				 * The postcompensation subtable, if present in the font. */
-  Lookup<OffsetTo<WidthDeltaCluster>>
-  		lookupTable;	/* Lookup table associating glyphs with width delta
+  Lookup<Offset16To<WidthDeltaCluster>>
+		lookupTable;	/* Lookup table associating glyphs with width delta
 				 * clusters. See the description of Width Delta Clusters
 				 * table for details on how to interpret the lookup values. */
 
@@ -397,14 +397,14 @@
   protected:
   FixedVersion<>version;	/* Version of the justification table
 				 * (0x00010000u for version 1.0). */
-  HBUINT16	format; 	/* Format of the justification table (set to 0). */
-  OffsetTo<JustificationHeader>
+  HBUINT16	format;		/* Format of the justification table (set to 0). */
+  Offset16To<JustificationHeader>
 		horizData;	/* Byte offset from the start of the justification table
 				 * to the header for tables that contain justification
 				 * information for horizontal text.
 				 * If you are not including this information,
 				 * store 0. */
-  OffsetTo<JustificationHeader>
+  Offset16To<JustificationHeader>
 		vertData;	/* ditto, vertical */
 
   public:
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index be1b339..0354b47 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -82,8 +82,8 @@
   }
 
   protected:
-  HBGlyphID	left;
-  HBGlyphID	right;
+  HBGlyphID16	left;
+  HBGlyphID16	right;
   FWORD		value;
   public:
   DEFINE_SIZE_STATIC (6);
@@ -229,9 +229,7 @@
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			const Entry<EntryData> &entry)
-    {
-      return Format1EntryT::performAction (entry);
-    }
+    { return Format1EntryT::performAction (entry); }
     void transition (StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
@@ -281,35 +279,28 @@
 
 	  hb_glyph_position_t &o = buffer->pos[idx];
 
-	  /* Testing shows that CoreText only applies kern (cross-stream or not)
-	   * if none has been applied by previous subtables.  That is, it does
-	   * NOT seem to accumulate as otherwise implied by specs. */
-
-	  /* The following flag is undocumented in the spec, but described
-	   * in the 'kern' table example. */
-	  if (v == -0x8000)
-	  {
-	    o.attach_type() = ATTACH_TYPE_NONE;
-	    o.attach_chain() = 0;
-	    o.x_offset = o.y_offset = 0;
-	  }
-	  else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+	  if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	  {
 	    if (crossStream)
 	    {
-	      if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset)
+	      /* The following flag is undocumented in the spec, but described
+	       * in the 'kern' table example. */
+	      if (v == -0x8000)
 	      {
-		o.y_offset = c->font->em_scale_y (v);
+		o.attach_type() = ATTACH_TYPE_NONE;
+		o.attach_chain() = 0;
+		o.y_offset = 0;
+	      }
+	      else if (o.attach_type())
+	      {
+		o.y_offset += c->font->em_scale_y (v);
 		buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 	      }
 	    }
 	    else if (buffer->info[idx].mask & kern_mask)
 	    {
-	      if (!buffer->pos[idx].x_offset)
-	      {
-		buffer->pos[idx].x_advance += c->font->em_scale_x (v);
-		buffer->pos[idx].x_offset += c->font->em_scale_x (v);
-	      }
+	      o.x_advance += c->font->em_scale_x (v);
+	      o.x_offset += c->font->em_scale_x (v);
 	    }
 	  }
 	  else
@@ -317,19 +308,22 @@
 	    if (crossStream)
 	    {
 	      /* CoreText doesn't do crossStream kerning in vertical.  We do. */
-	      if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset)
+	      if (v == -0x8000)
 	      {
-		o.x_offset = c->font->em_scale_x (v);
+		o.attach_type() = ATTACH_TYPE_NONE;
+		o.attach_chain() = 0;
+		o.x_offset = 0;
+	      }
+	      else if (o.attach_type())
+	      {
+		o.x_offset += c->font->em_scale_x (v);
 		buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 	      }
 	    }
 	    else if (buffer->info[idx].mask & kern_mask)
 	    {
-	      if (!buffer->pos[idx].y_offset)
-	      {
-		buffer->pos[idx].y_advance += c->font->em_scale_y (v);
-		buffer->pos[idx].y_offset += c->font->em_scale_y (v);
-	      }
+	      o.y_advance += c->font->em_scale_y (v);
+	      o.y_offset += c->font->em_scale_y (v);
 	    }
 	  }
 	}
@@ -488,7 +482,7 @@
     };
 
     driver_context_t (const KerxSubTableFormat4 *table,
-			     hb_aat_apply_context_t *c_) :
+		      hb_aat_apply_context_t *c_) :
 	c (c_),
 	action_type ((table->flags & ActionType) >> 30),
 	ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
@@ -497,9 +491,7 @@
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
 			const Entry<EntryData> &entry)
-    {
-      return entry.data.ankrActionIndex != 0xFFFF;
-    }
+    { return entry.data.ankrActionIndex != 0xFFFF; }
     void transition (StateTableDriver<Types, EntryData> *driver,
 		     const Entry<EntryData> &entry)
     {
@@ -512,11 +504,13 @@
 	{
 	  case 0: /* Control Point Actions.*/
 	  {
-	    /* indexed into glyph outline. */
-	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    /* Indexed into glyph outline. */
+	    /* Each action (record in ankrData) contains two 16-bit fields, so we must
+	       double the ankrActionIndex to get the correct offset here. */
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
 	    if (!c->sanitizer.check_array (data, 2)) return;
-	    HB_UNUSED unsigned int markControlPoint = *data++;
-	    HB_UNUSED unsigned int currControlPoint = *data++;
+	    unsigned int markControlPoint = *data++;
+	    unsigned int currControlPoint = *data++;
 	    hb_position_t markX = 0;
 	    hb_position_t markY = 0;
 	    hb_position_t currX = 0;
@@ -538,8 +532,10 @@
 
 	  case 1: /* Anchor Point Actions. */
 	  {
-	   /* Indexed into 'ankr' table. */
-	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    /* Indexed into 'ankr' table. */
+	    /* Each action (record in ankrData) contains two 16-bit fields, so we must
+	       double the ankrActionIndex to get the correct offset here. */
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
 	    if (!c->sanitizer.check_array (data, 2)) return;
 	    unsigned int markAnchorPoint = *data++;
 	    unsigned int currAnchorPoint = *data++;
@@ -557,7 +553,9 @@
 
 	  case 2: /* Control Point Coordinate Actions. */
 	  {
-	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
+	    /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
+	       by 4 to get the correct offset for the given action. */
+	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
 	    if (!c->sanitizer.check_array (data, 4)) return;
 	    int markX = *data++;
 	    int markY = *data++;
@@ -628,7 +626,7 @@
   bool is_long () const { return flags & ValuesAreLong; }
 
   int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
-			  hb_aat_apply_context_t *c) const
+		   hb_aat_apply_context_t *c) const
   {
     unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
     if (is_long ())
@@ -712,18 +710,18 @@
   {
     struct Long
     {
-      LNNOffsetTo<Lookup<HBUINT32>>		rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT32>>		columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD32>>	array;
+      NNOffset32To<Lookup<HBUINT32>>		rowIndexTable;
+      NNOffset32To<Lookup<HBUINT32>>		columnIndexTable;
+      NNOffset32To<UnsizedArrayOf<FWORD32>>	array;
     } l;
     struct Short
     {
-      LNNOffsetTo<Lookup<HBUINT16>>		rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT16>>		columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD>>	array;
+      NNOffset32To<Lookup<HBUINT16>>		rowIndexTable;
+      NNOffset32To<Lookup<HBUINT16>>		columnIndexTable;
+      NNOffset32To<UnsizedArrayOf<FWORD>>	array;
     } s;
   } u;
-  LNNOffsetTo<UnsizedArrayOf<FWORD>>	vector;
+  NNOffset32To<UnsizedArrayOf<FWORD>>	vector;
   public:
   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
 };
@@ -777,11 +775,11 @@
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:	return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
-    case 1:	return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
-    case 2:	return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
-    case 4:	return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
-    case 6:	return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
+    case 0:	return_trace (c->dispatch (u.format0, std::forward<Ts> (ds)...));
+    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 4:	return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 6:	return_trace (c->dispatch (u.format6, std::forward<Ts> (ds)...));
     default:	return_trace (c->default_return_value ());
     }
   }
@@ -891,7 +889,7 @@
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
-      if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index))
+      if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
 	goto skip;
 
       if (!seenCrossStream &&
@@ -923,7 +921,7 @@
       if (reverse)
 	c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index);
+      (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
 
     skip:
       st = &StructAfter<SubTable> (*st);
diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh
deleted file mode 100644
index 7063b38..0000000
--- a/src/hb-aat-layout-lcar-table.hh
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright © 2018  Ebrahim Byagowi
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
-#define HB_AAT_LAYOUT_LCAR_TABLE_HH
-
-#include "hb-open-type.hh"
-#include "hb-aat-layout-common.hh"
-
-/*
- * lcar -- Ligature caret
- * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
- */
-#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
-
-
-namespace AAT {
-
-typedef ArrayOf<HBINT16> LigCaretClassEntry;
-
-struct lcarFormat0
-{
-  unsigned int get_lig_carets (hb_font_t      *font,
-			       hb_direction_t  direction,
-			       hb_codepoint_t  glyph,
-			       unsigned int    start_offset,
-			       unsigned int   *caret_count /* IN/OUT */,
-			       hb_position_t  *caret_array /* OUT */,
-			       const void     *base) const
-  {
-    const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
-									      font->face->get_num_glyphs ());
-    const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
-    if (caret_count)
-    {
-      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
-      for (unsigned int i = 0; i < arr.length; ++i)
-	caret_array[i] = font->em_scale_dir (arr[i], direction);
-    }
-    return array.len;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
-  }
-
-  protected:
-  Lookup<OffsetTo<LigCaretClassEntry>>
-		lookupTable;	/* data Lookup table associating glyphs */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct lcarFormat1
-{
-  unsigned int get_lig_carets (hb_font_t      *font,
-			       hb_direction_t  direction,
-			       hb_codepoint_t  glyph,
-			       unsigned int    start_offset,
-			       unsigned int   *caret_count /* IN/OUT */,
-			       hb_position_t  *caret_array /* OUT */,
-			       const void     *base) const
-  {
-    const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
-									      font->face->get_num_glyphs ());
-    const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
-    if (caret_count)
-    {
-      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
-      for (unsigned int i = 0; i < arr.length; ++i)
-      {
-	hb_position_t x = 0, y = 0;
-	font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
-	caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
-      }
-    }
-    return array.len;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
-  }
-
-  protected:
-  Lookup<OffsetTo<LigCaretClassEntry>>
-		lookupTable;	/* data Lookup table associating glyphs */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct lcar
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
-
-  unsigned int get_lig_carets (hb_font_t      *font,
-			       hb_direction_t  direction,
-			       hb_codepoint_t  glyph,
-			       unsigned int    start_offset,
-			       unsigned int   *caret_count /* IN/OUT */,
-			       hb_position_t  *caret_array /* OUT */) const
-  {
-    switch (format)
-    {
-    case 0: return u.format0.get_lig_carets (font, direction, glyph, start_offset,
-					     caret_count, caret_array, this);
-    case 1: return u.format1.get_lig_carets (font, direction, glyph, start_offset,
-					     caret_count, caret_array, this);
-    default:if (caret_count) *caret_count = 0; return 0;
-    }
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this) || version.major != 1))
-      return_trace (false);
-
-    switch (format) {
-    case 0: return_trace (u.format0.sanitize (c, this));
-    case 1: return_trace (u.format1.sanitize (c, this));
-    default:return_trace (true);
-    }
-  }
-
-  protected:
-  FixedVersion<>version;	/* Version number of the ligature caret table */
-  HBUINT16	format;		/* Format of the ligature caret table. */
-  union {
-  lcarFormat0	format0;
-  lcarFormat0	format1;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (8);
-};
-
-} /* namespace AAT */
-
-#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index d8df579..b77c1f4 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -30,6 +30,7 @@
 #include "hb-open-type.hh"
 #include "hb-aat-layout-common.hh"
 #include "hb-ot-layout-common.hh"
+#include "hb-ot-layout-gdef-table.hh"
 #include "hb-aat-map.hh"
 
 /*
@@ -215,7 +216,9 @@
 			     hb_aat_apply_context_t *c_) :
 	ret (false),
 	c (c_),
+	gdef (*c->gdef_table),
 	mark_set (false),
+	has_glyph_classes (gdef.has_glyph_classes ()),
 	mark (0),
 	table (table_),
 	subs (table+table->substitutionTables) {}
@@ -240,21 +243,21 @@
       if (buffer->idx == buffer->len && !mark_set)
 	return;
 
-      const HBGlyphID *replacement;
+      const HBGlyphID16 *replacement;
 
       replacement = nullptr;
       if (Types::extended)
       {
 	if (entry.data.markIndex != 0xFFFF)
 	{
-	  const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex];
+	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
 	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
-	const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
+	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
 	  replacement = nullptr;
@@ -263,6 +266,9 @@
       {
 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
 	buffer->info[mark].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
 
@@ -272,14 +278,14 @@
       {
 	if (entry.data.currentIndex != 0xFFFF)
 	{
-	  const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex];
+	  const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
 	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
-	const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
+	const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
 	  replacement = nullptr;
@@ -287,6 +293,9 @@
       if (replacement)
       {
 	buffer->info[idx].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
 
@@ -301,10 +310,12 @@
     bool ret;
     private:
     hb_aat_apply_context_t *c;
+    const OT::GDEF &gdef;
     bool mark_set;
+    bool has_glyph_classes;
     unsigned int mark;
     const ContextualSubtable *table;
-    const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
+    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false> &subs;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -337,9 +348,9 @@
       const EntryData &data = entries[i].data;
 
       if (data.markIndex != 0xFFFF)
-	num_lookups = hb_max (num_lookups, 1 + data.markIndex);
+	num_lookups = hb_max (num_lookups, 1u + data.markIndex);
       if (data.currentIndex != 0xFFFF)
-	num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
+	num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
     }
 
     return_trace (substitutionTables.sanitize (c, this, num_lookups));
@@ -348,7 +359,7 @@
   protected:
   StateTable<Types, EntryData>
 		machine;
-  NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
+  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT>
 		substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
@@ -499,7 +510,7 @@
 	  }
 
 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
-	  buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
+	  if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
 
 	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
 	  action = *actionData;
@@ -520,30 +531,30 @@
 	  if (action & (LigActionStore | LigActionLast))
 	  {
 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
-	    const HBGlyphID &ligatureData = ligature[ligature_idx];
+	    const HBGlyphID16 &ligatureData = ligature[ligature_idx];
 	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
-	    buffer->replace_glyph (lig);
+	    if (unlikely (!buffer->replace_glyph (lig))) return;
 
 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
 	    while (match_length - 1u > cursor)
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
-	      buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
-	      buffer->replace_glyph (DELETED_GLYPH);
+	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
 	    }
 
-	    buffer->move_to (lig_end);
+	    if (unlikely (!buffer->move_to (lig_end))) return;
 	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
 	  }
 
 	  actionData++;
 	}
 	while (!(action & LigActionLast));
-	buffer->move_to (end);
+	if (unlikely (!buffer->move_to (end))) return;
       }
     }
 
@@ -554,7 +565,7 @@
     const LigatureSubtable *table;
     const UnsizedArrayOf<HBUINT32> &ligAction;
     const UnsizedArrayOf<HBUINT16> &component;
-    const UnsizedArrayOf<HBGlyphID> &ligature;
+    const UnsizedArrayOf<HBGlyphID16> &ligature;
     unsigned int match_length;
     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   };
@@ -586,7 +597,7 @@
 		ligAction;	/* Offset to the ligature action table. */
   NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
 		component;	/* Offset to the component table. */
-  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
 		ligature;	/* Offset to the actual ligature lists. */
   public:
   DEFINE_SIZE_STATIC (28);
@@ -599,6 +610,9 @@
   {
     TRACE_APPLY (this);
 
+    const OT::GDEF &gdef (*c->gdef_table);
+    bool has_glyph_classes = gdef.has_glyph_classes ();
+
     bool ret = false;
     unsigned int num_glyphs = c->face->get_num_glyphs ();
 
@@ -606,10 +620,13 @@
     unsigned int count = c->buffer->len;
     for (unsigned int i = 0; i < count; i++)
     {
-      const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
+      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
 	info[i].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&info[i],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
     }
@@ -624,7 +641,7 @@
   }
 
   protected:
-  Lookup<HBGlyphID>	substitute;
+  Lookup<HBGlyphID16>	substitute;
   public:
   DEFINE_SIZE_MIN (2);
 };
@@ -725,24 +742,24 @@
       if (entry.data.markedInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & MarkedInsertCount);
+	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
 	unsigned int start = entry.data.markedInsertIndex;
-	const HBGlyphID *glyphs = &insertionAction[start];
+	const HBGlyphID16 *glyphs = &insertionAction[start];
 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & MarkedInsertBefore;
 
 	unsigned int end = buffer->out_len;
-	buffer->move_to (mark);
+	if (unlikely (!buffer->move_to (mark))) return;
 
 	if (buffer->idx < buffer->len && !before)
-	  buffer->copy_glyph ();
+	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	for (unsigned int i = 0; i < count; i++)
-	  buffer->output_glyph (glyphs[i]);
+	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
-	buffer->move_to (end + count);
+	if (unlikely (!buffer->move_to (end + count))) return;
 
 	buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
       }
@@ -753,8 +770,9 @@
       if (entry.data.currentInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & CurrentInsertCount) >> 5;
+	if (unlikely ((buffer->max_ops -= count) <= 0)) return;
 	unsigned int start = entry.data.currentInsertIndex;
-	const HBGlyphID *glyphs = &insertionAction[start];
+	const HBGlyphID16 *glyphs = &insertionAction[start];
 	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & CurrentInsertBefore;
@@ -762,10 +780,9 @@
 	unsigned int end = buffer->out_len;
 
 	if (buffer->idx < buffer->len && !before)
-	  buffer->copy_glyph ();
+	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	for (unsigned int i = 0; i < count; i++)
-	  buffer->output_glyph (glyphs[i]);
+	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
@@ -784,7 +801,7 @@
 	 *
 	 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
 	 */
-	buffer->move_to ((flags & DontAdvance) ? end : end + count);
+	if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
       }
     }
 
@@ -793,7 +810,7 @@
     private:
     hb_aat_apply_context_t *c;
     unsigned int mark;
-    const UnsizedArrayOf<HBGlyphID> &insertionAction;
+    const UnsizedArrayOf<HBGlyphID16> &insertionAction;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -819,7 +836,7 @@
   protected:
   StateTable<Types, EntryData>
 		machine;
-  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
 		insertionAction;	/* Byte offset from stateHeader to the start of
 					 * the insertion glyph table. */
   public:
@@ -889,11 +906,11 @@
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case Rearrangement:		return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
-    case Contextual:		return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
-    case Ligature:		return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
-    case Noncontextual:		return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
-    case Insertion:		return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
+    case Rearrangement:		return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
+    case Contextual:		return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
+    case Ligature:		return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
+    case Noncontextual:		return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
+    case Insertion:		return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
     default:			return_trace (c->default_return_value ());
     }
   }
@@ -948,8 +965,10 @@
 	hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
 	hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
       retry:
-	const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
-	if (info && info->setting == setting)
+	// 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))
 	{
 	  flags &= feature.disableFlags;
 	  flags |= feature.enableFlags;
@@ -967,7 +986,7 @@
   }
 
   void apply (hb_aat_apply_context_t *c,
-		     hb_mask_t flags) const
+	      hb_mask_t flags) const
   {
     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
@@ -1015,7 +1034,7 @@
 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
-      if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
 	goto skip;
 
       if (reverse)
@@ -1026,7 +1045,7 @@
       if (reverse)
 	c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
 
       if (unlikely (!c->buffer->successful)) return;
 
diff --git a/src/hb-aat-layout-opbd-table.hh b/src/hb-aat-layout-opbd-table.hh
index 4e02340..b1a1512 100644
--- a/src/hb-aat-layout-opbd-table.hh
+++ b/src/hb-aat-layout-opbd-table.hh
@@ -58,7 +58,7 @@
   bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
 		   hb_glyph_extents_t *extents, const void *base) const
   {
-    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
     if (!bounds_offset) return false;
     const OpticalBounds &bounds = base+*bounds_offset;
 
@@ -79,7 +79,7 @@
   }
 
   protected:
-  Lookup<OffsetTo<OpticalBounds>>
+  Lookup<Offset16To<OpticalBounds>>
 		lookupTable;	/* Lookup table associating glyphs with the four
 				 * int16 values for the left-side, top-side,
 				 * right-side, and bottom-side optical bounds. */
@@ -92,7 +92,7 @@
   bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
 		   hb_glyph_extents_t *extents, const void *base) const
   {
-    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
     if (!bounds_offset) return false;
     const OpticalBounds &bounds = base+*bounds_offset;
 
@@ -116,7 +116,7 @@
   }
 
   protected:
-  Lookup<OffsetTo<OpticalBounds>>
+  Lookup<Offset16To<OpticalBounds>>
 		lookupTable;	/* Lookup table associating glyphs with the four
 				 * int16 values for the left-side, top-side,
 				 * right-side, and bottom-side optical bounds. */
@@ -160,8 +160,8 @@
 				 * Format 0 indicates distance and Format 1 indicates
 				 * control point. */
   union {
-  opbdFormat0 format0;
-  opbdFormat1 format1;
+  opbdFormat0	format0;
+  opbdFormat1	format1;
   } u;
   public:
   DEFINE_SIZE_MIN (8);
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index 99dddd8..68bcb23 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -62,11 +62,11 @@
   }
 
   protected:
-  HBFixed		track;		/* Track value for this record. */
+  HBFixed	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") */
-  NNOffsetTo<UnsizedArrayOf<FWORD>>
+  NNOffset16To<UnsizedArrayOf<FWORD>>
 		valuesZ;	/* Offset from start of tracking table to
 				 * per-size tracking values for this track. */
 
@@ -141,7 +141,7 @@
   protected:
   HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
   HBUINT16	nSizes;		/* Number of point sizes included in this table. */
-  LOffsetTo<UnsizedArrayOf<HBFixed>, false>
+  NNOffset32To<UnsizedArrayOf<HBFixed>>
 		sizeTable;	/* Offset from start of the tracking table to
 				 * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>
@@ -210,12 +210,12 @@
 
   protected:
   FixedVersion<>version;	/* Version of the tracking table
-					 * (0x00010000u for version 1.0). */
-  HBUINT16	format; 	/* Format of the tracking table (set to 0). */
-  OffsetTo<TrackData>
+				 * (0x00010000u for version 1.0). */
+  HBUINT16	format;		/* Format of the tracking table (set to 0). */
+  Offset16To<TrackData>
 		horizData;	/* Offset from start of tracking table to TrackData
 				 * for horizontal text (or 0 if none). */
-  OffsetTo<TrackData>
+  Offset16To<TrackData>
 		vertData;	/* Offset from start of tracking table to TrackData
 				 * for vertical text (or 0 if none). */
   HBUINT16	reserved;	/* Reserved. Set to 0. */
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 4e506de..e2d4de2 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -28,7 +28,6 @@
 #include "hb.hh"
 
 #include "hb-aat-layout.hh"
-#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-ankr-table.hh"
 #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-feat-table.hh"
@@ -55,9 +54,9 @@
 						       face (font->face),
 						       buffer (buffer_),
 						       sanitizer (),
-						       ankr_table (&Null(AAT::ankr)),
-						       lookup_index (0),
-						       debug_depth (0)
+						       ankr_table (&Null (AAT::ankr)),
+						       gdef_table (face->table.GDEF->table),
+						       lookup_index (0)
 {
   sanitizer.init (blob);
   sanitizer.set_num_glyphs (face->get_num_glyphs ());
@@ -81,13 +80,18 @@
  * @short_description: Apple Advanced Typography Layout
  * @include: hb-aat.h
  *
- * Functions for querying OpenType Layout features in the font face.
+ * Functions for querying AAT Layout features in the font face.
+ *
+ * HarfBuzz supports all of the AAT tables used to implement shaping. Other
+ * AAT tables and their associated features are not supported.
  **/
 
 
 #if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
 
-/* Table data courtesy of Apple.  Converted from mnemonics to integers
+/* Mapping from OpenType feature tags to AAT feature names and selectors.
+ *
+ * Table data courtesy of Apple.  Converted from mnemonics to integers
  * when moving to this file. */
 static const hb_aat_feature_mapping_t feature_mappings[] =
 {
@@ -169,14 +173,21 @@
   {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},
 };
 
+/**
+ * hb_aat_layout_find_feature_mapping:
+ * @tag: The requested #hb_tag_t feature tag
+ *
+ * Fetches the AAT feature-and-selector combination that corresponds
+ * to a given OpenType feature tag.
+ *
+ * Return value: the AAT features and selectors corresponding to the
+ * OpenType feature tag queried
+ *
+ **/
 const hb_aat_feature_mapping_t *
 hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 {
-  return (const hb_aat_feature_mapping_t *) hb_bsearch (&tag,
-							feature_mappings,
-							ARRAY_LENGTH (feature_mappings),
-							sizeof (feature_mappings[0]),
-							hb_aat_feature_mapping_t::cmp);
+  return hb_sorted_array (feature_mappings).bsearch (tag);
 }
 #endif
 
@@ -208,11 +219,17 @@
 }
 
 
-/*
+/**
  * hb_aat_layout_has_substitution:
- * @face:
+ * @face: #hb_face_t to work upon
  *
- * Returns:
+ * Tests whether the specified face includes any substitutions in the
+ * `morx` or `mort` tables.
+ *
+ * <note>Note: does not examine the `GSUB` table.</note>
+ *
+ * Return value: %true if data found, %false otherwise
+ *
  * Since: 2.3.0
  */
 hb_bool_t
@@ -232,7 +249,9 @@
   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);
+    (void) buffer->message (font, "end table morx");
     return;
   }
 
@@ -241,7 +260,9 @@
   if (mort.has_data ())
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
+    if (!buffer->message (font, "start table mort")) return;
     mort.apply (&c);
+    (void) buffer->message (font, "end table mort");
     return;
   }
 }
@@ -269,11 +290,17 @@
   hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
 }
 
-/*
+/**
  * hb_aat_layout_has_positioning:
- * @face:
+ * @face: #hb_face_t to work upon
  *
- * Returns:
+ * Tests whether the specified face includes any positioning information
+ * in the `kerx` table.
+ *
+ * <note>Note: does not examine the `GPOS` table.</note>
+ *
+ * Return value: %true if data found, %false otherwise
+ *
  * Since: 2.3.0
  */
 hb_bool_t
@@ -291,16 +318,22 @@
   const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
+  if (!buffer->message (font, "start table kerx")) return;
   c.set_ankr_table (font->face->table.ankr.get ());
   kerx.apply (&c);
+  (void) buffer->message (font, "end table kerx");
 }
 
 
-/*
+/**
  * hb_aat_layout_has_tracking:
- * @face:
+ * @face:: #hb_face_t to work upon
  *
- * Returns:
+ * Tests whether the specified face includes any tracking information
+ * in the `trak` table.
+ *
+ * Return value: %true if data found, %false otherwise
+ *
  * Since: 2.3.0
  */
 hb_bool_t
@@ -322,10 +355,13 @@
 
 /**
  * hb_aat_layout_get_feature_types:
- * @face: a face object
- * @start_offset: iteration's start offset
- * @feature_count:(inout) (allow-none): buffer size as input, filled size as output
- * @features: (out caller-allocates) (array length=feature_count): features buffer
+ * @face: #hb_face_t to work upon
+ * @start_offset: offset of the first feature type to retrieve
+ * @feature_count: (inout) (optional): Input = the maximum number of feature types to return;
+ *                 Output = the actual number of feature types returned (may be zero)
+ * @features: (out caller-allocates) (array length=feature_count): Array of feature types found
+ *
+ * Fetches a list of the AAT feature types included in the specified face.
  *
  * Return value: Number of all available feature types.
  *
@@ -342,10 +378,12 @@
 
 /**
  * hb_aat_layout_feature_type_get_name_id:
- * @face: a face object
- * @feature_type: feature id
+ * @face: #hb_face_t to work upon
+ * @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
  *
- * Return value: Name ID index
+ * Fetches the name identifier of the specified feature type in the face's `name` table.
+ *
+ * Return value: Name identifier of the requested feature type
  *
  * Since: 2.2.0
  */
@@ -357,19 +395,23 @@
 }
 
 /**
- * hb_aat_layout_feature_type_get_selectors:
- * @face:    a face object
- * @feature_type: feature id
- * @start_offset:    iteration's start offset
- * @selector_count: (inout) (allow-none): buffer size as input, filled size as output
- * @selectors: (out caller-allocates) (array length=selector_count): settings buffer
- * @default_index: (out) (allow-none): index of default selector if any
+ * hb_aat_layout_feature_type_get_selector_infos:
+ * @face: #hb_face_t to work upon
+ * @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
+ * @start_offset: offset of the first feature type to retrieve
+ * @selector_count: (inout) (optional): Input = the maximum number of selectors to return;
+ *                  Output = the actual number of selectors returned (may be zero)
+ * @selectors: (out caller-allocates) (array length=selector_count) (optional):
+ *             A buffer pointer. The selectors available for the feature type queries.
+ * @default_index: (out) (optional): The index of the feature's default selector, if any
+ *
+ * Fetches a list of the selectors available for the specified feature in the given face.
  *
  * If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then
  * the feature type is non-exclusive.  Otherwise, @default_index is the index of
  * the selector that is selected by default.
  *
- * Return value: Number of all available feature selectors.
+ * Return value: Number of all available feature selectors
  *
  * Since: 2.2.0
  */
diff --git a/src/hb-aat-layout.h b/src/hb-aat-layout.h
index b617e8b..9af2740 100644
--- a/src/hb-aat-layout.h
+++ b/src/hb-aat-layout.h
@@ -22,7 +22,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_AAT_H_IN
+#if !defined(HB_AAT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-aat.h> instead."
 #endif
 
@@ -37,7 +37,48 @@
 
 /**
  * hb_aat_layout_feature_type_t:
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING: [Number Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type6)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE: [Smart Swash](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type8)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE: [Diacritics](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type9)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION: [Vertical Position](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type10)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS: [Fractions](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type11)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE: [Overlapping Characters](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type13)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS: [Typographic Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type14)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS: [Mathematical Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type15)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE: [Ornament Sets](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type16)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES: [Character Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type17)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE: [Design Complexity](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type18)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS: [Style Options](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type19)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE: [Character Shape](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type20)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE: [Number Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type21)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING: [Text Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type22)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION: [Transliteration](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type23)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE: [Annotation](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type24)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE: [Kana Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type25)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE: [Ideographic Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type26)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE: [Unicode Decomposition](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type27)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA: [Ruby Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type28)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE: [CJK Symbol Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type29)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE: [Ideographic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type30)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE: [CJK Vertical Roman Placement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type31)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN: [Italic CJK Roman](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type32)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT: [Case Sensitive Layout](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type33)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA: [Alternate Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type34)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES: [Stylistic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type35)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES: [Contextual Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type36)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE: [Lower Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type37)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE: [Upper Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type38)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE: [Language Tag](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type39)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE: [CJK Roman Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type103)
  *
+ * The possible feature types defined for AAT shaping, from Apple [Font Feature Registry](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html).
  *
  * Since: 2.2.0
  */
@@ -85,12 +126,265 @@
   HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE			= 39,
   HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE		= 103,
 
+  /*< private >*/
   _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_type_t;
 
 /**
  * hb_aat_layout_feature_selector_t:
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID: Initial, unset feature selector
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS: Deprecated
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE
+ * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE
  *
+ * The selectors defined for specifying AAT feature settings.
  *
  * Since: 2.2.0
  */
@@ -424,6 +718,7 @@
   HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN		= 2,
   HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN		= 3,
 
+  /*< private >*/
   _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_selector_t;
 
@@ -437,8 +732,15 @@
 hb_aat_layout_feature_type_get_name_id (hb_face_t                    *face,
 					hb_aat_layout_feature_type_t  feature_type);
 
-typedef struct hb_aat_layout_feature_selector_info_t
-{
+/**
+ * hb_aat_layout_feature_selector_info_t:
+ * @name_id: The selector's name identifier
+ * @enable: The value to turn the selector on
+ * @disable: The value to turn the selector off
+ *
+ * Structure representing a setting for an #hb_aat_layout_feature_type_t.
+ */
+typedef struct hb_aat_layout_feature_selector_info_t {
   hb_ot_name_id_t			name_id;
   hb_aat_layout_feature_selector_t	enable;
   hb_aat_layout_feature_selector_t	disable;
@@ -446,6 +748,13 @@
   unsigned int				reserved;
 } hb_aat_layout_feature_selector_info_t;
 
+/**
+ * HB_AAT_LAYOUT_NO_SELECTOR_INDEX
+ *
+ * Used when getting or setting AAT feature selectors. Indicates that
+ * there is no selector index corresponding to the selector of interest.
+ *
+ */
 #define HB_AAT_LAYOUT_NO_SELECTOR_INDEX		0xFFFFu
 
 HB_EXTERN unsigned int
diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh
index 8310bfc..5e4e3bd 100644
--- a/src/hb-aat-layout.hh
+++ b/src/hb-aat-layout.hh
@@ -39,14 +39,8 @@
   hb_aat_layout_feature_selector_t selectorToEnable;
   hb_aat_layout_feature_selector_t selectorToDisable;
 
-  HB_INTERNAL static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (unsigned int *) key_;
-    const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
-    return key < entry->otFeatureTag ? -1 :
-	   key > entry->otFeatureTag ? 1 :
-	   0;
-  }
+  int cmp (hb_tag_t key) const
+  { return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
 };
 
 HB_INTERNAL const hb_aat_feature_mapping_t *
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 711f9aa..6d771e1 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -50,7 +50,7 @@
   }
 
   protected:
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
 		tag;		/* Offset from the start of the table to
 				 * the beginning of the string */
   HBUINT16	length;		/* String length (in bytes) */
@@ -80,7 +80,7 @@
   protected:
   HBUINT32	version;	/* Table version; currently 1 */
   HBUINT32	flags;		/* Table flags; currently none defined */
-  LArrayOf<FTStringRange>
+  Array32Of<FTStringRange>
 		tagRanges;	/* Range for each tag's string */
   public:
   DEFINE_SIZE_ARRAY (12, tagRanges);
diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc
index bc87935..2c38c35 100644
--- a/src/hb-aat-map.cc
+++ b/src/hb-aat-map.cc
@@ -33,25 +33,48 @@
 #include "hb-aat-map.hh"
 
 #include "hb-aat-layout.hh"
+#include "hb-aat-layout-feat-table.hh"
 
 
-void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
-					unsigned int value)
+void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
 {
+  if (!face->table.feat->has_data ()) return;
+
   if (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;
     return;
   }
 
   const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
   if (!mapping) return;
 
+  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
+  if (!feature->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.
+     * https://github.com/harfbuzz/harfbuzz/issues/2307 */
+    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;
+    }
+    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 ();
 }
 
 void
@@ -63,7 +86,11 @@
     features.qsort ();
     unsigned int j = 0;
     for (unsigned int i = 1; i < features.length; i++)
-      if (features[i].type != features[j].type)
+      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);
   }
diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh
index 984a59c..5a0fa70 100644
--- a/src/hb-aat-map.hh
+++ b/src/hb-aat-map.hh
@@ -64,19 +64,24 @@
   {
     hb_aat_layout_feature_type_t  type;
     hb_aat_layout_feature_selector_t  setting;
+    bool is_exclusive;
     unsigned  seq; /* For stable sorting only. */
 
     HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const feature_info_t *a = (const feature_info_t *) pa;
       const feature_info_t *b = (const feature_info_t *) pb;
-      return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
-	     (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
+      if (a->type != b->type) return (a->type < b->type ? -1 : 1);
+      if (!a->is_exclusive &&
+	  (a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1);
+	    return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
     }
 
-    int cmp (hb_aat_layout_feature_type_t ty) const
+    /* compares type & setting only, not is_exclusive flag or seq number */
+    int cmp (const feature_info_t& f) const
     {
-      return (type != ty) ? (type < ty ? -1 : 1) : 0;
+      return (f.type != type) ? (f.type < type ? -1 : 1) :
+	     (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
     }
   };
 
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 042e1c2..446d87e 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -34,6 +34,135 @@
 #include "hb-null.hh"
 #include "hb-number.hh"
 
+#include <algorithm>
+#include <initializer_list>
+#include <new>
+
+/*
+ * Flags
+ */
+
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another...  So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+ * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+	extern "C++" { \
+	  static inline 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 T& operator |= (T &l, T r) { l = l | r; return l; } \
+	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+	} \
+	static_assert (true, "")
+
+/* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+#define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
+#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
+#define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x))
+#define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
+#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
+
+
+/*
+ * Big-endian integers.
+ */
+
+/* Endian swap, used in Windows related backends */
+static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+template <typename Type, int Bytes = sizeof (Type)>
+struct BEInt;
+template <typename Type>
+struct BEInt<Type, 1>
+{
+  public:
+  BEInt () = default;
+  constexpr BEInt (Type V) : v {uint8_t (V)} {}
+  constexpr operator Type () const { return v; }
+  private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+  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 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+    return ((packed_uint16_t *) this)->v;
+#endif
+#else
+    return (v[0] <<  8)
+	 + (v[1]      );
+#endif
+  }
+  private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+  static_assert (!std::is_signed<Type>::value, "");
+  public:
+  BEInt () = default;
+  constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
+				uint8_t ((V >>  8) & 0xFF),
+				uint8_t ((V      ) & 0xFF)} {}
+
+  constexpr operator Type () const { return (v[0] << 16)
+					  + (v[1] <<  8)
+					  + (v[2]      ); }
+  private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+  public:
+  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]      ); }
+  private: uint8_t v[4];
+};
+
+/* Floats. */
+
+/* We want our rounding towards +infinity. */
+static inline float
+_hb_roundf (float x) { return floorf (x + .5f); }
+#define roundf(x) _hb_roundf(x)
+
 
 /* Encodes three unsigned integers in one 64-bit number.  If the inputs have more than 21 bits,
  * values will be truncated / overlap, and might not decode exactly. */
@@ -48,11 +177,12 @@
 #define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
 #define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
 
+
 struct
 {
   /* Note.  This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
   template <typename T> constexpr auto
-  operator () (T&& v) const HB_AUTO_RETURN ( hb_forward<T> (v) )
+  operator () (T&& v) const HB_AUTO_RETURN ( std::forward<T> (v) )
 }
 HB_FUNCOBJ (hb_identity);
 struct
@@ -76,7 +206,7 @@
 struct
 {
   template <typename T> constexpr bool
-  operator () (T&& v) const { return bool (hb_forward<T> (v)); }
+  operator () (T&& v) const { return bool (std::forward<T> (v)); }
 }
 HB_FUNCOBJ (hb_bool);
 
@@ -88,7 +218,7 @@
   impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
 
   template <typename T,
-	    hb_enable_if (hb_is_integral (T))> constexpr auto
+	    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: */
@@ -110,26 +240,26 @@
   /* Pointer-to-member-function. */
   template <typename Appl, typename T, typename ...Ts> auto
   impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
-  ((hb_deref (hb_forward<T> (v)).*hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+  ((hb_deref (std::forward<T> (v)).*std::forward<Appl> (a)) (std::forward<Ts> (ds)...))
 
   /* Pointer-to-member. */
   template <typename Appl, typename T> auto
   impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
-  ((hb_deref (hb_forward<T> (v))).*hb_forward<Appl> (a))
+  ((hb_deref (std::forward<T> (v))).*std::forward<Appl> (a))
 
   /* Operator(). */
   template <typename Appl, typename ...Ts> auto
   impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
-  (hb_deref (hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+  (hb_deref (std::forward<Appl> (a)) (std::forward<Ts> (ds)...))
 
   public:
 
   template <typename Appl, typename ...Ts> auto
   operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
   (
-    impl (hb_forward<Appl> (a),
+    impl (std::forward<Appl> (a),
 	  hb_prioritize,
-	  hb_forward<Ts> (ds)...)
+	  std::forward<Ts> (ds)...)
   )
 }
 HB_FUNCOBJ (hb_invoke);
@@ -148,9 +278,9 @@
 						   hb_declval (V),
 						   hb_declval (Ts)...))
   {
-    return hb_invoke (hb_forward<Appl> (a),
-		      hb_forward<V> (v),
-		      hb_forward<Ts> (ds)...);
+    return hb_invoke (std::forward<Appl> (a),
+		      std::forward<V> (v),
+		      std::forward<Ts> (ds)...);
   }
   template <typename T0, typename ...Ts,
 	    unsigned P = Pos,
@@ -160,10 +290,10 @@
 							    hb_declval (V),
 							    hb_declval (Ts)...))
   {
-    return hb_invoke (hb_forward<Appl> (a),
-		      hb_forward<T0> (d0),
-		      hb_forward<V> (v),
-		      hb_forward<Ts> (ds)...);
+    return hb_invoke (std::forward<Appl> (a),
+		      std::forward<T0> (d0),
+		      std::forward<V> (v),
+		      std::forward<Ts> (ds)...);
   }
 
   private:
@@ -197,14 +327,14 @@
 #define HB_PARTIALIZE(Pos) \
   template <typename _T> \
   decltype(auto) operator () (_T&& _v) const \
-  { return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
+  { return hb_partial<Pos> (this, std::forward<_T> (_v)); } \
   static_assert (true, "")
 #else
 /* https://github.com/harfbuzz/harfbuzz/issues/1724 */
 #define HB_PARTIALIZE(Pos) \
   template <typename _T> \
   auto operator () (_T&& _v) const HB_AUTO_RETURN \
-  (hb_partial<Pos> (+this, hb_forward<_T> (_v))) \
+  (hb_partial<Pos> (+this, std::forward<_T> (_v))) \
   static_assert (true, "")
 #endif
 
@@ -215,21 +345,23 @@
 
   template <typename Pred, typename Val> auto
   impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
-  (hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
+  (
+    hb_deref (std::forward<Pred> (p)).has (std::forward<Val> (v))
+  )
 
   template <typename Pred, typename Val> auto
   impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
   (
-    hb_invoke (hb_forward<Pred> (p),
-	       hb_forward<Val> (v))
+    hb_invoke (std::forward<Pred> (p),
+	       std::forward<Val> (v))
   )
 
   public:
 
   template <typename Pred, typename Val> auto
   operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
-    impl (hb_forward<Pred> (p),
-	  hb_forward<Val> (v),
+    impl (std::forward<Pred> (p),
+	  std::forward<Val> (v),
 	  hb_prioritize)
   )
 }
@@ -242,22 +374,22 @@
   template <typename Pred, typename Val> auto
   impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
   (
-    hb_has (hb_forward<Pred> (p),
-	    hb_forward<Val> (v))
+    hb_has (std::forward<Pred> (p),
+	    std::forward<Val> (v))
   )
 
   template <typename Pred, typename Val> auto
   impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
   (
-    hb_forward<Pred> (p) == hb_forward<Val> (v)
+    std::forward<Pred> (p) == std::forward<Val> (v)
   )
 
   public:
 
   template <typename Pred, typename Val> auto
   operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
-    impl (hb_forward<Pred> (p),
-	  hb_forward<Val> (v),
+    impl (std::forward<Pred> (p),
+	  std::forward<Val> (v),
 	  hb_prioritize)
   )
 }
@@ -269,19 +401,21 @@
 
   template <typename Proj, typename Val> auto
   impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
-  (hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
+  (
+    hb_deref (std::forward<Proj> (f)).get (std::forward<Val> (v))
+  )
 
   template <typename Proj, typename Val> auto
   impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
   (
-    hb_invoke (hb_forward<Proj> (f),
-	       hb_forward<Val> (v))
+    hb_invoke (std::forward<Proj> (f),
+	       std::forward<Val> (v))
   )
 
   template <typename Proj, typename Val> auto
   impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
   (
-    hb_forward<Proj> (f)[hb_forward<Val> (v)]
+    std::forward<Proj> (f)[std::forward<Val> (v)]
   )
 
   public:
@@ -289,13 +423,47 @@
   template <typename Proj, typename Val> auto
   operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN
   (
-    impl (hb_forward<Proj> (f),
-	  hb_forward<Val> (v),
+    impl (std::forward<Proj> (f),
+	  std::forward<Val> (v),
 	  hb_prioritize)
   )
 }
 HB_FUNCOBJ (hb_get);
 
+struct
+{
+  private:
+
+  template <typename T1, typename T2> auto
+  impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
+  (
+    std::forward<T2> (v2).cmp (std::forward<T1> (v1)) == 0
+  )
+
+  template <typename T1, typename T2> auto
+  impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
+  (
+    std::forward<T1> (v1).cmp (std::forward<T2> (v2)) == 0
+  )
+
+  template <typename T1, typename T2> auto
+  impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    std::forward<T1> (v1) == std::forward<T2> (v2)
+  )
+
+  public:
+
+  template <typename T1, typename T2> auto
+  operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN
+  (
+    impl (std::forward<T1> (v1),
+	  std::forward<T2> (v2),
+	  hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_equal);
+
 
 template <typename T1, typename T2>
 struct hb_pair_t
@@ -350,17 +518,34 @@
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (hb_forward<T> (a) <= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+  (a <= b ? std::forward<T> (a) : std::forward<T2> (b))
 }
 HB_FUNCOBJ (hb_min);
 struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (hb_forward<T> (a) >= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+  (a >= b ? std::forward<T> (a) : std::forward<T2> (b))
 }
 HB_FUNCOBJ (hb_max);
+struct
+{
+  template <typename T, typename T2, typename T3> constexpr auto
+  operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN
+  (hb_min (hb_max (std::forward<T> (x), std::forward<T2> (min)), std::forward<T3> (max)))
+}
+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.
@@ -368,7 +553,7 @@
 
 /* Return the number of 1 bits in v. */
 template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
 hb_popcount (T v)
 {
 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
@@ -409,7 +594,7 @@
 
 /* Returns the number of bits needed to store number */
 template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
 hb_bit_storage (T v)
 {
   if (unlikely (!v)) return 0;
@@ -483,10 +668,10 @@
 
 /* Returns the number of zero bits in the least significant side of v */
 template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
 hb_ctz (T v)
 {
-  if (unlikely (!v)) return 0;
+  if (unlikely (!v)) return 8 * sizeof (T);
 
 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
   if (sizeof (T) <= sizeof (unsigned int))
@@ -570,6 +755,12 @@
 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
 static inline unsigned char TOLOWER (unsigned char c)
 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
+static inline bool ISHEX (unsigned char c)
+{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
+static inline unsigned char TOHEX (uint8_t c)
+{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; }
+static inline uint8_t FROMHEX (unsigned char c)
+{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
 
 static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
 { return (a + (b - 1)) / b; }
@@ -582,6 +773,14 @@
 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
 
 
+static inline void *
+hb_memcpy (void *__restrict dst, const void *__restrict src, size_t len)
+{
+  /* It's illegal to pass 0 as size to memcpy. */
+  if (unlikely (!len)) return dst;
+  return memcpy (dst, src, len);
+}
+
 static inline int
 hb_memcmp (const void *a, const void *b, unsigned int len)
 {
@@ -600,12 +799,6 @@
   return memset (s, c, n);
 }
 
-static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
-{
-  return (size > 0) && (count >= ((unsigned int) -1) / size);
-}
-
 static inline unsigned int
 hb_ceil_to_4 (unsigned int v)
 {
@@ -615,7 +808,7 @@
 template <typename T> static inline bool
 hb_in_range (T u, T lo, T hi)
 {
-  static_assert (!hb_is_signed<T>::value, "");
+  static_assert (!std::is_signed<T>::value, "");
 
   /* The casts below are important as if T is smaller than int,
    * the subtract results will become a signed int! */
@@ -634,29 +827,90 @@
 
 
 /*
+ * Overflow checking.
+ */
+
+/* Consider __builtin_mul_overflow use here also */
+static inline bool
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+{
+  return (size > 0) && (count >= ((unsigned int) -1) / size);
+}
+
+
+/*
  * Sort and search.
  */
-template <typename ...Ts>
-static inline void *
-hb_bsearch (const void *key, const void *base,
-	    size_t nmemb, size_t size,
-	    int (*compar)(const void *_key, const void *_item, Ts... _ds),
-	    Ts... ds)
+
+template <typename K, typename V, typename ...Ts>
+static int
+_hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
 {
+  const K& key = * (const K*) pkey;
+  const V& val = * (const V*) pval;
+
+  return val.cmp (key, ds...);
+}
+
+template <typename V, typename K, typename ...Ts>
+static inline bool
+hb_bsearch_impl (unsigned *pos, /* Out */
+		 const K& key,
+		 V* base, size_t nmemb, size_t stride,
+		 int (*compar)(const void *_key, const void *_item, Ts... _ds),
+		 Ts... ds)
+{
+  /* This is our *only* bsearch implementation. */
+
   int min = 0, max = (int) nmemb - 1;
   while (min <= max)
   {
     int mid = ((unsigned int) min + (unsigned int) max) / 2;
-    const void *p = (const void *) (((const char *) base) + (mid * size));
-    int c = compar (key, p, ds...);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+    V* p = (V*) (((const char *) base) + (mid * stride));
+#pragma GCC diagnostic pop
+    int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...);
     if (c < 0)
       max = mid - 1;
     else if (c > 0)
       min = mid + 1;
     else
-      return (void *) p;
+    {
+      *pos = mid;
+      return true;
+    }
   }
-  return nullptr;
+  *pos = min;
+  return false;
+}
+
+template <typename V, typename K>
+static inline V*
+hb_bsearch (const K& key, V* base,
+	    size_t nmemb, size_t stride = sizeof (V),
+	    int (*compar)(const void *_key, const void *_item) = _hb_cmp_method<K, V>)
+{
+  unsigned pos;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ?
+	 (V*) (((const char *) base) + (pos * stride)) : nullptr;
+#pragma GCC diagnostic pop
+}
+template <typename V, typename K, typename ...Ts>
+static inline V*
+hb_bsearch (const K& key, V* base,
+	    size_t nmemb, size_t stride,
+	    int (*compar)(const void *_key, const void *_item, Ts... _ds),
+	    Ts... ds)
+{
+  unsigned pos;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ?
+	 (V*) (((const char *) base) + (pos * stride)) : nullptr;
+#pragma GCC diagnostic pop
 }
 
 
@@ -918,38 +1172,48 @@
 
 /* Operators. */
 
-struct hb_bitwise_and
+struct
 { HB_PARTIALIZE(2);
-  static constexpr bool passthru_left = false;
-  static constexpr bool passthru_right = false;
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
 }
 HB_FUNCOBJ (hb_bitwise_and);
-struct hb_bitwise_or
+struct
 { HB_PARTIALIZE(2);
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = true;
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
 }
 HB_FUNCOBJ (hb_bitwise_or);
-struct hb_bitwise_xor
+struct
 { HB_PARTIALIZE(2);
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = true;
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
 }
 HB_FUNCOBJ (hb_bitwise_xor);
-struct hb_bitwise_sub
+struct
 { HB_PARTIALIZE(2);
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = false;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
+}
+HB_FUNCOBJ (hb_bitwise_lt);
+struct
+{ HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
 }
-HB_FUNCOBJ (hb_bitwise_sub);
+HB_FUNCOBJ (hb_bitwise_gt); // aka sub
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
+}
+HB_FUNCOBJ (hb_bitwise_le);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
+}
+HB_FUNCOBJ (hb_bitwise_ge);
 struct
 {
   template <typename T> constexpr auto
@@ -972,6 +1236,12 @@
 struct
 { HB_PARTIALIZE(2);
   template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
+}
+HB_FUNCOBJ (hb_rsub);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
 }
 HB_FUNCOBJ (hb_mul);
diff --git a/src/hb-array.hh b/src/hb-array.hh
index d9adf2c..dd61509 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -36,16 +36,24 @@
 template <typename Type>
 struct hb_sorted_array_t;
 
+enum hb_not_found_t
+{
+  HB_NOT_FOUND_DONT_STORE,
+  HB_NOT_FOUND_STORE,
+  HB_NOT_FOUND_STORE_CLOSEST,
+};
+
+
 template <typename Type>
 struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 {
   /*
    * Constructors.
    */
-  hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
-  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
+  hb_array_t () = default;
+  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
   template <unsigned int length_>
-  hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
+  hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {}
 
   template <typename U,
 	    hb_enable_if (hb_is_cr_convertible(U, Type))>
@@ -129,20 +137,45 @@
   template <typename T>
   Type *lsearch (const T &x, Type *not_found = nullptr)
   {
-    unsigned int count = length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!this->arrayZ[i].cmp (x))
-	return &this->arrayZ[i];
-    return not_found;
+    unsigned i;
+    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
   }
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   {
-    unsigned int count = length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!this->arrayZ[i].cmp (x))
-	return &this->arrayZ[i];
-    return not_found;
+    unsigned i;
+    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
+  }
+  template <typename T>
+  bool lfind (const T &x, unsigned *pos = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
+  {
+    for (unsigned i = 0; i < length; ++i)
+      if (hb_equal (x, this->arrayZ[i]))
+      {
+	if (pos)
+	  *pos = i;
+	return true;
+      }
+
+    if (pos)
+    {
+      switch (not_found)
+      {
+	case HB_NOT_FOUND_DONT_STORE:
+	  break;
+
+	case HB_NOT_FOUND_STORE:
+	  *pos = to_store;
+	  break;
+
+	case HB_NOT_FOUND_STORE_CLOSEST:
+	  *pos = length;
+	  break;
+      }
+    }
+    return false;
   }
 
   hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
@@ -171,6 +204,24 @@
 
   unsigned int get_size () const { return length * this->get_item_size (); }
 
+  /*
+   * Reverse the order of items in this array in the range [start, end).
+   */
+  void reverse (unsigned start = 0, unsigned end = -1)
+  {
+    start = hb_min (start, length);
+    end = hb_min (end, length);
+
+    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;
+    }
+  }
+
   hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
   {
     if (!start_offset && !seg_count)
@@ -194,20 +245,21 @@
 	    unsigned P = sizeof (Type),
 	    hb_enable_if (P == 1)>
   const T *as () const
-  { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
+  { return length < hb_min_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
 
   template <typename T,
 	    unsigned P = sizeof (Type),
 	    hb_enable_if (P == 1)>
-  bool in_range (const T *p, unsigned int size = T::static_size) const
+  bool check_range (const T *p, unsigned int size = T::static_size) const
   {
-    return ((const char *) p) >= arrayZ
-	&& ((const char *) p + size) <= arrayZ + length;
+    return arrayZ <= ((const char *) p)
+	&& ((const char *) p) <= arrayZ + length
+	&& (unsigned int) (arrayZ + length - (const char *) p) >= size;
   }
 
-  /* Only call if you allocated the underlying array using malloc() or similar. */
-  void free ()
-  { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
+  /* Only call if you allocated the underlying array using hb_malloc() or similar. */
+  void fini ()
+  { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
 
   template <typename hb_serialize_context_t>
   hb_array_t copy (hb_serialize_context_t *c) const
@@ -229,9 +281,9 @@
    */
 
   public:
-  Type *arrayZ;
-  unsigned int length;
-  unsigned int backwards_length;
+  Type *arrayZ = nullptr;
+  unsigned int length = 0;
+  unsigned int backwards_length = 0;
 };
 template <typename T> inline hb_array_t<T>
 hb_array (T *array, unsigned int length)
@@ -240,13 +292,6 @@
 hb_array (T (&array_)[length_])
 { return hb_array_t<T> (array_); }
 
-enum hb_bfind_not_found_t
-{
-  HB_BFIND_NOT_FOUND_DONT_STORE,
-  HB_BFIND_NOT_FOUND_STORE,
-  HB_BFIND_NOT_FOUND_STORE_CLOSEST,
-};
-
 template <typename Type>
 struct hb_sorted_array_t :
 	hb_iter_t<hb_sorted_array_t<Type>, Type&>,
@@ -257,7 +302,7 @@
   static constexpr bool is_random_access_iterator = true;
   static constexpr bool is_sorted_iterator = true;
 
-  hb_sorted_array_t () : hb_array_t<Type> () {}
+  hb_sorted_array_t () = default;
   hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
   template <unsigned int length_>
   hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
@@ -297,46 +342,46 @@
   }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   {
-    int min = 0, max = (int) this->length - 1;
-    const Type *array = this->arrayZ;
-    while (min <= max)
+    unsigned pos;
+
+    if (bsearch_impl (x, &pos))
     {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      int c = array[mid].cmp (x);
-      if (c < 0)
-	max = mid - 1;
-      else if (c > 0)
-	min = mid + 1;
-      else
-      {
-	if (i)
-	  *i = mid;
-	return true;
-      }
+      if (i)
+	*i = pos;
+      return true;
     }
+
     if (i)
     {
       switch (not_found)
       {
-	case HB_BFIND_NOT_FOUND_DONT_STORE:
+	case HB_NOT_FOUND_DONT_STORE:
 	  break;
 
-	case HB_BFIND_NOT_FOUND_STORE:
+	case HB_NOT_FOUND_STORE:
 	  *i = to_store;
 	  break;
 
-	case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
-	  if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
-	    max++;
-	  *i = max;
+	case HB_NOT_FOUND_STORE_CLOSEST:
+	  *i = pos;
 	  break;
       }
     }
     return false;
   }
+  template <typename T>
+  bool bsearch_impl (const T &x, unsigned *pos) const
+  {
+    return hb_bsearch_impl (pos,
+			    x,
+			    this->arrayZ,
+			    this->length,
+			    sizeof (Type),
+			    _hb_cmp_method<T, Type>);
+  }
 };
 template <typename T> inline hb_sorted_array_t<T>
 hb_sorted_array (T *array, unsigned int length)
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index b3fb296..e640d1b 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -52,7 +52,7 @@
 
 #elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
 
-/* C++11-style GCC primitives. */
+/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
 
 #define _hb_memory_barrier()			__sync_synchronize ()
 
@@ -73,7 +73,8 @@
 }
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	_hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
 
-#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
+
+#elif !defined(HB_NO_MT)
 
 /* C++11 atomics. */
 
@@ -101,131 +102,12 @@
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	_hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
 
 
-#elif !defined(HB_NO_MT) && defined(_WIN32)
-
-#include <windows.h>
-
-static inline void _hb_memory_barrier ()
-{
-#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
-  /* MinGW has a convoluted history of supporting MemoryBarrier. */
-  LONG dummy = 0;
-  InterlockedExchange (&dummy, 1);
-#else
-  MemoryBarrier ();
-#endif
-}
-#define _hb_memory_barrier()			_hb_memory_barrier ()
-
-#define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd ((LONG *) (AI), (V))
-static_assert ((sizeof (LONG) == sizeof (int)), "");
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-#define _hb_memory_barrier()			__sync_synchronize ()
-
-#define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
-
-#include <atomic.h>
-#include <mbarrier.h>
-
-#define _hb_memory_r_barrier()			__machine_r_barrier ()
-#define _hb_memory_w_barrier()			__machine_w_barrier ()
-#define _hb_memory_barrier()			__machine_rw_barrier ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
-  _hb_memory_w_barrier ();
-  int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
-  _hb_memory_r_barrier ();
-  return result;
-}
-static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
-{
-  _hb_memory_w_barrier ();
-  bool result = atomic_cas_ptr (P, O, N) == O;
-  _hb_memory_r_barrier ();
-  return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V)           _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)       _hb_compare_and_swap_ptr ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(__APPLE__)
-
-#include <libkern/OSAtomic.h>
-#ifdef __MAC_OS_X_MIN_REQUIRED
-#include <AvailabilityMacros.h>
-#elif defined(__IPHONE_OS_MIN_REQUIRED)
-#include <Availability.h>
-#endif
-
-#define _hb_memory_barrier()			OSMemoryBarrier ()
-
-#define hb_atomic_int_impl_add(AI, V)		(OSAtomicAdd32Barrier ((V), (AI)) - (V))
-
-#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
-#else
-#if __ppc64__ || __x86_64__ || __aarch64__
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
-#else
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
-#endif
-#endif
-
-
-#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
-
-#include <builtins.h>
-
-#define _hb_memory_barrier()			__lwsync ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
-  _hb_memory_barrier ();
-  int result = __fetch_and_add (AI, V);
-  _hb_memory_barrier ();
-  return result;
-}
-static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
-{
-  _hb_memory_barrier ();
-  bool result = __compare_and_swaplp (P, &O, N);
-  _hb_memory_barrier ();
-  return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V)           _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)       _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N))
-static_assert ((sizeof (long) == sizeof (void *)), "");
-
-
-#elif defined(HB_NO_MT)
+#else /* defined(HB_NO_MT) */
 
 #define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
-
 #define _hb_memory_barrier()			do {} while (0)
-
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
-
-#else
-
-#error "Could not find any system to define atomic_int macros."
-#error "Check hb-atomic.hh for possible resolutions."
-
 #endif
 
 
@@ -259,9 +141,11 @@
 #endif
 
 
-#define HB_ATOMIC_INT_INIT(V)          {V}
 struct hb_atomic_int_t
 {
+  hb_atomic_int_t () = default;
+  constexpr hb_atomic_int_t (int v) : v (v) {}
+
   void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
   void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
   int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
@@ -269,16 +153,17 @@
   int inc () { return hb_atomic_int_impl_add (&v,  1); }
   int dec () { return hb_atomic_int_impl_add (&v, -1); }
 
-  int v;
+  int v = 0;
 };
 
-
-#define HB_ATOMIC_PTR_INIT(V)          {V}
 template <typename P>
 struct hb_atomic_ptr_t
 {
   typedef hb_remove_pointer<P> T;
 
+  hb_atomic_ptr_t () = default;
+  constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+
   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); }
@@ -288,7 +173,7 @@
   T * operator -> () const                    { return get (); }
   template <typename C> operator C * () const { return get (); }
 
-  T *v;
+  T *v = nullptr;
 };
 
 
diff --git a/src/hb-bimap.hh b/src/hb-bimap.hh
index cae0a4d..d466af8 100644
--- a/src/hb-bimap.hh
+++ b/src/hb-bimap.hh
@@ -33,15 +33,14 @@
 /* Bi-directional map */
 struct hb_bimap_t
 {
-  hb_bimap_t () { init (); }
-  ~hb_bimap_t () { fini (); }
-
+  /* XXX(remove) */
   void init ()
   {
     forw_map.init ();
     back_map.init ();
   }
 
+  /* XXX(remove) */
   void fini ()
   {
     forw_map.fini ();
@@ -58,10 +57,15 @@
 
   void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
   {
+    if (in_error ()) return;
     if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
     if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
+
     forw_map.set (lhs, rhs);
+    if (in_error ()) return;
+
     back_map.set (rhs, lhs);
+    if (in_error ()) forw_map.del (lhs);
   }
 
   hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
@@ -94,14 +98,6 @@
 /* Inremental bimap: only lhs is given, rhs is incrementally assigned */
 struct hb_inc_bimap_t : hb_bimap_t
 {
-  hb_inc_bimap_t () { init (); }
-
-  void init ()
-  {
-    hb_bimap_t::init ();
-    next_value = 0;
-  }
-
   /* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
    * Return the rhs value as the result.
    */
@@ -151,16 +147,16 @@
 
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
       work[rhs] = back_map[rhs];
-  
+
     work.qsort (cmp_id);
-  
+
     clear ();
     for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
       set (work[rhs], rhs);
   }
 
   protected:
-  unsigned int	next_value;
+  unsigned int next_value = 0;
 };
 
 #endif /* HB_BIMAP_HH */
diff --git a/src/hb-bit-page.hh b/src/hb-bit-page.hh
new file mode 100644
index 0000000..263be3d
--- /dev/null
+++ b/src/hb-bit-page.hh
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 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
+ */
+
+#ifndef HB_BIT_PAGE_HH
+#define HB_BIT_PAGE_HH
+
+#include "hb.hh"
+
+struct hb_bit_page_t
+{
+  void init0 () { v.clear (); }
+  void init1 () { v.clear (0xFF); }
+
+  constexpr unsigned len () const
+  { return ARRAY_LENGTH_CONST (v); }
+
+  bool is_empty () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return false;
+    return true;
+  }
+
+  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); }
+  bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
+
+  void add_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);
+    else
+    {
+      *la |= ~(mask (a) - 1);
+      la++;
+
+      memset (la, 0xff, (char *) lb - (char *) la);
+
+      *lb |= ((mask (b) << 1) - 1);
+    }
+  }
+  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));
+    else
+    {
+      *la &= mask (a) - 1;
+      la++;
+
+      memset (la, 0, (char *) lb - (char *) la);
+
+      *lb &= ~((mask (b) << 1) - 1);
+    }
+  }
+  void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
+  { if (v) add_range (a, b); else del_range (a, b); }
+
+  bool is_equal (const hb_bit_page_t &other) const
+  {
+    return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+  }
+  bool is_subset (const hb_bit_page_t &larger_page) const
+  {
+    for (unsigned i = 0; i < len (); i++)
+      if (~larger_page.v[i] & v[i])
+	return false;
+    return true;
+  }
+
+  unsigned int get_population () const
+  {
+    unsigned int pop = 0;
+    for (unsigned int i = 0; i < len (); i++)
+      pop += hb_popcount (v[i]);
+    return pop;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint + 1) & MASK;
+    if (!m)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
+    for (const elt_t *p = &vv; i < len (); p = &v[++i])
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_min (*p);
+	return true;
+      }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint - 1) & MASK;
+    if (m == MASK)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
+    const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
+		       ((elt_t (1) << (j + 1)) - 1) :
+		       (elt_t) -1;
+    const elt_t vv = v[i] & mask;
+    const elt_t *p = &vv;
+    while (true)
+    {
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_max (*p);
+	return true;
+      }
+      if ((int) i <= 0) break;
+      p = &v[--i];
+    }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  hb_codepoint_t get_min () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return i * ELT_BITS + elt_get_min (v[i]);
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    for (int i = len () - 1; i >= 0; i--)
+      if (v[i])
+	return i * ELT_BITS + elt_get_max (v[i]);
+    return 0;
+  }
+
+  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+  typedef unsigned long long elt_t;
+  static constexpr unsigned PAGE_BITS = 512;
+  static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+
+  static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
+  static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
+
+  typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
+
+  static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+  static constexpr unsigned BITS = sizeof (vector_t) * 8;
+  static constexpr unsigned MASK = BITS - 1;
+  static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
+
+  elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
+  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); }
+
+  vector_t v;
+};
+static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
+
+
+#endif /* HB_BIT_PAGE_HH */
diff --git a/src/hb-bit-set-invertible.hh b/src/hb-bit-set-invertible.hh
new file mode 100644
index 0000000..0832b0f
--- /dev/null
+++ b/src/hb-bit-set-invertible.hh
@@ -0,0 +1,364 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 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
+ */
+
+#ifndef HB_BIT_SET_INVERTIBLE_HH
+#define HB_BIT_SET_INVERTIBLE_HH
+
+#include "hb.hh"
+#include "hb-bit-set.hh"
+
+
+struct hb_bit_set_invertible_t
+{
+  hb_bit_set_t s;
+  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& operator= (const hb_bit_set_invertible_t& o) = default;
+  hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& o) = default;
+  friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
+  {
+    if (likely (!a.s.successful || !b.s.successful))
+      return;
+    hb_swap (a.inverted, b.inverted);
+    hb_swap (a.s, b.s);
+  }
+
+  void init () { s.init (); inverted = false; }
+  void fini () { s.fini (); }
+  void err () { s.err (); }
+  bool in_error () const { return s.in_error (); }
+  explicit operator bool () const { return !is_empty (); }
+
+  void reset ()
+  {
+    s.reset ();
+    inverted = false;
+  }
+  void clear ()
+  {
+    s.clear ();
+    if (likely (s.successful))
+      inverted = false;
+  }
+  void invert ()
+  {
+    if (likely (s.successful))
+      inverted = !inverted;
+  }
+
+  bool is_empty () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v == INVALID;
+  }
+  hb_codepoint_t get_min () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v;
+  }
+  hb_codepoint_t get_max () const
+  {
+    hb_codepoint_t v = INVALID;
+    previous (&v);
+    return v;
+  }
+  unsigned int get_population () const
+  { return inverted ? INVALID - s.get_population () : s.get_population (); }
+
+
+  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); }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return inverted ? s.del_sorted_array (array, count, stride) : s.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 ()); }
+
+  void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  { unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
+
+  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; }
+  /* 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)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+
+  void set (const hb_bit_set_invertible_t &other)
+  {
+    s.set (other.s);
+    if (likely (s.successful))
+      inverted = other.inverted;
+  }
+
+  bool is_equal (const hb_bit_set_invertible_t &other) const
+  {
+    if (likely (inverted == other.inverted))
+      return s.is_equal (other.s);
+    else
+    {
+      /* TODO Add iter_ranges() and use here. */
+      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; }));
+    }
+  }
+
+  bool is_subset (const hb_bit_set_invertible_t &larger_set) const
+  {
+    if (unlikely (inverted != larger_set.inverted))
+      return hb_all (hb_iter (s) | hb_map (larger_set.s));
+    else
+      return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
+  }
+
+  protected:
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_invertible_t &other)
+  { s.process (op, other.s); }
+  public:
+  void union_ (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_and, other);
+      else
+	process (hb_bitwise_or, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_gt, other);
+      else
+	process (hb_bitwise_lt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted || other.inverted;
+  }
+  void intersect (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && other.inverted;
+  }
+  void subtract (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && !other.inverted;
+  }
+  void symmetric_difference (const hb_bit_set_invertible_t &other)
+  {
+    process (hb_bitwise_xor, other);
+    if (likely (s.successful))
+      inverted = inverted ^ other.inverted;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.next (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old + 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.next (&v);
+    if (old + 1 < v)
+    {
+      *codepoint = old + 1;
+      return true;
+    }
+
+    v = old;
+    s.next_range (&old, &v);
+
+    *codepoint = v + 1;
+    return *codepoint != INVALID;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.previous (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old - 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.previous (&v);
+
+    if (old - 1 > v || v == INVALID)
+    {
+      *codepoint = old - 1;
+      return true;
+    }
+
+    v = old;
+    s.previous_range (&v, &old);
+
+    *codepoint = v - 1;
+    return *codepoint != INVALID;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.next_range (first, last);
+
+    if (!next (last))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *first = *last;
+    s.next (last);
+    --*last;
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.previous_range (first, last);
+
+    if (!previous (first))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *last = *first;
+    s.previous (first);
+    ++*first;
+    return true;
+  }
+
+  static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = 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)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () 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; }
+
+    protected:
+    const hb_bit_set_invertible_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+};
+
+
+#endif /* HB_BIT_SET_INVERTIBLE_HH */
diff --git a/src/hb-bit-set.hh b/src/hb-bit-set.hh
new file mode 100644
index 0000000..a471ee4
--- /dev/null
+++ b/src/hb-bit-set.hh
@@ -0,0 +1,817 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 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
+ */
+
+#ifndef HB_BIT_SET_HH
+#define HB_BIT_SET_HH
+
+#include "hb.hh"
+#include "hb-bit-page.hh"
+#include "hb-machinery.hh"
+
+
+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 ( 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; }
+  friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
+  {
+    if (likely (!a.successful || !b.successful))
+      return;
+    hb_swap (a.population, b.population);
+    hb_swap (a.last_page_lookup, b.last_page_lookup);
+    hb_swap (a.page_map, b.page_map);
+    hb_swap (a.pages, b.pages);
+  }
+
+  void init ()
+  {
+    successful = true;
+    population = 0;
+    last_page_lookup = 0;
+    page_map.init ();
+    pages.init ();
+  }
+  void fini ()
+  {
+    page_map.fini ();
+    pages.fini ();
+  }
+
+  using page_t = hb_bit_page_t;
+  struct page_map_t
+  {
+    int cmp (const page_map_t &o) const { return cmp (o.major); }
+    int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
+
+    uint32_t major;
+    uint32_t index;
+  };
+
+  bool successful = true; /* Allocations successful */
+  mutable unsigned int population = 0;
+  mutable unsigned int 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)
+  {
+    if (unlikely (!successful)) return false;
+    if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+    {
+      pages.resize (page_map.length);
+      successful = false;
+      return false;
+    }
+    return true;
+  }
+
+  void reset ()
+  {
+    successful = true;
+    clear ();
+  }
+
+  void clear ()
+  {
+    resize (0);
+    if (likely (successful))
+      population = 0;
+  }
+  bool is_empty () const
+  {
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      if (!pages[i].is_empty ())
+	return false;
+    return true;
+  }
+  explicit operator bool () const { return !is_empty (); }
+
+  private:
+  void dirty () { population = UINT_MAX; }
+  public:
+
+  void add (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (g == INVALID)) return;
+    dirty ();
+    page_t *page = page_for (g, true); if (unlikely (!page)) return;
+    page->add (g);
+  }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    if (ma == mb)
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, b);
+    }
+    else
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, major_start (ma + 1) - 1);
+
+      for (unsigned int m = ma + 1; m < mb; m++)
+      {
+	page = page_for (major_start (m), true); if (unlikely (!page)) return false;
+	page->init1 ();
+      }
+
+      page = page_for (b, true); if (unlikely (!page)) return false;
+      page->add_range (major_start (mb), b);
+    }
+    return true;
+  }
+
+  template <typename T>
+  void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (!successful)) return;
+    if (!count) return;
+    dirty ();
+    hb_codepoint_t g = *array;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
+      unsigned int start = major_start (m);
+      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. */
+	  page->set (g, v);
+
+	array = &StructAtOffsetUnaligned<T> (array, stride);
+	count--;
+      }
+      while (count && (g = *array, start <= g && g < end));
+    }
+  }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (true, array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  template <typename T>
+  void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (false, array, count, stride); }
+  template <typename T>
+  void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename 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;
+    dirty ();
+    hb_codepoint_t g = *array;
+    hb_codepoint_t last_g = g;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
+      unsigned int end = major_start (m + 1);
+      do
+      {
+	/* If we try harder we can change the following comparison to <=;
+	 * Not sure if it's worth it. */
+	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. */
+	  page->add (g);
+
+	array = (const T *) ((const char *) array + stride);
+	count--;
+      }
+      while (count && (g = *array, g < end));
+    }
+    return true;
+  }
+
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (true, 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 ()); }
+
+  template <typename T>
+  bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (false, array, count, stride); }
+  template <typename T>
+  bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
+
+  void del (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    page_t *page = page_for (g);
+    if (!page)
+      return;
+    dirty ();
+    page->del (g);
+  }
+
+  private:
+  void del_pages (int ds, int de)
+  {
+    if (ds <= de)
+    {
+      // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+      // before attempting to rewrite the page map.
+      hb_vector_t<unsigned> compact_workspace;
+      if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+      unsigned int write_index = 0;
+      for (unsigned int i = 0; i < page_map.length; i++)
+      {
+	int m = (int) page_map[i].major;
+	if (m < ds || de < m)
+	  page_map[write_index++] = page_map[i];
+      }
+      compact (compact_workspace, write_index);
+      resize (write_index);
+    }
+  }
+
+
+  public:
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (a > b || a == INVALID)) return;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    /* Delete pages from ds through de if ds <= de. */
+    int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
+    int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
+    if (ds > de || (int) ma < ds)
+    {
+      page_t *page = page_for (a);
+      if (page)
+      {
+	if (ma == mb)
+	  page->del_range (a, b);
+	else
+	  page->del_range (a, major_start (ma + 1) - 1);
+      }
+    }
+    if (de < (int) mb && ma != mb)
+    {
+      page_t *page = page_for (b);
+      if (page)
+	page->del_range (major_start (mb), b);
+    }
+    del_pages (ds, de);
+  }
+
+  bool get (hb_codepoint_t g) const
+  {
+    const page_t *page = page_for (g);
+    if (!page)
+      return false;
+    return page->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; }
+  /* 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)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+  void set (const hb_bit_set_t &other)
+  {
+    if (unlikely (!successful)) return;
+    unsigned int count = other.pages.length;
+    if (unlikely (!resize (count)))
+      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);
+  }
+
+  bool is_equal (const hb_bit_set_t &other) const
+  {
+    if (has_population () && other.has_population () &&
+	get_population () != other.get_population ())
+      return false;
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_at (a).is_empty ()) { a++; continue; }
+      if (other.page_at (b).is_empty ()) { b++; continue; }
+      if (page_map[a].major != other.page_map[b].major ||
+	  !page_at (a).is_equal (other.page_at (b)))
+	return false;
+      a++;
+      b++;
+    }
+    for (; a < na; a++)
+      if (!page_at (a).is_empty ()) { return false; }
+    for (; b < nb; b++)
+      if (!other.page_at (b).is_empty ()) { return false; }
+
+    return true;
+  }
+
+  bool is_subset (const hb_bit_set_t &larger_set) const
+  {
+    if (has_population () && larger_set.has_population () &&
+	get_population () != larger_set.get_population ())
+      return false;
+
+    uint32_t spi = 0;
+    for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
+    {
+      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;
+
+      if (lpm < spm)
+        continue;
+
+      if (!sp.is_subset (lp))
+        return false;
+
+      spi++;
+    }
+
+    while (spi < page_map.length)
+      if (!page_at (spi++).is_empty ())
+        return false;
+
+    return true;
+  }
+
+  private:
+  bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
+  {
+    if (unlikely (!workspace.resize (pages.length)))
+    {
+      successful = false;
+      return false;
+    }
+
+    return true;
+  }
+
+  /*
+   * workspace should be a pre-sized vector allocated to hold at exactly pages.length
+   * elements.
+   */
+  void compact (hb_vector_t<unsigned>& workspace,
+                unsigned int length)
+  {
+    assert(workspace.length == pages.length);
+    hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
+
+    hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
+    for (unsigned i = 0; i < length; i++)
+      old_index_to_page_map_index[page_map[i].index] =  i;
+
+    compact_pages (old_index_to_page_map_index);
+  }
+  void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
+  {
+    unsigned int write_index = 0;
+    for (unsigned int i = 0; i < pages.length; i++)
+    {
+      if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
+
+      if (write_index < i)
+	pages[write_index] = pages[i];
+
+      page_map[old_index_to_page_map_index[i]].index = write_index;
+      write_index++;
+    }
+  }
+  public:
+
+  template <typename Op>
+  void process (const Op& op, 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 ();
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+    unsigned int next_page = na;
+
+    unsigned int count = 0, newCount = 0;
+    unsigned int a = 0, b = 0;
+    unsigned int write_index = 0;
+
+    // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+    // before attempting to rewrite the page map.
+    hb_vector_t<unsigned> compact_workspace;
+    if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+    for (; a < na && b < nb; )
+    {
+      if (page_map[a].major == other.page_map[b].major)
+      {
+	if (!passthru_left)
+	{
+	  // Move page_map entries that we're keeping from the left side set
+	  // to the front of the page_map vector. This isn't necessary if
+	  // passthru_left is set since no left side pages will be removed
+	  // in that case.
+	  if (write_index < a)
+	    page_map[write_index] = page_map[a];
+	  write_index++;
+	}
+
+	count++;
+	a++;
+	b++;
+      }
+      else if (page_map[a].major < other.page_map[b].major)
+      {
+	if (passthru_left)
+	  count++;
+	a++;
+      }
+      else
+      {
+	if (passthru_right)
+	  count++;
+	b++;
+      }
+    }
+    if (passthru_left)
+      count += na - a;
+    if (passthru_right)
+      count += nb - b;
+
+    if (!passthru_left)
+    {
+      na  = write_index;
+      next_page = write_index;
+      compact (compact_workspace, write_index);
+    }
+
+    if (unlikely (!resize (count)))
+      return;
+
+    newCount = count;
+
+    /* Process in-place backward. */
+    a = na;
+    b = nb;
+    for (; a && b; )
+    {
+      if (page_map[a - 1].major == other.page_map[b - 1].major)
+      {
+	a--;
+	b--;
+	count--;
+	page_map[count] = page_map[a];
+	page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+      }
+      else if (page_map[a - 1].major > other.page_map[b - 1].major)
+      {
+	a--;
+	if (passthru_left)
+	{
+	  count--;
+	  page_map[count] = page_map[a];
+	}
+      }
+      else
+      {
+	b--;
+	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;
+	}
+      }
+    }
+    if (passthru_left)
+      while (a)
+      {
+	a--;
+	count--;
+	page_map[count] = page_map [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;
+      }
+    assert (!count);
+    resize (newCount);
+  }
+
+  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); }
+  void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
+  void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
+
+  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;
+    }
+
+    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) {
+        *codepoint = INVALID;
+        return false;
+      }
+    }
+
+    const auto* pages_array = pages.arrayZ;
+    const page_map_t &current = page_map_array[i];
+    if (likely (current.major == major))
+    {
+      if (pages_array[current.index].next (codepoint))
+      {
+        *codepoint += current.major * page_t::PAGE_BITS;
+        last_page_lookup = i;
+        return true;
+      }
+      i++;
+    }
+
+    for (; i < page_map.length; i++)
+    {
+      const page_map_t &current = page_map.arrayZ[i];
+      hb_codepoint_t m = pages_array[current.index].get_min ();
+      if (m != INVALID)
+      {
+	*codepoint = current.major * page_t::PAGE_BITS + m;
+        last_page_lookup = i;
+	return true;
+      }
+    }
+    last_page_lookup = 0;
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (unlikely (*codepoint == INVALID)) {
+      *codepoint = get_max ();
+      return *codepoint != INVALID;
+    }
+
+    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 (pages[page_map[i].index].previous (codepoint))
+      {
+	*codepoint += page_map[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 ();
+      if (m != INVALID)
+      {
+	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+	return true;
+      }
+    }
+    *codepoint = INVALID;
+    return false;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *first;
+    if (!previous (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (previous (&i) && i == *first - 1)
+      (*first)--;
+
+    return true;
+  }
+
+  bool has_population () const { return population != UINT_MAX; }
+  unsigned int get_population () const
+  {
+    if (has_population ())
+      return population;
+
+    unsigned int pop = 0;
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      pop += pages[i].get_population ();
+
+    population = pop;
+    return pop;
+  }
+  hb_codepoint_t get_min () const
+  {
+    unsigned count = pages.length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      const auto& map = page_map[i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_min ();
+    }
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    unsigned count = pages.length;
+    for (signed i = count - 1; i >= 0; i--)
+    {
+      const auto& map = page_map[(unsigned) i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_max ();
+    }
+    return INVALID;
+  }
+
+  static constexpr hb_codepoint_t INVALID = page_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
+	    bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () 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; }
+
+    protected:
+    const hb_bit_set_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+
+  protected:
+
+  page_t *page_for (hb_codepoint_t g, bool insert = false)
+  {
+    page_map_t map = {get_major (g), pages.length};
+    unsigned int i;
+    if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
+    {
+      if (!insert)
+        return nullptr;
+
+      if (unlikely (!resize (pages.length + 1)))
+	return nullptr;
+
+      pages[map.index].init0 ();
+      memmove (page_map + i + 1,
+	       page_map + i,
+	       (page_map.length - 1 - i) * page_map.item_size);
+      page_map[i] = map;
+    }
+    return &pages[page_map[i].index];
+  }
+  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;
+  }
+  page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
+  const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
+  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
+};
+
+
+#endif /* HB_BIT_SET_HH */
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 2e72683..f120002 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -25,18 +25,6 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1308
- * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
- * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
- */
-#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-#define _POSIX_C_SOURCE 200809L
-#pragma GCC diagnostic pop
-#endif
-
 #include "hb.hh"
 #include "hb-blob.hh"
 
@@ -47,9 +35,6 @@
 #include <sys/mman.h>
 #endif /* HAVE_SYS_MMAN_H */
 
-#include <stdio.h>
-#include <stdlib.h>
-
 
 /**
  * SECTION: hb-blob
@@ -70,7 +55,7 @@
  * @length: Length of @data in bytes.
  * @mode: Memory mode for @data.
  * @user_data: Data parameter to pass to @destroy.
- * @destroy: Callback to call when @data is not needed anymore.
+ * @destroy: (nullable): Callback to call when @data is not needed anymore.
  *
  * Creates a new "blob" object wrapping @data.  The @mode parameter is used
  * to negotiate ownership and lifecycle of @data.
@@ -87,16 +72,54 @@
 		void              *user_data,
 		hb_destroy_func_t  destroy)
 {
-  hb_blob_t *blob;
-
-  if (!length ||
-      length >= 1u << 31 ||
-      !(blob = hb_object_create<hb_blob_t> ())) {
+  if (!length)
+  {
     if (destroy)
       destroy (user_data);
     return hb_blob_get_empty ();
   }
 
+  hb_blob_t *blob = hb_blob_create_or_fail (data, length, mode,
+					    user_data, destroy);
+  return likely (blob) ? blob : hb_blob_get_empty ();
+}
+
+/**
+ * hb_blob_create_or_fail: (skip)
+ * @data: Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: (nullable): Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data.  The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Note that this function returns a freshly-allocated empty blob even if @length
+ * 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().
+ *
+ * Since: 2.8.2
+ **/
+hb_blob_t *
+hb_blob_create_or_fail (const char        *data,
+			unsigned int       length,
+			hb_memory_mode_t   mode,
+			void              *user_data,
+			hb_destroy_func_t  destroy)
+{
+  hb_blob_t *blob;
+
+  if (length >= 1u << 31 ||
+      !(blob = hb_object_create<hb_blob_t> ()))
+  {
+    if (destroy)
+      destroy (user_data);
+    return nullptr;
+  }
+
   blob->data = data;
   blob->length = length;
   blob->mode = mode;
@@ -106,9 +129,10 @@
 
   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
     blob->mode = HB_MEMORY_MODE_READONLY;
-    if (!blob->try_make_writable ()) {
+    if (!blob->try_make_writable ())
+    {
       hb_blob_destroy (blob);
-      return hb_blob_get_empty ();
+      return nullptr;
     }
   }
 
@@ -128,7 +152,7 @@
  * @length: Length of sub-blob.
  *
  * Returns a blob that represents a range of bytes in @parent.  The new
- * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * blob is always created with #HB_MEMORY_MODE_READONLY, meaning that it
  * will never modify data in the parent blob.  The parent data is not
  * expected to be modified, and will result in undefined behavior if it
  * is.
@@ -168,7 +192,7 @@
  *
  * Makes a writable copy of @blob.
  *
- * Return value: New blob, or nullptr if allocation failed.
+ * Return value: The new blob, or nullptr if allocation failed
  *
  * Since: 1.8.0
  **/
@@ -194,14 +218,14 @@
  *
  * See TODO:link object types for more information.
  *
- * Return value: (transfer full): the empty blob.
+ * Return value: (transfer full): The empty blob.
  *
  * Since: 0.9.2
  **/
 hb_blob_t *
 hb_blob_get_empty ()
 {
-  return const_cast<hb_blob_t *> (&Null(hb_blob_t));
+  return const_cast<hb_blob_t *> (&Null (hb_blob_t));
 }
 
 /**
@@ -241,18 +265,20 @@
 
   blob->fini_shallow ();
 
-  free (blob);
+  hb_free (blob);
 }
 
 /**
  * hb_blob_set_user_data: (skip)
- * @blob: a blob.
- * @key: key for data to set.
- * @data: data to set.
- * @destroy: callback to call when @data is not needed anymore.
- * @replace: whether to replace an existing data with the same key.
+ * @blob: An #hb_blob_t
+ * @key: The user-data key to set
+ * @data: A pointer to the user data to set
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
  *
- * Return value:
+ * Attaches a user-data key/data pair to the specified blob.
+ *
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -268,12 +294,13 @@
 
 /**
  * hb_blob_get_user_data: (skip)
- * @blob: a blob.
- * @key: key for data to get.
+ * @blob: a blob
+ * @key: The user-data key to query
  *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified font-functions structure.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -287,9 +314,9 @@
 
 /**
  * hb_blob_make_immutable:
- * @blob: a blob.
+ * @blob: a blob
  *
- *
+ * Makes a blob immutable.
  *
  * Since: 0.9.2
  **/
@@ -306,9 +333,9 @@
  * hb_blob_is_immutable:
  * @blob: a blob.
  *
+ * Tests whether a blob is immutable.
  *
- *
- * Return value: TODO
+ * Return value: %true if @blob is immutable, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -323,9 +350,9 @@
  * hb_blob_get_length:
  * @blob: a blob.
  *
+ * Fetches the length of a blob's data.
  *
- *
- * Return value: the length of blob data in bytes.
+ * Return value: the length of @blob data in bytes.
  *
  * Since: 0.9.2
  **/
@@ -338,11 +365,11 @@
 /**
  * hb_blob_get_data:
  * @blob: a blob.
- * @length: (out):
+ * @length: (out): The length in bytes of the data retrieved
  *
+ * Fetches the data from a blob.
  *
- *
- * Returns: (transfer none) (array length=length):
+ * Returns: (transfer none) (array length=length): the byte data of @blob.
  *
  * Since: 0.9.2
  **/
@@ -374,16 +401,14 @@
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
 {
-  if (!blob->try_make_writable ()) {
-    if (length)
-      *length = 0;
-
+  if (hb_object_is_immutable (blob) ||
+     !blob->try_make_writable ())
+  {
+    if (length) *length = 0;
     return nullptr;
   }
 
-  if (length)
-    *length = blob->length;
-
+  if (length) *length = blob->length;
   return const_cast<char *> (blob->data);
 }
 
@@ -449,8 +474,8 @@
 bool
 hb_blob_t::try_make_writable ()
 {
-  if (hb_object_is_immutable (this))
-    return false;
+  if (unlikely (!length))
+    mode = HB_MEMORY_MODE_WRITABLE;
 
   if (this->mode == HB_MEMORY_MODE_WRITABLE)
     return true;
@@ -466,7 +491,7 @@
 
   char *new_data;
 
-  new_data = (char *) malloc (this->length);
+  new_data = (char *) hb_malloc (this->length);
   if (unlikely (!new_data))
     return false;
 
@@ -477,7 +502,7 @@
   this->mode = HB_MEMORY_MODE_WRITABLE;
   this->data = new_data;
   this->user_data = new_data;
-  this->destroy = free;
+  this->destroy = hb_free;
 
   return true;
 }
@@ -488,6 +513,9 @@
 
 #ifndef HB_NO_OPEN
 #ifdef HAVE_MMAP
+# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__)
+#  include <sys/paths.h>
+# endif
 # include <sys/types.h>
 # include <sys/stat.h>
 # include <fcntl.h>
@@ -528,25 +556,81 @@
   assert (0); // If we don't have mmap we shouldn't reach here
 #endif
 
-  free (file);
+  hb_free (file);
+}
+#endif
+
+#ifdef _PATH_RSRCFORKSPEC
+static int
+_open_resource_fork (const char *file_name, hb_mapped_file_t *file)
+{
+  size_t name_len = strlen (file_name);
+  size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
+
+  char *rsrc_name = (char *) hb_malloc (len);
+  if (unlikely (!rsrc_name)) return -1;
+
+  strncpy (rsrc_name, file_name, name_len);
+  strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
+	   sizeof (_PATH_RSRCFORKSPEC) - 1);
+
+  int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
+  hb_free (rsrc_name);
+
+  if (fd != -1)
+  {
+    struct stat st;
+    if (fstat (fd, &st) != -1)
+      file->length = (unsigned long) st.st_size;
+    else
+    {
+      close (fd);
+      fd = -1;
+    }
+  }
+
+  return fd;
 }
 #endif
 
 /**
  * hb_blob_create_from_file:
- * @file_name: font filename.
+ * @file_name: A font filename
  *
- * Returns: A hb_blob_t pointer with the content of the file
+ * Creates a new blob containing the data from the
+ * specified binary font file.
+ *
+ * Returns: An #hb_blob_t pointer with the content of the file,
+ * or hb_blob_get_empty() if failed.
  *
  * Since: 1.7.7
  **/
 hb_blob_t *
 hb_blob_create_from_file (const char *file_name)
 {
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
+  return likely (blob) ? blob : hb_blob_get_empty ();
+}
+
+/**
+ * hb_blob_create_from_file_or_fail:
+ * @file_name: A font filename
+ *
+ * Creates a new blob containing the data from the
+ * specified binary font file.
+ *
+ * Returns: An #hb_blob_t pointer with the content of the file,
+ * or %NULL if failed.
+ *
+ * Since: 2.8.2
+ **/
+hb_blob_t *
+hb_blob_create_from_file_or_fail (const char *file_name)
+{
   /* Adopted from glib's gmappedfile.c with Matthias Clasen and
      Allison Lortie permission but changed a lot to suit our need. */
 #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
-  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  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 ();
 
   int fd = open (file_name, O_RDONLY | O_BINARY, 0);
@@ -556,6 +640,19 @@
   if (unlikely (fstat (fd, &st) == -1)) goto fail;
 
   file->length = (unsigned long) st.st_size;
+
+#ifdef _PATH_RSRCFORKSPEC
+  if (unlikely (file->length == 0))
+  {
+    int rfd = _open_resource_fork (file_name, file);
+    if (rfd != -1)
+    {
+      close (fd);
+      fd = rfd;
+    }
+  }
+#endif
+
   file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
 				  MAP_PRIVATE | MAP_NORESERVE, fd, 0);
 
@@ -563,25 +660,25 @@
 
   close (fd);
 
-  return hb_blob_create (file->contents, file->length,
-			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
-			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+  return hb_blob_create_or_fail (file->contents, file->length,
+				 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+				 (hb_destroy_func_t) _hb_mapped_file_destroy);
 
 fail:
   close (fd);
 fail_without_close:
-  free (file);
+  hb_free (file);
 
 #elif defined(_WIN32) && !defined(HB_NO_MMAP)
-  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  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 ();
 
   HANDLE fd;
   unsigned int size = strlen (file_name) + 1;
-  wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
-  if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
+  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 defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   {
     CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
     ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@@ -598,11 +695,11 @@
 		    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
 		    nullptr);
 #endif
-  free (wchar_file_name);
+  hb_free (wchar_file_name);
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   {
     LARGE_INTEGER length;
     GetFileSizeEx (fd, &length);
@@ -613,35 +710,35 @@
   file->length = (unsigned long) GetFileSize (fd, nullptr);
   file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
 #endif
-  if (unlikely (file->mapping == nullptr)) goto fail;
+  if (unlikely (!file->mapping)) goto fail;
 
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
 #else
   file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
 #endif
-  if (unlikely (file->contents == nullptr)) goto fail;
+  if (unlikely (!file->contents)) goto fail;
 
   CloseHandle (fd);
-  return hb_blob_create (file->contents, file->length,
-			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
-			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+  return hb_blob_create_or_fail (file->contents, file->length,
+				 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+				 (hb_destroy_func_t) _hb_mapped_file_destroy);
 
 fail:
   CloseHandle (fd);
 fail_without_close:
-  free (file);
+  hb_free (file);
 
 #endif
 
   /* The following tries to read a file without knowing its size beforehand
      It's used as a fallback for systems without mmap or to read from pipes */
   unsigned long len = 0, allocated = BUFSIZ * 16;
-  char *data = (char *) malloc (allocated);
-  if (unlikely (data == nullptr)) return hb_blob_get_empty ();
+  char *data = (char *) hb_malloc (allocated);
+  if (unlikely (!data)) return nullptr;
 
   FILE *fp = fopen (file_name, "rb");
-  if (unlikely (fp == nullptr)) goto fread_fail_without_close;
+  if (unlikely (!fp)) goto fread_fail_without_close;
 
   while (!feof (fp))
   {
@@ -651,8 +748,8 @@
       /* Don't allocate and go more than ~536MB, our mmap reader still
 	 can cover files like that but lets limit our fallback reader */
       if (unlikely (allocated > (2 << 28))) goto fread_fail;
-      char *new_data = (char *) realloc (data, allocated);
-      if (unlikely (new_data == nullptr)) goto fread_fail;
+      char *new_data = (char *) hb_realloc (data, allocated);
+      if (unlikely (!new_data)) goto fread_fail;
       data = new_data;
     }
 
@@ -666,14 +763,15 @@
 
     len += addition;
   }
+	fclose (fp);
 
-  return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
-			 (hb_destroy_func_t) free);
+  return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
+				 (hb_destroy_func_t) hb_free);
 
 fread_fail:
   fclose (fp);
 fread_fail_without_close:
-  free (data);
-  return hb_blob_get_empty ();
+  hb_free (data);
+  return nullptr;
 }
 #endif /* !HB_NO_OPEN */
diff --git a/src/hb-blob.h b/src/hb-blob.h
index f80e9af..203f9e1 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,25 +36,36 @@
 HB_BEGIN_DECLS
 
 
-/*
- * Note re various memory-modes:
+/**
+ * hb_memory_mode_t:
+ * @HB_MEMORY_MODE_DUPLICATE: HarfBuzz immediately makes a copy of the data.
+ * @HB_MEMORY_MODE_READONLY: HarfBuzz client will never modify the data,
+ *     and HarfBuzz will never modify the data.
+ * @HB_MEMORY_MODE_WRITABLE: HarfBuzz client made a copy of the data solely
+ *     for HarfBuzz, so HarfBuzz may modify the data.
+ * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE: See above
+ *
+ * Data type holding the memory modes available to
+ * client programs.
+ *
+ * Regarding these various memory-modes:
  *
  * - In no case shall the HarfBuzz client modify memory
  *   that is passed to HarfBuzz in a blob.  If there is
- *   any such possibility, MODE_DUPLICATE should be used
+ *   any such possibility, @HB_MEMORY_MODE_DUPLICATE should be used
  *   such that HarfBuzz makes a copy immediately,
  *
- * - Use MODE_READONLY otherwise, unless you really really
+ * - Use @HB_MEMORY_MODE_READONLY otherwise, unless you really really
  *   really know what you are doing,
  *
- * - MODE_WRITABLE is appropriate if you really made a
+ * - @HB_MEMORY_MODE_WRITABLE is appropriate if you really made a
  *   copy of data solely for the purpose of passing to
  *   HarfBuzz and doing that just once (no reuse!),
  *
- * - If the font is mmap()ed, it's ok to use
- *   READONLY_MAY_MAKE_WRITABLE, however, using that mode
- *   correctly is very tricky.  Use MODE_READONLY instead.
- */
+ * - If the font is mmap()ed, it's okay to use
+ *   @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ *   correctly is very tricky.  Use @HB_MEMORY_MODE_READONLY instead.
+ **/
 typedef enum {
   HB_MEMORY_MODE_DUPLICATE,
   HB_MEMORY_MODE_READONLY,
@@ -62,6 +73,14 @@
   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
 } hb_memory_mode_t;
 
+/**
+ * hb_blob_t:
+ *
+ * Data type for blobs. A blob wraps a chunk of binary
+ * data and facilitates its lifecycle management between
+ * a client program and HarfBuzz.
+ *
+ **/
 typedef struct hb_blob_t hb_blob_t;
 
 HB_EXTERN hb_blob_t *
@@ -72,8 +91,18 @@
 		hb_destroy_func_t  destroy);
 
 HB_EXTERN hb_blob_t *
+hb_blob_create_or_fail (const char        *data,
+			unsigned int       length,
+			hb_memory_mode_t   mode,
+			void              *user_data,
+			hb_destroy_func_t  destroy);
+
+HB_EXTERN hb_blob_t *
 hb_blob_create_from_file (const char *file_name);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_from_file_or_fail (const char *file_name);
+
 /* Always creates with MEMORY_MODE_READONLY.
  * Even if the parent blob is writable, we don't
  * want the user of the sub-blob to be able to
diff --git a/src/hb-blob.hh b/src/hb-blob.hh
index d85bd82..a3683a6 100644
--- a/src/hb-blob.hh
+++ b/src/hb-blob.hh
@@ -88,8 +88,9 @@
   const T * get () const { return b->as<T> (); }
   hb_blob_t * get_blob () const { return b.get_raw (); }
   unsigned int get_length () const { return b.get ()->length; }
-  void destroy () { hb_blob_destroy (b.get ()); b = nullptr; }
+  void destroy () { hb_blob_destroy (b.get_raw ()); b = nullptr; }
 
+  private:
   hb_nonnull_ptr_t<hb_blob_t> b;
 };
 
diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh
index 1f9e2e9..e80cfea 100644
--- a/src/hb-buffer-deserialize-json.hh
+++ b/src/hb-buffer-deserialize-json.hh
@@ -34,30 +34,33 @@
 
 #line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
-	0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
+	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, 
-	65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+	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
 };
 
 static const char _deserialize_json_key_spans[] = {
-	0, 115, 26, 7, 2, 1, 50, 49, 
+	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, 
-	58, 89, 117, 117, 85, 115, 0
+	59, 117, 59, 117, 117, 1, 50, 49, 
+	117, 85, 115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
-	0, 0, 116, 143, 151, 154, 156, 207, 
-	257, 268, 386, 504, 622, 624, 675, 725, 
-	736, 854, 972, 974, 976, 1027, 1077, 1195, 
-	1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666, 
-	1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069, 
-	2119, 2178, 2268, 2386, 2504, 2590, 2706
+	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
 };
 
 static const char _deserialize_json_indicies[] = {
@@ -80,26 +83,27 @@
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 3, 1, 4, 1, 
 	5, 1, 6, 7, 1, 1, 8, 1, 
-	9, 10, 1, 11, 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, 9, 1, 10, 11, 
+	1, 12, 1, 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, 12, 1, 
-	12, 12, 12, 12, 12, 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, 12, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 13, 1, 1, 14, 
-	15, 15, 15, 15, 15, 15, 15, 15, 
-	15, 1, 16, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 1, 18, 18, 18, 
-	18, 18, 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, 1, 1, 1, 1, 
-	1, 1, 1, 1, 18, 1, 1, 1, 
+	1, 1, 1, 1, 1, 13, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	19, 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, 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, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -109,11 +113,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, 20, 1, 21, 21, 21, 21, 21, 
+	1, 1, 1, 1, 1, 1, 1, 21, 
+	1, 22, 22, 22, 22, 22, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 21, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 3, 1, 
+	22, 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, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -123,14 +128,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, 1, 1, 1, 1, 1, 1, 22, 
-	1, 18, 18, 18, 18, 18, 1, 1, 
+	1, 1, 1, 1, 1, 23, 1, 19, 
+	19, 19, 19, 19, 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, 
-	18, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 19, 1, 1, 1, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 1, 1, 1, 1, 1, 1, 
+	1, 1, 20, 1, 1, 1, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 18, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -138,27 +142,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, 20, 1, 23, 
-	1, 23, 23, 23, 23, 23, 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, 
-	23, 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, 1, 24, 1, 24, 24, 24, 24, 
-	24, 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, 24, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 31, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	25, 1, 1, 26, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 1, 28, 29, 
-	29, 29, 29, 29, 29, 29, 29, 29, 
-	1, 30, 30, 30, 30, 30, 1, 1, 
+	1, 1, 32, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	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, 1, 1, 1, 1, 
+	1, 1, 1, 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, 
@@ -167,13 +187,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, 1, 1, 1, 1, 32, 1, 30, 
-	30, 30, 30, 30, 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, 30, 1, 
+	1, 1, 1, 1, 1, 1, 35, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 31, 1, 1, 1, 29, 29, 
-	29, 29, 29, 29, 29, 29, 29, 29, 
+	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, 1, 
+	1, 36, 1, 1, 1, 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, 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, 
@@ -182,25 +213,15 @@
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 32, 1, 33, 1, 34, 
-	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, 
+	41, 1, 39, 39, 39, 39, 39, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 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, 36, 37, 37, 37, 37, 
-	37, 37, 37, 37, 37, 1, 38, 38, 
-	38, 38, 38, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 38, 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, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -208,43 +229,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, 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, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 40, 1, 38, 38, 38, 38, 
-	38, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 38, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 39, 
-	1, 1, 1, 41, 41, 41, 41, 41, 
-	41, 41, 41, 41, 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, 
-	40, 1, 42, 43, 1, 44, 1, 44, 
-	44, 44, 44, 44, 1, 1, 1, 1, 
-	1, 1, 1, 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, 
-	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, 1, 1, 1, 1, 1, 46, 1, 
-	1, 47, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 1, 49, 50, 50, 50, 
-	50, 50, 50, 50, 50, 50, 1, 51, 
-	51, 51, 51, 51, 1, 1, 1, 1, 
+	46, 46, 46, 46, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 51, 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, 1, 1, 1, 1, 
+	1, 1, 1, 1, 52, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	53, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 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, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 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, 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, 
+	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, 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, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -254,41 +302,47 @@
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 53, 1, 51, 51, 51, 
-	51, 51, 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, 51, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	52, 1, 1, 1, 50, 50, 50, 50, 
-	50, 50, 50, 50, 50, 50, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 53, 1, 54, 1, 54, 54, 54, 
-	54, 54, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 54, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 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, 1, 1, 56, 1, 1, 57, 
-	58, 58, 58, 58, 58, 58, 58, 58, 
-	58, 1, 59, 60, 60, 60, 60, 60, 
-	60, 60, 60, 60, 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, 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, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 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, 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, 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, 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, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -298,96 +352,19 @@
 	1, 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, 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, 60, 60, 60, 60, 60, 60, 
-	60, 60, 60, 60, 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, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 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, 64, 1, 64, 64, 64, 64, 64, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 64, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 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, 66, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 67, 68, 68, 
-	68, 68, 68, 68, 68, 68, 68, 1, 
-	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, 1, 1, 1, 1, 1, 1, 
-	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, 1, 70, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 71, 71, 
-	1, 71, 71, 71, 71, 71, 71, 71, 
-	71, 71, 71, 1, 1, 1, 1, 1, 
-	1, 1, 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, 1, 1, 1, 1, 
-	71, 1, 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, 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, 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, 1, 1, 1, 1, 1, 1, 
-	1, 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, 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, 1, 73, 1, 
-	1, 1, 75, 75, 75, 75, 75, 75, 
-	75, 75, 75, 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, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 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, 76, 76, 76, 76, 76, 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, 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, 78, 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, 76, 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, 
@@ -398,48 +375,117 @@
 	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, 76, 76, 76, 76, 76, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 2, 1, 1, 0
+	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, 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, 1, 1, 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, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 85, 85, 85, 
+	85, 85, 1, 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, 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, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 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
 };
 
 static const char _deserialize_json_trans_targs[] = {
 	1, 0, 2, 2, 3, 4, 18, 24, 
-	37, 5, 12, 6, 7, 8, 9, 11, 
-	9, 11, 10, 2, 44, 10, 44, 13, 
-	14, 15, 16, 17, 16, 17, 10, 2, 
-	44, 19, 20, 21, 22, 23, 10, 2, 
-	44, 23, 25, 31, 26, 27, 28, 29, 
-	30, 29, 30, 10, 2, 44, 32, 33, 
-	34, 35, 36, 35, 36, 10, 2, 44, 
-	38, 39, 40, 42, 43, 41, 10, 41, 
-	10, 2, 44, 43, 44, 45, 46
+	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
 };
 
 static const char _deserialize_json_trans_actions[] = {
 	0, 0, 1, 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, 0, 2, 2, 2, 14, 0, 
-	15, 15, 16, 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
 };
 
 static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 44;
+static const int deserialize_json_first_final = 49;
 static const int deserialize_json_error = 0;
 
 static const int deserialize_json_en_main = 1;
 
 
-#line 97 "hb-buffer-deserialize-json.rl"
+#line 108 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
-_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+_hb_buffer_deserialize_json (hb_buffer_t *buffer,
 				    const char *buf,
 				    unsigned int buf_len,
 				    const char **end_ptr,
@@ -462,12 +508,12 @@
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 466 "hb-buffer-deserialize-json.hh"
+#line 512 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
-#line 471 "hb-buffer-deserialize-json.hh"
+#line 517 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
 	int _trans;
@@ -515,41 +561,84 @@
 	tok = p;
 }
 	break;
-	case 14:
+	case 15:
 #line 55 "hb-buffer-deserialize-json.rl"
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 21:
+#line 56 "hb-buffer-deserialize-json.rl"
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 16:
+#line 58 "hb-buffer-deserialize-json.rl"
 	{
+	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
 }
 	break;
-	case 15:
-#line 62 "hb-buffer-deserialize-json.rl"
+	case 18:
+#line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
 	case 8:
-#line 63 "hb-buffer-deserialize-json.rl"
+#line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
 	case 10:
-#line 64 "hb-buffer-deserialize-json.rl"
+#line 68 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
 	case 12:
-#line 65 "hb-buffer-deserialize-json.rl"
+#line 69 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
 	case 3:
-#line 66 "hb-buffer-deserialize-json.rl"
+#line 70 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
 	case 6:
-#line 67 "hb-buffer-deserialize-json.rl"
+#line 71 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
-	case 16:
-#line 62 "hb-buffer-deserialize-json.rl"
+	case 14:
+#line 51 "hb-buffer-deserialize-json.rl"
+	{
+	tok = p;
+}
+#line 55 "hb-buffer-deserialize-json.rl"
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 20:
+#line 51 "hb-buffer-deserialize-json.rl"
+	{
+	tok = p;
+}
+#line 56 "hb-buffer-deserialize-json.rl"
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 17:
+#line 58 "hb-buffer-deserialize-json.rl"
+	{
+	/* TODO Unescape \" and \\ if found. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  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;
+	case 19:
+#line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -561,7 +650,7 @@
 }
 	break;
 	case 9:
-#line 63 "hb-buffer-deserialize-json.rl"
+#line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -573,7 +662,7 @@
 }
 	break;
 	case 11:
-#line 64 "hb-buffer-deserialize-json.rl"
+#line 68 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -585,7 +674,7 @@
 }
 	break;
 	case 13:
-#line 65 "hb-buffer-deserialize-json.rl"
+#line 69 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -597,7 +686,7 @@
 }
 	break;
 	case 4:
-#line 66 "hb-buffer-deserialize-json.rl"
+#line 70 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -609,7 +698,7 @@
 }
 	break;
 	case 7:
-#line 67 "hb-buffer-deserialize-json.rl"
+#line 71 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
@@ -620,7 +709,7 @@
 	*end_ptr = p;
 }
 	break;
-#line 624 "hb-buffer-deserialize-json.hh"
+#line 713 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -632,7 +721,7 @@
 	_out: {}
 	}
 
-#line 125 "hb-buffer-deserialize-json.rl"
+#line 136 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
index f3abb02..382423f 100644
--- a/src/hb-buffer-deserialize-json.rl
+++ b/src/hb-buffer-deserialize-json.rl
@@ -52,14 +52,18 @@
 	tok = p;
 }
 
-action parse_glyph {
+action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; }
+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,
 					&info.codepoint))
 	  return false;
 }
 
-action parse_gid       { if (!parse_uint (tok, p, &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; }
@@ -72,20 +76,27 @@
 comma = space* ',' space*;
 colon = space* ':' space*;
 
-glyph_id = unum;
-glyph_name = alpha (alnum|'_'|'.'|'-')*;
+codepoint = unum;
+glyph_name = '"' ([^\\"] | '\\' [\\"])* '"';
 
-glyph_string   = '"' (glyph_name >tok %parse_glyph) '"';
-glyph_number = (glyph_id >tok %parse_gid);
+parse_glyph_name   = (glyph_name >tok %parse_glyph_name);
+parse_codepoint = (codepoint >tok %parse_codepoint);
 
-glyph	= "\"g\""  colon (glyph_string | glyph_number);
+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);
 
-element = glyph | cluster | xoffset | yoffset | xadvance | yadvance;
+element = glyph @ensure_glyphs
+	| unicode @ensure_unicode
+	| cluster
+	| xoffset
+	| yoffset
+	| xadvance
+	| yadvance;
 item	=
 	( '{' space* element (comma element)* space* '}')
 	>clear_item
@@ -97,7 +108,7 @@
 }%%
 
 static hb_bool_t
-_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+_hb_buffer_deserialize_json (hb_buffer_t *buffer,
 				    const char *buf,
 				    unsigned int buf_len,
 				    const char **end_ptr,
diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh
index 67f0a12..b599e96 100644
--- a/src/hb-buffer-deserialize-text.hh
+++ b/src/hb-buffer-deserialize-text.hh
@@ -34,24 +34,27 @@
 
 #line 36 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
-	0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
-	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 
-	9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 0
+	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, 114, 13, 10, 13, 10, 10, 13, 
-	10, 1, 13, 10, 14, 116, 116, 0, 
-	114, 116, 116, 116, 116, 116, 116, 116, 
-	116, 116, 116
+	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, 115, 129, 140, 154, 165, 176, 
-	190, 201, 203, 217, 228, 243, 360, 477, 
-	478, 593, 710, 827, 944, 1061, 1178, 1295, 
-	1412, 1529, 1646
+	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[] = {
@@ -60,95 +63,174 @@
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	0, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	2, 3, 3, 3, 3, 3, 3, 3, 
-	3, 3, 1, 1, 1, 1, 1, 1, 
-	1, 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, 1, 1, 1, 1, 1, 
-	1, 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, 1, 5, 1, 1, 6, 
-	7, 7, 7, 7, 7, 7, 7, 7, 
-	7, 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, 
+	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, 
-	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, 28, 28, 
-	28, 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, 28, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 29, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	30, 1, 1, 31, 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, 
-	32, 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, 33, 
-	1, 34, 34, 34, 34, 34, 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, 
-	34, 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, 35, 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, 36, 1, 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, 1, 1, 1, 1, 1, 2, 3, 
-	3, 3, 3, 3, 3, 3, 3, 3, 
-	1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 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, 1, 28, 28, 28, 28, 28, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 28, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 29, 1, 1, 1, 
-	1, 37, 37, 37, 37, 37, 37, 37, 
-	37, 37, 37, 1, 1, 1, 30, 1, 
-	1, 31, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 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, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 33, 1, 38, 
-	38, 38, 38, 38, 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, 1, 38, 1, 
+	1, 1, 1, 1, 1, 42, 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, 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, 
@@ -158,165 +240,172 @@
 	1, 1, 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, 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, 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, 
-	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, 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, 
-	14, 14, 14, 14, 14, 14, 14, 14, 
-	14, 14, 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, 44, 1, 38, 38, 
-	38, 38, 38, 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, 38, 1, 1, 
+	1, 1, 1, 1, 1, 72, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 39, 1, 1, 1, 9, 9, 9, 
-	9, 9, 9, 9, 9, 9, 9, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 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, 41, 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, 1, 1, 1, 46, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 47, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 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, 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, 1, 1, 1, 1, 1, 1, 
-	1, 1, 51, 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, 1, 1, 52, 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, 1, 1, 53, 1, 50, 50, 50, 
-	50, 50, 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, 50, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 51, 
-	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, 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, 52, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	53, 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, 1, 1, 1, 46, 1, 1, 1, 
-	1, 54, 54, 54, 54, 54, 54, 54, 
-	54, 54, 54, 1, 1, 1, 1, 1, 
-	1, 47, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 48, 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, 
-	1, 1, 1, 1, 1, 49, 1, 28, 
-	28, 28, 28, 28, 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, 28, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 29, 1, 55, 55, 1, 55, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	1, 1, 1, 30, 1, 1, 31, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 1, 1, 32, 1, 55, 1, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 55, 55, 55, 55, 55, 55, 55, 
-	55, 1, 33, 1, 0
+	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, 13, 17, 26, 3, 18, 21, 
-	18, 21, 5, 19, 20, 19, 20, 22, 
-	25, 8, 9, 12, 9, 12, 10, 11, 
-	23, 24, 23, 24, 14, 2, 6, 7, 
-	15, 16, 14, 15, 16, 17, 14, 4, 
-	15, 16, 14, 15, 16, 14, 2, 7, 
-	15, 16, 14, 2, 15, 16, 25, 26
+	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, 1, 1, 1, 2, 2, 2, 
-	0, 0, 2, 2, 2, 0, 0, 2, 
-	2, 2, 2, 2, 0, 0, 3, 2, 
-	2, 2, 0, 0, 4, 5, 5, 5, 
-	4, 4, 0, 0, 0, 0, 6, 7, 
-	6, 6, 8, 8, 8, 9, 10, 10, 
-	9, 9, 11, 12, 11, 11, 0, 0
+	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, 4, 0, 0, 
-	0, 4, 6, 8, 8, 6, 9, 11, 
-	11, 9, 4
+	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 = 13;
+static const int deserialize_text_first_final = 19;
 static const int deserialize_text_error = 0;
 
 static const int deserialize_text_en_main = 1;
 
 
-#line 91 "hb-buffer-deserialize-text.rl"
+#line 114 "hb-buffer-deserialize-text.rl"
 
 
 static hb_bool_t
-_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
+_hb_buffer_deserialize_text (hb_buffer_t *buffer,
 				    const char *buf,
 				    unsigned int buf_len,
 				    const char **end_ptr,
@@ -329,22 +418,18 @@
 
   while (p < pe && ISSPACE (*p))
     p++;
-  if (p < pe && *p == (buffer->len ? '|' : '['))
-  {
-    *end_ptr = ++p;
-  }
 
   const char *eof = pe, *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 343 "hb-buffer-deserialize-text.hh"
+#line 428 "hb-buffer-deserialize-text.hh"
 	{
 	cs = deserialize_text_start;
 	}
 
-#line 348 "hb-buffer-deserialize-text.hh"
+#line 433 "hb-buffer-deserialize-text.hh"
 	{
 	int _slen;
 	int _trans;
@@ -369,7 +454,14 @@
 		goto _again;
 
 	switch ( _deserialize_text_trans_actions[_trans] ) {
-	case 2:
+	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;
@@ -377,30 +469,43 @@
 	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 10:
-#line 62 "hb-buffer-deserialize-text.rl"
+	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 3:
-#line 63 "hb-buffer-deserialize-text.rl"
+	case 6:
+#line 69 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 12:
-#line 64 "hb-buffer-deserialize-text.rl"
+	case 23:
+#line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 7:
-#line 65 "hb-buffer-deserialize-text.rl"
+	case 20:
+#line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 1:
+	case 15:
 #line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
@@ -412,8 +517,25 @@
 }
 	break;
 	case 4:
-#line 55 "hb-buffer-deserialize-text.rl"
+#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))
@@ -428,8 +550,20 @@
 	*end_ptr = p;
 }
 	break;
-	case 9:
-#line 62 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -440,8 +574,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 11:
-#line 64 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -452,8 +586,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 6:
-#line 65 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -464,8 +598,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 8:
-#line 66 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -476,7 +610,115 @@
 	*end_ptr = p;
 }
 	break;
-#line 480 "hb-buffer-deserialize-text.hh"
+	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:
@@ -488,9 +730,10 @@
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_eof_actions[cs] ) {
-	case 4:
-#line 55 "hb-buffer-deserialize-text.rl"
+	case 16:
+#line 58 "hb-buffer-deserialize-text.rl"
 	{
+	/* TODO Unescape delimeters. */
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
@@ -505,8 +748,20 @@
 	*end_ptr = p;
 }
 	break;
-	case 9:
-#line 62 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -517,8 +772,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 11:
-#line 64 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -529,8 +784,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 6:
-#line 65 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -541,8 +796,8 @@
 	*end_ptr = p;
 }
 	break;
-	case 8:
-#line 66 "hb-buffer-deserialize-text.rl"
+	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"
 	{
@@ -553,14 +808,41 @@
 	*end_ptr = p;
 }
 	break;
-#line 557 "hb-buffer-deserialize-text.hh"
+	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 119 "hb-buffer-deserialize-text.rl"
+#line 138 "hb-buffer-deserialize-text.rl"
 
 
   *end_ptr = p;
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
index 6268a6c..a217028 100644
--- a/src/hb-buffer-deserialize-text.rl
+++ b/src/hb-buffer-deserialize-text.rl
@@ -52,30 +52,37 @@
 	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. */
 	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; }
 
-unum	= '0' | [1-9] digit*;
+unum  = '0' | [1-9] digit*;
 num	= '-'? unum;
 
 glyph_id = unum;
-glyph_name = alpha (alnum|'_'|'.'|'-')*;
+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))?;
-item	=
+
+glyph_item	=
 	(
 		glyph
 		cluster?
@@ -83,15 +90,31 @@
 		advances?
 	)
 	>clear_item
+	@ensure_glyphs
 	%add_item
 	;
 
-main := space* item (space* '|' space* item)* space* ('|'|']')?;
+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* ('|'|'>')?;
+
+main := space* ( ('[' glyphs) | ('<' unicodes) );
 
 }%%
 
 static hb_bool_t
-_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
+_hb_buffer_deserialize_text (hb_buffer_t *buffer,
 				    const char *buf,
 				    unsigned int buf_len,
 				    const char **end_ptr,
@@ -104,10 +127,6 @@
 
   while (p < pe && ISSPACE (*p))
     p++;
-  if (p < pe && *p == (buffer->len ? '|' : '['))
-  {
-    *end_ptr = ++p;
-  }
 
   const char *eof = pe, *tok = nullptr;
   int cs;
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index e64eb0e..6539b89 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -91,26 +91,26 @@
 {
   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 serialize_formats[0];
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
     default:
-    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return nullptr;
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:  return nullptr;
   }
 }
 
 static unsigned int
 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
-				  unsigned int start,
-				  unsigned int end,
-				  char *buf,
-				  unsigned int buf_size,
-				  unsigned int *buf_consumed,
-				  hb_font_t *font,
-				  hb_buffer_serialize_flags_t flags)
+                                  unsigned int start,
+                                  unsigned int end,
+                                  char *buf,
+                                  unsigned int buf_size,
+                                  unsigned int *buf_consumed,
+                                  hb_font_t *font,
+                                  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
+                             nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   hb_position_t x = 0, y = 0;
@@ -125,6 +125,8 @@
 
     if (i)
       *p++ = ',';
+    else
+      *p++ = '[';
 
     *p++ = '{';
 
@@ -134,8 +136,9 @@
       char g[128];
       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
       *p++ = '"';
-      for (char *q = g; *q; q++) {
-	if (*q == '"')
+      for (char *q = g; *q; q++)
+      {
+	if (unlikely (*q == '"' || *q == '\\'))
 	  *p++ = '\\';
 	*p++ = *q;
       }
@@ -151,16 +154,16 @@
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
-			     x+pos[i].x_offset, y+pos[i].y_offset));
+		   x+pos[i].x_offset, y+pos[i].y_offset));
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
-	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
-			       pos[i].x_advance, pos[i].y_advance));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+		     pos[i].x_advance, pos[i].y_advance));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@@ -168,12 +171,14 @@
       hb_glyph_extents_t extents;
       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
-		extents.x_bearing, extents.y_bearing));
+                                extents.x_bearing, extents.y_bearing));
       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
-		extents.width, extents.height));
+                                extents.width, extents.height));
     }
 
     *p++ = '}';
+    if (i == end-1)
+      *p++ = ']';
 
     unsigned int l = p - b;
     if (buf_size > l)
@@ -197,18 +202,71 @@
 }
 
 static unsigned int
+_hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
+          unsigned int start,
+          unsigned int end,
+          char *buf,
+          unsigned int buf_size,
+          unsigned int *buf_consumed,
+          hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    if (i)
+      *p++ = ',';
+    else
+      *p++ = '[';
+
+    *p++ = '{';
+
+    APPEND ("\"u\":");
+
+    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+    }
+
+    *p++ = '}';
+
+    if (i == end-1)
+      *p++ = ']';
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+
+  }
+
+  return end - start;
+}
+
+static unsigned int
 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
-				  unsigned int start,
-				  unsigned int end,
-				  char *buf,
-				  unsigned int buf_size,
-				  unsigned int *buf_consumed,
-				  hb_font_t *font,
-				  hb_buffer_serialize_flags_t flags)
+                                  unsigned int start,
+                                  unsigned int end,
+                                  char *buf,
+                                  unsigned int buf_size,
+                                  unsigned int *buf_consumed,
+                                  hb_font_t *font,
+                                  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
+           nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   hb_position_t x = 0, y = 0;
@@ -221,9 +279,12 @@
 
     if (i)
       *p++ = '|';
+    else
+      *p++ = '[';
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
     {
+      /* TODO Escape delimiters we use. */
       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
       p += strlen (p);
     }
@@ -237,21 +298,21 @@
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       if (x+pos[i].x_offset || y+pos[i].y_offset)
-	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
 
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
       {
-	*p++ = '+';
-	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
-	if (pos[i].y_advance)
-	  p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+        *p++ = '+';
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+        if (pos[i].y_advance)
+          p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
       }
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@@ -261,6 +322,10 @@
       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
     }
 
+    if (i == end-1) {
+      *p++ = ']';
+    }
+
     unsigned int l = p - b;
     if (buf_size > l)
     {
@@ -282,6 +347,51 @@
   return end - start;
 }
 
+
+static unsigned int
+_hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
+                                   unsigned int start,
+                                   unsigned int end,
+                                   char *buf,
+                                   unsigned int buf_size,
+                                   unsigned int *buf_consumed,
+                                   hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    if (i)
+      *p++ = '|';
+    else
+      *p++ = '<';
+
+    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "U+%04X", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+    }
+
+    if (i == end-1)
+      *p++ = '>';
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+  return end - start;
+}
+
 /**
  * hb_buffer_serialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
@@ -290,8 +400,8 @@
  * @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) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
- * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes 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.
  * @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
@@ -308,6 +418,7 @@
  * ```
  * [uni0651=0@518,0+0|uni0628=0+1897]
  * ```
+ *
  * - The serialized glyphs are delimited with `[` and `]`.
  * - Glyphs are separated with `|`
  * - Each glyph starts with glyph name, or glyph index if
@@ -316,12 +427,28 @@
  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
  *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
  *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
- *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
- *     #hb_glyph_extents_t in the format
- *     `&lt;x_bearing,y_bearing,width,height&gt;`
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `<x_bearing,y_bearing,width,height>`
  *
  * ## json
- * TODO.
+ * A machine-readable, structured format.
+ * The serialized glyphs will look something like:
+ *
+ * ```
+ * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0},
+ * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}]
+ * ```
+ *
+ * Each glyph is a JSON object, with the following properties:
+ * - `g`: the glyph name or glyph index if
+ *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set.
+ * - `cl`: #hb_glyph_info_t.cluster if
+ *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
+ * - `dx`,`dy`,`ax`,`ay`: #hb_glyph_position_t.x_offset, #hb_glyph_position_t.y_offset,
+ *    #hb_glyph_position_t.x_advance and #hb_glyph_position_t.y_advance
+ *    respectively, if #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set.
+ * - `xb`,`yb`,`w`,`h`: #hb_glyph_extents_t.x_bearing, #hb_glyph_extents_t.y_bearing,
+ *    #hb_glyph_extents_t.width and #hb_glyph_extents_t.height respectively if
+ *    #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set.
  *
  * Return value:
  * The number of serialized items.
@@ -330,16 +457,17 @@
  **/
 unsigned int
 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
-			    unsigned int start,
-			    unsigned int end,
-			    char *buf,
-			    unsigned int buf_size,
-			    unsigned int *buf_consumed,
-			    hb_font_t *font,
-			    hb_buffer_serialize_format_t format,
-			    hb_buffer_serialize_flags_t flags)
+                            unsigned int start,
+                            unsigned int end,
+                            char *buf,
+                            unsigned int buf_size,
+                            unsigned int *buf_consumed,
+                            hb_font_t *font,
+                            hb_buffer_serialize_format_t format,
+                            hb_buffer_serialize_flags_t flags)
 {
-  assert (start <= end && end <= buffer->len);
+  end = hb_clamp (end, start, buffer->len);
+  start = hb_min (start, end);
 
   unsigned int sconsumed;
   if (!buf_consumed)
@@ -348,8 +476,7 @@
   if (buf_size)
     *buf = '\0';
 
-  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
-	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+  buffer->assert_glyphs ();
 
   if (!buffer->have_positions)
     flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
@@ -364,13 +491,13 @@
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
       return _hb_buffer_serialize_glyphs_text (buffer, start, end,
-					       buf, buf_size, buf_consumed,
-					       font, flags);
+                 buf, buf_size, buf_consumed,
+                 font, flags);
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
       return _hb_buffer_serialize_glyphs_json (buffer, start, end,
-					       buf, buf_size, buf_consumed,
-					       font, flags);
+                 buf, buf_size, buf_consumed,
+                 font, flags);
 
     default:
     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
@@ -379,6 +506,184 @@
   }
 }
 
+/**
+ * hb_buffer_serialize_unicode:
+ * @buffer: an #hb_buffer_t buffer.
+ * @start: the first item in @buffer to serialize.
+ * @end: the last item in @buffer to serialize.
+ * @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.
+ * @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.
+ *
+ * Serializes @buffer into a textual representation of its content,
+ * 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:
+ *
+ * ## text
+ * A human-readable, plain text format.
+ * The serialized codepoints will look something like:
+ *
+ * ```
+ *  <U+0651=0|U+0628=1>
+ * ```
+ *
+ * - Glyphs are separated with `|`
+ * - Unicode codepoints are expressed as zero-padded four (or more)
+ *   digit hexadecimal numbers preceded by `U+`
+ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, the cluster
+ *   will be indicated with a `=` then #hb_glyph_info_t.cluster.
+ *
+ * ## json
+ * A machine-readable, structured format.
+ * The serialized codepoints will be a list of objects with the following
+ * properties:
+ * - `u`: the Unicode codepoint as a decimal integer
+ * - `cl`: #hb_glyph_info_t.cluster if
+ *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
+ *
+ * For example:
+ *
+ * ```
+ * [{u:1617,cl:0},{u:1576,cl:1}]
+ * ```
+ *
+ * Return value:
+ * The number of serialized items.
+ *
+ * Since: 2.7.3
+ **/
+unsigned int
+hb_buffer_serialize_unicode (hb_buffer_t *buffer,
+                             unsigned int start,
+                             unsigned int end,
+                             char *buf,
+                             unsigned int buf_size,
+                             unsigned int *buf_consumed,
+                             hb_buffer_serialize_format_t format,
+                             hb_buffer_serialize_flags_t flags)
+{
+  end = hb_clamp (end, start, buffer->len);
+  start = hb_min (start, end);
+
+  unsigned int sconsumed;
+  if (!buf_consumed)
+    buf_consumed = &sconsumed;
+  *buf_consumed = 0;
+  if (buf_size)
+    *buf = '\0';
+
+  buffer->assert_unicode ();
+
+  if (unlikely (start == end))
+    return 0;
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_serialize_unicode_text (buffer, start, end,
+                                                buf, buf_size, buf_consumed, flags);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_serialize_unicode_json (buffer, start, end,
+                                                buf, buf_size, buf_consumed, flags);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return 0;
+
+  }
+}
+
+static unsigned int
+_hb_buffer_serialize_invalid (hb_buffer_t *buffer,
+                              unsigned int start,
+                              unsigned int end,
+                              char *buf,
+                              unsigned int buf_size,
+                              unsigned int *buf_consumed,
+                              hb_buffer_serialize_format_t format,
+                              hb_buffer_serialize_flags_t flags)
+{
+  assert (!buffer->len);
+
+  unsigned int sconsumed;
+  if (!buf_consumed)
+    buf_consumed = &sconsumed;
+  if (buf_size < 3)
+    return 0;
+  if (format == HB_BUFFER_SERIALIZE_FORMAT_JSON) {
+    *buf++ = '[';
+    *buf++ = ']';
+    *buf = '\0';
+  } else if (format == HB_BUFFER_SERIALIZE_FORMAT_TEXT) {
+    *buf++ = '!';
+    *buf++ = '!';
+    *buf = '\0';
+  }
+  *buf_consumed = 2;
+  return 0;
+}
+
+/**
+ * hb_buffer_serialize:
+ * @buffer: an #hb_buffer_t buffer.
+ * @start: the first item in @buffer to serialize.
+ * @end: the last item in @buffer to serialize.
+ * @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.
+ * @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.
+ * @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.
+ *
+ * Serializes @buffer into a textual representation of its content, whether
+ * Unicode codepoints or glyph identifiers and positioning information. This is
+ * useful for showing the contents of the buffer, for example during debugging.
+ * See the documentation of hb_buffer_serialize_unicode() and
+ * hb_buffer_serialize_glyphs() for a description of the output format.
+ *
+ * Return value:
+ * The number of serialized items.
+ *
+ * Since: 2.7.3
+ **/
+unsigned int
+hb_buffer_serialize (hb_buffer_t *buffer,
+                     unsigned int start,
+                     unsigned int end,
+                     char *buf,
+                     unsigned int buf_size,
+                     unsigned int *buf_consumed,
+                     hb_font_t *font,
+                     hb_buffer_serialize_format_t format,
+                     hb_buffer_serialize_flags_t flags)
+{
+  switch (buffer->content_type)
+  {
+
+    case HB_BUFFER_CONTENT_TYPE_GLYPHS:
+      return hb_buffer_serialize_glyphs (buffer, start, end, buf, buf_size,
+					 buf_consumed, font, format, flags);
+
+    case HB_BUFFER_CONTENT_TYPE_UNICODE:
+      return hb_buffer_serialize_unicode (buffer, start, end, buf, buf_size,
+					  buf_consumed, format, flags);
+
+    case HB_BUFFER_CONTENT_TYPE_INVALID:
+    default:
+      return _hb_buffer_serialize_invalid (buffer, start, end, buf, buf_size,
+					   buf_consumed, format, flags);
+  }
+}
+
 static bool
 parse_int (const char *pp, const char *end, int32_t *pv)
 {
@@ -403,39 +708,59 @@
   return true;
 }
 
+static bool
+parse_hex (const char *pp, const char *end, uint32_t *pv)
+{
+  unsigned int v;
+  const char *p = pp;
+  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, 16)))
+    return false;
+
+  *pv = v;
+  return true;
+}
+
 #include "hb-buffer-deserialize-json.hh"
 #include "hb-buffer-deserialize-text.hh"
 
 /**
  * hb_buffer_deserialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
- * @buf: (array length=buf_len):
- * @buf_len:
- * @end_ptr: (out):
- * @font:
- * @format:
+ * @buf: (array length=buf_len): string to deserialize
+ * @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
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
  *
+ * Deserializes glyphs @buffer from textual representation in the format
+ * produced by hb_buffer_serialize_glyphs().
  *
- *
- * Return value:
+ * Return value: %true if @buf is not fully consumed, %false otherwise.
  *
  * Since: 0.9.7
  **/
 hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
-			      const char *buf,
-			      int buf_len, /* -1 means nul-terminated */
-			      const char **end_ptr, /* May be NULL */
-			      hb_font_t *font, /* May be NULL */
-			      hb_buffer_serialize_format_t format)
+                              const char *buf,
+                              int buf_len, /* -1 means nul-terminated */
+                              const char **end_ptr, /* May be NULL */
+                              hb_font_t *font, /* May be NULL */
+                              hb_buffer_serialize_format_t format)
 {
   const char *end;
   if (!end_ptr)
     end_ptr = &end;
   *end_ptr = buf;
 
-  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
-	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+  buffer->assert_glyphs ();
+
+  if (unlikely (hb_object_is_immutable (buffer)))
+  {
+    if (end_ptr)
+      *end_ptr = buf;
+    return false;
+  }
 
   if (buf_len == -1)
     buf_len = strlen (buf);
@@ -454,14 +779,84 @@
   switch (format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
-      return _hb_buffer_deserialize_glyphs_text (buffer,
-						 buf, buf_len, end_ptr,
-						 font);
+      return _hb_buffer_deserialize_text (buffer,
+                                          buf, buf_len, end_ptr,
+                                          font);
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
-      return _hb_buffer_deserialize_glyphs_json (buffer,
-						 buf, buf_len, end_ptr,
-						 font);
+      return _hb_buffer_deserialize_json (buffer,
+                                          buf, buf_len, end_ptr,
+                                          font);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return false;
+
+  }
+}
+
+
+/**
+ * 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
+ * @end_ptr: (out) (optional): output pointer to the character after last
+ *                               consumed one.
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
+ *
+ * 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.
+ *
+ * Since: 2.7.3
+ **/
+hb_bool_t
+hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
+                               const char *buf,
+                               int buf_len, /* -1 means nul-terminated */
+                               const char **end_ptr, /* May be NULL */
+                               hb_buffer_serialize_format_t format)
+{
+  const char *end;
+  if (!end_ptr)
+    end_ptr = &end;
+  *end_ptr = buf;
+
+  buffer->assert_unicode ();
+
+  if (unlikely (hb_object_is_immutable (buffer)))
+  {
+    if (end_ptr)
+      *end_ptr = buf;
+    return false;
+  }
+
+  if (buf_len == -1)
+    buf_len = strlen (buf);
+
+  if (!buf_len)
+  {
+    *end_ptr = buf;
+    return false;
+  }
+
+  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+  hb_font_t* font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_deserialize_text (buffer,
+                                          buf, buf_len, end_ptr,
+                                          font);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_deserialize_json (buffer,
+                                          buf, buf_len, end_ptr,
+                                          font);
 
     default:
     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 6131c86..b4f7f72 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -37,8 +37,9 @@
  * @short_description: Input and output buffers
  * @include: hb.h
  *
- * Buffers serve dual role in HarfBuzz; they hold the input characters that are
- * passed to hb_shape(), and after shaping they hold the output glyphs.
+ * 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.
  **/
 
 
@@ -50,7 +51,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
  **/
@@ -95,14 +96,15 @@
  * As an optimization, both info and out_info may point to the
  * same piece of memory, which is owned by info.  This remains the
  * case as long as out_len doesn't exceed i at any time.
- * In that case, swap_buffers() is no-op and the glyph operations operate
- * mostly in-place.
+ * In that case, swap_buffers() is mostly no-op and the glyph operations
+ * operate mostly in-place.
  *
  * As soon as out_info gets longer than info, out_info is moved over
- * to an alternate buffer (which we reuse the pos buffer for!), and its
+ * to an alternate buffer (which we reuse the pos buffer for), and its
  * current contents (out_len entries) are copied to the new place.
+ *
  * This should all remain transparent to the user.  swap_buffers() then
- * switches info and out_info.
+ * switches info over to out_info and does housekeeping.
  */
 
 
@@ -135,8 +137,8 @@
   if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
-  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
-  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
+  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]));
 
 done:
   if (unlikely (!new_pos || !new_info))
@@ -217,14 +219,12 @@
 void
 hb_buffer_t::reset ()
 {
-  if (unlikely (hb_object_is_immutable (this)))
-    return;
-
   hb_unicode_funcs_destroy (unicode);
   unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
   flags = HB_BUFFER_FLAG_DEFAULT;
   replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
   invisible = 0;
+  not_found = 0;
 
   clear ();
 }
@@ -232,9 +232,6 @@
 void
 hb_buffer_t::clear ()
 {
-  if (unlikely (hb_object_is_immutable (this)))
-    return;
-
   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
   scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
@@ -287,27 +284,12 @@
 
 
 void
-hb_buffer_t::remove_output ()
-{
-  if (unlikely (hb_object_is_immutable (this)))
-    return;
-
-  have_output = false;
-  have_positions = false;
-
-  out_len = 0;
-  out_info = info;
-}
-
-void
 hb_buffer_t::clear_output ()
 {
-  if (unlikely (hb_object_is_immutable (this)))
-    return;
-
   have_output = true;
   have_positions = false;
 
+  idx = 0;
   out_len = 0;
   out_info = info;
 }
@@ -315,9 +297,6 @@
 void
 hb_buffer_t::clear_positions ()
 {
-  if (unlikely (hb_object_is_immutable (this)))
-    return;
-
   have_output = false;
   have_positions = true;
 
@@ -330,53 +309,26 @@
 void
 hb_buffer_t::swap_buffers ()
 {
-  if (unlikely (!successful)) return;
-
   assert (have_output);
-  have_output = false;
+
+  assert (idx <= len);
+
+  if (unlikely (!successful || !next_glyphs (len - idx)))
+    goto reset;
 
   if (out_info != info)
   {
-    hb_glyph_info_t *tmp_string;
-    tmp_string = info;
+    pos = (hb_glyph_position_t *) info;
     info = out_info;
-    out_info = tmp_string;
-    pos = (hb_glyph_position_t *) out_info;
   }
-
-  unsigned int tmp;
-  tmp = len;
   len = out_len;
-  out_len = tmp;
 
+reset:
+  have_output = false;
+  out_len = 0;
   idx = 0;
 }
 
-
-void
-hb_buffer_t::replace_glyphs (unsigned int num_in,
-			     unsigned int num_out,
-			     const uint32_t *glyph_data)
-{
-  if (unlikely (!make_room_for (num_in, num_out))) return;
-
-  assert (idx + num_in <= len);
-
-  merge_clusters (idx, idx + num_in);
-
-  hb_glyph_info_t orig_info = info[idx];
-  hb_glyph_info_t *pinfo = &out_info[out_len];
-  for (unsigned int i = 0; i < num_out; i++)
-  {
-    *pinfo = orig_info;
-    pinfo->codepoint = glyph_data[i];
-    pinfo++;
-  }
-
-  idx  += num_in;
-  out_len += num_out;
-}
-
 bool
 hb_buffer_t::move_to (unsigned int i)
 {
@@ -408,12 +360,11 @@
     /* This will blow in our face if memory allocation fails later
      * in this same lookup...
      *
-     * We used to shift with extra 32 items, instead of the 0 below.
+     * We used to shift with extra 32 items.
      * But that would leave empty slots in the buffer in case of allocation
-     * failures.  Setting to zero for now to avoid other problems (see
-     * comments in shift_forward().  This can cause O(N^2) behavior more
-     * severely than adding 32 empty slots can... */
-    if (unlikely (idx < count && !shift_forward (count + 0))) return false;
+     * failures.  See comments in shift_forward().  This can cause O(N^2)
+     * behavior more severely than adding 32 empty slots can... */
+    if (unlikely (idx < count && !shift_forward (count - idx))) return false;
 
     assert (idx >= count);
 
@@ -438,13 +389,6 @@
   if (!mask)
     return;
 
-  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      info[i].mask = (info[i].mask & not_mask) | value;
-    return;
-  }
-
   unsigned int count = len;
   for (unsigned int i = 0; i < count; i++)
     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
@@ -455,27 +399,13 @@
 hb_buffer_t::reverse_range (unsigned int start,
 			    unsigned int end)
 {
-  unsigned int i, j;
-
   if (end - start < 2)
     return;
 
-  for (i = start, j = end - 1; i < j; i++, j--) {
-    hb_glyph_info_t t;
-
-    t = info[i];
-    info[i] = info[j];
-    info[j] = t;
-  }
+  hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
 
   if (have_positions) {
-    for (i = start, j = end - 1; i < j; i++, j--) {
-      hb_glyph_position_t t;
-
-      t = pos[i];
-      pos[i] = pos[j];
-      pos[j] = t;
-    }
+    hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
   }
 }
 
@@ -612,7 +542,7 @@
 void
 hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
 {
-  unsigned int cluster = (unsigned int) -1;
+  unsigned int cluster = UINT_MAX;
   cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
   _unsafe_to_break_set_mask (info, start, end, cluster);
 }
@@ -628,7 +558,7 @@
   assert (start <= out_len);
   assert (idx <= end);
 
-  unsigned int cluster = (unsigned int) -1;
+  unsigned int cluster = UINT_MAX;
   cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
   cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
   _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
@@ -638,8 +568,7 @@
 void
 hb_buffer_t::guess_segment_properties ()
 {
-  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
-	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+  assert_unicode ();
 
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
@@ -680,6 +609,7 @@
   HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
   HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
   0, /* invisible */
+  0, /* not_found */
   HB_BUFFER_SCRATCH_FLAG_DEFAULT,
   HB_BUFFER_MAX_LEN_DEFAULT,
   HB_BUFFER_MAX_OPS_DEFAULT,
@@ -687,7 +617,7 @@
   HB_BUFFER_CONTENT_TYPE_INVALID,
   HB_SEGMENT_PROPERTIES_DEFAULT,
   false, /* successful */
-  true, /* have_output */
+  false, /* have_output */
   true  /* have_positions */
 
   /* Zero is good enough for everything else. */
@@ -727,21 +657,21 @@
 /**
  * hb_buffer_get_empty:
  *
+ * Fetches an empty #hb_buffer_t.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The empty buffer
  *
  * Since: 0.9.2
  **/
 hb_buffer_t *
 hb_buffer_get_empty ()
 {
-  return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
+  return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
 }
 
 /**
  * hb_buffer_reference: (skip)
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Increases the reference count on @buffer by one. This prevents @buffer from
  * being destroyed until a matching call to hb_buffer_destroy() is made.
@@ -759,7 +689,7 @@
 
 /**
  * hb_buffer_destroy: (skip)
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Deallocate the @buffer.
  * Decreases the reference count on @buffer by one. If the result is zero, then
@@ -774,27 +704,27 @@
 
   hb_unicode_funcs_destroy (buffer->unicode);
 
-  free (buffer->info);
-  free (buffer->pos);
+  hb_free (buffer->info);
+  hb_free (buffer->pos);
 #ifndef HB_NO_BUFFER_MESSAGE
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
 #endif
 
-  free (buffer);
+  hb_free (buffer);
 }
 
 /**
  * hb_buffer_set_user_data: (skip)
- * @buffer: an #hb_buffer_t.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @buffer: An #hb_buffer_t
+ * @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 buffer. 
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -810,12 +740,13 @@
 
 /**
  * hb_buffer_get_user_data: (skip)
- * @buffer: an #hb_buffer_t.
- * @key:
+ * @buffer: An #hb_buffer_t
+ * @key: The user-data key to query
  *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified buffer.
  *
- *
- * Return value:
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -829,11 +760,11 @@
 
 /**
  * hb_buffer_set_content_type:
- * @buffer: an #hb_buffer_t.
- * @content_type: the type of buffer contents to set
+ * @buffer: An #hb_buffer_t
+ * @content_type: The type of buffer contents to set
  *
- * Sets the type of @buffer contents, buffers are either empty, contain
- * characters (before shaping) or glyphs (the result of shaping).
+ * Sets the type of @buffer contents. Buffers are either empty, contain
+ * characters (before shaping), or contain glyphs (the result of shaping).
  *
  * Since: 0.9.5
  **/
@@ -846,12 +777,13 @@
 
 /**
  * hb_buffer_get_content_type:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
- * see hb_buffer_set_content_type().
+ * Fetches the type of @buffer contents. Buffers are either empty, contain
+ * characters (before shaping), or contain glyphs (the result of shaping).
  *
  * Return value:
- * The type of @buffer contents.
+ * The type of @buffer contents
  *
  * Since: 0.9.5
  **/
@@ -864,10 +796,11 @@
 
 /**
  * hb_buffer_set_unicode_funcs:
- * @buffer: an #hb_buffer_t.
- * @unicode_funcs:
+ * @buffer: An #hb_buffer_t
+ * @unicode_funcs: The Unicode-functions structure
  *
- *
+ * Sets the Unicode-functions structure of a buffer to
+ * @unicode_funcs.
  *
  * Since: 0.9.2
  **/
@@ -888,11 +821,11 @@
 
 /**
  * hb_buffer_get_unicode_funcs:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
+ * Fetches the Unicode-functions structure of a buffer.
  *
- *
- * Return value:
+ * Return value: The Unicode-functions structure
  *
  * Since: 0.9.2
  **/
@@ -904,7 +837,7 @@
 
 /**
  * hb_buffer_set_direction:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  * @direction: the #hb_direction_t of the @buffer
  *
  * Set the text flow direction of the buffer. No shaping can happen without
@@ -930,7 +863,7 @@
 
 /**
  * hb_buffer_get_direction:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * See hb_buffer_set_direction()
  *
@@ -947,8 +880,8 @@
 
 /**
  * hb_buffer_set_script:
- * @buffer: an #hb_buffer_t.
- * @script: an #hb_script_t to set.
+ * @buffer: An #hb_buffer_t
+ * @script: An #hb_script_t to set.
  *
  * Sets the script of @buffer to @script.
  *
@@ -958,7 +891,7 @@
  *
  * You can pass one of the predefined #hb_script_t values, or use
  * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
- * corresponding script from an ISO 15924 script tag.
+ * corresponding script from an ISO 15924 script tag.
  *
  * Since: 0.9.2
  **/
@@ -974,12 +907,12 @@
 
 /**
  * hb_buffer_get_script:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
- * See hb_buffer_set_script().
+ * Fetches the script of @buffer.
  *
  * Return value:
- * The #hb_script_t of the @buffer.
+ * The #hb_script_t of the @buffer
  *
  * Since: 0.9.2
  **/
@@ -991,8 +924,8 @@
 
 /**
  * hb_buffer_set_language:
- * @buffer: an #hb_buffer_t.
- * @language: an hb_language_t to set.
+ * @buffer: An #hb_buffer_t
+ * @language: An hb_language_t to set
  *
  * Sets the language of @buffer to @language.
  *
@@ -1001,7 +934,7 @@
  * are orthogonal to the scripts, and though they are related, they are
  * different concepts and should not be confused with each other.
  *
- * Use hb_language_from_string() to convert from BCP 47 language tags to
+ * Use hb_language_from_string() to convert from BCP 47 language tags to
  * #hb_language_t.
  *
  * Since: 0.9.2
@@ -1018,7 +951,7 @@
 
 /**
  * hb_buffer_get_language:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * See hb_buffer_set_language().
  *
@@ -1035,8 +968,8 @@
 
 /**
  * hb_buffer_set_segment_properties:
- * @buffer: an #hb_buffer_t.
- * @props: an #hb_segment_properties_t to use.
+ * @buffer: An #hb_buffer_t
+ * @props: An #hb_segment_properties_t to use
  *
  * Sets the segment properties of the buffer, a shortcut for calling
  * hb_buffer_set_direction(), hb_buffer_set_script() and
@@ -1056,8 +989,8 @@
 
 /**
  * hb_buffer_get_segment_properties:
- * @buffer: an #hb_buffer_t.
- * @props: (out): the output #hb_segment_properties_t.
+ * @buffer: An #hb_buffer_t
+ * @props: (out): The output #hb_segment_properties_t
  *
  * Sets @props to the #hb_segment_properties_t of @buffer.
  *
@@ -1073,8 +1006,8 @@
 
 /**
  * hb_buffer_set_flags:
- * @buffer: an #hb_buffer_t.
- * @flags: the buffer flags to set.
+ * @buffer: An #hb_buffer_t
+ * @flags: The buffer flags to set
  *
  * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
  *
@@ -1092,12 +1025,12 @@
 
 /**
  * hb_buffer_get_flags:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
- * See hb_buffer_set_flags().
+ * Fetches the #hb_buffer_flags_t of @buffer.
  *
  * Return value:
- * The @buffer flags.
+ * The @buffer flags
  *
  * Since: 0.9.7
  **/
@@ -1109,16 +1042,18 @@
 
 /**
  * hb_buffer_set_cluster_level:
- * @buffer: an #hb_buffer_t.
- * @cluster_level:
+ * @buffer: An #hb_buffer_t
+ * @cluster_level: The cluster level to set on the buffer
  *
- *
+ * Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t
+ * dictates one aspect of how HarfBuzz will treat non-base characters 
+ * during shaping.
  *
  * Since: 0.9.42
  **/
 void
-hb_buffer_set_cluster_level (hb_buffer_t       *buffer,
-		     hb_buffer_cluster_level_t  cluster_level)
+hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
+			     hb_buffer_cluster_level_t  cluster_level)
 {
   if (unlikely (hb_object_is_immutable (buffer)))
     return;
@@ -1128,11 +1063,13 @@
 
 /**
  * hb_buffer_get_cluster_level:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
+ * Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t
+ * dictates one aspect of how HarfBuzz will treat non-base characters 
+ * during shaping.
  *
- *
- * Return value:
+ * Return value: The cluster level of @buffer
  *
  * Since: 0.9.42
  **/
@@ -1145,13 +1082,13 @@
 
 /**
  * hb_buffer_set_replacement_codepoint:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  * @replacement: the replacement #hb_codepoint_t
  *
  * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
  * when adding text to @buffer.
  *
- * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
  *
  * Since: 0.9.31
  **/
@@ -1167,12 +1104,13 @@
 
 /**
  * hb_buffer_get_replacement_codepoint:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
- * See hb_buffer_set_replacement_codepoint().
+ * Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding
+ * when adding text to @buffer.
  *
  * Return value:
- * The @buffer replacement #hb_codepoint_t.
+ * The @buffer replacement #hb_codepoint_t
  *
  * Since: 0.9.31
  **/
@@ -1185,7 +1123,7 @@
 
 /**
  * hb_buffer_set_invisible_glyph:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  * @invisible: the invisible #hb_codepoint_t
  *
  * Sets the #hb_codepoint_t that replaces invisible characters in
@@ -1207,12 +1145,12 @@
 
 /**
  * hb_buffer_get_invisible_glyph:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * See hb_buffer_set_invisible_glyph().
  *
  * Return value:
- * The @buffer invisible #hb_codepoint_t.
+ * The @buffer invisible #hb_codepoint_t
  *
  * Since: 2.0.0
  **/
@@ -1222,10 +1160,50 @@
   return buffer->invisible;
 }
 
+/**
+ * hb_buffer_set_not_found_glyph:
+ * @buffer: An #hb_buffer_t
+ * @not_found: the not-found #hb_codepoint_t
+ *
+ * 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
+ * ".notdef" glyph.  This API allows for differentiating the two.
+ *
+ * Since: 3.1.0
+ **/
+void
+hb_buffer_set_not_found_glyph (hb_buffer_t    *buffer,
+			       hb_codepoint_t  not_found)
+{
+  if (unlikely (hb_object_is_immutable (buffer)))
+    return;
+
+  buffer->not_found = not_found;
+}
+
+/**
+ * hb_buffer_get_not_found_glyph:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_not_found_glyph().
+ *
+ * Return value:
+ * The @buffer not-found #hb_codepoint_t
+ *
+ * Since: 3.1.0
+ **/
+hb_codepoint_t
+hb_buffer_get_not_found_glyph (hb_buffer_t    *buffer)
+{
+  return buffer->not_found;
+}
+
 
 /**
  * hb_buffer_reset:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Resets the buffer to its initial status, as if it was just newly created
  * with hb_buffer_create().
@@ -1235,12 +1213,15 @@
 void
 hb_buffer_reset (hb_buffer_t *buffer)
 {
+  if (unlikely (hb_object_is_immutable (buffer)))
+    return;
+
   buffer->reset ();
 }
 
 /**
  * hb_buffer_clear_contents:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
  * the replacement code point.
@@ -1250,18 +1231,21 @@
 void
 hb_buffer_clear_contents (hb_buffer_t *buffer)
 {
+  if (unlikely (hb_object_is_immutable (buffer)))
+    return;
+
   buffer->clear ();
 }
 
 /**
  * hb_buffer_pre_allocate:
- * @buffer: an #hb_buffer_t.
- * @size: number of items to pre allocate.
+ * @buffer: An #hb_buffer_t
+ * @size: Number of items to pre allocate.
  *
  * 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
  **/
@@ -1273,7 +1257,7 @@
 
 /**
  * hb_buffer_allocation_successful:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Check if allocating memory for the buffer succeeded.
  *
@@ -1290,9 +1274,9 @@
 
 /**
  * hb_buffer_add:
- * @buffer: an #hb_buffer_t.
- * @codepoint: a Unicode code point.
- * @cluster: the cluster value of @codepoint.
+ * @buffer: An #hb_buffer_t
+ * @codepoint: A Unicode code point.
+ * @cluster: The cluster value of @codepoint.
  *
  * Appends a character with the Unicode value of @codepoint to @buffer, and
  * gives it the initial cluster value of @cluster. Clusters can be any thing
@@ -1316,8 +1300,8 @@
 
 /**
  * hb_buffer_set_length:
- * @buffer: an #hb_buffer_t.
- * @length: the new length of @buffer.
+ * @buffer: An #hb_buffer_t
+ * @length: The new length of @buffer
  *
  * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
  * end.
@@ -1334,7 +1318,7 @@
   if (unlikely (hb_object_is_immutable (buffer)))
     return length == 0;
 
-  if (!buffer->ensure (length))
+  if (unlikely (!buffer->ensure (length)))
     return false;
 
   /* Wipe the new space */
@@ -1358,7 +1342,7 @@
 
 /**
  * hb_buffer_get_length:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Returns the number of items in the buffer.
  *
@@ -1376,8 +1360,8 @@
 
 /**
  * hb_buffer_get_glyph_infos:
- * @buffer: an #hb_buffer_t.
- * @length: (out): output array length.
+ * @buffer: An #hb_buffer_t
+ * @length: (out): The output-array length.
  *
  * Returns @buffer glyph information array.  Returned pointer
  * is valid as long as @buffer contents are not modified.
@@ -1400,12 +1384,17 @@
 
 /**
  * hb_buffer_get_glyph_positions:
- * @buffer: an #hb_buffer_t.
- * @length: (out): output length.
+ * @buffer: An #hb_buffer_t
+ * @length: (out): The output length
  *
  * Returns @buffer glyph position array.  Returned pointer
  * is valid as long as @buffer contents are not modified.
  *
+ * 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.
+ *
  * Return value: (transfer none) (array length=length):
  * The @buffer glyph position array.
  * The value valid as long as buffer has not been modified.
@@ -1416,23 +1405,47 @@
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
 			       unsigned int *length)
 {
-  if (!buffer->have_positions)
-    buffer->clear_positions ();
-
   if (length)
     *length = buffer->len;
 
+  if (!buffer->have_positions)
+  {
+    if (unlikely (buffer->message_depth))
+      return nullptr;
+
+    buffer->clear_positions ();
+  }
+
   return (hb_glyph_position_t *) buffer->pos;
 }
 
 /**
+ * hb_buffer_has_positions:
+ * @buffer: an #hb_buffer_t.
+ *
+ * Returns whether @buffer has glyph position data.
+ * A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,
+ * and cleared of position data when hb_buffer_clear_contents() is called.
+ *
+ * Return value:
+ * %true if the @buffer has position array, %false otherwise.
+ *
+ * Since: 2.7.3
+ **/
+HB_EXTERN hb_bool_t
+hb_buffer_has_positions (hb_buffer_t  *buffer)
+{
+  return buffer->have_positions;
+}
+
+/**
  * hb_glyph_info_get_glyph_flags:
- * @info: a #hb_glyph_info_t.
+ * @info: a #hb_glyph_info_t
  *
  * Returns glyph flags encoded within a #hb_glyph_info_t.
  *
  * Return value:
- * The #hb_glyph_flags_t encoded within @info.
+ * The #hb_glyph_flags_t encoded within @info
  *
  * Since: 1.5.0
  **/
@@ -1444,7 +1457,7 @@
 
 /**
  * hb_buffer_reverse:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Reverses buffer contents.
  *
@@ -1458,11 +1471,11 @@
 
 /**
  * hb_buffer_reverse_range:
- * @buffer: an #hb_buffer_t.
- * @start: start index.
- * @end: end index.
+ * @buffer: An #hb_buffer_t
+ * @start: start index
+ * @end: end index
  *
- * Reverses buffer contents between start to end.
+ * Reverses buffer contents between @start and @end.
  *
  * Since: 0.9.41
  **/
@@ -1475,7 +1488,7 @@
 
 /**
  * hb_buffer_reverse_clusters:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Reverses buffer clusters.  That is, the buffer contents are
  * reversed, then each cluster (consecutive items having the
@@ -1491,24 +1504,24 @@
 
 /**
  * hb_buffer_guess_segment_properties:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Sets unset buffer segment properties based on buffer Unicode
  * contents.  If buffer is not empty, it must have content type
- * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ * #HB_BUFFER_CONTENT_TYPE_UNICODE.
  *
- * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it
  * will be set to the Unicode script of the first character in
- * the buffer that has a script other than %HB_SCRIPT_COMMON,
- * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ * the buffer that has a script other than #HB_SCRIPT_COMMON,
+ * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.
  *
- * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),
  * it will be set to the natural horizontal direction of the
  * buffer script as returned by hb_script_get_horizontal_direction().
- * If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID,
- * then %HB_DIRECTION_LTR is used.
+ * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,
+ * then #HB_DIRECTION_LTR is used.
  *
- * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),
  * it will be set to the process's default language as returned by
  * hb_language_get_default().  This may change in the future by
  * taking buffer script into consideration when choosing a language.
@@ -1534,8 +1547,7 @@
   typedef typename utf_t::codepoint_t T;
   const hb_codepoint_t replacement = buffer->replacement;
 
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
-	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+  buffer->assert_unicode ();
 
   if (unlikely (hb_object_is_immutable (buffer)))
     return;
@@ -1546,7 +1558,10 @@
   if (item_length == -1)
     item_length = text_length - item_offset;
 
-  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+  if (unlikely (item_length < 0 ||
+		item_length > INT_MAX / 8 ||
+		!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
+    return;
 
   /* If buffer is empty and pre-context provided, install it.
    * This check is written this way, to make sure people can
@@ -1594,12 +1609,12 @@
 
 /**
  * hb_buffer_add_utf8:
- * @buffer: an #hb_buffer_t.
- * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ * @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.
- * @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
+ * @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).
  *
  * See hb_buffer_add_codepoints().
@@ -1621,12 +1636,12 @@
 
 /**
  * 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.
- * @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).
+ * @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
+ * @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)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1647,12 +1662,12 @@
 
 /**
  * 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.
- * @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).
+ * @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
+ * @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)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1673,13 +1688,13 @@
 
 /**
  * hb_buffer_add_latin1:
- * @buffer: an #hb_buffer_t.
+ * @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.
- * @item_offset: the offset of the first character to add to the @buffer.
+ *               characters to append
+ * @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.
@@ -1735,10 +1750,10 @@
 
 /**
  * hb_buffer_append:
- * @buffer: an #hb_buffer_t.
- * @source: source #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
+ * @source: source #hb_buffer_t
  * @start: start index into source buffer to copy.  Use 0 to copy from start of buffer.
- * @end: end index into source buffer to copy.  Use (unsigned int) -1 to copy to end of buffer.
+ * @end: end index into source buffer to copy.  Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.
  *
  * Append (part of) contents of another buffer to this buffer.
  *
@@ -1763,11 +1778,6 @@
   if (start == end)
     return;
 
-  if (!buffer->len)
-    buffer->content_type = source->content_type;
-  if (!buffer->have_positions && source->have_positions)
-    buffer->clear_positions ();
-
   if (buffer->len + (end - start) < buffer->len) /* Overflows. */
   {
     buffer->successful = false;
@@ -1779,9 +1789,36 @@
   if (unlikely (!buffer->successful))
     return;
 
+  if (!orig_len)
+    buffer->content_type = source->content_type;
+  if (!buffer->have_positions && source->have_positions)
+    buffer->clear_positions ();
+
   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]));
+
+  if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
+  {
+    /* See similar logic in add_utf. */
+
+    /* pre-context */
+    if (!orig_len && start + source->context_len[0] > 0)
+    {
+      buffer->clear_context (0);
+      while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+	buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
+      for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
+	buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
+    }
+
+    /* post-context */
+    buffer->clear_context (1);
+    while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+      buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
+    for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
+      buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
+  }
 }
 
 
@@ -1842,7 +1879,7 @@
 
 /**
  * hb_buffer_normalize_glyphs:
- * @buffer: an #hb_buffer_t.
+ * @buffer: An #hb_buffer_t
  *
  * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
  * The resulting clusters should behave identical to pre-reordering clusters.
@@ -1855,23 +1892,13 @@
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
 {
   assert (buffer->have_positions);
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
-	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
+  buffer->assert_glyphs ();
 
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
-  unsigned int count = buffer->len;
-  if (unlikely (!count)) return;
-  hb_glyph_info_t *info = buffer->info;
-
-  unsigned int start = 0;
-  unsigned int end;
-  for (end = start + 1; end < count; end++)
-    if (info[start].cluster != info[end].cluster) {
-      normalize_glyphs_cluster (buffer, start, end, backward);
-      start = end;
-    }
-  normalize_glyphs_cluster (buffer, start, end, backward);
+  foreach_cluster (buffer, start, end)
+    normalize_glyphs_cluster (buffer, start, end, backward);
 }
 
 void
@@ -1907,8 +1934,8 @@
  * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
  * @position_fuzz: allowed absolute difference in position values.
  *
- * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
- * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned.  This should be used by most
+ * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+ * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned.  This should be used by most
  * callers if just comparing two buffers is needed.
  *
  * Since: 1.5.0
@@ -1998,12 +2025,12 @@
 #ifndef HB_NO_BUFFER_MESSAGE
 /**
  * hb_buffer_set_message_func:
- * @buffer: an #hb_buffer_t.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @buffer: An #hb_buffer_t
+ * @func: (closure user_data) (destroy destroy) (scope notified): Callback function
+ * @user_data: (nullable): Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
  *
- *
+ * Sets the implementation function for #hb_buffer_message_func_t.
  *
  * Since: 1.1.3
  **/
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index d5cb746..a183cb9 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -27,7 +27,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -59,8 +59,7 @@
  * The #hb_glyph_info_t is the structure that holds information about the
  * glyphs and their relation to input text.
  */
-typedef struct hb_glyph_info_t
-{
+typedef struct hb_glyph_info_t {
   hb_codepoint_t codepoint;
   /*< private >*/
   hb_mask_t      mask;
@@ -91,6 +90,8 @@
  * 				   breaking point only.
  * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
  *
+ * Flags for #hb_glyph_info_t.
+ *
  * Since: 1.5.0
  */
 typedef enum { /*< flags >*/
@@ -151,6 +152,11 @@
   void           *reserved2;
 } hb_segment_properties_t;
 
+/**
+ * HB_SEGMENT_PROPERTIES_DEFAULT:
+ *
+ * The default #hb_segment_properties_t of of freshly created #hb_buffer_t.
+ */
 #define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
 				       HB_SCRIPT_INVALID, \
 				       HB_LANGUAGE_INVALID, \
@@ -204,6 +210,8 @@
  * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
  * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
  * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ *
+ * The type of #hb_buffer_t contents.
  */
 typedef enum {
   HB_BUFFER_CONTENT_TYPE_INVALID = 0,
@@ -289,6 +297,8 @@
  *                      not be inserted in the rendering of incorrect
  *                      character sequences (such at <0905 093E>). Since: 2.4
  *
+ * Flags for #hb_buffer_t.
+ *
  * Since: 0.9.20
  */
 typedef enum { /*< flags >*/
@@ -315,6 +325,23 @@
  * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
  * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
  *   equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
+ * 
+ * Data type for holding HarfBuzz's clustering behavior options. The cluster level
+ * dictates one aspect of how HarfBuzz will treat non-base characters 
+ * during shaping.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
+ * characters are merged into the cluster of the base character that precedes them.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
+ * assigned their own cluster values, which are not merged into preceding base
+ * clusters. This allows HarfBuzz to perform additional operations like reorder
+ * sequences of adjacent marks.
+ *
+ * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
+ * backward compatibility with older versions of HarfBuzz. New client programs that
+ * do not need to maintain such backward compatibility are recommended to use
+ * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS instead of the default.
  *
  * Since: 0.9.42
  */
@@ -356,6 +383,13 @@
 HB_EXTERN hb_codepoint_t
 hb_buffer_get_invisible_glyph (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_EXTERN void
 hb_buffer_reset (hb_buffer_t *buffer);
@@ -365,7 +399,7 @@
 
 HB_EXTERN hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t  *buffer,
-		        unsigned int  size);
+			unsigned int  size);
 
 
 HB_EXTERN hb_bool_t
@@ -447,6 +481,9 @@
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
 			       unsigned int *length);
 
+HB_EXTERN hb_bool_t
+hb_buffer_has_positions (hb_buffer_t  *buffer);
+
 
 HB_EXTERN void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
@@ -518,6 +555,27 @@
 			    hb_buffer_serialize_format_t format,
 			    hb_buffer_serialize_flags_t flags);
 
+HB_EXTERN unsigned int
+hb_buffer_serialize_unicode (hb_buffer_t *buffer,
+					unsigned int start,
+					unsigned int end,
+					char *buf,
+					unsigned int buf_size,
+					unsigned int *buf_consumed,
+					hb_buffer_serialize_format_t format,
+					hb_buffer_serialize_flags_t flags);
+
+HB_EXTERN unsigned int
+hb_buffer_serialize (hb_buffer_t *buffer,
+					unsigned int start,
+					unsigned int end,
+					char *buf,
+					unsigned int buf_size,
+					unsigned int *buf_consumed,
+					hb_font_t *font,
+					hb_buffer_serialize_format_t format,
+					hb_buffer_serialize_flags_t flags);
+
 HB_EXTERN hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 			      const char *buf,
@@ -526,11 +584,48 @@
 			      hb_font_t *font,
 			      hb_buffer_serialize_format_t format);
 
+HB_EXTERN hb_bool_t
+hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
+            const char *buf,
+            int buf_len,
+            const char **end_ptr,
+            hb_buffer_serialize_format_t format);
+
+
 
 /*
  * Compare buffers
  */
 
+/**
+ * hb_buffer_diff_flags_t:
+ * @HB_BUFFER_DIFF_FLAG_EQUAL: equal buffers.
+ * @HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH: buffers with different
+ *     #hb_buffer_content_type_t.
+ * @HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH: buffers with differing length.
+ * @HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT: `.notdef` glyph is present in the
+ *     reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT: dotted circle glyph is present
+ *     in the reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH: difference in #hb_glyph_info_t.codepoint
+ * @HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH: difference in #hb_glyph_info_t.cluster
+ * @HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH: difference in #hb_glyph_flags_t.
+ * @HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH: difference in #hb_glyph_position_t.
+ *
+ * Flags from comparing two #hb_buffer_t's.
+ *
+ * Buffer with different #hb_buffer_content_type_t cannot be meaningfully
+ * compared in any further detail.
+ *
+ * For buffers with differing length, the per-glyph comparison is not
+ * attempted, though we do still scan reference buffer for dotted circle and
+ * `.notdef` glyphs.
+ *
+ * If the buffers have the same length, we compare them glyph-by-glyph and
+ * report which aspect(s) of the glyph info/position are different.
+ *
+ * Since: 1.5.0
+ */
 typedef enum { /*< flags >*/
   HB_BUFFER_DIFF_FLAG_EQUAL			= 0x0000,
 
@@ -570,6 +665,23 @@
  * Debugging.
  */
 
+/**
+ * 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
+ * @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
+ * the next one.
+ *
+ * Return value: %true to perform the shaping step, %false to skip it.
+ *
+ * Since: 1.1.3
+ */
 typedef hb_bool_t	(*hb_buffer_message_func_t)	(hb_buffer_t *buffer,
 							 hb_font_t   *font,
 							 const char  *message,
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index b5596d9..bde2893 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -35,20 +35,20 @@
 
 
 #ifndef HB_BUFFER_MAX_LEN_FACTOR
-#define HB_BUFFER_MAX_LEN_FACTOR 32
+#define HB_BUFFER_MAX_LEN_FACTOR 64
 #endif
 #ifndef HB_BUFFER_MAX_LEN_MIN
-#define HB_BUFFER_MAX_LEN_MIN 8192
+#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 64
+#define HB_BUFFER_MAX_OPS_FACTOR 1024
 #endif
 #ifndef HB_BUFFER_MAX_OPS_MIN
-#define HB_BUFFER_MAX_OPS_MIN 1024
+#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! */
@@ -93,6 +93,7 @@
   hb_buffer_cluster_level_t cluster_level;
   hb_codepoint_t replacement; /* U+FFFD or something else. */
   hb_codepoint_t invisible; /* 0 or something else. */
+  hb_codepoint_t not_found; /* 0 or something else. */
   hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
   unsigned int max_len; /* Maximum allowed len. */
   int max_ops; /* Maximum allowed operations. */
@@ -107,7 +108,7 @@
 
   unsigned int idx; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
-  unsigned int out_len; /* Length of ->out array if have_output */
+  unsigned int out_len; /* Length of ->out_info array if have_output */
 
   unsigned int allocated; /* Length of allocated arrays */
   hb_glyph_info_t     *info;
@@ -128,6 +129,9 @@
   hb_buffer_message_func_t message_func;
   void *message_data;
   hb_destroy_func_t message_destroy;
+  unsigned message_depth; /* How deeply are we inside a message callback? */
+#else
+  static constexpr unsigned message_depth = 0u;
 #endif
 
   /* Internal debugging. */
@@ -139,7 +143,7 @@
 
   /* Methods */
 
-  bool in_error () const { return !successful; }
+  HB_NODISCARD bool in_error () const { return !successful; }
 
   void allocate_var (unsigned int start, unsigned int count)
   {
@@ -186,13 +190,10 @@
   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]; }
 
-  bool has_separate_output () const { return info != out_info; }
-
-
   HB_INTERNAL void reset ();
   HB_INTERNAL void clear ();
 
-  unsigned int backtrack_len () const { return have_output? out_len : idx; }
+  unsigned int backtrack_len () const { return have_output ? out_len : idx; }
   unsigned int lookahead_len () const { return len - idx; }
   unsigned int next_serial () { return serial++; }
 
@@ -206,90 +207,92 @@
   HB_INTERNAL void guess_segment_properties ();
 
   HB_INTERNAL void swap_buffers ();
-  HB_INTERNAL void remove_output ();
   HB_INTERNAL void clear_output ();
   HB_INTERNAL void clear_positions ();
 
-  HB_INTERNAL void replace_glyphs (unsigned int num_in,
-				   unsigned int num_out,
-				   const hb_codepoint_t *glyph_data);
-
-  void replace_glyph (hb_codepoint_t glyph_index)
+  template <typename T>
+  HB_NODISCARD bool replace_glyphs (unsigned int num_in,
+				    unsigned int num_out,
+				    const T *glyph_data)
   {
-    if (unlikely (out_info != info || out_len != idx)) {
-      if (unlikely (!make_room_for (1, 1))) return;
-      out_info[out_len] = info[idx];
+    if (unlikely (!make_room_for (num_in, num_out))) return false;
+
+    assert (idx + num_in <= len);
+
+    merge_clusters (idx, idx + num_in);
+
+    hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
+
+    hb_glyph_info_t *pinfo = &out_info[out_len];
+    for (unsigned int i = 0; i < num_out; i++)
+    {
+      *pinfo = orig_info;
+      pinfo->codepoint = glyph_data[i];
+      pinfo++;
     }
-    out_info[out_len].codepoint = glyph_index;
 
-    idx++;
-    out_len++;
+    idx  += num_in;
+    out_len += num_out;
+    return true;
   }
+
+  HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
+  { return replace_glyphs (1, 1, &glyph_index); }
+
   /* Makes a copy of the glyph at idx to output and replace glyph_index */
-  hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
+  HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
+  { return replace_glyphs (0, 1, &glyph_index); }
+
+  HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
   {
-    if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
-
-    if (unlikely (idx == len && !out_len))
-      return Crap(hb_glyph_info_t);
-
-    out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
-    out_info[out_len].codepoint = glyph_index;
-
-    out_len++;
-
-    return out_info[out_len - 1];
-  }
-  void output_info (const hb_glyph_info_t &glyph_info)
-  {
-    if (unlikely (!make_room_for (0, 1))) return;
+    if (unlikely (!make_room_for (0, 1))) return false;
 
     out_info[out_len] = glyph_info;
 
     out_len++;
+    return true;
   }
   /* Copies glyph at idx to output but doesn't advance idx */
-  void copy_glyph ()
+  HB_NODISCARD bool copy_glyph ()
   {
-    if (unlikely (!make_room_for (0, 1))) return;
-
-    out_info[out_len] = info[idx];
-
-    out_len++;
+    /* Extra copy because cur()'s return can be freed within
+     * output_info() call if buffer reallocates. */
+    return output_info (hb_glyph_info_t (cur()));
   }
+
   /* Copies glyph at idx to output and advance idx.
    * If there's no output, just advance idx. */
-  void
-  next_glyph ()
+  HB_NODISCARD bool next_glyph ()
   {
     if (have_output)
     {
       if (out_info != info || out_len != idx)
       {
-	if (unlikely (!make_room_for (1, 1))) return;
+	if (unlikely (!make_room_for (1, 1))) return false;
 	out_info[out_len] = info[idx];
       }
       out_len++;
     }
 
     idx++;
+    return true;
   }
   /* Copies n glyphs at idx to output and advance idx.
    * If there's no output, just advance idx. */
-  void
-  next_glyphs (unsigned int n)
+  HB_NODISCARD bool next_glyphs (unsigned int n)
   {
     if (have_output)
     {
       if (out_info != info || out_len != idx)
       {
-	if (unlikely (!make_room_for (n, n))) return;
+	if (unlikely (!make_room_for (n, n))) return false;
 	memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
       }
       out_len += n;
     }
 
     idx += n;
+    return true;
   }
   /* Advance idx without copying to output. */
   void skip_glyph () { idx++; }
@@ -318,7 +321,7 @@
   HB_INTERNAL void delete_glyph ();
 
   void unsafe_to_break (unsigned int start,
-			       unsigned int end)
+			unsigned int end)
   {
     if (end - start < 2)
       return;
@@ -329,18 +332,51 @@
 
 
   /* Internal methods */
-  HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+  HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
 
-  HB_INTERNAL bool enlarge (unsigned int size);
+  HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
 
-  bool ensure (unsigned int size)
+  HB_NODISCARD bool ensure (unsigned int size)
   { return likely (!size || size < allocated) ? true : enlarge (size); }
 
-  bool ensure_inplace (unsigned int size)
+  HB_NODISCARD bool ensure_inplace (unsigned int size)
   { return likely (!size || size < allocated); }
 
-  HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
-  HB_INTERNAL bool shift_forward (unsigned int count);
+  void assert_glyphs ()
+  {
+    assert ((content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) ||
+	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
+  }
+  void assert_unicode ()
+  {
+    assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
+	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
+  }
+  HB_NODISCARD bool ensure_glyphs ()
+  {
+    if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
+    {
+      if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
+	return false;
+      assert (len == 0);
+      content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+    }
+    return true;
+  }
+  HB_NODISCARD bool ensure_unicode ()
+  {
+    if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
+    {
+      if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
+	return false;
+      assert (len == 0);
+      content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
+    }
+    return true;
+  }
+
+  HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+  HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
 
   typedef long scratch_buffer_t;
   HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
@@ -364,10 +400,16 @@
 #else
     if (!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
   }
@@ -386,7 +428,7 @@
     inf.cluster = cluster;
   }
 
-  int
+  unsigned int
   _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
 				     unsigned int start, unsigned int end,
 				     unsigned int cluster) const
diff --git a/src/hb-cache.hh b/src/hb-cache.hh
index bf26d96..e617b75 100644
--- a/src/hb-cache.hh
+++ b/src/hb-cache.hh
@@ -30,7 +30,7 @@
 #include "hb.hh"
 
 
-/* Implements a lock-free cache for int->int functions. */
+/* Implements a lockfree cache for int->int functions. */
 
 template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
 struct hb_cache_t
diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh
index 780f618..c251e2d 100644
--- a/src/hb-cff-interp-common.hh
+++ b/src/hb-cff-interp-common.hh
@@ -252,30 +252,27 @@
 struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
 {
   // encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
-  template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
+  template <typename T, typename V>
+  static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
   {
     TRACE_SERIALIZE (this);
 
-    if (unlikely ((value < minVal || value > maxVal)))
-      return_trace (false);
-
     HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-    if (unlikely (p == nullptr)) return_trace (false);
+    if (unlikely (!p)) return_trace (false);
     *p = intOp;
 
-    INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
-    if (unlikely (ip == nullptr)) return_trace (false);
-    *ip = (unsigned int) value;
-
-    return_trace (true);
+    T *ip = c->allocate_size<T> (T::static_size);
+    if (unlikely (!ip)) return_trace (false);
+    return_trace (c->check_assign (*ip, value, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
-  static bool serialize_int4 (hb_serialize_context_t *c, int value)
-  { return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
+  template <typename V>
+  static bool serialize_int4 (hb_serialize_context_t *c, V value)
+  { return serialize_int<HBINT32> (c, OpCode_longintdict, value); }
 
-  static bool serialize_int2 (hb_serialize_context_t *c, int value)
-  { return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
+  template <typename V>
+  static bool serialize_int2 (hb_serialize_context_t *c, V value)
+  { return serialize_int<HBINT16> (c, OpCode_shortint, value); }
 
   /* Defining null_size allows a Null object may be created. Should be safe because:
    * A descendent struct Dict uses a Null pointer to indicate a missing table,
@@ -408,7 +405,7 @@
     else
     {
       set_error ();
-      return Crap(ELEM);
+      return Crap (ELEM);
     }
   }
 
@@ -419,7 +416,7 @@
     else
     {
       set_error ();
-      return Crap(ELEM);
+      return Crap (ELEM);
     }
   }
   void pop (unsigned int n)
@@ -435,7 +432,7 @@
     if (unlikely (count < 0))
     {
       set_error ();
-      return Null(ELEM);
+      return Null (ELEM);
     }
     return elements[count - 1];
   }
@@ -542,7 +539,7 @@
     TRACE_SERIALIZE (this);
 
     HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
-    if (unlikely (d == nullptr)) return_trace (false);
+    if (unlikely (!d)) return_trace (false);
     memcpy (d, &opstr.str[0], opstr.str.length);
     return_trace (true);
   }
diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh
index d9ad4d0..52d778f 100644
--- a/src/hb-cff-interp-cs-common.hh
+++ b/src/hb-cff-interp-cs-common.hh
@@ -76,13 +76,13 @@
 
   void fini () {}
 
-  unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; }
+  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
   {
-    if (unlikely ((subrs == nullptr) || index >= subrs->count))
-      return Null(byte_str_t);
+    if (unlikely (!subrs || index >= subrs->count))
+      return Null (byte_str_t);
     else
       return (*subrs)[index];
   }
@@ -551,8 +551,13 @@
 
   static void rcurveline (ENV &env, PARAM& param)
   {
+    unsigned int arg_count = env.argStack.get_count ();
+    if (unlikely (arg_count < 8))
+      return;
+
     unsigned int i = 0;
-    for (; i + 6 <= env.argStack.get_count (); i += 6)
+    unsigned int curve_limit = arg_count - 2;
+    for (; i + 6 <= curve_limit; i += 6)
     {
       point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
@@ -562,34 +567,34 @@
       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
       PATH::curve (env, param, pt1, pt2, pt3);
     }
-    for (; i + 2 <= env.argStack.get_count (); i += 2)
-    {
-      point_t pt1 = env.get_pt ();
-      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      PATH::line (env, param, pt1);
-    }
+
+    point_t pt1 = env.get_pt ();
+    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
+    PATH::line (env, param, pt1);
   }
 
   static void rlinecurve (ENV &env, PARAM& param)
   {
+    unsigned int arg_count = env.argStack.get_count ();
+    if (unlikely (arg_count < 8))
+      return;
+
     unsigned int i = 0;
-    unsigned int line_limit = (env.argStack.get_count () % 6);
+    unsigned int line_limit = arg_count - 6;
     for (; i + 2 <= line_limit; i += 2)
     {
       point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
       PATH::line (env, param, pt1);
     }
-    for (; i + 6 <= env.argStack.get_count (); i += 6)
-    {
-      point_t pt1 = env.get_pt ();
-      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      point_t pt2 = pt1;
-      pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
-      point_t pt3 = pt2;
-      pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
-      PATH::curve (env, param, pt1, pt2, pt3);
-    }
+
+    point_t pt1 = env.get_pt ();
+    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
+    point_t pt2 = pt1;
+    pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
+    point_t pt3 = pt2;
+    pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
+    PATH::curve (env, param, pt1, pt2, pt3);
   }
 
   static void vvcurveto (ENV &env, PARAM& param)
diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh
index 1f03d82..a520ca3 100644
--- a/src/hb-cff-interp-dict-common.hh
+++ b/src/hb-cff-interp-dict-common.hh
@@ -27,8 +27,6 @@
 #define HB_CFF_INTERP_DICT_COMMON_HH
 
 #include "hb-cff-interp-common.hh"
-#include <math.h>
-#include <float.h>
 
 namespace CFF {
 
@@ -58,19 +56,6 @@
   }
   void fini () { dict_values_t<OPSTR>::fini (); }
 
-  unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_CharStrings:
-      case OpCode_FDArray:
-	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-	return opstr.str.length;
-    }
-  }
-
   unsigned int  charStringsOffset;
   unsigned int  FDArrayOffset;
 };
diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh
index a72100e..d961566 100644
--- a/src/hb-cff2-interp-cs.hh
+++ b/src/hb-cff2-interp-cs.hh
@@ -52,7 +52,7 @@
   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_)
+		   unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
   {
     numValues = numValues_;
     valueIndex = valueIndex_;
@@ -80,7 +80,7 @@
 {
   template <typename ACC>
   void init (const byte_str_t &str, ACC &acc, unsigned int fd,
-		    const int *coords_=nullptr, unsigned int num_coords_=0)
+	     const int *coords_=nullptr, unsigned int num_coords_=0)
   {
     SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
 
@@ -90,7 +90,7 @@
     seen_blend = false;
     seen_vsindex_ = false;
     scalars.init ();
-    do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
+    do_blend = num_coords && coords && varStore->size;
     set_ivs (acc.privateDicts[fd].ivs);
   }
 
@@ -133,10 +133,11 @@
       region_count = varStore->varStore.get_region_index_count (get_ivs ());
       if (do_blend)
       {
-	scalars.resize (region_count);
-	varStore->varStore.get_scalars (get_ivs (),
-					(int *)coords, num_coords,
-					&scalars[0], region_count);
+	if (unlikely (!scalars.resize (region_count)))
+	  set_error ();
+	else
+	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
+						 &scalars[0], region_count);
       }
       seen_blend = true;
     }
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 0ae0c05..26c8ad0 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -69,7 +69,6 @@
 	if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
 
       OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
-      OPTION ("aat", aat);
 
 #undef OPTION
 
@@ -87,12 +86,15 @@
 
 /**
  * hb_tag_from_string:
- * @str: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): String to convert
+ * @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
+ * padded with spaces. Longer input strings will be
+ * truncated.
  *
- *
- * Return value:
+ * Return value: The #hb_tag_t corresponding to @str
  *
  * Since: 0.9.2
  **/
@@ -117,10 +119,11 @@
 
 /**
  * hb_tag_to_string:
- * @tag:
- * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
+ * @tag: #hb_tag_t to convert
+ * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
  *
- *
+ * Converts an #hb_tag_t to a string and returns it in @buf. 
+ * Strings will be four characters long.
  *
  * Since: 0.9.5
  **/
@@ -145,12 +148,17 @@
 
 /**
  * hb_direction_from_string:
- * @str: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): String to convert
+ * @len: Length of @str, or -1 if it is %NULL-terminated
  *
+ * Converts a string to an #hb_direction_t. 
  *
+ * Matching is loose and applies only to the first letter. For
+ * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
  *
- * Return value:
+ * Unmatched strings will return #HB_DIRECTION_INVALID.
+ * 
+ * Return value: The #hb_direction_t matching @str
  *
  * Since: 0.9.2
  **/
@@ -173,11 +181,11 @@
 
 /**
  * hb_direction_to_string:
- * @direction:
+ * @direction: The #hb_direction_t to convert
  *
+ * Converts an #hb_direction_t to a string.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): The string corresponding to @direction
  *
  * Since: 0.9.2
  **/
@@ -249,13 +257,11 @@
   bool operator == (const char *s) const
   { return lang_equal (lang, s); }
 
-  hb_language_item_t & operator = (const char *s) {
-    /* If a custom allocated is used calling strdup() pairs
-    badly with a call to the custom free() in fini() below.
-    Therefore don't call strdup(), implement its behavior.
-    */
+  hb_language_item_t & operator = (const char *s)
+  {
+    /* We can't call strdup(), because we allow custom allocators. */
     size_t len = strlen(s) + 1;
-    lang = (hb_language_t) malloc(len);
+    lang = (hb_language_t) hb_malloc(len);
     if (likely (lang))
     {
       memcpy((unsigned char *) lang, s, len);
@@ -266,16 +272,15 @@
     return *this;
   }
 
-  void fini () { free ((void *) lang); }
+  void fini () { hb_free ((void *) lang); }
 };
 
 
-/* Thread-safe lock-free language list */
+/* Thread-safe lockfree language list */
 
 static hb_atomic_ptr_t <hb_language_item_t> langs;
 
-#if HB_USE_ATEXIT
-static void
+static inline void
 free_langs ()
 {
 retry:
@@ -286,11 +291,10 @@
   while (first_lang) {
     hb_language_item_t *next = first_lang->next;
     first_lang->fini ();
-    free (first_lang);
+    hb_free (first_lang);
     first_lang = next;
   }
 }
-#endif
 
 static hb_language_item_t *
 lang_find_or_insert (const char *key)
@@ -303,28 +307,26 @@
       return lang;
 
   /* Not found; allocate one. */
-  hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
+  hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
   if (unlikely (!lang))
     return nullptr;
   lang->next = first_lang;
   *lang = key;
   if (unlikely (!lang->lang))
   {
-    free (lang);
+    hb_free (lang);
     return nullptr;
   }
 
   if (unlikely (!langs.cmpexch (first_lang, lang)))
   {
     lang->fini ();
-    free (lang);
+    hb_free (lang);
     goto retry;
   }
 
-#if HB_USE_ATEXIT
   if (!first_lang)
-    atexit (free_langs); /* First person registers atexit() callback. */
-#endif
+    hb_atexit (free_langs); /* First person registers atexit() callback. */
 
   return lang;
 }
@@ -333,14 +335,14 @@
 /**
  * hb_language_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing
- *       a BCP 47 language tag
+ *       a BCP 47 language tag
  * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
- * Converts @str representing a BCP 47 language tag to the corresponding
+ * Converts @str representing a BCP 47 language tag to the corresponding
  * #hb_language_t.
  *
  * Return value: (transfer none):
- * The #hb_language_t corresponding to the BCP 47 language tag.
+ * The #hb_language_t corresponding to the BCP 47 language tag.
  *
  * Since: 0.9.2
  **/
@@ -368,9 +370,9 @@
 
 /**
  * hb_language_to_string:
- * @language: an #hb_language_t to convert.
+ * @language: The #hb_language_t to convert
  *
- * See hb_language_from_string().
+ * Converts an #hb_language_t to a string.
  *
  * Return value: (transfer none):
  * A %NULL-terminated string representing the @language. Must not be freed by
@@ -389,16 +391,17 @@
 /**
  * hb_language_get_default:
  *
- * Get default language from current locale.
+ * Fetch the default language from current locale.
  *
- * Note that the first time this function is called, it calls
+ * <note>Note that the first time this function is called, it calls
  * "setlocale (LC_CTYPE, nullptr)" to fetch current locale.  The underlying
  * setlocale function is, in many implementations, NOT threadsafe.  To avoid
  * problems, call this function once before multiple threads can call it.
  * This function is only used from hb_buffer_guess_segment_properties() by
- * HarfBuzz itself.
+ * HarfBuzz itself.</note>
  *
- * Return value: (transfer none):
+ * Return value: (transfer none): The default language of the locale as
+ * an #hb_language_t
  *
  * Since: 0.9.2
  **/
@@ -422,12 +425,12 @@
 
 /**
  * hb_script_from_iso15924_tag:
- * @tag: an #hb_tag_t representing an ISO 15924 tag.
+ * @tag: an #hb_tag_t representing an ISO 15924 tag.
  *
- * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
+ * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
  *
  * Return value:
- * An #hb_script_t corresponding to the ISO 15924 tag.
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
@@ -449,7 +452,12 @@
     case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
 
     /* Script variants from https://unicode.org/iso15924/ */
+    case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
     case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
+    case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
+    case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
+    case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
+    case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
     case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
     case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
     case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
@@ -468,15 +476,15 @@
 /**
  * hb_script_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing an
- *       ISO 15924 tag.
+ *       ISO 15924 tag.
  * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
- * Converts a string @str representing an ISO 15924 script tag to a
+ * Converts a string @str representing an ISO 15924 script tag to a
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
  * hb_script_from_iso15924_tag().
  *
  * Return value:
- * An #hb_script_t corresponding to the ISO 15924 tag.
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
@@ -490,10 +498,10 @@
  * hb_script_to_iso15924_tag:
  * @script: an #hb_script_t to convert.
  *
- * See hb_script_from_iso15924_tag().
+ * Converts an #hb_script_t to a corresponding ISO 15924 script tag.
  *
  * Return value:
- * An #hb_tag_t representing an ISO 15924 script tag.
+ * An #hb_tag_t representing an ISO 15924 script tag.
  *
  * Since: 0.9.2
  **/
@@ -505,11 +513,16 @@
 
 /**
  * hb_script_get_horizontal_direction:
- * @script:
+ * @script: The #hb_script_t to query
  *
+ * Fetches the #hb_direction_t of a script when it is
+ * set horizontally. All right-to-left scripts will return
+ * #HB_DIRECTION_RTL. All left-to-right scripts will return
+ * #HB_DIRECTION_LTR.  Scripts that can be written either
+ * horizontally or vertically will return #HB_DIRECTION_INVALID.
+ * Unknown scripts will return #HB_DIRECTION_LTR.
  *
- *
- * Return value:
+ * Return value: The horizontal #hb_direction_t of @script
  *
  * Since: 0.9.2
  **/
@@ -575,6 +588,16 @@
     case HB_SCRIPT_OLD_SOGDIAN:
     case HB_SCRIPT_SOGDIAN:
 
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_ELYMAIC:
+
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_YEZIDI:
+
+    /* Unicode-14.0 additions */
+    case HB_SCRIPT_OLD_UYGHUR:
+
       return HB_DIRECTION_RTL;
 
 
@@ -590,38 +613,6 @@
 }
 
 
-/* hb_user_data_array_t */
-
-bool
-hb_user_data_array_t::set (hb_user_data_key_t *key,
-			   void *              data,
-			   hb_destroy_func_t   destroy,
-			   hb_bool_t           replace)
-{
-  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;
-}
-
-void *
-hb_user_data_array_t::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;
-}
-
-
 /* hb_version */
 
 
@@ -639,9 +630,9 @@
 
 /**
  * hb_version:
- * @major: (out): Library major version component.
- * @minor: (out): Library minor version component.
- * @micro: (out): Library micro version component.
+ * @major: (out): Library major version component
+ * @minor: (out): Library minor version component
+ * @micro: (out): Library micro version component
  *
  * Returns library version as three integer components.
  *
@@ -662,7 +653,7 @@
  *
  * Returns library version as a string with three components.
  *
- * Return value: library version string.
+ * Return value: Library version string
  *
  * Since: 0.9.2
  **/
@@ -674,13 +665,15 @@
 
 /**
  * hb_version_atleast:
- * @major:
- * @minor:
- * @micro:
+ * @major: Library major version component
+ * @minor: Library minor version component
+ * @micro: Library micro version component
  *
+ * Tests the library version against a minimum value,
+ * as three integer components.
  *
- *
- * Return value:
+ * Return value: %true if the library is equal to or greater than
+ * the test value, %false otherwise
  *
  * Since: 0.9.30
  **/
@@ -909,7 +902,7 @@
  * </informaltable>
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise.
+ * %true if @str is successfully parsed, %false otherwise
  *
  * Since: 0.9.5
  **/
@@ -960,14 +953,14 @@
   len += 4;
   while (len && s[len - 1] == ' ')
     len--;
-  if (feature->start != 0 || feature->end != (unsigned int) -1)
+  if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
   {
     s[len++] = '[';
     if (feature->start)
       len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
-      if (feature->end != (unsigned int) -1)
+      if (feature->end != HB_FEATURE_GLOBAL_END)
 	len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
     }
     s[len++] = ']';
@@ -1007,6 +1000,21 @@
 
 /**
  * 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
+ * @variation: (out): the #hb_variation_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_variation_t.
+ *
+ * The format for specifying variation settings follows. All valid CSS
+ * font-variation-settings values other than 'normal' and 'inherited' are also
+ * accepted, though, not documented below.
+ *
+ * The format is a tag, optionally followed by an equals sign, followed by a
+ * number. For example `wght=500`, or `slnt=-7.5`.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise
  *
  * Since: 1.4.2
  */
@@ -1033,6 +1041,13 @@
 
 /**
  * hb_variation_to_string:
+ * @variation: an #hb_variation_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * 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.
  *
  * Since: 1.4.2
  */
@@ -1059,9 +1074,11 @@
 
 /**
  * hb_color_get_alpha:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
  *
- * Return value: Alpha channel value of the given color
+ * Fetches the alpha channel of the given @color.
+ *
+ * Return value: Alpha channel value
  *
  * Since: 2.1.0
  */
@@ -1073,9 +1090,11 @@
 
 /**
  * hb_color_get_red:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
  *
- * Return value: Red channel value of the given color
+ * Fetches the red channel of the given @color.
+ *
+ * Return value: Red channel value
  *
  * Since: 2.1.0
  */
@@ -1087,9 +1106,11 @@
 
 /**
  * hb_color_get_green:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
  *
- * Return value: Green channel value of the given color
+ * Fetches the green channel of the given @color.
+ *
+ * Return value: Green channel value
  *
  * Since: 2.1.0
  */
@@ -1101,9 +1122,11 @@
 
 /**
  * hb_color_get_blue:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
  *
- * Return value: Blue channel value of the given color
+ * Fetches the blue channel of the given @color.
+ *
+ * Return value: Blue channel value
  *
  * Since: 2.1.0
  */
diff --git a/src/hb-common.h b/src/hb-common.h
index 037e508..0384117 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -26,7 +26,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -88,11 +88,37 @@
 
 HB_BEGIN_DECLS
 
-
+/**
+ * hb_bool_t:
+ * 
+ * Data type for booleans.
+ *
+ **/
 typedef int hb_bool_t;
 
+/**
+ * hb_codepoint_t:
+ * 
+ * Data type for holding Unicode codepoints. Also
+ * used to hold glyph IDs.
+ *
+ **/
 typedef uint32_t hb_codepoint_t;
+/**
+ * hb_position_t:
+ * 
+ * Data type for holding a single coordinate value.
+ * Contour points and other multi-dimensional data are
+ * stored as tuples of #hb_position_t's.
+ *
+ **/
 typedef int32_t hb_position_t;
+/**
+ * hb_mask_t:
+ * 
+ * Data type for bitmasks.
+ *
+ **/
 typedef uint32_t hb_mask_t;
 
 typedef union _hb_var_int_t {
@@ -107,13 +133,63 @@
 
 /* hb_tag_t */
 
+/**
+ * hb_tag_t:
+ *
+ * Data type for tag identifiers. Tags are four
+ * byte integers, each byte representing a character.
+ *
+ * Tags are used to identify tables, design-variation axes,
+ * scripts, languages, font features, and baselines with
+ * human-readable names.
+ *
+ **/
 typedef uint32_t hb_tag_t;
 
+/**
+ * HB_TAG:
+ * @c1: 1st character of the tag
+ * @c2: 2nd character of the tag
+ * @c3: 3rd character of the tag
+ * @c4: 4th character of the tag
+ *
+ * Constructs an #hb_tag_t from four character literals.
+ *
+ **/
 #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
+
+/**
+ * HB_UNTAG:
+ * @tag: an #hb_tag_t
+ *
+ * Extracts four character literals from an #hb_tag_t.
+ *
+ * Since: 0.6.0
+ *
+ **/
 #define HB_UNTAG(tag)   (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
 
+/**
+ * HB_TAG_NONE:
+ *
+ * Unset #hb_tag_t.
+ */
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
+/**
+ * HB_TAG_MAX:
+ *
+ * Maximum possible unsigned #hb_tag_t.
+ *
+ * Since: 0.9.26
+ */
 #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+/**
+ * HB_TAG_MAX_SIGNED:
+ *
+ * Maximum possible signed #hb_tag_t.
+ *
+ * Since: 0.9.33
+ */
 #define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
 
 /* len=-1 means str is NUL-terminated. */
@@ -132,6 +208,13 @@
  * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
  * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
  * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
+ *
+ * The direction of a text segment or buffer.
+ * 
+ * A segment can also be tested for horizontal or vertical
+ * orientation (irrespective of specific direction) with 
+ * HB_DIRECTION_IS_HORIZONTAL() or HB_DIRECTION_IS_VERTICAL().
+ *
  */
 typedef enum {
   HB_DIRECTION_INVALID = 0,
@@ -148,17 +231,71 @@
 HB_EXTERN const char *
 hb_direction_to_string (hb_direction_t direction);
 
+/**
+ * HB_DIRECTION_IS_VALID:
+ * @dir: #hb_direction_t to test
+ *
+ * Tests whether a text direction is valid.
+ *
+ **/
 #define HB_DIRECTION_IS_VALID(dir)	((((unsigned int) (dir)) & ~3U) == 4)
 /* Direction must be valid for the following */
+/**
+ * HB_DIRECTION_IS_HORIZONTAL:
+ * @dir: #hb_direction_t to test
+ *
+ * Tests whether a text direction is horizontal. Requires
+ * that the direction be valid.
+ *
+ **/
 #define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 4)
+/**
+ * HB_DIRECTION_IS_VERTICAL:
+ * @dir: #hb_direction_t to test
+ *
+ * Tests whether a text direction is vertical. Requires
+ * that the direction be valid.
+ *
+ **/
 #define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 6)
+/**
+ * HB_DIRECTION_IS_FORWARD:
+ * @dir: #hb_direction_t to test
+ *
+ * Tests whether a text direction moves forward (from left to right, or from
+ * top to bottom). Requires that the direction be valid.
+ *
+ **/
 #define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 4)
+/**
+ * HB_DIRECTION_IS_BACKWARD:
+ * @dir: #hb_direction_t to test
+ *
+ * Tests whether a text direction moves backward (from right to left, or from
+ * bottom to top). Requires that the direction be valid.
+ *
+ **/
 #define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 5)
+/**
+ * HB_DIRECTION_REVERSE:
+ * @dir: #hb_direction_t to reverse
+ *
+ * Reverses a text direction. Requires that the direction
+ * be valid.
+ *
+ **/
 #define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1))
 
 
 /* hb_language_t */
 
+/**
+ * hb_language_t:
+ *
+ * Data type for languages. Each #hb_language_t corresponds to a BCP 47
+ * language tag.
+ *
+ */
 typedef const struct hb_language_impl_t *hb_language_t;
 
 HB_EXTERN hb_language_t
@@ -167,208 +304,403 @@
 HB_EXTERN const char *
 hb_language_to_string (hb_language_t language);
 
+/**
+ * HB_LANGUAGE_INVALID:
+ *
+ * An unset #hb_language_t.
+ *
+ * Since: 0.6.0
+ */
 #define HB_LANGUAGE_INVALID ((hb_language_t) 0)
 
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
 
-/* hb_script_t */
+/**
+ * hb_script_t:
+ * @HB_SCRIPT_COMMON: `Zyyy`
+ * @HB_SCRIPT_INHERITED: `Zinh`
+ * @HB_SCRIPT_UNKNOWN: `Zzzz`
+ * @HB_SCRIPT_ARABIC: `Arab`
+ * @HB_SCRIPT_ARMENIAN: `Armn`
+ * @HB_SCRIPT_BENGALI: `Beng`
+ * @HB_SCRIPT_CYRILLIC: `Cyrl`
+ * @HB_SCRIPT_DEVANAGARI: `Deva`
+ * @HB_SCRIPT_GEORGIAN: `Geor`
+ * @HB_SCRIPT_GREEK: `Grek`
+ * @HB_SCRIPT_GUJARATI: `Gujr`
+ * @HB_SCRIPT_GURMUKHI: `Guru`
+ * @HB_SCRIPT_HANGUL: `Hang`
+ * @HB_SCRIPT_HAN: `Hani`
+ * @HB_SCRIPT_HEBREW: `Hebr`
+ * @HB_SCRIPT_HIRAGANA: `Hira`
+ * @HB_SCRIPT_KANNADA: `Knda`
+ * @HB_SCRIPT_KATAKANA: `Kana`
+ * @HB_SCRIPT_LAO: `Laoo`
+ * @HB_SCRIPT_LATIN: `Latn`
+ * @HB_SCRIPT_MALAYALAM: `Mlym`
+ * @HB_SCRIPT_ORIYA: `Orya`
+ * @HB_SCRIPT_TAMIL: `Taml`
+ * @HB_SCRIPT_TELUGU: `Telu`
+ * @HB_SCRIPT_THAI: `Thai`
+ * @HB_SCRIPT_TIBETAN: `Tibt`
+ * @HB_SCRIPT_BOPOMOFO: `Bopo`
+ * @HB_SCRIPT_BRAILLE: `Brai`
+ * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
+ * @HB_SCRIPT_CHEROKEE: `Cher`
+ * @HB_SCRIPT_ETHIOPIC: `Ethi`
+ * @HB_SCRIPT_KHMER: `Khmr`
+ * @HB_SCRIPT_MONGOLIAN: `Mong`
+ * @HB_SCRIPT_MYANMAR: `Mymr`
+ * @HB_SCRIPT_OGHAM: `Ogam`
+ * @HB_SCRIPT_RUNIC: `Runr`
+ * @HB_SCRIPT_SINHALA: `Sinh`
+ * @HB_SCRIPT_SYRIAC: `Syrc`
+ * @HB_SCRIPT_THAANA: `Thaa`
+ * @HB_SCRIPT_YI: `Yiii`
+ * @HB_SCRIPT_DESERET: `Dsrt`
+ * @HB_SCRIPT_GOTHIC: `Goth`
+ * @HB_SCRIPT_OLD_ITALIC: `Ital`
+ * @HB_SCRIPT_BUHID: `Buhd`
+ * @HB_SCRIPT_HANUNOO: `Hano`
+ * @HB_SCRIPT_TAGALOG: `Tglg`
+ * @HB_SCRIPT_TAGBANWA: `Tagb`
+ * @HB_SCRIPT_CYPRIOT: `Cprt`
+ * @HB_SCRIPT_LIMBU: `Limb`
+ * @HB_SCRIPT_LINEAR_B: `Linb`
+ * @HB_SCRIPT_OSMANYA: `Osma`
+ * @HB_SCRIPT_SHAVIAN: `Shaw`
+ * @HB_SCRIPT_TAI_LE: `Tale`
+ * @HB_SCRIPT_UGARITIC: `Ugar`
+ * @HB_SCRIPT_BUGINESE: `Bugi`
+ * @HB_SCRIPT_COPTIC: `Copt`
+ * @HB_SCRIPT_GLAGOLITIC: `Glag`
+ * @HB_SCRIPT_KHAROSHTHI: `Khar`
+ * @HB_SCRIPT_NEW_TAI_LUE: `Talu`
+ * @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
+ * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
+ * @HB_SCRIPT_TIFINAGH: `Tfng`
+ * @HB_SCRIPT_BALINESE: `Bali`
+ * @HB_SCRIPT_CUNEIFORM: `Xsux`
+ * @HB_SCRIPT_NKO: `Nkoo`
+ * @HB_SCRIPT_PHAGS_PA: `Phag`
+ * @HB_SCRIPT_PHOENICIAN: `Phnx`
+ * @HB_SCRIPT_CARIAN: `Cari`
+ * @HB_SCRIPT_CHAM: `Cham`
+ * @HB_SCRIPT_KAYAH_LI: `Kali`
+ * @HB_SCRIPT_LEPCHA: `Lepc`
+ * @HB_SCRIPT_LYCIAN: `Lyci`
+ * @HB_SCRIPT_LYDIAN: `Lydi`
+ * @HB_SCRIPT_OL_CHIKI: `Olck`
+ * @HB_SCRIPT_REJANG: `Rjng`
+ * @HB_SCRIPT_SAURASHTRA: `Saur`
+ * @HB_SCRIPT_SUNDANESE: `Sund`
+ * @HB_SCRIPT_VAI: `Vaii`
+ * @HB_SCRIPT_AVESTAN: `Avst`
+ * @HB_SCRIPT_BAMUM: `Bamu`
+ * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
+ * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
+ * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
+ * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
+ * @HB_SCRIPT_JAVANESE: `Java`
+ * @HB_SCRIPT_KAITHI: `Kthi`
+ * @HB_SCRIPT_LISU: `Lisu`
+ * @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
+ * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
+ * @HB_SCRIPT_OLD_TURKIC: `Orkh`
+ * @HB_SCRIPT_SAMARITAN: `Samr`
+ * @HB_SCRIPT_TAI_THAM: `Lana`
+ * @HB_SCRIPT_TAI_VIET: `Tavt`
+ * @HB_SCRIPT_BATAK: `Batk`
+ * @HB_SCRIPT_BRAHMI: `Brah`
+ * @HB_SCRIPT_MANDAIC: `Mand`
+ * @HB_SCRIPT_CHAKMA: `Cakm`
+ * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
+ * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
+ * @HB_SCRIPT_MIAO: `Plrd`
+ * @HB_SCRIPT_SHARADA: `Shrd`
+ * @HB_SCRIPT_SORA_SOMPENG: `Sora`
+ * @HB_SCRIPT_TAKRI: `Takr`
+ * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
+ * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
+ * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
+ * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
+ * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
+ * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
+ * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
+ * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
+ * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
+ * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
+ * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
+ * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
+ * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
+ * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
+ * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
+ * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
+ * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
+ * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
+ * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
+ * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
+ * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
+ * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
+ * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
+ * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
+ * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
+ * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
+ * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
+ * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
+ * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
+ * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
+ * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
+ * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
+ * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
+ * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
+ * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
+ * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
+ * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
+ * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
+ * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
+ * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
+ * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
+ * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
+ * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
+ * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
+ * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
+ * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
+ * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
+ * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
+ * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
+ * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
+ * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
+ * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
+ * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
+ * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
+ * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
+ * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
+ * @HB_SCRIPT_INVALID: No script set
+ *
+ * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
+ * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
+ *
+ * See also the Script (sc) property of the Unicode Character Database.
+ *
+ **/
 
-/* https://unicode.org/iso15924/ */
 /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
-/* Unicode Character Database property: Script (sc) */
 typedef enum
 {
-  /*1.1*/ HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
-  /*1.1*/ HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
-  /*5.0*/ HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),
+  HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'), /*1.1*/
+  HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'), /*1.1*/
+  HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'), /*5.0*/
 
-  /*1.1*/ HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
-  /*1.1*/ HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'),
-  /*1.1*/ HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'),
-  /*1.1*/ HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'),
-  /*1.1*/ HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'),
-  /*1.1*/ HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'),
-  /*1.1*/ HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'),
-  /*1.1*/ HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'),
-  /*1.1*/ HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'),
-  /*1.1*/ HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'),
-  /*1.1*/ HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'),
-  /*1.1*/ HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'),
-  /*1.1*/ HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'),
-  /*1.1*/ HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'),
-  /*1.1*/ HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'),
-  /*1.1*/ HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'),
-  /*1.1*/ HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'),
-  /*1.1*/ HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'),
-  /*1.1*/ HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'),
-  /*1.1*/ HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'),
-  /*1.1*/ HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'),
-  /*1.1*/ HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'),
+  HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'), /*1.1*/
+  HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'), /*1.1*/
+  HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'), /*1.1*/
+  HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'), /*1.1*/
+  HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'), /*1.1*/
+  HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'), /*1.1*/
+  HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'), /*1.1*/
+  HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'), /*1.1*/
+  HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'), /*1.1*/
+  HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'), /*1.1*/
+  HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'), /*1.1*/
+  HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'), /*1.1*/
+  HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'), /*1.1*/
+  HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'), /*1.1*/
+  HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'), /*1.1*/
+  HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'), /*1.1*/
+  HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'), /*1.1*/
+  HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'), /*1.1*/
+  HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'), /*1.1*/
+  HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'), /*1.1*/
+  HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'), /*1.1*/
+  HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'), /*1.1*/
 
-  /*2.0*/ HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'),
+  HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'), /*2.0*/
 
-  /*3.0*/ HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'),
-  /*3.0*/ HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'),
-  /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS		= HB_TAG ('C','a','n','s'),
-  /*3.0*/ HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'),
-  /*3.0*/ HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'),
-  /*3.0*/ HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'),
-  /*3.0*/ HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'),
-  /*3.0*/ HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'),
-  /*3.0*/ HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'),
-  /*3.0*/ HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'),
-  /*3.0*/ HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'),
-  /*3.0*/ HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'),
-  /*3.0*/ HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'),
-  /*3.0*/ HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'),
+  HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'), /*3.0*/
+  HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'), /*3.0*/
+  HB_SCRIPT_CANADIAN_SYLLABICS		= HB_TAG ('C','a','n','s'), /*3.0*/
+  HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'), /*3.0*/
+  HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'), /*3.0*/
+  HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'), /*3.0*/
+  HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'), /*3.0*/
+  HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'), /*3.0*/
+  HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'), /*3.0*/
+  HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'), /*3.0*/
+  HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'), /*3.0*/
+  HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'), /*3.0*/
+  HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'), /*3.0*/
+  HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'), /*3.0*/
 
-  /*3.1*/ HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'),
-  /*3.1*/ HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'),
-  /*3.1*/ HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'),
+  HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'), /*3.1*/
+  HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'), /*3.1*/
+  HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'), /*3.1*/
 
-  /*3.2*/ HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'),
-  /*3.2*/ HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'),
-  /*3.2*/ HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'),
-  /*3.2*/ HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'),
+  HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'), /*3.2*/
+  HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'), /*3.2*/
+  HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'), /*3.2*/
+  HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'), /*3.2*/
 
-  /*4.0*/ HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'),
-  /*4.0*/ HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'),
-  /*4.0*/ HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'),
-  /*4.0*/ HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'),
-  /*4.0*/ HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'),
-  /*4.0*/ HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'),
-  /*4.0*/ HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'),
+  HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'), /*4.0*/
+  HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'), /*4.0*/
+  HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'), /*4.0*/
+  HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'), /*4.0*/
+  HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'), /*4.0*/
+  HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'), /*4.0*/
+  HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'), /*4.0*/
 
-  /*4.1*/ HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'),
-  /*4.1*/ HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'),
-  /*4.1*/ HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'),
-  /*4.1*/ HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'),
-  /*4.1*/ HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'),
-  /*4.1*/ HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'),
-  /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'),
-  /*4.1*/ HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'),
+  HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'), /*4.1*/
+  HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'), /*4.1*/
+  HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'), /*4.1*/
+  HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'), /*4.1*/
+  HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'), /*4.1*/
+  HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'), /*4.1*/
+  HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'), /*4.1*/
+  HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'), /*4.1*/
 
-  /*5.0*/ HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'),
-  /*5.0*/ HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'),
-  /*5.0*/ HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'),
-  /*5.0*/ HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'),
-  /*5.0*/ HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'),
+  HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'), /*5.0*/
+  HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'), /*5.0*/
+  HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'), /*5.0*/
+  HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'), /*5.0*/
+  HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'), /*5.0*/
 
-  /*5.1*/ HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'),
-  /*5.1*/ HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'),
-  /*5.1*/ HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'),
-  /*5.1*/ HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'),
-  /*5.1*/ HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'),
-  /*5.1*/ HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'),
-  /*5.1*/ HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'),
-  /*5.1*/ HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'),
-  /*5.1*/ HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'),
-  /*5.1*/ HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'),
-  /*5.1*/ HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'),
+  HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'), /*5.1*/
+  HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'), /*5.1*/
+  HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'), /*5.1*/
+  HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'), /*5.1*/
+  HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'), /*5.1*/
+  HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'), /*5.1*/
+  HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'), /*5.1*/
+  HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'), /*5.1*/
+  HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'), /*5.1*/
+  HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'), /*5.1*/
+  HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'), /*5.1*/
 
-  /*5.2*/ HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'),
-  /*5.2*/ HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'),
-  /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'),
-  /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'),
-  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'),
-  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'),
-  /*5.2*/ HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'),
-  /*5.2*/ HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'),
-  /*5.2*/ HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'),
-  /*5.2*/ HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'),
-  /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'),
-  /*5.2*/ HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'),
-  /*5.2*/ HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'),
-  /*5.2*/ HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'),
-  /*5.2*/ HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'),
+  HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'), /*5.2*/
+  HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'), /*5.2*/
+  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'), /*5.2*/
+  HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'), /*5.2*/
+  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'), /*5.2*/
+  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'), /*5.2*/
+  HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'), /*5.2*/
+  HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'), /*5.2*/
+  HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'), /*5.2*/
+  HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'), /*5.2*/
+  HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'), /*5.2*/
+  HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'), /*5.2*/
+  HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'), /*5.2*/
+  HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'), /*5.2*/
+  HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'), /*5.2*/
 
-  /*6.0*/ HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'),
-  /*6.0*/ HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'),
-  /*6.0*/ HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'),
+  HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'), /*6.0*/
+  HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'), /*6.0*/
+  HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'), /*6.0*/
 
-  /*6.1*/ HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'),
-  /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'),
-  /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'),
-  /*6.1*/ HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'),
-  /*6.1*/ HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'),
-  /*6.1*/ HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'),
-  /*6.1*/ HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'),
+  HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'), /*6.1*/
+  HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'), /*6.1*/
+  HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'), /*6.1*/
+  HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'), /*6.1*/
+  HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'), /*6.1*/
+  HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'), /*6.1*/
+  HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'), /*6.1*/
 
   /*
    * Since: 0.9.30
    */
-  /*7.0*/ HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'),
-  /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'),
-  /*7.0*/ HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'),
-  /*7.0*/ HB_SCRIPT_ELBASAN			= HB_TAG ('E','l','b','a'),
-  /*7.0*/ HB_SCRIPT_GRANTHA			= HB_TAG ('G','r','a','n'),
-  /*7.0*/ HB_SCRIPT_KHOJKI			= HB_TAG ('K','h','o','j'),
-  /*7.0*/ HB_SCRIPT_KHUDAWADI			= HB_TAG ('S','i','n','d'),
-  /*7.0*/ HB_SCRIPT_LINEAR_A			= HB_TAG ('L','i','n','a'),
-  /*7.0*/ HB_SCRIPT_MAHAJANI			= HB_TAG ('M','a','h','j'),
-  /*7.0*/ HB_SCRIPT_MANICHAEAN			= HB_TAG ('M','a','n','i'),
-  /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI		= HB_TAG ('M','e','n','d'),
-  /*7.0*/ HB_SCRIPT_MODI			= HB_TAG ('M','o','d','i'),
-  /*7.0*/ HB_SCRIPT_MRO				= HB_TAG ('M','r','o','o'),
-  /*7.0*/ HB_SCRIPT_NABATAEAN			= HB_TAG ('N','b','a','t'),
-  /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN		= HB_TAG ('N','a','r','b'),
-  /*7.0*/ HB_SCRIPT_OLD_PERMIC			= HB_TAG ('P','e','r','m'),
-  /*7.0*/ HB_SCRIPT_PAHAWH_HMONG		= HB_TAG ('H','m','n','g'),
-  /*7.0*/ HB_SCRIPT_PALMYRENE			= HB_TAG ('P','a','l','m'),
-  /*7.0*/ HB_SCRIPT_PAU_CIN_HAU			= HB_TAG ('P','a','u','c'),
-  /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI		= HB_TAG ('P','h','l','p'),
-  /*7.0*/ HB_SCRIPT_SIDDHAM			= HB_TAG ('S','i','d','d'),
-  /*7.0*/ HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'),
-  /*7.0*/ HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'),
+  HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'), /*7.0*/
+  HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'), /*7.0*/
+  HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'), /*7.0*/
+  HB_SCRIPT_ELBASAN			= HB_TAG ('E','l','b','a'), /*7.0*/
+  HB_SCRIPT_GRANTHA			= HB_TAG ('G','r','a','n'), /*7.0*/
+  HB_SCRIPT_KHOJKI			= HB_TAG ('K','h','o','j'), /*7.0*/
+  HB_SCRIPT_KHUDAWADI			= HB_TAG ('S','i','n','d'), /*7.0*/
+  HB_SCRIPT_LINEAR_A			= HB_TAG ('L','i','n','a'), /*7.0*/
+  HB_SCRIPT_MAHAJANI			= HB_TAG ('M','a','h','j'), /*7.0*/
+  HB_SCRIPT_MANICHAEAN			= HB_TAG ('M','a','n','i'), /*7.0*/
+  HB_SCRIPT_MENDE_KIKAKUI		= HB_TAG ('M','e','n','d'), /*7.0*/
+  HB_SCRIPT_MODI			= HB_TAG ('M','o','d','i'), /*7.0*/
+  HB_SCRIPT_MRO				= HB_TAG ('M','r','o','o'), /*7.0*/
+  HB_SCRIPT_NABATAEAN			= HB_TAG ('N','b','a','t'), /*7.0*/
+  HB_SCRIPT_OLD_NORTH_ARABIAN		= HB_TAG ('N','a','r','b'), /*7.0*/
+  HB_SCRIPT_OLD_PERMIC			= HB_TAG ('P','e','r','m'), /*7.0*/
+  HB_SCRIPT_PAHAWH_HMONG		= HB_TAG ('H','m','n','g'), /*7.0*/
+  HB_SCRIPT_PALMYRENE			= HB_TAG ('P','a','l','m'), /*7.0*/
+  HB_SCRIPT_PAU_CIN_HAU			= HB_TAG ('P','a','u','c'), /*7.0*/
+  HB_SCRIPT_PSALTER_PAHLAVI		= HB_TAG ('P','h','l','p'), /*7.0*/
+  HB_SCRIPT_SIDDHAM			= HB_TAG ('S','i','d','d'), /*7.0*/
+  HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'), /*7.0*/
+  HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'), /*7.0*/
 
-  /*8.0*/ HB_SCRIPT_AHOM			= HB_TAG ('A','h','o','m'),
-  /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS	= HB_TAG ('H','l','u','w'),
-  /*8.0*/ HB_SCRIPT_HATRAN			= HB_TAG ('H','a','t','r'),
-  /*8.0*/ HB_SCRIPT_MULTANI			= HB_TAG ('M','u','l','t'),
-  /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN		= HB_TAG ('H','u','n','g'),
-  /*8.0*/ HB_SCRIPT_SIGNWRITING			= HB_TAG ('S','g','n','w'),
+  HB_SCRIPT_AHOM			= HB_TAG ('A','h','o','m'), /*8.0*/
+  HB_SCRIPT_ANATOLIAN_HIEROGLYPHS	= HB_TAG ('H','l','u','w'), /*8.0*/
+  HB_SCRIPT_HATRAN			= HB_TAG ('H','a','t','r'), /*8.0*/
+  HB_SCRIPT_MULTANI			= HB_TAG ('M','u','l','t'), /*8.0*/
+  HB_SCRIPT_OLD_HUNGARIAN		= HB_TAG ('H','u','n','g'), /*8.0*/
+  HB_SCRIPT_SIGNWRITING			= HB_TAG ('S','g','n','w'), /*8.0*/
 
   /*
    * Since 1.3.0
    */
-  /*9.0*/ HB_SCRIPT_ADLAM			= HB_TAG ('A','d','l','m'),
-  /*9.0*/ HB_SCRIPT_BHAIKSUKI			= HB_TAG ('B','h','k','s'),
-  /*9.0*/ HB_SCRIPT_MARCHEN			= HB_TAG ('M','a','r','c'),
-  /*9.0*/ HB_SCRIPT_OSAGE			= HB_TAG ('O','s','g','e'),
-  /*9.0*/ HB_SCRIPT_TANGUT			= HB_TAG ('T','a','n','g'),
-  /*9.0*/ HB_SCRIPT_NEWA			= HB_TAG ('N','e','w','a'),
+  HB_SCRIPT_ADLAM			= HB_TAG ('A','d','l','m'), /*9.0*/
+  HB_SCRIPT_BHAIKSUKI			= HB_TAG ('B','h','k','s'), /*9.0*/
+  HB_SCRIPT_MARCHEN			= HB_TAG ('M','a','r','c'), /*9.0*/
+  HB_SCRIPT_OSAGE			= HB_TAG ('O','s','g','e'), /*9.0*/
+  HB_SCRIPT_TANGUT			= HB_TAG ('T','a','n','g'), /*9.0*/
+  HB_SCRIPT_NEWA			= HB_TAG ('N','e','w','a'), /*9.0*/
 
   /*
    * Since 1.6.0
    */
-  /*10.0*/HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'),
-  /*10.0*/HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'),
-  /*10.0*/HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'),
-  /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'),
+  HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'), /*10.0*/
+  HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'), /*10.0*/
+  HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'), /*10.0*/
+  HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'), /*10.0*/
 
   /*
    * Since 1.8.0
    */
-  /*11.0*/HB_SCRIPT_DOGRA			= HB_TAG ('D','o','g','r'),
-  /*11.0*/HB_SCRIPT_GUNJALA_GONDI		= HB_TAG ('G','o','n','g'),
-  /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA		= HB_TAG ('R','o','h','g'),
-  /*11.0*/HB_SCRIPT_MAKASAR			= HB_TAG ('M','a','k','a'),
-  /*11.0*/HB_SCRIPT_MEDEFAIDRIN			= HB_TAG ('M','e','d','f'),
-  /*11.0*/HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'),
-  /*11.0*/HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'),
+  HB_SCRIPT_DOGRA			= HB_TAG ('D','o','g','r'), /*11.0*/
+  HB_SCRIPT_GUNJALA_GONDI		= HB_TAG ('G','o','n','g'), /*11.0*/
+  HB_SCRIPT_HANIFI_ROHINGYA		= HB_TAG ('R','o','h','g'), /*11.0*/
+  HB_SCRIPT_MAKASAR			= HB_TAG ('M','a','k','a'), /*11.0*/
+  HB_SCRIPT_MEDEFAIDRIN			= HB_TAG ('M','e','d','f'), /*11.0*/
+  HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'), /*11.0*/
+  HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'), /*11.0*/
 
   /*
    * Since 2.4.0
    */
-  /*12.0*/HB_SCRIPT_ELYMAIC			= HB_TAG ('E','l','y','m'),
-  /*12.0*/HB_SCRIPT_NANDINAGARI			= HB_TAG ('N','a','n','d'),
-  /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG	= HB_TAG ('H','m','n','p'),
-  /*12.0*/HB_SCRIPT_WANCHO			= HB_TAG ('W','c','h','o'),
+  HB_SCRIPT_ELYMAIC			= HB_TAG ('E','l','y','m'), /*12.0*/
+  HB_SCRIPT_NANDINAGARI			= HB_TAG ('N','a','n','d'), /*12.0*/
+  HB_SCRIPT_NYIAKENG_PUACHUE_HMONG	= HB_TAG ('H','m','n','p'), /*12.0*/
+  HB_SCRIPT_WANCHO			= HB_TAG ('W','c','h','o'), /*12.0*/
+
+  /*
+   * Since 2.6.7
+   */
+  HB_SCRIPT_CHORASMIAN			= HB_TAG ('C','h','r','s'), /*13.0*/
+  HB_SCRIPT_DIVES_AKURU			= HB_TAG ('D','i','a','k'), /*13.0*/
+  HB_SCRIPT_KHITAN_SMALL_SCRIPT		= HB_TAG ('K','i','t','s'), /*13.0*/
+  HB_SCRIPT_YEZIDI			= HB_TAG ('Y','e','z','i'), /*13.0*/
+
+  /*
+   * Since 3.0.0
+   */
+  HB_SCRIPT_CYPRO_MINOAN		= HB_TAG ('C','p','m','n'), /*14.0*/
+  HB_SCRIPT_OLD_UYGHUR			= HB_TAG ('O','u','g','r'), /*14.0*/
+  HB_SCRIPT_TANGSA			= HB_TAG ('T','n','s','a'), /*14.0*/
+  HB_SCRIPT_TOTO			= HB_TAG ('T','o','t','o'), /*14.0*/
+  HB_SCRIPT_VITHKUQI			= HB_TAG ('V','i','t','h'), /*14.0*/
 
   /* No script set. */
-  HB_SCRIPT_INVALID				= HB_TAG_NONE,
+  HB_SCRIPT_INVALID			= HB_TAG_NONE,
+
+  /*< private >*/
 
   /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
    * without risking undefined behavior.  We have two, for historical reasons.
@@ -402,24 +734,44 @@
 
 /* User data */
 
+/**
+ * hb_user_data_key_t:
+ *
+ * Data structure for holding user-data keys.
+ *
+ **/
 typedef struct hb_user_data_key_t {
   /*< private >*/
   char unused;
 } hb_user_data_key_t;
 
+/**
+ * hb_destroy_func_t:
+ * @user_data: the data to be destroyed
+ *
+ * A virtual method for destroy user-data callbacks.
+ *
+ */
 typedef void (*hb_destroy_func_t) (void *user_data);
 
 
 /* Font features and variations. */
 
 /**
- * HB_FEATURE_GLOBAL_START
+ * HB_FEATURE_GLOBAL_START:
+ *
+ * Special setting for #hb_feature_t.start to apply the feature from the start
+ * of the buffer.
  *
  * Since: 2.0.0
  */
 #define HB_FEATURE_GLOBAL_START	0
+
 /**
- * HB_FEATURE_GLOBAL_END
+ * HB_FEATURE_GLOBAL_END:
+ *
+ * Special setting for #hb_feature_t.end to apply the feature from to the end
+ * of the buffer.
  *
  * Since: 2.0.0
  */
@@ -427,17 +779,17 @@
 
 /**
  * hb_feature_t:
- * @tag: a feature tag
- * @value: 0 disables the feature, non-zero (usually 1) enables the feature.
- * For features implemented as lookup type 3 (like 'salt') the @value is a one
- * based index into the alternates.
+ * @tag: The #hb_tag_t tag of the feature
+ * @value: The value of the feature. 0 disables the feature, non-zero (usually
+ * 1) enables the feature.  For features implemented as lookup type 3 (like
+ * 'salt') the @value is a one based index into the alternates.
  * @start: the cluster to start applying this feature setting (inclusive).
  * @end: the cluster to end applying this feature setting (exclusive).
  *
  * The #hb_feature_t is the structure that holds information about requested
  * feature application. The feature will be applied with the given value to all
  * glyphs which are in clusters between @start (inclusive) and @end (exclusive).
- * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
+ * Setting start to #HB_FEATURE_GLOBAL_START and end to #HB_FEATURE_GLOBAL_END
  * specifies that the feature always applies to the entire buffer.
  */
 typedef struct hb_feature_t {
@@ -457,7 +809,13 @@
 
 /**
  * hb_variation_t:
+ * @tag: The #hb_tag_t tag of the variation-axis name
+ * @value: The value of the variation axis
  *
+ * Data type for holding variation data. Registered OpenType
+ * variation-axis tags are listed in
+ * [OpenType Axis Tag Registry](https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg).
+ * 
  * Since: 1.4.2
  */
 typedef struct hb_variation_t {
@@ -476,12 +834,24 @@
 /**
  * hb_color_t:
  *
- * Data type for holding color values.
+ * Data type for holding color values. Colors are eight bits per
+ * channel RGB plus alpha transparency.
  *
  * Since: 2.1.0
  */
 typedef uint32_t hb_color_t;
 
+/**
+ * HB_COLOR:
+ * @b: blue channel value
+ * @g: green channel value
+ * @r: red channel value
+ * @a: alpha channel value
+ *
+ * Constructs an #hb_color_t from four integers.
+ *
+ * Since: 2.1.0
+ */
 #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
 
 HB_EXTERN uint8_t
diff --git a/src/hb-config.hh b/src/hb-config.hh
index 14c5395..ad800f0 100644
--- a/src/hb-config.hh
+++ b/src/hb-config.hh
@@ -58,6 +58,7 @@
 #define HB_NO_BITMAP
 #define HB_NO_CFF
 #define HB_NO_COLOR
+#define HB_NO_DRAW
 #define HB_NO_ERRNO
 #define HB_NO_FACE_COLLECT_UNICODES
 #define HB_NO_GETENV
@@ -75,7 +76,7 @@
 #define HB_NO_SETLOCALE
 #define HB_NO_OT_FONT_GLYPH_NAMES
 #define HB_NO_OT_SHAPE_FRACTIONS
-#define HB_NO_STAT
+#define HB_NO_STYLE
 #define HB_NO_SUBSET_LAYOUT
 #define HB_NO_VAR
 #endif
@@ -85,6 +86,9 @@
 #define HB_NO_LEGACY
 #endif
 
+#ifdef HAVE_CONFIG_OVERRIDE_H
+#include "config-override.h"
+#endif
 
 /* Closure of options. */
 
@@ -116,7 +120,7 @@
 #define HB_NO_CMAP_LEGACY_SUBTABLES
 #define HB_NO_FALLBACK_SHAPE
 #define HB_NO_OT_KERN
-#define HB_NO_OT_LAYOUT_BLACKLIST
+#define HB_NO_OT_LAYOUT_BLOCKLIST
 #define HB_NO_OT_SHAPE_FALLBACK
 #endif
 
@@ -154,9 +158,5 @@
 #endif
 #endif
 
-#ifdef HAVE_CONFIG_OVERRIDE_H
-#include "config-override.h"
-#endif
-
 
 #endif /* HB_CONFIG_HH */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 8885cfe..4b6c67c 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -34,7 +34,6 @@
 
 #include "hb-coretext.h"
 #include "hb-aat-layout.hh"
-#include <math.h>
 
 
 /**
@@ -190,7 +189,10 @@
    * reconfiguring the cascade list causes CoreText crashes. For details, see
    * crbug.com/549610 */
   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
   if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
+#pragma GCC diagnostic pop
     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
     CFRelease (fontName);
@@ -278,13 +280,32 @@
   CFRelease ((CGFontRef) data);
 }
 
+/**
+ * hb_coretext_face_create:
+ * @cg_font: The CGFontRef to work upon
+ *
+ * Creates an #hb_face_t face object from the specified
+ * CGFontRef.
+ *
+ * Return value: the new #hb_face_t face object
+ *
+ * Since: 0.9.10
+ */
 hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font)
 {
   return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
 }
 
-/*
+/**
+ * hb_coretext_face_get_cg_font:
+ * @face: The #hb_face_t to work upon
+ *
+ * Fetches the CGFontRef associated with an #hb_face_t
+ * face object
+ *
+ * Return value: the CGFontRef found
+ *
  * Since: 0.9.10
  */
 CGFontRef
@@ -311,6 +332,44 @@
     return nullptr;
   }
 
+  if (font->coords)
+  {
+    CFMutableDictionaryRef variations =
+      CFDictionaryCreateMutable (kCFAllocatorDefault,
+				 font->num_coords,
+				 &kCFTypeDictionaryKeyCallBacks,
+				 &kCFTypeDictionaryValueCallBacks);
+
+    for (unsigned i = 0; i < font->num_coords; i++)
+    {
+      if (font->coords[i] == 0.) continue;
+
+      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])
+      );
+    }
+
+    CFDictionaryRef attributes =
+      CFDictionaryCreate (kCFAllocatorDefault,
+			  (const void **) &kCTFontVariationAttribute,
+			  (const void **) &variations,
+			  1,
+			  &kCFTypeDictionaryKeyCallBacks,
+			  &kCFTypeDictionaryValueCallBacks);
+
+    CTFontDescriptorRef varDesc = CTFontDescriptorCreateWithAttributes (attributes);
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0, nullptr, varDesc);
+
+    CFRelease (ct_font);
+    CFRelease (attributes);
+    CFRelease (variations);
+    ct_font = new_ct_font;
+  }
+
   return (hb_coretext_font_data_t *) ct_font;
 }
 
@@ -327,7 +386,7 @@
   const hb_coretext_font_data_t *data = font->data.coretext;
   if (unlikely (!data)) return nullptr;
 
-  if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
+  if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5)
   {
     /* XXX-MT-bug
      * Note that evaluating condition above can be dangerous if another thread
@@ -351,10 +410,17 @@
   return font->data.coretext;
 }
 
-
-/*
+/**
+ * hb_coretext_font_create:
+ * @ct_font: The CTFontRef to work upon
+ *
+ * Creates an #hb_font_t font object from the specified
+ * CTFontRef.
+ *
+ * Return value: the new #hb_font_t font object
+ *
  * Since: 1.7.2
- */
+ **/
 hb_font_t *
 hb_coretext_font_create (CTFontRef ct_font)
 {
@@ -375,6 +441,17 @@
   return font;
 }
 
+/**
+ * hb_coretext_font_get_ct_font:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the CTFontRef associated with the specified
+ * #hb_font_t font object.
+ *
+ * Return value: the CTFontRef found
+ *
+ * Since: 0.9.10
+ */
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
@@ -475,13 +552,19 @@
     hb_vector_t<feature_event_t> feature_events;
     for (unsigned int i = 0; i < num_features; i++)
     {
+      active_feature_t feature;
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
       const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
       if (!mapping)
 	continue;
 
-      active_feature_t feature;
       feature.rec.feature = mapping->aatFeatureType;
       feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+#else
+      feature.rec.feature = features[i].tag;
+      feature.rec.setting = features[i].value;
+#endif
       feature.order = i;
 
       feature_event_t *event;
@@ -530,6 +613,7 @@
 	  /* active_features.qsort (); */
 	  for (unsigned int j = 0; j < active_features.length; j++)
 	  {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
 	    CFStringRef keys[] = {
 	      kCTFontFeatureTypeIdentifierKey,
 	      kCTFontFeatureSelectorIdentifierKey
@@ -538,6 +622,17 @@
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
 	    };
+#else
+	    char tag[5] = {HB_UNTAG (active_features[j].rec.feature)};
+	    CFTypeRef keys[] = {
+	      kCTFontOpenTypeFeatureTag,
+	      kCTFontOpenTypeFeatureValue
+	    };
+	    CFTypeRef values[] = {
+	      CFStringCreateWithCString (kCFAllocatorDefault, tag, kCFStringEncodingASCII),
+	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+	    };
+#endif
 	    static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
 	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
 						       (const void **) keys,
@@ -605,7 +700,7 @@
     scratch_size -= _consumed; \
   } while (0)
 
-  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
+  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, ((void)nullptr) /*nothing*/);
   unsigned int chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++) {
     hb_codepoint_t c = buffer->info[i].codepoint;
@@ -619,7 +714,7 @@
     }
   }
 
-  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
+  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, ((void)nullptr) /*nothing*/);
   chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
@@ -803,7 +898,7 @@
 
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
-    double advances_so_far = 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
      * to fix for that.  Test with any RTL string with trailing spaces.
@@ -825,10 +920,10 @@
       status_or  |= run_status;
       status_and &= run_status;
       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
-      double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
+      CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
 	  run_advance = -run_advance;
-      DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+      DEBUG_MSG (CORETEXT, run, "Run advance: %g", (double) run_advance);
 
       /* CoreText does automatic font fallback (AKA "cascading") for  characters
        * not supported by the requested font, and provides no way to turn it off,
@@ -1004,32 +1099,32 @@
 	hb_glyph_info_t *info = run_info;
 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	{
-	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+	  hb_position_t x_offset = round ((positions[0].x - advances_so_far) * x_mult);
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
-	    double advance;
+	    CGFloat advance;
 	    if (likely (j + 1 < num_glyphs))
 	      advance = positions[j + 1].x - positions[j].x;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].x - positions[0].x);
-	    info->mask = advance * x_mult;
+	    info->mask = round (advance * x_mult);
 	    info->var1.i32 = x_offset;
-	    info->var2.i32 = positions[j].y * y_mult;
+	    info->var2.i32 = round (positions[j].y * y_mult);
 	    info++;
 	  }
 	}
 	else
 	{
-	  hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+	  hb_position_t y_offset = round ((positions[0].y - advances_so_far) * y_mult);
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
-	    double advance;
+	    CGFloat advance;
 	    if (likely (j + 1 < num_glyphs))
 	      advance = positions[j + 1].y - positions[j].y;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].y - positions[0].y);
-	    info->mask = advance * y_mult;
-	    info->var1.i32 = positions[j].x * x_mult;
+	    info->mask = round (advance * y_mult);
+	    info->var1.i32 = round (positions[j].x * x_mult);
 	    info->var2.i32 = y_offset;
 	    info++;
 	  }
diff --git a/src/hb-coretext.h b/src/hb-coretext.h
index 4b0a6f0..e53dbaf 100644
--- a/src/hb-coretext.h
+++ b/src/hb-coretext.h
@@ -40,8 +40,40 @@
 HB_BEGIN_DECLS
 
 
+/**
+ * HB_CORETEXT_TAG_MORT:
+ *
+ * The #hb_tag_t tag for the `mort` (glyph metamorphosis) table,
+ * which holds AAT features. 
+ *
+ * For more information, see 
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
+ *
+ **/
 #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+
+/**
+ * HB_CORETEXT_TAG_MORX:
+ *
+ * The #hb_tag_t tag for the `morx` (extended glyph metamorphosis)
+ * table, which holds AAT features. 
+ *
+ * For more information, see
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
+ *
+ **/
 #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+/**
+ * HB_CORETEXT_TAG_KERX:
+ *
+ * The #hb_tag_t tag for the `kerx` (extended kerning) table, which
+ * holds AAT kerning information. 
+ *
+ * For more information, see 
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
+ *
+ **/
 #define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
 
 
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index a7e52c8..3ac7440 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -46,7 +46,6 @@
   bool unused : 1; /* In-case sign bit is here. */
   bool initialized : 1;
   bool uniscribe_bug_compatible : 1;
-  bool aat : 1;
 };
 
 union hb_options_union_t {
@@ -230,7 +229,7 @@
 		  ...) {}
 
 #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
-#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    false, 0, 0, __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    false, 0, 0, __VA_ARGS__)
 #define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
 
 
@@ -303,16 +302,16 @@
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
-      return hb_forward<T> (v);
+      return std::forward<T> (v);
     }
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
 			      "return %s (line %d)",
-			      hb_printer_t<decltype (v)>().print (v), line);
+			      hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
     if (plevel) --*plevel;
     plevel = nullptr;
     returned = true;
-    return hb_forward<T> (v);
+    return std::forward<T> (v);
   }
 
   private:
@@ -334,7 +333,7 @@
   template <typename T>
   T ret (T&& v,
 	 const char *func HB_UNUSED = nullptr,
-	 unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
+	 unsigned int line HB_UNUSED = 0) { return std::forward<T> (v); }
 };
 
 /* For disabled tracing; optimize out everything.
@@ -344,7 +343,7 @@
   template <typename T>
   T ret (T&& v,
 	 const char *func HB_UNUSED = nullptr,
-	 unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
+	 unsigned int line HB_UNUSED = 0) { return std::forward<T> (v); }
 };
 
 #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
@@ -374,10 +373,6 @@
 #define HB_DEBUG_FT (HB_DEBUG+0)
 #endif
 
-#ifndef HB_DEBUG_GET_COVERAGE
-#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
-#endif
-
 #ifndef HB_DEBUG_OBJECT
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
@@ -443,6 +438,10 @@
 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 #endif
 
+#ifndef HB_DEBUG_SUBSET_REPACK
+#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
+#endif
+
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
 	HB_DEBUG_APPLY + \
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index 43f89a4..a130d77 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -53,11 +53,50 @@
 #ifndef HB_DISABLE_DEPRECATED
 
 
+/**
+ * HB_SCRIPT_CANADIAN_ABORIGINAL:
+ *
+ * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
+ *
+ * Deprecated: 0.9.20
+ */
 #define HB_SCRIPT_CANADIAN_ABORIGINAL		HB_SCRIPT_CANADIAN_SYLLABICS
 
+/**
+ * HB_BUFFER_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
 #define HB_BUFFER_FLAGS_DEFAULT			HB_BUFFER_FLAG_DEFAULT
+/**
+ * HB_BUFFER_SERIALIZE_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_SERIALIZE_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
 #define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT	HB_BUFFER_SERIALIZE_FLAG_DEFAULT
 
+/**
+ * hb_font_get_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The  variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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
+ * Deprecated: 1.2.3
+ *
+ **/
 typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
 					       hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 					       hb_codepoint_t *glyph,
@@ -68,11 +107,13 @@
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
-HB_EXTERN HB_DEPRECATED void
-hb_set_invert (hb_set_t *set);
-
 /**
  * hb_unicode_eastasian_width_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
  *
  * Deprecated: 2.0.0
  */
@@ -82,12 +123,12 @@
 
 /**
  * hb_unicode_funcs_set_eastasian_width_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: a Unicode-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_unicode_eastasian_width_func_t.
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
@@ -99,6 +140,10 @@
 
 /**
  * hb_unicode_eastasian_width:
+ * @ufuncs: a Unicode-function structure
+ * @unicode: The code point to query
+ *
+ * Don't use. Not used by HarfBuzz.
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
@@ -112,7 +157,7 @@
  * hb_unicode_decompose_compatibility_func_t:
  * @ufuncs: a Unicode function structure
  * @u: codepoint to decompose
- * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @decomposed: address of codepoint array (of length #HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
  * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
  *
  * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
@@ -120,7 +165,7 @@
  *
  * If @u has no compatibility decomposition, zero should be returned.
  *
- * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * The Unicode standard guarantees that a buffer of length #HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
  * compatibility decomposition plus an terminating value of 0.  Consequently, @decompose must be allocated by the caller to be at least this length.  Implementations
  * of this function type must ensure that they do not write past the provided array.
  *
@@ -144,10 +189,12 @@
 
 /**
  * hb_unicode_funcs_set_decompose_compatibility_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_decompose_compatibility_func_t.
  *
  * 
  *
@@ -165,16 +212,25 @@
 				    hb_codepoint_t     *decomposed);
 
 
+/**
+ * hb_font_get_glyph_v_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for vertical text segments.
+ *
+ **/
 typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
 
 /**
  * hb_font_funcs_set_glyph_v_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_v_kerning_func_t.
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index efb2029..db7b53b 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -32,6 +32,16 @@
 
 #include "hb-directwrite.h"
 
+#include "hb-ms-feature-ranges.hh"
+
+/**
+ * SECTION:hb-directwrite
+ * @title: hb-directwrite
+ * @short_description: DirectWrite integration
+ * @include: hb-directwrite.h
+ *
+ * Functions for using HarfBuzz with DirectWrite fonts.
+ **/
 
 /* Declare object creator for dynamic support of DWRITE */
 typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
@@ -40,16 +50,6 @@
   IUnknown            **factory
 );
 
-/*
- * hb-directwrite uses new/delete syntatically but as we let users
- * to override malloc/free, we will redefine new/delete so users
- * won't need to do that by their own.
- */
-void* operator new (size_t size)        { return malloc (size); }
-void* operator new [] (size_t size)     { return malloc (size); }
-void operator delete (void* pointer)    { free (pointer); }
-void operator delete [] (void* pointer) { free (pointer); }
-
 
 /*
  * DirectWrite font stream helpers
@@ -543,13 +543,12 @@
  * shaper
  */
 
-static hb_bool_t
-_hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
-			    hb_font_t          *font,
-			    hb_buffer_t        *buffer,
-			    const hb_feature_t *features,
-			    unsigned int        num_features,
-			    float               lineWidth)
+hb_bool_t
+_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   const hb_directwrite_face_data_t *face_data = face->data.directwrite;
@@ -602,8 +601,6 @@
       log_clusters[chars_len++] = cluster; /* Surrogates. */
   }
 
-  // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
-
   DWRITE_READING_DIRECTION readingDirection;
   readingDirection = buffer->props.direction ?
 		     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
@@ -614,7 +611,7 @@
   * but we never attempt to shape a word longer than 64K characters
   * in a single gfxShapedWord, so we cannot exceed that limit.
   */
-  uint32_t textLength = buffer->len;
+  uint32_t textLength = chars_len;
 
   TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
   TextAnalysis::Run *runHead;
@@ -635,42 +632,58 @@
   bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
   const wchar_t localeName[20] = {0};
-  if (buffer->props.language != nullptr)
+  if (buffer->props.language)
     mbstowcs ((wchar_t*) localeName,
 	      hb_language_to_string (buffer->props.language), 20);
 
-  // TODO: it does work but doesn't care about ranges
-  DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
-  typographic_features.featureCount = num_features;
+  /*
+   * Set up features.
+   */
+  static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
+  static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
+  hb_vector_t<hb_ms_features_t *> range_features;
+  hb_vector_t<uint32_t> range_char_counts;
   if (num_features)
   {
-    typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
-    for (unsigned int i = 0; i < num_features; ++i)
-    {
-      typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
-						 hb_uint32_swap (features[i].tag);
-      typographic_features.features[i].parameter = features[i].value;
-    }
+    hb_vector_t<hb_ms_feature_t> feature_records;
+    hb_vector_t<hb_ms_range_record_t> range_records;
+    if (hb_ms_setup_features (features, num_features, feature_records, range_records))
+      hb_ms_make_feature_ranges (feature_records,
+				 range_records,
+				 0,
+				 chars_len,
+				 log_clusters,
+				 range_features,
+				 range_char_counts);
   }
-  const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures;
-  dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
-  const uint32_t featureRangeLengths[] = { textLength };
-  //
 
   uint16_t* clusterMap;
   clusterMap = new uint16_t[textLength];
   DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
   textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
+
 retry_getglyphs:
   uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
   DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
   glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
 
-  hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
-			    isRightToLeft, &runHead->mScript, localeName,
-			    nullptr, &dwFeatures, featureRangeLengths, 1,
-			    maxGlyphCount, clusterMap, textProperties,
-			    glyphIndices, glyphProperties, &glyphCount);
+  hr = analyzer->GetGlyphs (textString,
+			    chars_len,
+			    fontFace,
+			    false,
+			    isRightToLeft,
+			    &runHead->mScript,
+			    localeName,
+			    nullptr,
+			    (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+			    range_char_counts.arrayZ,
+			    range_features.length,
+			    maxGlyphCount,
+			    clusterMap,
+			    textProperties,
+			    glyphIndices,
+			    glyphProperties,
+			    &glyphCount);
 
   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
@@ -706,101 +719,28 @@
   double x_mult = (double) font->x_scale / fontEmSize;
   double y_mult = (double) font->y_scale / fontEmSize;
 
-  hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
-				     textLength, glyphIndices, glyphProperties,
-				     glyphCount, fontFace, fontEmSize,
-				     false, isRightToLeft, &runHead->mScript, localeName,
-				     &dwFeatures, featureRangeLengths, 1,
-				     glyphAdvances, glyphOffsets);
+  hr = analyzer->GetGlyphPlacements (textString,
+				     clusterMap,
+				     textProperties,
+				     chars_len,
+				     glyphIndices,
+				     glyphProperties,
+				     glyphCount,
+				     fontFace,
+				     fontEmSize,
+				     false,
+				     isRightToLeft,
+				     &runHead->mScript,
+				     localeName,
+				     (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+				     range_char_counts.arrayZ,
+				     range_features.length,
+				     glyphAdvances,
+				     glyphOffsets);
 
   if (FAILED (hr))
     FAIL ("Analyzer failed to get glyph placements.");
 
-  IDWriteTextAnalyzer1* analyzer1;
-  analyzer->QueryInterface (&analyzer1);
-
-  if (analyzer1 && lineWidth)
-  {
-    DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
-      new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
-    hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript,
-						   textLength, glyphCount, textString,
-						   clusterMap, glyphProperties,
-						   justificationOpportunities);
-
-    if (FAILED (hr))
-      FAIL ("Analyzer failed to get justification opportunities.");
-
-    float* justifiedGlyphAdvances = new float[maxGlyphCount];
-    DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
-    hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
-					  glyphAdvances, glyphOffsets, justifiedGlyphAdvances,
-					  justifiedGlyphOffsets);
-
-    if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances.");
-
-    DWRITE_SCRIPT_PROPERTIES scriptProperties;
-    hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
-    if (FAILED (hr)) FAIL ("Analyzer failed to get script properties.");
-    uint32_t justificationCharacter = scriptProperties.justificationCharacter;
-
-    // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
-    if (justificationCharacter != 32)
-    {
-      uint16_t* modifiedClusterMap = new uint16_t[textLength];
-    retry_getjustifiedglyphs:
-      uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
-      float* modifiedGlyphAdvances = new float[maxGlyphCount];
-      DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
-      uint32_t actualGlyphsCount;
-      hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
-					  textLength, glyphCount, maxGlyphCount,
-					  clusterMap, glyphIndices, glyphAdvances,
-					  justifiedGlyphAdvances, justifiedGlyphOffsets,
-					  glyphProperties, &actualGlyphsCount,
-					  modifiedClusterMap, modifiedGlyphIndices,
-					  modifiedGlyphAdvances, modifiedGlyphOffsets);
-
-      if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
-      {
-	maxGlyphCount = actualGlyphsCount;
-	delete [] modifiedGlyphIndices;
-	delete [] modifiedGlyphAdvances;
-	delete [] modifiedGlyphOffsets;
-
-	maxGlyphCount = actualGlyphsCount;
-
-	goto retry_getjustifiedglyphs;
-      }
-      if (FAILED (hr))
-	FAIL ("Analyzer failed to get justified glyphs.");
-
-      delete [] clusterMap;
-      delete [] glyphIndices;
-      delete [] glyphAdvances;
-      delete [] glyphOffsets;
-
-      glyphCount = actualGlyphsCount;
-      clusterMap = modifiedClusterMap;
-      glyphIndices = modifiedGlyphIndices;
-      glyphAdvances = modifiedGlyphAdvances;
-      glyphOffsets = modifiedGlyphOffsets;
-
-      delete [] justifiedGlyphAdvances;
-      delete [] justifiedGlyphOffsets;
-    }
-    else
-    {
-      delete [] glyphAdvances;
-      delete [] glyphOffsets;
-
-      glyphAdvances = justifiedGlyphAdvances;
-      glyphOffsets = justifiedGlyphOffsets;
-    }
-
-    delete [] justificationOpportunities;
-  }
-
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
 
@@ -861,43 +801,10 @@
   delete [] glyphAdvances;
   delete [] glyphOffsets;
 
-  if (num_features)
-    delete [] typographic_features.features;
-
   /* Wow, done! */
   return true;
 }
 
-hb_bool_t
-_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
-		       hb_font_t          *font,
-		       hb_buffer_t        *buffer,
-		       const hb_feature_t *features,
-		       unsigned int        num_features)
-{
-  return _hb_directwrite_shape_full (shape_plan, font, buffer,
-				     features, num_features, 0);
-}
-
-HB_UNUSED static bool
-_hb_directwrite_shape_experimental_width (hb_font_t          *font,
-					  hb_buffer_t        *buffer,
-					  const hb_feature_t *features,
-					  unsigned int        num_features,
-					  float               width)
-{
-  static const char *shapers = "directwrite";
-  hb_shape_plan_t *shape_plan;
-  shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
-					    features, num_features, &shapers);
-  hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
-					      features, num_features, width);
-
-  buffer->unsafe_to_break_all ();
-
-  return res;
-}
-
 struct _hb_directwrite_font_table_context {
   IDWriteFontFace *face;
   void *table_context;
@@ -908,7 +815,7 @@
 {
   _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
   context->face->ReleaseFontTable (context->table_context);
-  delete context;
+  hb_free (context);
 }
 
 static hb_blob_t *
@@ -929,7 +836,7 @@
     return nullptr;
   }
 
-  _hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
+  _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
   context->face = dw_face;
   context->table_context = table_context;
 
@@ -948,6 +855,8 @@
  * hb_directwrite_face_create:
  * @font_face: a DirectWrite IDWriteFontFace object.
  *
+ * Constructs a new face object from the specified DirectWrite IDWriteFontFace.
+ *
  * Return value: #hb_face_t object corresponding to the given input
  *
  * Since: 2.4.0
@@ -965,6 +874,8 @@
 * hb_directwrite_face_get_font_face:
 * @face: a #hb_face_t object
 *
+* Gets the DirectWrite IDWriteFontFace associated with @face.
+*
 * Return value: DirectWrite IDWriteFontFace object corresponding to the given input
 *
 * Since: 2.5.0
diff --git a/src/hb-dispatch.hh b/src/hb-dispatch.hh
index 1ce3fac..37ca681 100644
--- a/src/hb-dispatch.hh
+++ b/src/hb-dispatch.hh
@@ -35,7 +35,7 @@
  * Dispatch
  */
 
-template <typename Context, typename Return, unsigned int MaxDebugDepth>
+template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
 struct hb_dispatch_context_t
 {
   private:
@@ -43,15 +43,17 @@
   const Context* thiz () const { return static_cast<const Context *> (this); }
 	Context* thiz ()       { return static_cast<      Context *> (this); }
   public:
+  const char *get_name () { return "UNKNOWN"; }
   static constexpr unsigned max_debug_depth = MaxDebugDepth;
   typedef Return return_t;
   template <typename T, typename F>
   bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
   template <typename T, typename ...Ts>
   return_t dispatch (const T &obj, Ts&&... ds)
-  { return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
+  { return obj.dispatch (thiz (), std::forward<Ts> (ds)...); }
   static return_t no_dispatch_return_value () { return Context::default_return_value (); }
   static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
+  unsigned debug_depth = 0;
 };
 
 
diff --git a/src/hb-draw.cc b/src/hb-draw.cc
new file mode 100644
index 0000000..c0af6ce
--- /dev/null
+++ b/src/hb-draw.cc
@@ -0,0 +1,261 @@
+/*
+ * Copyright © 2019-2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.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
+ *
+ * Sets move-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
+				hb_draw_move_to_func_t  move_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->move_to = move_to;
+}
+
+/**
+ * hb_draw_funcs_set_line_to_func:
+ * @funcs: draw functions object
+ * @line_to: line-to callback
+ *
+ * Sets line-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
+				hb_draw_line_to_func_t  line_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->line_to = line_to;
+}
+
+/**
+ * hb_draw_funcs_set_quadratic_to_func:
+ * @funcs: draw functions object
+ * @move_to: quadratic-to callback
+ *
+ * Sets quadratic-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
+				     hb_draw_quadratic_to_func_t  quadratic_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->quadratic_to = quadratic_to;
+  funcs->is_quadratic_to_set = true;
+}
+
+/**
+ * hb_draw_funcs_set_cubic_to_func:
+ * @funcs: draw functions
+ * @cubic_to: cubic-to callback
+ *
+ * Sets cubic-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
+				 hb_draw_cubic_to_func_t  cubic_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->cubic_to = cubic_to;
+}
+
+/**
+ * hb_draw_funcs_set_close_path_func:
+ * @funcs: draw functions object
+ * @close_path: close-path callback
+ *
+ * Sets close-path callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
+				   hb_draw_close_path_func_t  close_path)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->close_path = close_path;
+}
+
+static void
+_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+
+static void
+_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+
+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) {}
+
+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) {}
+
+static void
+_close_path_nil (void *user_data HB_UNUSED) {}
+
+/**
+ * hb_draw_funcs_create:
+ *
+ * Creates a new draw callbacks object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_create ()
+{
+  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));
+
+  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_draw_funcs_reference:
+ * @funcs: draw functions
+ *
+ * Add to callbacks object refcount.
+ *
+ * Returns: The same object.
+ * Since: EXPERIMENTAL
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
+{
+  return hb_object_reference (funcs);
+}
+
+/**
+ * hb_draw_funcs_destroy:
+ * @funcs: draw functions
+ *
+ * Decreases refcount of callbacks object and deletes the object if it reaches
+ * to zero.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
+{
+  if (!hb_object_destroy (funcs)) return;
+
+  hb_free (funcs);
+}
+
+/**
+ * hb_draw_funcs_make_immutable:
+ * @funcs: draw functions
+ *
+ * Makes funcs object immutable.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
+{
+  if (hb_object_is_immutable (funcs))
+    return;
+
+  hb_object_make_immutable (funcs);
+}
+
+/**
+ * hb_draw_funcs_is_immutable:
+ * @funcs: draw functions
+ *
+ * Checks whether funcs is immutable.
+ *
+ * Returns: If is immutable.
+ * Since: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
+{
+  return hb_object_is_immutable (funcs);
+}
+
+/**
+ * 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
+ *
+ * Draw a glyph.
+ *
+ * Returns: Whether the font had the glyph and the operation completed successfully.
+ * Since: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
+		    const hb_draw_funcs_t *funcs,
+		    void *user_data)
+{
+  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
+
+  return false;
+}
+
+#endif
+#endif
diff --git a/src/hb-draw.h b/src/hb-draw.h
new file mode 100644
index 0000000..bddc876
--- /dev/null
+++ b/src/hb-draw.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2019-2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_DRAW_H
+#define HB_DRAW_H
+
+#include "hb.h"
+
+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_funcs_t:
+ *
+ * Glyph draw callbacks.
+ *
+ * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we
+ * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
+ *
+ * Since: EXPERIMENTAL
+ **/
+typedef struct hb_draw_funcs_t hb_draw_funcs_t;
+
+HB_EXTERN void
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
+				hb_draw_move_to_func_t  move_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
+				hb_draw_line_to_func_t  line_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
+				     hb_draw_quadratic_to_func_t  quadratic_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
+				 hb_draw_cubic_to_func_t  cubic_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
+				   hb_draw_close_path_func_t  close_path);
+
+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_EXTERN void
+hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
+
+HB_EXTERN void
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
+
+HB_EXTERN hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_DRAW_H */
diff --git a/src/hb-draw.hh b/src/hb-draw.hh
new file mode 100644
index 0000000..2aa0a5b
--- /dev/null
+++ b/src/hb-draw.hh
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_DRAW_HH
+#define HB_DRAW_HH
+
+#include "hb.hh"
+
+#ifdef HB_EXPERIMENTAL_API
+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 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)
+  {
+    if (path_open) end_path ();
+    current_x = path_start_x = x;
+    current_y = path_start_y = y;
+  }
+
+  void line_to (hb_position_t x, hb_position_t 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;
+  }
+
+  void
+  quadratic_to (hb_position_t control_x, hb_position_t control_y,
+		hb_position_t to_x, hb_position_t 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;
+  }
+
+  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)
+  {
+    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;
+  }
+
+  void end_path ()
+  {
+    if (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);
+    }
+    path_open = false;
+    path_start_x = current_x = path_start_y = 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 ()
+  {
+    if (path_open) end_path ();
+    path_open = true;
+    funcs->move_to (path_start_x, path_start_y, user_data);
+  }
+
+  hb_position_t path_start_x;
+  hb_position_t path_start_y;
+
+  hb_position_t current_x;
+  hb_position_t current_y;
+
+  bool path_open;
+  const hb_draw_funcs_t *funcs;
+  void *user_data;
+};
+#endif
+
+#endif /* HB_DRAW_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 0c9949f..2c00873 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -33,6 +33,7 @@
 #include "hb-open-file.hh"
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
+#include "hb-map.hh"
 
 
 /**
@@ -41,8 +42,10 @@
  * @short_description: Font face objects
  * @include: hb.h
  *
- * Font face is objects represent a single face in a font family.
- * More exactly, a font face represents a single face in a binary font file.
+ * A font face is an object that represents a single face from within a
+ * font family.
+ *
+ * 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.
  **/
@@ -52,7 +55,7 @@
  * hb_face_count:
  * @blob: a blob.
  *
- * Get number of faces in a blob.
+ * Fetches the number of faces in a blob.
  *
  * Return value: Number of faces in @blob
  *
@@ -87,8 +90,8 @@
   nullptr, /* destroy */
 
   0,    /* index */
-  HB_ATOMIC_INT_INIT (1000), /* upem */
-  HB_ATOMIC_INT_INIT (0),    /* num_glyphs */
+  1000, /* upem */
+  0,    /* num_glyphs */
 
   /* Zero for the rest is fine. */
 };
@@ -96,13 +99,19 @@
 
 /**
  * hb_face_create_for_tables:
- * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
+ * @user_data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
  *
+ * Variant of hb_face_create(), built for those cases where it is more
+ * convenient to provide data for individual tables instead of the whole font
+ * data. With the caveat that hb_face_get_table_tags() does not currently work
+ * with faces created this way.
  *
+ * Creates a new face object from the specified @user_data and @reference_table_func,
+ * with the @destroy callback.
  *
- * Return value: (transfer full)
+ * Return value: (transfer full): The new face object
  *
  * Since: 0.9.2
  **/
@@ -142,7 +151,7 @@
 {
   hb_face_for_data_closure_t *closure;
 
-  closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
+  closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
     return nullptr;
 
@@ -158,7 +167,7 @@
   hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
 
   hb_blob_destroy (closure->blob);
-  free (closure);
+  hb_free (closure);
 }
 
 static hb_blob_t *
@@ -182,12 +191,15 @@
 
 /**
  * hb_face_create: (Xconstructor)
- * @blob:
- * @index:
+ * @blob: #hb_blob_t to work upon
+ * @index: The index of the face within @blob
  *
+ * Constructs a new face object from the specified blob and
+ * a face index into that blob. This is used for blobs of
+ * file formats such as Dfont and TTC that can contain more
+ * than one face.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The new face object
  *
  * Since: 0.9.2
  **/
@@ -200,10 +212,15 @@
   if (unlikely (!blob))
     blob = hb_blob_get_empty ();
 
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
+  blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
+
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
 
   if (unlikely (!closure))
+  {
+    hb_blob_destroy (blob);
     return hb_face_get_empty ();
+  }
 
   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
 				    closure,
@@ -217,26 +234,26 @@
 /**
  * hb_face_get_empty:
  *
+ * Fetches the singleton empty face object.
  *
- *
- * Return value: (transfer full)
+ * Return value: (transfer full): The empty face object
  *
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_get_empty ()
 {
-  return const_cast<hb_face_t *> (&Null(hb_face_t));
+  return const_cast<hb_face_t *> (&Null (hb_face_t));
 }
 
 
 /**
  * hb_face_reference: (skip)
- * @face: a face.
+ * @face: A face object
  *
+ * Increases the reference count on a face object.
  *
- *
- * Return value:
+ * Return value: The @face object
  *
  * Since: 0.9.2
  **/
@@ -248,9 +265,11 @@
 
 /**
  * hb_face_destroy: (skip)
- * @face: a face.
+ * @face: A face object
  *
- *
+ * Decreases the reference count on a face object. When the
+ * reference count reaches zero, the face is destroyed,
+ * freeing all memory.
  *
  * Since: 0.9.2
  **/
@@ -263,7 +282,7 @@
   {
     hb_face_t::plan_node_t *next = node->next;
     hb_shape_plan_destroy (node->shape_plan);
-    free (node);
+    hb_free (node);
     node = next;
   }
 
@@ -273,20 +292,20 @@
   if (face->destroy)
     face->destroy (face->user_data);
 
-  free (face);
+  hb_free (face);
 }
 
 /**
  * hb_face_set_user_data: (skip)
- * @face: a face.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @face: A face 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 face object.
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -302,12 +321,13 @@
 
 /**
  * hb_face_get_user_data: (skip)
- * @face: a face.
- * @key:
+ * @face: A face object
+ * @key: The user-data key to query
  *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified face object.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -320,9 +340,9 @@
 
 /**
  * hb_face_make_immutable:
- * @face: a face.
+ * @face: A face object
  *
- *
+ * Makes the given face object immutable.
  *
  * Since: 0.9.2
  **/
@@ -337,11 +357,11 @@
 
 /**
  * hb_face_is_immutable:
- * @face: a face.
+ * @face: A face object
  *
+ * Tests whether the given face object is immutable.
  *
- *
- * Return value:
+ * Return value: %true is @face is immutable, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -354,12 +374,13 @@
 
 /**
  * hb_face_reference_table:
- * @face: a face.
- * @tag:
+ * @face: A face object
+ * @tag: The #hb_tag_t of the table to query
  *
+ * Fetches a reference to the specified table within
+ * the specified face.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): A pointer to the @tag table within @face
  *
  * Since: 0.9.2
  **/
@@ -375,11 +396,13 @@
 
 /**
  * hb_face_reference_blob:
- * @face: a face.
+ * @face: A face object
  *
+ * Fetches a pointer to the binary blob that contains the
+ * specified face. Returns an empty blob if referencing face data is not
+ * possible.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): A pointer to the blob for @face
  *
  * Since: 0.9.2
  **/
@@ -391,10 +414,13 @@
 
 /**
  * hb_face_set_index:
- * @face: a face.
- * @index:
+ * @face: A face object
+ * @index: The index to assign
  *
+ * Assigns the specified face-index to @face. Fails if the
+ * face is immutable.
  *
+ * <note>Note: face indices within a collection are zero-based.</note>
  *
  * Since: 0.9.2
  **/
@@ -410,11 +436,13 @@
 
 /**
  * hb_face_get_index:
- * @face: a face.
+ * @face: A face object
  *
+ * Fetches the face-index corresponding to the given face.
  *
+ * <note>Note: face indices within a collection are zero-based.</note>
  *
- * Return value:
+ * Return value: The index of @face.
  *
  * Since: 0.9.2
  **/
@@ -426,10 +454,10 @@
 
 /**
  * hb_face_set_upem:
- * @face: a face.
- * @upem:
+ * @face: A face object
+ * @upem: The units-per-em value to assign
  *
- *
+ * Sets the units-per-em (upem) for a face object to the specified value.
  *
  * Since: 0.9.2
  **/
@@ -445,11 +473,11 @@
 
 /**
  * hb_face_get_upem:
- * @face: a face.
+ * @face: A face object
  *
+ * Fetches the units-per-em (upem) value of the specified face object.
  *
- *
- * Return value:
+ * Return value: The upem value of @face
  *
  * Since: 0.9.2
  **/
@@ -461,10 +489,10 @@
 
 /**
  * hb_face_set_glyph_count:
- * @face: a face.
- * @glyph_count:
+ * @face: A face object
+ * @glyph_count: The glyph-count value to assign
  *
- *
+ * Sets the glyph count for a face object to the specified value.
  *
  * Since: 0.9.7
  **/
@@ -480,11 +508,11 @@
 
 /**
  * hb_face_get_glyph_count:
- * @face: a face.
+ * @face: A face object
  *
+ * Fetches the glyph-count value of the specified face object.
  *
- *
- * Return value:
+ * Return value: The glyph-count value of @face
  *
  * Since: 0.9.7
  **/
@@ -496,14 +524,16 @@
 
 /**
  * hb_face_get_table_tags:
- * @face: a face.
- * @start_offset: index of first tag to return.
- * @table_count: input length of @table_tags array, output number of items written.
- * @table_tags: array to write tags into.
+ * @face: A face object
+ * @start_offset: The index of first table tag to retrieve
+ * @table_count: (inout): Input = the maximum number of table tags to return;
+ *                Output = the actual number of table tags returned (may be zero)
+ * @table_tags: (out) (array length=table_count): The array of table tags found
  *
- * Retrieves table tags for a face, if possible.
+ * Fetches a list of all table tags for a face, if possible. The list returned will
+ * begin at the offset provided
  *
- * Return value: total number of tables, or 0 if not possible to list.
+ * Return value: Total number of tables, or zero if it is not possible to list
  *
  * Since: 1.6.0
  **/
@@ -537,8 +567,11 @@
 #ifndef HB_NO_FACE_COLLECT_UNICODES
 /**
  * hb_face_collect_unicodes:
- * @face: font face.
- * @out: set to add Unicode characters covered by @face to.
+ * @face: A face object
+ * @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.
  *
  * Since: 1.9.0
  */
@@ -546,14 +579,15 @@
 hb_face_collect_unicodes (hb_face_t *face,
 			  hb_set_t  *out)
 {
-  face->table.cmap->collect_unicodes (out);
+  face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
 }
 /**
  * hb_face_collect_variation_selectors:
- * @face: font face.
- * @out: set to add Variation Selector characters covered by @face to.
+ * @face: A face object
+ * @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.
  *
  * Since: 1.9.0
  */
@@ -565,10 +599,12 @@
 }
 /**
  * hb_face_collect_variation_unicodes:
- * @face: font face.
- * @out: set to add Unicode characters for @variation_selector covered by @face to.
+ * @face: A face object
+ * @variation_selector: The Variation Selector to query
+ * @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.
  *
  * Since: 1.9.0
  */
@@ -588,26 +624,26 @@
 
 struct hb_face_builder_data_t
 {
-  struct table_entry_t
-  {
-    int cmp (hb_tag_t t) const
-    {
-      if (t < tag) return -1;
-      if (t > tag) return -1;
-      return 0;
-    }
-
-    hb_tag_t   tag;
-    hb_blob_t *blob;
-  };
-
-  hb_vector_t<table_entry_t> tables;
+  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 *) calloc (1, sizeof (hb_face_builder_data_t));
+  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;
 
@@ -621,25 +657,25 @@
 {
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
 
-  for (unsigned int i = 0; i < data->tables.length; i++)
-    hb_blob_destroy (data->tables[i].blob);
+  for (hb_blob_t* b : data->tables.values())
+    hb_blob_destroy (b);
 
   data->tables.fini ();
 
-  free (data);
+  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.length;
+  unsigned int table_count = data->tables.get_population ();
   unsigned int face_length = table_count * 16 + 12;
 
-  for (unsigned int i = 0; i < table_count; i++)
-    face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
+  for (hb_blob_t* b : data->tables.values())
+    face_length += hb_ceil_to_4 (hb_blob_get_length (b));
 
-  char *buf = (char *) malloc (face_length);
+  char *buf = (char *) hb_malloc (face_length);
   if (unlikely (!buf))
     return nullptr;
 
@@ -647,20 +683,31 @@
   c.propagate_error (data->tables);
   OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
 
-  bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
+  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;
 
-  bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
+  // 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))
   {
-    free (buf);
+    hb_free (buf);
     return nullptr;
   }
 
-  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
+  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
 }
 
 static hb_blob_t *
@@ -671,11 +718,7 @@
   if (!tag)
     return _hb_face_builder_data_reference_blob (data);
 
-  hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
-  if (entry)
-    return hb_blob_reference (entry->blob);
-
-  return nullptr;
+  return hb_blob_reference (data->tables[tag]);
 }
 
 
@@ -703,6 +746,9 @@
 
 /**
  * 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().
@@ -712,14 +758,21 @@
 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_face_builder_data_t::table_entry_t *entry = data->tables.push ();
 
-  entry->tag = tag;
-  entry->blob = hb_blob_reference (blob);
+  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;
 }
diff --git a/src/hb-face.h b/src/hb-face.h
index e8ff090..6ef2f8b 100644
--- a/src/hb-face.h
+++ b/src/hb-face.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -46,12 +46,31 @@
  * hb_face_t
  */
 
+/**
+ * hb_face_t:
+ *
+ * Data type for holding font faces.
+ *
+ **/
 typedef struct hb_face_t hb_face_t;
 
 HB_EXTERN hb_face_t *
 hb_face_create (hb_blob_t    *blob,
 		unsigned int  index);
 
+/**
+ * hb_reference_table_func_t:
+ * @face: an #hb_face_t to reference table for
+ * @tag: the tag of the table to reference
+ * @user_data: User data pointer passed by the caller
+ *
+ * Callback function for hb_face_create_for_tables().
+ *
+ * Return value: (transfer full): A pointer to the @tag table within @face
+ *
+ * Since: 0.9.2
+ */
+
 typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
 
 /* calls destroy() when not needing user_data anymore */
diff --git a/src/hb-face.hh b/src/hb-face.hh
index 68834ba..765f272 100644
--- a/src/hb-face.hh
+++ b/src/hb-face.hh
@@ -81,7 +81,7 @@
     return blob;
   }
 
-  HB_PURE_FUNC unsigned int get_upem () const
+  unsigned int get_upem () const
   {
     unsigned int ret = upem.get_relaxed ();
     if (unlikely (!ret))
@@ -94,7 +94,7 @@
   unsigned int get_num_glyphs () const
   {
     unsigned int ret = num_glyphs.get_relaxed ();
-    if (unlikely (ret == (unsigned int) -1))
+    if (unlikely (ret == UINT_MAX))
       return load_num_glyphs ();
     return ret;
   }
diff --git a/src/hb-font.cc b/src/hb-font.cc
index e89ad69..fa8da96 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -33,6 +33,9 @@
 
 #include "hb-ot.h"
 
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+
 
 /**
  * SECTION:hb-font
@@ -40,10 +43,20 @@
  * @short_description: Font objects
  * @include: hb.h
  *
- * Font objects represent a font face at a certain size and other
- * parameters (pixels per EM, points per EM, variation settings.)
- * Fonts are created from font faces, and are used as input to
- * hb_shape() among other things.
+ * Functions for working with font objects.
+ *
+ * A font object represents a font face at a specific size and with
+ * certain other parameters (pixels-per-em, points-per-em, variation
+ * settings) specified. Font objects are created from font face
+ * objects, and are used as input to hb_shape(), among other things.
+ *
+ * Client programs can optionally pass in their own functions that
+ * implement the basic, lower-level queries of font objects. This set
+ * of font functions is defined by the virtual methods in
+ * #hb_font_funcs_t.
+ *
+ * HarfBuzz provides a built-in set of lightweight default
+ * functions for each method in #hb_font_funcs_t.
  **/
 
 
@@ -52,19 +65,20 @@
  */
 
 static hb_bool_t
-hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
-				void *font_data HB_UNUSED,
+hb_font_get_font_h_extents_nil (hb_font_t         *font HB_UNUSED,
+				void              *font_data HB_UNUSED,
 				hb_font_extents_t *extents,
-				void *user_data HB_UNUSED)
+				void              *user_data HB_UNUSED)
 {
   memset (extents, 0, sizeof (*extents));
   return false;
 }
+
 static hb_bool_t
-hb_font_get_font_h_extents_default (hb_font_t *font,
-				    void *font_data HB_UNUSED,
+hb_font_get_font_h_extents_default (hb_font_t         *font,
+				    void              *font_data HB_UNUSED,
 				    hb_font_extents_t *extents,
-				    void *user_data HB_UNUSED)
+				    void              *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_font_h_extents (extents);
   if (ret) {
@@ -76,19 +90,20 @@
 }
 
 static hb_bool_t
-hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
-				void *font_data HB_UNUSED,
+hb_font_get_font_v_extents_nil (hb_font_t         *font HB_UNUSED,
+				void              *font_data HB_UNUSED,
 				hb_font_extents_t *extents,
-				void *user_data HB_UNUSED)
+				void              *user_data HB_UNUSED)
 {
   memset (extents, 0, sizeof (*extents));
   return false;
 }
+
 static hb_bool_t
-hb_font_get_font_v_extents_default (hb_font_t *font,
-				    void *font_data HB_UNUSED,
+hb_font_get_font_v_extents_default (hb_font_t         *font,
+				    void              *font_data HB_UNUSED,
 				    hb_font_extents_t *extents,
-				    void *user_data HB_UNUSED)
+				    void              *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_font_v_extents (extents);
   if (ret) {
@@ -100,21 +115,22 @@
 }
 
 static hb_bool_t
-hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
-			       void *font_data HB_UNUSED,
-			       hb_codepoint_t unicode HB_UNUSED,
+hb_font_get_nominal_glyph_nil (hb_font_t      *font HB_UNUSED,
+			       void           *font_data HB_UNUSED,
+			       hb_codepoint_t  unicode HB_UNUSED,
 			       hb_codepoint_t *glyph,
-			       void *user_data HB_UNUSED)
+			       void           *user_data HB_UNUSED)
 {
   *glyph = 0;
   return false;
 }
+
 static hb_bool_t
-hb_font_get_nominal_glyph_default (hb_font_t *font,
-				   void *font_data HB_UNUSED,
-				   hb_codepoint_t unicode,
+hb_font_get_nominal_glyph_default (hb_font_t      *font,
+				   void           *font_data HB_UNUSED,
+				   hb_codepoint_t  unicode,
 				   hb_codepoint_t *glyph,
-				   void *user_data HB_UNUSED)
+				   void           *user_data HB_UNUSED)
 {
   if (font->has_nominal_glyphs_func_set ())
   {
@@ -124,15 +140,16 @@
 }
 
 #define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default
+
 static unsigned int
-hb_font_get_nominal_glyphs_default (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    unsigned int count,
+hb_font_get_nominal_glyphs_default (hb_font_t            *font,
+				    void                 *font_data HB_UNUSED,
+				    unsigned int          count,
 				    const hb_codepoint_t *first_unicode,
-				    unsigned int unicode_stride,
-				    hb_codepoint_t *first_glyph,
-				    unsigned int glyph_stride,
-				    void *user_data HB_UNUSED)
+				    unsigned int          unicode_stride,
+				    hb_codepoint_t       *first_glyph,
+				    unsigned int          glyph_stride,
+				    void                 *user_data HB_UNUSED)
 {
   if (font->has_nominal_glyph_func_set ())
   {
@@ -153,41 +170,43 @@
 }
 
 static hb_bool_t
-hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
-				 void *font_data HB_UNUSED,
-				 hb_codepoint_t unicode HB_UNUSED,
-				 hb_codepoint_t variation_selector HB_UNUSED,
+hb_font_get_variation_glyph_nil (hb_font_t      *font HB_UNUSED,
+				 void           *font_data HB_UNUSED,
+				 hb_codepoint_t  unicode HB_UNUSED,
+				 hb_codepoint_t  variation_selector HB_UNUSED,
 				 hb_codepoint_t *glyph,
-				 void *user_data HB_UNUSED)
+				 void           *user_data HB_UNUSED)
 {
   *glyph = 0;
   return false;
 }
+
 static hb_bool_t
-hb_font_get_variation_glyph_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t unicode,
-				     hb_codepoint_t variation_selector,
+hb_font_get_variation_glyph_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  unicode,
+				     hb_codepoint_t  variation_selector,
 				     hb_codepoint_t *glyph,
-				     void *user_data HB_UNUSED)
+				     void           *user_data HB_UNUSED)
 {
   return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
 }
 
 
 static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font,
-				 void *font_data HB_UNUSED,
-				 hb_codepoint_t glyph HB_UNUSED,
-				 void *user_data HB_UNUSED)
+hb_font_get_glyph_h_advance_nil (hb_font_t      *font,
+				 void           *font_data HB_UNUSED,
+				 hb_codepoint_t  glyph HB_UNUSED,
+				 void           *user_data HB_UNUSED)
 {
   return font->x_scale;
 }
+
 static hb_position_t
-hb_font_get_glyph_h_advance_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t glyph,
-				     void *user_data HB_UNUSED)
+hb_font_get_glyph_h_advance_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  glyph,
+				     void           *user_data HB_UNUSED)
 {
   if (font->has_glyph_h_advances_func_set ())
   {
@@ -199,19 +218,20 @@
 }
 
 static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font,
-				 void *font_data HB_UNUSED,
-				 hb_codepoint_t glyph HB_UNUSED,
-				 void *user_data HB_UNUSED)
+hb_font_get_glyph_v_advance_nil (hb_font_t      *font,
+				 void           *font_data HB_UNUSED,
+				 hb_codepoint_t  glyph HB_UNUSED,
+				 void           *user_data HB_UNUSED)
 {
   /* TODO use font_extents.ascender+descender */
   return font->y_scale;
 }
+
 static hb_position_t
-hb_font_get_glyph_v_advance_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t glyph,
-				     void *user_data HB_UNUSED)
+hb_font_get_glyph_v_advance_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  glyph,
+				     void           *user_data HB_UNUSED)
 {
   if (font->has_glyph_v_advances_func_set ())
   {
@@ -223,15 +243,16 @@
 }
 
 #define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default
+
 static void
-hb_font_get_glyph_h_advances_default (hb_font_t* font,
-				      void* font_data HB_UNUSED,
-				      unsigned int count,
+hb_font_get_glyph_h_advances_default (hb_font_t*            font,
+				      void*                 font_data HB_UNUSED,
+				      unsigned int          count,
 				      const hb_codepoint_t *first_glyph,
-				      unsigned int glyph_stride,
-				      hb_position_t *first_advance,
-				      unsigned int advance_stride,
-				      void *user_data HB_UNUSED)
+				      unsigned int          glyph_stride,
+				      hb_position_t        *first_advance,
+				      unsigned int          advance_stride,
+				      void                 *user_data HB_UNUSED)
 {
   if (font->has_glyph_h_advance_func_set ())
   {
@@ -256,14 +277,14 @@
 
 #define hb_font_get_glyph_v_advances_nil hb_font_get_glyph_v_advances_default
 static void
-hb_font_get_glyph_v_advances_default (hb_font_t* font,
-				      void* font_data HB_UNUSED,
-				      unsigned int count,
+hb_font_get_glyph_v_advances_default (hb_font_t*            font,
+				      void*                 font_data HB_UNUSED,
+				      unsigned int          count,
 				      const hb_codepoint_t *first_glyph,
-				      unsigned int glyph_stride,
-				      hb_position_t *first_advance,
-				      unsigned int advance_stride,
-				      void *user_data HB_UNUSED)
+				      unsigned int          glyph_stride,
+				      hb_position_t        *first_advance,
+				      unsigned int          advance_stride,
+				      void                 *user_data HB_UNUSED)
 {
   if (font->has_glyph_v_advance_func_set ())
   {
@@ -287,23 +308,24 @@
 }
 
 static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
-				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph HB_UNUSED,
-				hb_position_t *x,
-				hb_position_t *y,
-				void *user_data HB_UNUSED)
+hb_font_get_glyph_h_origin_nil (hb_font_t      *font HB_UNUSED,
+				void           *font_data HB_UNUSED,
+				hb_codepoint_t  glyph HB_UNUSED,
+				hb_position_t  *x,
+				hb_position_t  *y,
+				void           *user_data HB_UNUSED)
 {
   *x = *y = 0;
   return true;
 }
+
 static hb_bool_t
-hb_font_get_glyph_h_origin_default (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t glyph,
-				    hb_position_t *x,
-				    hb_position_t *y,
-				    void *user_data HB_UNUSED)
+hb_font_get_glyph_h_origin_default (hb_font_t      *font,
+				    void           *font_data HB_UNUSED,
+				    hb_codepoint_t  glyph,
+				    hb_position_t  *x,
+				    hb_position_t  *y,
+				    void           *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
   if (ret)
@@ -312,23 +334,24 @@
 }
 
 static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
-				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph HB_UNUSED,
-				hb_position_t *x,
-				hb_position_t *y,
-				void *user_data HB_UNUSED)
+hb_font_get_glyph_v_origin_nil (hb_font_t      *font HB_UNUSED,
+				void           *font_data HB_UNUSED,
+				hb_codepoint_t  glyph HB_UNUSED,
+				hb_position_t  *x,
+				hb_position_t  *y,
+				void           *user_data HB_UNUSED)
 {
   *x = *y = 0;
   return false;
 }
+
 static hb_bool_t
-hb_font_get_glyph_v_origin_default (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t glyph,
-				    hb_position_t *x,
-				    hb_position_t *y,
-				    void *user_data HB_UNUSED)
+hb_font_get_glyph_v_origin_default (hb_font_t      *font,
+				    void           *font_data HB_UNUSED,
+				    hb_codepoint_t  glyph,
+				    hb_position_t  *x,
+				    hb_position_t  *y,
+				    void           *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
   if (ret)
@@ -337,61 +360,64 @@
 }
 
 static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
-				 void *font_data HB_UNUSED,
-				 hb_codepoint_t left_glyph HB_UNUSED,
-				 hb_codepoint_t right_glyph HB_UNUSED,
-				 void *user_data HB_UNUSED)
+hb_font_get_glyph_h_kerning_nil (hb_font_t      *font HB_UNUSED,
+				 void           *font_data HB_UNUSED,
+				 hb_codepoint_t  left_glyph HB_UNUSED,
+				 hb_codepoint_t  right_glyph HB_UNUSED,
+				 void           *user_data HB_UNUSED)
 {
   return 0;
 }
+
 static hb_position_t
-hb_font_get_glyph_h_kerning_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t left_glyph,
-				     hb_codepoint_t right_glyph,
-				     void *user_data HB_UNUSED)
+hb_font_get_glyph_h_kerning_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  left_glyph,
+				     hb_codepoint_t  right_glyph,
+				     void           *user_data HB_UNUSED)
 {
   return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
 }
 
 #ifndef HB_DISABLE_DEPRECATED
 static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
-				 void *font_data HB_UNUSED,
-				 hb_codepoint_t top_glyph HB_UNUSED,
-				 hb_codepoint_t bottom_glyph HB_UNUSED,
-				 void *user_data HB_UNUSED)
+hb_font_get_glyph_v_kerning_nil (hb_font_t      *font HB_UNUSED,
+				 void           *font_data HB_UNUSED,
+				 hb_codepoint_t  top_glyph HB_UNUSED,
+				 hb_codepoint_t  bottom_glyph HB_UNUSED,
+				 void           *user_data HB_UNUSED)
 {
   return 0;
 }
+
 static hb_position_t
-hb_font_get_glyph_v_kerning_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t top_glyph,
-				     hb_codepoint_t bottom_glyph,
-				     void *user_data HB_UNUSED)
+hb_font_get_glyph_v_kerning_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  top_glyph,
+				     hb_codepoint_t  bottom_glyph,
+				     void           *user_data HB_UNUSED)
 {
   return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
 }
 #endif
 
 static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
-			       void *font_data HB_UNUSED,
-			       hb_codepoint_t glyph HB_UNUSED,
+hb_font_get_glyph_extents_nil (hb_font_t          *font HB_UNUSED,
+			       void               *font_data HB_UNUSED,
+			       hb_codepoint_t      glyph HB_UNUSED,
 			       hb_glyph_extents_t *extents,
-			       void *user_data HB_UNUSED)
+			       void               *user_data HB_UNUSED)
 {
   memset (extents, 0, sizeof (*extents));
   return false;
 }
+
 static hb_bool_t
-hb_font_get_glyph_extents_default (hb_font_t *font,
-				   void *font_data HB_UNUSED,
-				   hb_codepoint_t glyph,
+hb_font_get_glyph_extents_default (hb_font_t          *font,
+				   void               *font_data HB_UNUSED,
+				   hb_codepoint_t      glyph,
 				   hb_glyph_extents_t *extents,
-				   void *user_data HB_UNUSED)
+				   void               *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
   if (ret) {
@@ -402,25 +428,26 @@
 }
 
 static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
-				     void *font_data HB_UNUSED,
-				     hb_codepoint_t glyph HB_UNUSED,
-				     unsigned int point_index HB_UNUSED,
-				     hb_position_t *x,
-				     hb_position_t *y,
-				     void *user_data HB_UNUSED)
+hb_font_get_glyph_contour_point_nil (hb_font_t      *font HB_UNUSED,
+				     void           *font_data HB_UNUSED,
+				     hb_codepoint_t  glyph HB_UNUSED,
+				     unsigned int    point_index HB_UNUSED,
+				     hb_position_t  *x,
+				     hb_position_t  *y,
+				     void           *user_data HB_UNUSED)
 {
   *x = *y = 0;
   return false;
 }
+
 static hb_bool_t
-hb_font_get_glyph_contour_point_default (hb_font_t *font,
-					 void *font_data HB_UNUSED,
-					 hb_codepoint_t glyph,
-					 unsigned int point_index,
-					 hb_position_t *x,
-					 hb_position_t *y,
-					 void *user_data HB_UNUSED)
+hb_font_get_glyph_contour_point_default (hb_font_t      *font,
+					 void           *font_data HB_UNUSED,
+					 hb_codepoint_t  glyph,
+					 unsigned int    point_index,
+					 hb_position_t  *x,
+					 hb_position_t  *y,
+					 void           *user_data HB_UNUSED)
 {
   hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
   if (ret)
@@ -429,42 +456,47 @@
 }
 
 static hb_bool_t
-hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
-			    void *font_data HB_UNUSED,
-			    hb_codepoint_t glyph HB_UNUSED,
-			    char *name, unsigned int size,
-			    void *user_data HB_UNUSED)
+hb_font_get_glyph_name_nil (hb_font_t      *font HB_UNUSED,
+			    void           *font_data HB_UNUSED,
+			    hb_codepoint_t  glyph HB_UNUSED,
+			    char           *name,
+			    unsigned int    size,
+			    void           *user_data HB_UNUSED)
 {
   if (size) *name = '\0';
   return false;
 }
+
 static hb_bool_t
-hb_font_get_glyph_name_default (hb_font_t *font,
-				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph,
-				char *name, unsigned int size,
-				void *user_data HB_UNUSED)
+hb_font_get_glyph_name_default (hb_font_t      *font,
+				void           *font_data HB_UNUSED,
+				hb_codepoint_t  glyph,
+				char           *name,
+				unsigned int    size,
+				void           *user_data HB_UNUSED)
 {
   return font->parent->get_glyph_name (glyph, name, size);
 }
 
 static hb_bool_t
-hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
-				 void *font_data HB_UNUSED,
-				 const char *name HB_UNUSED,
-				 int len HB_UNUSED, /* -1 means nul-terminated */
+hb_font_get_glyph_from_name_nil (hb_font_t      *font HB_UNUSED,
+				 void           *font_data HB_UNUSED,
+				 const char     *name HB_UNUSED,
+				 int             len HB_UNUSED, /* -1 means nul-terminated */
 				 hb_codepoint_t *glyph,
-				 void *user_data HB_UNUSED)
+				 void           *user_data HB_UNUSED)
 {
   *glyph = 0;
   return false;
 }
+
 static hb_bool_t
-hb_font_get_glyph_from_name_default (hb_font_t *font,
-				     void *font_data HB_UNUSED,
-				     const char *name, int len, /* -1 means nul-terminated */
+hb_font_get_glyph_from_name_default (hb_font_t      *font,
+				     void           *font_data HB_UNUSED,
+				     const char     *name,
+				     int             len, /* -1 means nul-terminated */
 				     hb_codepoint_t *glyph,
-				     void *user_data HB_UNUSED)
+				     void           *user_data HB_UNUSED)
 {
   return font->parent->get_glyph_from_name (name, len, glyph);
 }
@@ -518,9 +550,9 @@
 /**
  * hb_font_funcs_create: (Xconstructor)
  *
+ * Creates a new #hb_font_funcs_t structure of font functions.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The font-functions structure
  *
  * Since: 0.9.2
  **/
@@ -540,9 +572,9 @@
 /**
  * hb_font_funcs_get_empty:
  *
+ * Fetches an empty font-functions structure.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The font-functions structure
  *
  * Since: 0.9.2
  **/
@@ -554,11 +586,11 @@
 
 /**
  * hb_font_funcs_reference: (skip)
- * @ffuncs: font functions.
+ * @ffuncs: The font-functions structure
  *
+ * Increases the reference count on a font-functions structure.
  *
- *
- * Return value:
+ * Return value: The font-functions structure
  *
  * Since: 0.9.2
  **/
@@ -570,9 +602,11 @@
 
 /**
  * hb_font_funcs_destroy: (skip)
- * @ffuncs: font functions.
+ * @ffuncs: The font-functions structure
  *
- *
+ * Decreases the reference count on a font-functions structure. When
+ * the reference count reaches zero, the font-functions structure is
+ * destroyed, freeing all memory.
  *
  * Since: 0.9.2
  **/
@@ -586,20 +620,20 @@
   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
-  free (ffuncs);
+  hb_free (ffuncs);
 }
 
 /**
  * hb_font_funcs_set_user_data: (skip)
- * @ffuncs: font functions.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @ffuncs: The font-functions structure
+ * @key: The user-data key to set
+ * @data: A pointer to the user data set
+ * @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 font-functions structure. 
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -607,7 +641,7 @@
 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
 			     hb_user_data_key_t *key,
 			     void *              data,
-			     hb_destroy_func_t   destroy,
+			     hb_destroy_func_t   destroy /* May be NULL. */,
 			     hb_bool_t           replace)
 {
   return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
@@ -615,12 +649,13 @@
 
 /**
  * hb_font_funcs_get_user_data: (skip)
- * @ffuncs: font functions.
- * @key:
+ * @ffuncs: The font-functions structure
+ * @key: The user-data key to query
  *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified font-functions structure.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -634,9 +669,9 @@
 
 /**
  * hb_font_funcs_make_immutable:
- * @ffuncs: font functions.
+ * @ffuncs: The font-functions structure
  *
- *
+ * Makes a font-functions structure immutable.
  *
  * Since: 0.9.2
  **/
@@ -651,11 +686,11 @@
 
 /**
  * hb_font_funcs_is_immutable:
- * @ffuncs: font functions.
+ * @ffuncs: The font-functions structure
  *
+ * Tests whether a font-functions structure is immutable.
  *
- *
- * Return value:
+ * Return value: %true if @ffuncs is immutable, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -674,7 +709,8 @@
 				 void                        *user_data, \
 				 hb_destroy_func_t            destroy)   \
 {                                                                        \
-  if (hb_object_is_immutable (ffuncs)) {                                 \
+  if (hb_object_is_immutable (ffuncs))                                   \
+  {                                                                      \
     if (destroy)                                                         \
       destroy (user_data);                                               \
     return;                                                              \
@@ -714,17 +750,18 @@
 
 /**
  * hb_font_get_h_extents:
- * @font: a font.
- * @extents: (out):
+ * @font: #hb_font_t to work upon
+ * @extents: (out): The font extents retrieved
  *
+ * Fetches the extents for a specified font, for horizontal
+ * text segments.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 1.1.3
  **/
 hb_bool_t
-hb_font_get_h_extents (hb_font_t *font,
+hb_font_get_h_extents (hb_font_t         *font,
 		       hb_font_extents_t *extents)
 {
   return font->get_font_h_extents (extents);
@@ -732,17 +769,18 @@
 
 /**
  * hb_font_get_v_extents:
- * @font: a font.
- * @extents: (out):
+ * @font: #hb_font_t to work upon
+ * @extents: (out): The font extents retrieved
  *
+ * Fetches the extents for a specified font, for vertical
+ * text segments.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 1.1.3
  **/
 hb_bool_t
-hb_font_get_v_extents (hb_font_t *font,
+hb_font_get_v_extents (hb_font_t         *font,
 		       hb_font_extents_t *extents)
 {
   return font->get_font_v_extents (extents);
@@ -750,20 +788,25 @@
 
 /**
  * hb_font_get_glyph:
- * @font: a font.
- * @unicode:
- * @variation_selector:
- * @glyph: (out):
+ * @font: #hb_font_t to work upon
+ * @unicode: The Unicode code point to query
+ * @variation_selector: A variation-selector code point
+ * @glyph: (out): The glyph ID retrieved
  *
+ * Fetches the glyph ID for a Unicode code point in the specified
+ * font, with an optional variation selector.
  *
+ * If @variation_selector is 0, calls hb_font_get_nominal_glyph();
+ * otherwise calls hb_font_get_variation_glyph().
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph (hb_font_t *font,
-		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+hb_font_get_glyph (hb_font_t      *font,
+		   hb_codepoint_t  unicode,
+		   hb_codepoint_t  variation_selector,
 		   hb_codepoint_t *glyph)
 {
   if (unlikely (variation_selector))
@@ -773,19 +816,24 @@
 
 /**
  * hb_font_get_nominal_glyph:
- * @font: a font.
- * @unicode:
- * @glyph: (out):
+ * @font: #hb_font_t to work upon
+ * @unicode: The Unicode code point to query
+ * @glyph: (out): The glyph ID retrieved
  *
+ * Fetches the nominal glyph ID for a Unicode code point in the
+ * specified font. 
  *
+ * 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 hb_font_get_variation_glyph() or use hb_font_get_glyph().
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 1.2.3
  **/
 hb_bool_t
-hb_font_get_nominal_glyph (hb_font_t *font,
-			   hb_codepoint_t unicode,
+hb_font_get_nominal_glyph (hb_font_t      *font,
+			   hb_codepoint_t  unicode,
 			   hb_codepoint_t *glyph)
 {
   return font->get_nominal_glyph (unicode, glyph);
@@ -793,11 +841,17 @@
 
 /**
  * hb_font_get_nominal_glyphs:
- * @font: a font.
+ * @font: #hb_font_t to work upon
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @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.
  *
- *
- * Return value:
+ * Return value: the number of code points processed
  *
  * Since: 2.6.3
  **/
@@ -816,20 +870,23 @@
 
 /**
  * hb_font_get_variation_glyph:
- * @font: a font.
- * @unicode:
- * @variation_selector:
- * @glyph: (out):
+ * @font: #hb_font_t to work upon
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The  variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
  *
+ * Fetches the glyph ID for a Unicode code point when followed by
+ * by the specified variation-selector code point, in the specified
+ * font.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 1.2.3
  **/
 hb_bool_t
-hb_font_get_variation_glyph (hb_font_t *font,
-			     hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+hb_font_get_variation_glyph (hb_font_t      *font,
+			     hb_codepoint_t  unicode,
+			     hb_codepoint_t  variation_selector,
 			     hb_codepoint_t *glyph)
 {
   return font->get_variation_glyph (unicode, variation_selector, glyph);
@@ -837,134 +894,157 @@
 
 /**
  * hb_font_get_glyph_h_advance:
- * @font: a font.
- * @glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
  *
+ * Fetches the advance for a glyph ID in the specified font,
+ * for horizontal text segments.
  *
- *
- * Return value:
+ * Return value: The advance of @glyph within @font
  *
  * Since: 0.9.2
  **/
 hb_position_t
-hb_font_get_glyph_h_advance (hb_font_t *font,
-			     hb_codepoint_t glyph)
+hb_font_get_glyph_h_advance (hb_font_t      *font,
+			     hb_codepoint_t  glyph)
 {
   return font->get_glyph_h_advance (glyph);
 }
 
 /**
  * hb_font_get_glyph_v_advance:
- * @font: a font.
- * @glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
  *
+ * Fetches the advance for a glyph ID in the specified font,
+ * for vertical text segments.
  *
- *
- * Return value:
+ * Return value: The advance of @glyph within @font
  *
  * Since: 0.9.2
  **/
 hb_position_t
-hb_font_get_glyph_v_advance (hb_font_t *font,
-			     hb_codepoint_t glyph)
+hb_font_get_glyph_v_advance (hb_font_t      *font,
+			     hb_codepoint_t  glyph)
 {
   return font->get_glyph_v_advance (glyph);
 }
 
 /**
  * hb_font_get_glyph_h_advances:
- * @font: a font.
+ * @font: #hb_font_t to work upon
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: The stride between successive advances
  *
- *
+ * Fetches the advances for a sequence of glyph IDs in the specified
+ * font, for horizontal text segments. 
  *
  * Since: 1.8.6
  **/
 void
-hb_font_get_glyph_h_advances (hb_font_t* font,
-			      unsigned int count,
+hb_font_get_glyph_h_advances (hb_font_t*            font,
+			      unsigned int          count,
 			      const hb_codepoint_t *first_glyph,
-			      unsigned glyph_stride,
-			      hb_position_t *first_advance,
-			      unsigned advance_stride)
+			      unsigned              glyph_stride,
+			      hb_position_t        *first_advance,
+			      unsigned              advance_stride)
 {
   font->get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
 }
 /**
  * hb_font_get_glyph_v_advances:
- * @font: a font.
+ * @font: #hb_font_t to work upon
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: (out): The stride between successive advances
  *
- *
+ * Fetches the advances for a sequence of glyph IDs in the specified
+ * font, for vertical text segments.  
  *
  * Since: 1.8.6
  **/
 void
-hb_font_get_glyph_v_advances (hb_font_t* font,
-			      unsigned int count,
+hb_font_get_glyph_v_advances (hb_font_t*            font,
+			      unsigned int          count,
 			      const hb_codepoint_t *first_glyph,
-			      unsigned glyph_stride,
-			      hb_position_t *first_advance,
-			      unsigned advance_stride)
+			      unsigned              glyph_stride,
+			      hb_position_t        *first_advance,
+			      unsigned              advance_stride)
 {
   font->get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
 }
 
 /**
  * hb_font_get_glyph_h_origin:
- * @font: a font.
- * @glyph:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @x: (out): The X coordinate of the origin
+ * @y: (out): The Y coordinate of the origin
  *
+ * Fetches the (X,Y) coordinates of the origin for a glyph ID
+ * in the specified font, for horizontal text segments.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_h_origin (hb_font_t *font,
-			    hb_codepoint_t glyph,
-			    hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_h_origin (hb_font_t      *font,
+			    hb_codepoint_t  glyph,
+			    hb_position_t  *x,
+			    hb_position_t  *y)
 {
   return font->get_glyph_h_origin (glyph, x, y);
 }
 
 /**
  * hb_font_get_glyph_v_origin:
- * @font: a font.
- * @glyph:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @x: (out): The X coordinate of the origin
+ * @y: (out): The Y coordinate of the origin
  *
+ * Fetches the (X,Y) coordinates of the origin for a glyph ID
+ * in the specified font, for vertical text segments.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_v_origin (hb_font_t *font,
-			    hb_codepoint_t glyph,
-			    hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_v_origin (hb_font_t      *font,
+			    hb_codepoint_t  glyph,
+			    hb_position_t  *x,
+			    hb_position_t  *y)
 {
   return font->get_glyph_v_origin (glyph, x, y);
 }
 
 /**
  * hb_font_get_glyph_h_kerning:
- * @font: a font.
- * @left_glyph:
- * @right_glyph:
+ * @font: #hb_font_t to work upon
+ * @left_glyph: The glyph ID of the left glyph in the glyph pair
+ * @right_glyph: The glyph ID of the right glyph in the glyph pair
  *
+ * Fetches the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
  *
+ * <note>It handles legacy kerning only (as returned by the corresponding
+ * #hb_font_funcs_t function).</note>
  *
- * Return value:
+ * Return value: The kerning adjustment value
  *
  * Since: 0.9.2
  **/
 hb_position_t
-hb_font_get_glyph_h_kerning (hb_font_t *font,
-			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+hb_font_get_glyph_h_kerning (hb_font_t      *font,
+			     hb_codepoint_t  left_glyph,
+			     hb_codepoint_t  right_glyph)
 {
   return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
@@ -972,20 +1052,25 @@
 #ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_font_get_glyph_v_kerning:
- * @font: a font.
- * @top_glyph:
- * @bottom_glyph:
+ * @font: #hb_font_t to work upon
+ * @top_glyph: The glyph ID of the top glyph in the glyph pair
+ * @bottom_glyph: The glyph ID of the bottom glyph in the glyph pair
  *
+ * Fetches the kerning-adjustment value for a glyph-pair in
+ * the specified font, for vertical text segments.
  *
+ * <note>It handles legacy kerning only (as returned by the corresponding
+ * #hb_font_funcs_t function).</note>
  *
- * Return value:
+ * Return value: The kerning adjustment value
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
  **/
 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_v_kerning (hb_font_t      *font,
+			     hb_codepoint_t  top_glyph,
+			     hb_codepoint_t  bottom_glyph)
 {
   return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
 }
@@ -993,19 +1078,20 @@
 
 /**
  * hb_font_get_glyph_extents:
- * @font: a font.
- * @glyph:
- * @extents: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @extents: (out): The #hb_glyph_extents_t retrieved
  *
+ * Fetches the #hb_glyph_extents_t data for a glyph ID
+ * in the specified font.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_extents (hb_font_t *font,
-			   hb_codepoint_t glyph,
+hb_font_get_glyph_extents (hb_font_t          *font,
+			   hb_codepoint_t      glyph,
 			   hb_glyph_extents_t *extents)
 {
   return font->get_glyph_extents (glyph, extents);
@@ -1013,63 +1099,70 @@
 
 /**
  * hb_font_get_glyph_contour_point:
- * @font: a font.
- * @glyph:
- * @point_index:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @point_index: The contour-point index to query
+ * @x: (out): The X value retrieved for the contour point
+ * @y: (out): The Y value retrieved for the contour point
  *
+ * Fetches the (x,y) coordinates of a specified contour-point index
+ * in the specified glyph, within the specified font.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_contour_point (hb_font_t *font,
-				 hb_codepoint_t glyph, unsigned int point_index,
-				 hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_contour_point (hb_font_t      *font,
+				 hb_codepoint_t  glyph,
+				 unsigned int    point_index,
+				 hb_position_t  *x,
+				 hb_position_t  *y)
 {
   return font->get_glyph_contour_point (glyph, point_index, x, y);
 }
 
 /**
  * hb_font_get_glyph_name:
- * @font: a font.
- * @glyph:
- * @name: (array length=size):
- * @size:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @name: (out) (array length=size): Name string retrieved for the glyph ID
+ * @size: Length of the glyph-name string retrieved
  *
+ * Fetches the glyph-name string for a glyph ID in the specified @font.
  *
- *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_name (hb_font_t *font,
-			hb_codepoint_t glyph,
-			char *name, unsigned int size)
+hb_font_get_glyph_name (hb_font_t      *font,
+			hb_codepoint_t  glyph,
+			char           *name,
+			unsigned int    size)
 {
   return font->get_glyph_name (glyph, name, size);
 }
 
 /**
  * hb_font_get_glyph_from_name:
- * @font: a font.
- * @name: (array length=len):
- * @len:
- * @glyph: (out):
+ * @font: #hb_font_t to work upon
+ * @name: (array length=len): The name string to query
+ * @len: The length of the name queried
+ * @glyph: (out): The glyph ID retrieved
  *
+ * Fetches the glyph ID that corresponds to a name string in the specified @font.
  *
+ * <note>Note: @len == -1 means the name string is null-terminated.</note>
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_from_name (hb_font_t *font,
-			     const char *name, int len, /* -1 means nul-terminated */
+hb_font_get_glyph_from_name (hb_font_t      *font,
+			     const char     *name,
+			     int             len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph)
 {
   return font->get_glyph_from_name (name, len, glyph);
@@ -1080,164 +1173,211 @@
 
 /**
  * hb_font_get_extents_for_direction:
- * @font: a font.
- * @direction:
- * @extents: (out):
+ * @font: #hb_font_t to work upon
+ * @direction: The direction of the text segment
+ * @extents: (out): The #hb_font_extents_t retrieved
  *
+ * Fetches the extents for a font in a text segment of the
+ * specified direction.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 1.1.3
  **/
 void
-hb_font_get_extents_for_direction (hb_font_t *font,
-				   hb_direction_t direction,
+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);
 }
 /**
  * hb_font_get_glyph_advance_for_direction:
- * @font: a font.
- * @glyph:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @direction: The direction of the text segment
+ * @x: (out): The horizontal advance retrieved
+ * @y: (out):  The vertical advance retrieved
  *
+ * Fetches the advance for a glyph ID from the specified font,
+ * in a text segment of the specified direction.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_get_glyph_advance_for_direction (hb_font_t *font,
-					 hb_codepoint_t glyph,
-					 hb_direction_t direction,
-					 hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_advance_for_direction (hb_font_t      *font,
+					 hb_codepoint_t  glyph,
+					 hb_direction_t  direction,
+					 hb_position_t  *x,
+					 hb_position_t  *y)
 {
   return font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 /**
  * hb_font_get_glyph_advances_for_direction:
- * @font: a font.
- * @direction:
+ * @font: #hb_font_t to work upon
+ * @direction: The direction of the text segment
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: (out): The stride between successive advances
  *
+ * Fetches the advances for a sequence of glyph IDs in the specified
+ * font, in a text segment of the specified direction.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 1.8.6
  **/
 HB_EXTERN void
-hb_font_get_glyph_advances_for_direction (hb_font_t* font,
-					  hb_direction_t direction,
-					  unsigned int count,
+hb_font_get_glyph_advances_for_direction (hb_font_t*            font,
+					  hb_direction_t        direction,
+					  unsigned int          count,
 					  const hb_codepoint_t *first_glyph,
-					  unsigned glyph_stride,
-					  hb_position_t *first_advance,
-					  unsigned advance_stride)
+					  unsigned              glyph_stride,
+					  hb_position_t        *first_advance,
+					  unsigned              advance_stride)
 {
   font->get_glyph_advances_for_direction (direction, count, first_glyph, glyph_stride, first_advance, advance_stride);
 }
 
 /**
  * hb_font_get_glyph_origin_for_direction:
- * @font: a font.
- * @glyph:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @direction: The direction of the text segment
+ * @x: (out): The X coordinate retrieved for the origin
+ * @y: (out): The Y coordinate retrieved for the origin
  *
+ * Fetches the (X,Y) coordinates of the origin for a glyph in
+ * the specified font.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_get_glyph_origin_for_direction (hb_font_t *font,
-					hb_codepoint_t glyph,
-					hb_direction_t direction,
-					hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_origin_for_direction (hb_font_t      *font,
+					hb_codepoint_t  glyph,
+					hb_direction_t  direction,
+					hb_position_t  *x,
+					hb_position_t  *y)
 {
   return font->get_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 /**
  * hb_font_add_glyph_origin_for_direction:
- * @font: a font.
- * @glyph:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @direction: The direction of the text segment
+ * @x: (inout): Input = The original X coordinate 
+ *     Output = The X coordinate plus the X-coordinate of the origin
+ * @y: (inout): Input = The original Y coordinate
+ *     Output = The Y coordinate plus the Y-coordinate of the origin
  *
+ * Adds the origin coordinates to an (X,Y) point coordinate, in
+ * the specified glyph ID in the specified font.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_add_glyph_origin_for_direction (hb_font_t *font,
-					hb_codepoint_t glyph,
-					hb_direction_t direction,
-					hb_position_t *x, hb_position_t *y)
+hb_font_add_glyph_origin_for_direction (hb_font_t      *font,
+					hb_codepoint_t  glyph,
+					hb_direction_t  direction,
+					hb_position_t  *x,
+					hb_position_t  *y)
 {
   return font->add_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 /**
  * hb_font_subtract_glyph_origin_for_direction:
- * @font: a font.
- * @glyph:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @direction: The direction of the text segment
+ * @x: (inout): Input = The original X coordinate 
+ *     Output = The X coordinate minus the X-coordinate of the origin
+ * @y: (inout): Input = The original Y coordinate
+ *     Output = The Y coordinate minus the Y-coordinate of the origin
  *
+ * Subtracts the origin coordinates from an (X,Y) point coordinate,
+ * in the specified glyph ID in the specified font.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
-					     hb_codepoint_t glyph,
-					     hb_direction_t direction,
-					     hb_position_t *x, hb_position_t *y)
+hb_font_subtract_glyph_origin_for_direction (hb_font_t      *font,
+					     hb_codepoint_t  glyph,
+					     hb_direction_t  direction,
+					     hb_position_t  *x,
+					     hb_position_t  *y)
 {
   return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
 /**
  * hb_font_get_glyph_kerning_for_direction:
- * @font: a font.
- * @first_glyph:
- * @second_glyph:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @first_glyph: The glyph ID of the first glyph in the glyph pair to query
+ * @second_glyph: The glyph ID of the second glyph in the glyph pair to query
+ * @direction: The direction of the text segment
+ * @x: (out): The horizontal kerning-adjustment value retrieved
+ * @y: (out): The vertical kerning-adjustment value retrieved
  *
+ * Fetches the kerning-adjustment value for a glyph-pair in the specified font.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
-					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
-					 hb_direction_t direction,
-					 hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_kerning_for_direction (hb_font_t      *font,
+					 hb_codepoint_t  first_glyph,
+					 hb_codepoint_t  second_glyph,
+					 hb_direction_t  direction,
+					 hb_position_t  *x,
+					 hb_position_t  *y)
 {
   return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
 }
 
 /**
  * hb_font_get_glyph_extents_for_origin:
- * @font: a font.
- * @glyph:
- * @direction:
- * @extents: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @direction: The direction of the text segment
+ * @extents: (out): The #hb_glyph_extents_t retrieved
  *
+ * Fetches the #hb_glyph_extents_t data for a glyph ID
+ * in the specified font, with respect to the origin in
+ * a text segment in the specified direction.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_extents_for_origin (hb_font_t *font,
-				      hb_codepoint_t glyph,
-				      hb_direction_t direction,
+hb_font_get_glyph_extents_for_origin (hb_font_t          *font,
+				      hb_codepoint_t      glyph,
+				      hb_direction_t      direction,
 				      hb_glyph_extents_t *extents)
 {
   return font->get_glyph_extents_for_origin (glyph, direction, extents);
@@ -1245,65 +1385,79 @@
 
 /**
  * hb_font_get_glyph_contour_point_for_origin:
- * @font: a font.
- * @glyph:
- * @point_index:
- * @direction:
- * @x: (out):
- * @y: (out):
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @point_index: The contour-point index to query
+ * @direction: The direction of the text segment
+ * @x: (out): The X value retrieved for the contour point
+ * @y: (out): The Y value retrieved for the contour point
  *
+ * 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.
  *
+ * Calls the appropriate direction-specific variant (horizontal
+ * or vertical) depending on the value of @direction.
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
-					    hb_codepoint_t glyph, unsigned int point_index,
-					    hb_direction_t direction,
-					    hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_contour_point_for_origin (hb_font_t      *font,
+					    hb_codepoint_t  glyph,
+					    unsigned int    point_index,
+					    hb_direction_t  direction,
+					    hb_position_t  *x,
+					    hb_position_t  *y)
 {
   return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
 }
 
-/* Generates gidDDD if glyph has no name. */
 /**
  * hb_font_glyph_to_string:
- * @font: a font.
- * @glyph:
- * @s: (array length=size):
- * @size:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID to query
+ * @s: (out) (array length=size): The string containing the glyph name
+ * @size: Length of string @s
  *
+ * Fetches the name of the specified glyph ID in @font and returns
+ * it in string @s.
  *
+ * If the glyph ID has no name in @font, a string of the form `gidDDD` is
+ * generated, with `DDD` being the glyph ID.
  *
  * Since: 0.9.2
  **/
 void
-hb_font_glyph_to_string (hb_font_t *font,
-			 hb_codepoint_t glyph,
-			 char *s, unsigned int size)
+hb_font_glyph_to_string (hb_font_t      *font,
+			 hb_codepoint_t  glyph,
+			 char           *s,
+			 unsigned int    size)
 {
   font->glyph_to_string (glyph, s, size);
 }
 
-/* Parses gidDDD and uniUUUU strings automatically. */
 /**
  * hb_font_glyph_from_string:
- * @font: a font.
- * @s: (array length=len) (element-type uint8_t):
- * @len:
- * @glyph: (out):
+ * @font: #hb_font_t to work upon
+ * @s: (array length=len) (element-type uint8_t): string to query
+ * @len: The length of the string @s
+ * @glyph: (out): The glyph ID corresponding to the string requested
  *
+ * Fetches the glyph ID from @font that matches the specified string.
+ * Strings of the format `gidDDD` or `uniUUUU` are parsed automatically.
  *
+ * <note>Note: @len == -1 means the string is null-terminated.</note>
  *
- * Return value:
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_font_glyph_from_string (hb_font_t *font,
-			   const char *s, int len, /* -1 means nul-terminated */
+hb_font_glyph_from_string (hb_font_t      *font,
+			   const char     *s,
+			   int             len,
 			   hb_codepoint_t *glyph)
 {
   return font->glyph_from_string (s, len, glyph);
@@ -1332,6 +1486,7 @@
 
   0, /* num_coords */
   nullptr, /* coords */
+  nullptr, /* design_coords */
 
   const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t),
 
@@ -1364,9 +1519,9 @@
  * hb_font_create: (Xconstructor)
  * @face: a face.
  *
+ * Constructs a new font object from the specified face.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The new font object
  *
  * Since: 0.9.2
  **/
@@ -1383,13 +1538,28 @@
   return font;
 }
 
+static void
+_hb_font_adopt_var_coords (hb_font_t *font,
+			   int *coords, /* 2.14 normalized */
+			   float *design_coords,
+			   unsigned int coords_length)
+{
+  hb_free (font->coords);
+  hb_free (font->design_coords);
+
+  font->coords = coords;
+  font->design_coords = design_coords;
+  font->num_coords = coords_length;
+}
+
 /**
  * hb_font_create_sub_font:
- * @parent: parent font.
+ * @parent: The parent font object
  *
+ * Constructs a sub-font font object from the specified @parent font,
+ * replicating the parent's properties.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The new sub-font font object
  *
  * Since: 0.9.2
  **/
@@ -1413,15 +1583,22 @@
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
 
-  font->num_coords = parent->num_coords;
-  if (font->num_coords)
+  unsigned int num_coords = parent->num_coords;
+  if (num_coords)
   {
-    unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
-    font->coords = (int *) malloc (size);
-    if (unlikely (!font->coords))
-      font->num_coords = 0;
+    int *coords = (int *) hb_calloc (num_coords, sizeof (parent->coords[0]));
+    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_font_adopt_var_coords (font, coords, design_coords, num_coords);
+    }
     else
-      memcpy (font->coords, parent->coords, size);
+    {
+      hb_free (coords);
+      hb_free (design_coords);
+    }
   }
 
   return font;
@@ -1430,25 +1607,25 @@
 /**
  * hb_font_get_empty:
  *
+ * Fetches the empty font object.
  *
- *
- * Return value: (transfer full)
+ * Return value: (transfer full): The empty font object
  *
  * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_get_empty ()
 {
-  return const_cast<hb_font_t *> (&Null(hb_font_t));
+  return const_cast<hb_font_t *> (&Null (hb_font_t));
 }
 
 /**
  * hb_font_reference: (skip)
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
+ * Increases the reference count on the given font object.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The @font object
  *
  * Since: 0.9.2
  **/
@@ -1460,9 +1637,11 @@
 
 /**
  * hb_font_destroy: (skip)
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
- *
+ * Decreases the reference count on the given font object. When the
+ * reference count reaches zero, the font is destroyed,
+ * freeing all memory.
  *
  * Since: 0.9.2
  **/
@@ -1480,22 +1659,23 @@
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
-  free (font->coords);
+  hb_free (font->coords);
+  hb_free (font->design_coords);
 
-  free (font);
+  hb_free (font);
 }
 
 /**
  * hb_font_set_user_data: (skip)
- * @font: a font.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @font: #hb_font_t to work upon
+ * @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 font object. 
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -1503,7 +1683,7 @@
 hb_font_set_user_data (hb_font_t          *font,
 		       hb_user_data_key_t *key,
 		       void *              data,
-		       hb_destroy_func_t   destroy,
+		       hb_destroy_func_t   destroy /* May be NULL. */,
 		       hb_bool_t           replace)
 {
   return hb_object_set_user_data (font, key, data, destroy, replace);
@@ -1511,12 +1691,13 @@
 
 /**
  * hb_font_get_user_data: (skip)
- * @font: a font.
- * @key:
+ * @font: #hb_font_t to work upon
+ * @key: The user-data key to query
  *
+ * Fetches the user-data object associated with the specified key,
+ * attached to the specified font object.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): Pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -1529,9 +1710,9 @@
 
 /**
  * hb_font_make_immutable:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
- *
+ * Makes @font immutable.
  *
  * Since: 0.9.2
  **/
@@ -1549,11 +1730,11 @@
 
 /**
  * hb_font_is_immutable:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
+ * Tests whether a font object is immutable.
  *
- *
- * Return value:
+ * Return value: %true if @font is immutable, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -1565,10 +1746,10 @@
 
 /**
  * hb_font_set_parent:
- * @font: a font.
- * @parent: new parent.
+ * @font: #hb_font_t to work upon
+ * @parent: The parent font object to assign
  *
- * Sets parent font of @font.
+ * Sets the parent font of @font.
  *
  * Since: 1.0.5
  **/
@@ -1591,11 +1772,11 @@
 
 /**
  * hb_font_get_parent:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
+ * Fetches the parent font of @font.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): The parent font object
  *
  * Since: 0.9.2
  **/
@@ -1607,10 +1788,10 @@
 
 /**
  * hb_font_set_face:
- * @font: a font.
- * @face: new face.
+ * @font: #hb_font_t to work upon
+ * @face: The #hb_face_t to assign
  *
- * Sets font-face of @font.
+ * Sets @face as the font-face value of @font.
  *
  * Since: 1.4.3
  **/
@@ -1635,11 +1816,11 @@
 
 /**
  * hb_font_get_face:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
+ * Fetches the face associated with the specified font object.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): The #hb_face_t value
  *
  * Since: 0.9.2
  **/
@@ -1652,12 +1833,13 @@
 
 /**
  * hb_font_set_funcs:
- * @font: a font.
- * @klass: (closure font_data) (destroy destroy) (scope notified):
- * @font_data:
- * @destroy:
+ * @font: #hb_font_t to work upon
+ * @klass: (closure font_data) (destroy destroy) (scope notified): The font-functions structure.
+ * @font_data: Data to attach to @font
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
  *
- *
+ * Replaces the font-functions structure attached to a font, updating
+ * the font's user-data with @font-data and the @destroy callback.
  *
  * Since: 0.9.2
  **/
@@ -1665,7 +1847,7 @@
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
 		   void              *font_data,
-		   hb_destroy_func_t  destroy)
+		   hb_destroy_func_t  destroy /* May be NULL. */)
 {
   if (hb_object_is_immutable (font))
   {
@@ -1689,18 +1871,19 @@
 
 /**
  * hb_font_set_funcs_data:
- * @font: a font.
- * @font_data: (destroy destroy) (scope notified):
- * @destroy:
+ * @font: #hb_font_t to work upon
+ * @font_data: (destroy destroy) (scope notified): Data to attach to @font
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
  *
- *
+ * Replaces the user data attached to a font, updating the font's 
+ * @destroy callback.
  *
  * Since: 0.9.2
  **/
 void
 hb_font_set_funcs_data (hb_font_t         *font,
-			void              *font_data,
-			hb_destroy_func_t  destroy)
+		        void              *font_data,
+		        hb_destroy_func_t  destroy /* May be NULL. */)
 {
   /* Destroy user_data? */
   if (hb_object_is_immutable (font))
@@ -1720,18 +1903,18 @@
 
 /**
  * hb_font_set_scale:
- * @font: a font.
- * @x_scale:
- * @y_scale:
+ * @font: #hb_font_t to work upon
+ * @x_scale: Horizontal scale value to assign
+ * @y_scale: Vertical scale value to assign
  *
- *
+ * Sets the horizontal and vertical scale of a font.
  *
  * Since: 0.9.2
  **/
 void
 hb_font_set_scale (hb_font_t *font,
-		   int x_scale,
-		   int y_scale)
+		   int        x_scale,
+		   int        y_scale)
 {
   if (hb_object_is_immutable (font))
     return;
@@ -1743,18 +1926,18 @@
 
 /**
  * hb_font_get_scale:
- * @font: a font.
- * @x_scale: (out):
- * @y_scale: (out):
+ * @font: #hb_font_t to work upon
+ * @x_scale: (out): Horizontal scale value
+ * @y_scale: (out): Vertical scale value
  *
- *
+ * Fetches the horizontal and vertical scale of a font.
  *
  * Since: 0.9.2
  **/
 void
 hb_font_get_scale (hb_font_t *font,
-		   int *x_scale,
-		   int *y_scale)
+		   int       *x_scale,
+		   int       *y_scale)
 {
   if (x_scale) *x_scale = font->x_scale;
   if (y_scale) *y_scale = font->y_scale;
@@ -1762,18 +1945,18 @@
 
 /**
  * hb_font_set_ppem:
- * @font: a font.
- * @x_ppem:
- * @y_ppem:
+ * @font: #hb_font_t to work upon
+ * @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. 
  *
  * Since: 0.9.2
  **/
 void
-hb_font_set_ppem (hb_font_t *font,
-		  unsigned int x_ppem,
-		  unsigned int y_ppem)
+hb_font_set_ppem (hb_font_t    *font,
+		  unsigned int  x_ppem,
+		  unsigned int  y_ppem)
 {
   if (hb_object_is_immutable (font))
     return;
@@ -1784,16 +1967,16 @@
 
 /**
  * hb_font_get_ppem:
- * @font: a font.
- * @x_ppem: (out):
- * @y_ppem: (out):
+ * @font: #hb_font_t to work upon
+ * @x_ppem: (out): Horizontal ppem value
+ * @y_ppem: (out): Vertical ppem value
  *
- *
+ * Fetches the horizontal and vertical points-per-em (ppem) of a font. 
  *
  * Since: 0.9.2
  **/
 void
-hb_font_get_ppem (hb_font_t *font,
+hb_font_get_ppem (hb_font_t    *font,
 		  unsigned int *x_ppem,
 		  unsigned int *y_ppem)
 {
@@ -1803,17 +1986,19 @@
 
 /**
  * hb_font_set_ptem:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  * @ptem: font size in points.
  *
- * Sets "point size" of the font.  Set to 0 to unset.
+ * Sets the "point size" of a font. Set to zero to unset.
+ * Used in CoreText to implement optical sizing.
  *
- * There are 72 points in an inch.
+ * <note>Note: There are 72 points in an inch.</note>
  *
  * Since: 1.6.0
  **/
 void
-hb_font_set_ptem (hb_font_t *font, float ptem)
+hb_font_set_ptem (hb_font_t *font,
+		  float      ptem)
 {
   if (hb_object_is_immutable (font))
     return;
@@ -1823,11 +2008,12 @@
 
 /**
  * hb_font_get_ptem:
- * @font: a font.
+ * @font: #hb_font_t to work upon
  *
- * Gets the "point size" of the font.  A value of 0 means unset.
+ * Fetches the "point size" of a font. Used in CoreText to
+ * implement optical sizing.
  *
- * Return value: Point size.
+ * Return value: Point size.  A value of zero means "not set."
  *
  * Since: 0.9.2
  **/
@@ -1842,26 +2028,20 @@
  * Variations
  */
 
-static void
-_hb_font_adopt_var_coords_normalized (hb_font_t *font,
-				      int *coords, /* 2.14 normalized */
-				      unsigned int coords_length)
-{
-  free (font->coords);
-
-  font->coords = coords;
-  font->num_coords = coords_length;
-}
-
 /**
  * hb_font_set_variations:
+ * @font: #hb_font_t to work upon
+ * @variations: (array length=variations_length): Array of variation settings to apply
+ * @variations_length: Number of variations to apply
+ *
+ * Applies a list of font-variation settings to a font.
  *
  * Since: 1.4.2
  */
 void
-hb_font_set_variations (hb_font_t *font,
+hb_font_set_variations (hb_font_t            *font,
 			const hb_variation_t *variations,
-			unsigned int variations_length)
+			unsigned int          variations_length)
 {
   if (hb_object_is_immutable (font))
     return;
@@ -1872,37 +2052,70 @@
     return;
   }
 
-  unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
+  const OT::fvar &fvar = *font->face->table.fvar;
+  auto axes = fvar.get_axes ();
+  const unsigned coords_length = axes.length;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  if (unlikely (coords_length && !normalized))
+  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;
+  }
 
-  hb_ot_var_normalize_variations (font->face,
-				  variations, variations_length,
-				  normalized, coords_length);
-  _hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
+  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_font_adopt_var_coords (font, normalized, design_coords, coords_length);
 }
 
 /**
  * hb_font_set_var_coords_design:
+ * @font: #hb_font_t to work upon
+ * @coords: (array length=coords_length): Array of variation coordinates to apply
+ * @coords_length: Number of coordinates to apply
+ *
+ * Applies a list of variation coordinates (in design-space units)
+ * to a font.
  *
  * Since: 1.4.2
  */
 void
-hb_font_set_var_coords_design (hb_font_t *font,
-			       const float *coords,
-			       unsigned int coords_length)
+hb_font_set_var_coords_design (hb_font_t    *font,
+			       const float  *coords,
+			       unsigned int  coords_length)
 {
   if (hb_object_is_immutable (font))
     return;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  if (unlikely (coords_length && !normalized))
+  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;
+  }
+
+  if (coords_length)
+    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_normalized (font, normalized, coords_length);
+  _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
 }
 
 /**
@@ -1923,40 +2136,70 @@
 
   unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
 
-  float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
   if (unlikely (coords_length && !coords))
     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);
-  free (coords);
+  hb_free (coords);
 }
 
 /**
  * hb_font_set_var_coords_normalized:
+ * @font: #hb_font_t to work upon
+ * @coords: (array length=coords_length): Array of variation coordinates to apply
+ * @coords_length: Number of coordinates to apply
+ *
+ * Applies a list of variation coordinates (in normalized units)
+ * to a font.
+ *
+ * <note>Note: Coordinates should be normalized to 2.14.</note>
  *
  * Since: 1.4.2
  */
 void
-hb_font_set_var_coords_normalized (hb_font_t *font,
-				   const int *coords, /* 2.14 normalized */
-				   unsigned int coords_length)
+hb_font_set_var_coords_normalized (hb_font_t    *font,
+				   const int    *coords, /* 2.14 normalized */
+				   unsigned int  coords_length)
 {
   if (hb_object_is_immutable (font))
     return;
 
-  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
-  if (unlikely (coords_length && !copy))
+  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;
+
+  if (unlikely (coords_length && !(copy && unmapped && design_coords)))
+  {
+    hb_free (copy);
+    hb_free (unmapped);
+    hb_free (design_coords);
     return;
+  }
 
   if (coords_length)
+  {
     memcpy (copy, coords, coords_length * sizeof (coords[0]));
+    memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
+  }
 
-  _hb_font_adopt_var_coords_normalized (font, copy, coords_length);
+  /* Best effort design coords simulation */
+  font->face->table.avar->unmap_coords (unmapped, coords_length);
+  for (unsigned int i = 0; i < coords_length; ++i)
+    design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]);
+  hb_free (unmapped);
+
+  _hb_font_adopt_var_coords (font, copy, design_coords, coords_length);
 }
 
 /**
  * hb_font_get_var_coords_normalized:
+ * @font: #hb_font_t to work upon
+ * @length: Number of coordinates retrieved
+ *
+ * Fetches the list of normalized variation coordinates currently
+ * set on a font.
  *
  * Return value is valid as long as variation coordinates of the font
  * are not modified.
@@ -1964,7 +2207,7 @@
  * Since: 1.4.2
  */
 const int *
-hb_font_get_var_coords_normalized (hb_font_t *font,
+hb_font_get_var_coords_normalized (hb_font_t    *font,
 				   unsigned int *length)
 {
   if (length)
@@ -1972,6 +2215,30 @@
 
   return font->coords;
 }
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_font_get_var_coords_design:
+ * @font: #hb_font_t to work upon
+ * @length: (out): number of coordinates
+ *
+ * Return value is valid as long as variation coordinates of the font
+ * are not modified.
+ *
+ * Return value: coordinates array
+ *
+ * Since: EXPERIMENTAL
+ */
+const float *
+hb_font_get_var_coords_design (hb_font_t *font,
+			       unsigned int *length)
+{
+  if (length)
+    *length = font->num_coords;
+
+  return font->design_coords;
+}
+#endif
 #endif
 
 #ifndef HB_DISABLE_DEPRECATED
@@ -2001,7 +2268,7 @@
 {
   typedef hb_trampoline_t<FuncType> trampoline_t;
 
-  trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
+  trampoline_t *trampoline = (trampoline_t *) hb_calloc (1, sizeof (trampoline_t));
 
   if (unlikely (!trampoline))
     return nullptr;
@@ -2030,29 +2297,29 @@
 
   if (closure->destroy)
     closure->destroy (closure->user_data);
-  free (closure);
+  hb_free (closure);
 }
 
 typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;
 
 static hb_bool_t
-hb_font_get_nominal_glyph_trampoline (hb_font_t *font,
-				      void *font_data,
-				      hb_codepoint_t unicode,
+hb_font_get_nominal_glyph_trampoline (hb_font_t      *font,
+				      void           *font_data,
+				      hb_codepoint_t  unicode,
 				      hb_codepoint_t *glyph,
-				      void *user_data)
+				      void           *user_data)
 {
   hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
   return trampoline->func (font, font_data, unicode, 0, glyph, trampoline->closure.user_data);
 }
 
 static hb_bool_t
-hb_font_get_variation_glyph_trampoline (hb_font_t *font,
-					void *font_data,
-					hb_codepoint_t unicode,
-					hb_codepoint_t variation_selector,
+hb_font_get_variation_glyph_trampoline (hb_font_t      *font,
+					void           *font_data,
+					hb_codepoint_t  unicode,
+					hb_codepoint_t  variation_selector,
 					hb_codepoint_t *glyph,
-					void *user_data)
+					void           *user_data)
 {
   hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
   return trampoline->func (font, font_data, unicode, variation_selector, glyph, trampoline->closure.user_data);
@@ -2060,10 +2327,10 @@
 
 /**
  * hb_font_funcs_set_glyph_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified): callback function.
- * @user_data: data to pass to @func.
- * @destroy: function to call when @user_data is not needed anymore.
+ * @ffuncs: The font-functions structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): callback function
+ * @user_data: data to pass to @func
+ * @destroy: (nullable): function to call when @user_data is not needed anymore
  *
  * Deprecated.  Use hb_font_funcs_set_nominal_glyph_func() and
  * hb_font_funcs_set_variation_glyph_func() instead.
@@ -2072,10 +2339,18 @@
  * Deprecated: 1.2.3
  **/
 void
-hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
-			      hb_font_get_glyph_func_t func,
-			      void *user_data, hb_destroy_func_t destroy)
+hb_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 /* May be NULL. */)
 {
+  if (hb_object_is_immutable (ffuncs))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+
   hb_font_get_glyph_trampoline_t *trampoline;
 
   trampoline = trampoline_create (func, user_data, destroy);
diff --git a/src/hb-font.h b/src/hb-font.h
index 01ff201..15dc126 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -33,10 +33,16 @@
 
 #include "hb-common.h"
 #include "hb-face.h"
+#include "hb-draw.h"
 
 HB_BEGIN_DECLS
 
-
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
 typedef struct hb_font_t hb_font_t;
 
 
@@ -44,6 +50,19 @@
  * hb_font_funcs_t
  */
 
+/**
+ * hb_font_funcs_t:
+ *
+ * Data type containing a set of virtual methods used for
+ * working on #hb_font_t font objects.
+ *
+ * HarfBuzz provides a lightweight default function for each of 
+ * the methods in #hb_font_funcs_t. 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.
+ *
+ **/
 typedef struct hb_font_funcs_t hb_font_funcs_t;
 
 HB_EXTERN hb_font_funcs_t *
@@ -80,12 +99,21 @@
 
 /* font and glyph extents */
 
-/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
-typedef struct hb_font_extents_t
-{
-  hb_position_t ascender; /* typographic ascender. */
-  hb_position_t descender; /* typographic descender. */
-  hb_position_t line_gap; /* suggested line spacing gap. */
+/**
+ * hb_font_extents_t:
+ * @ascender: The height of typographic ascenders.
+ * @descender: The depth of typographic descenders.
+ * @line_gap: The suggested line-spacing gap.
+ *
+ * Font-wide extent values, measured in font units.
+ *
+ * Note that typically @ascender is positive and @descender
+ * negative, in coordinate systems that grow up.
+ **/
+typedef struct hb_font_extents_t {
+  hb_position_t ascender;
+  hb_position_t descender;
+  hb_position_t line_gap;
   /*< private >*/
   hb_position_t reserved9;
   hb_position_t reserved8;
@@ -98,33 +126,130 @@
   hb_position_t reserved1;
 } hb_font_extents_t;
 
-/* Note that height is negative in coordinate systems that grow up. */
-typedef struct hb_glyph_extents_t
-{
-  hb_position_t x_bearing; /* left side of glyph from origin. */
-  hb_position_t y_bearing; /* top side of glyph from origin. */
-  hb_position_t width; /* distance from left to right side. */
-  hb_position_t height; /* distance from top to bottom side. */
+/**
+ * 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 */
 
+/**
+ * hb_font_get_font_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @extents: (out): The font extents retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the extents for a font.
+ *
+ **/
 typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
 						       hb_font_extents_t *extents,
 						       void *user_data);
+
+/**
+ * hb_font_get_font_h_extents_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the extents for a font, for horizontal-direction
+ * text segments. Extents must be returned in an #hb_glyph_extents output
+ * parameter.
+ * 
+ **/
 typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
+
+/**
+ * hb_font_get_font_v_extents_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the extents for a font, for vertical-direction
+ * text segments. Extents must be returned in an #hb_glyph_extents output
+ * parameter.
+ * 
+ **/
 typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
 
 
+/**
+ * hb_font_get_nominal_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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
+ *
+ **/
 typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
 						       hb_codepoint_t unicode,
 						       hb_codepoint_t *glyph,
 						       void *user_data);
+
+/**
+ * hb_font_get_variation_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The  variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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 #hb_codepoint_t output parameter.
+ * 
+ * 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,
 							 hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 							 hb_codepoint_t *glyph,
 							 void *user_data);
 
+
+/**
+ * hb_font_get_nominal_glyphs_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @glyph_stride: The stride between successive glyph IDs
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the nominal glyph IDs for a sequence of
+ * Unicode code points. Glyph IDs must be returned in a #hb_codepoint_t
+ * output parameter.
+ *
+ * Return value: the number of code points processed
+ * 
+ **/
 typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
 							   unsigned int count,
 							   const hb_codepoint_t *first_unicode,
@@ -133,13 +258,65 @@
 							   unsigned int glyph_stride,
 							   void *user_data);
 
-
+/**
+ * hb_font_get_glyph_advance_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advance for a specified glyph. The
+ * method must return an #hb_position_t.
+ * 
+ * Return value: The advance of @glyph within @font
+ *
+ **/
 typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
 							   hb_codepoint_t glyph,
 							   void *user_data);
+
+/**
+ * hb_font_get_glyph_h_advance_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advance for a specified glyph, in
+ * horizontal-direction text segments. Advances must be returned in
+ * an #hb_position_t output parameter.
+ * 
+ **/
 typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
+
+/**
+ * hb_font_get_glyph_v_advance_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advance for a specified glyph, in
+ * vertical-direction text segments. Advances must be returned in
+ * an #hb_position_t output parameter.
+ * 
+ **/
 typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
 
+/**
+ * hb_font_get_glyph_advances_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: The stride between successive advances
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advances for a sequence of glyphs.
+ * 
+ **/
 typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data,
 						   unsigned int count,
 						   const hb_codepoint_t *first_glyph,
@@ -147,36 +324,188 @@
 						   hb_position_t *first_advance,
 						   unsigned advance_stride,
 						   void *user_data);
+
+/**
+ * hb_font_get_glyph_h_advances_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advances for a sequence of glyphs, in
+ * horizontal-direction text segments.
+ * 
+ **/
 typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t;
+
+/**
+ * hb_font_get_glyph_v_advances_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the advances for a sequence of glyphs, in
+ * vertical-direction text segments.
+ * 
+ **/
 typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
 
+/**
+ * hb_font_get_glyph_origin_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @x: (out): The X coordinate of the origin
+ * @y: (out): The Y coordinate of the origin
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * origin for a glyph. Each coordinate must be returned in an #hb_position_t
+ * output parameter.
+ *
+ * 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,
 						      hb_codepoint_t glyph,
 						      hb_position_t *x, hb_position_t *y,
 						      void *user_data);
+
+/**
+ * hb_font_get_glyph_h_origin_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * origin for a glyph, for horizontal-direction text segments. Each
+ * coordinate must be returned in an #hb_position_t output parameter.
+ * 
+ **/
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
+
+/**
+ * hb_font_get_glyph_v_origin_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the (X,Y) coordinates (in font units) of the
+ * origin for a glyph, for vertical-direction text segments. Each coordinate
+ * must be returned in an #hb_position_t output parameter.
+ * 
+ **/
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
 
+/**
+ * hb_font_get_glyph_kerning_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @first_glyph: The glyph ID of the first glyph in the glyph pair
+ * @second_glyph: The glyph ID of the second glyph in the glyph pair
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
 typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
 							   hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
 							   void *user_data);
+/**
+ * hb_font_get_glyph_h_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
 typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
 
 
+/**
+ * hb_font_get_glyph_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @extents: (out): The #hb_glyph_extents_t retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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
+ * 
+ **/
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
 						       hb_codepoint_t glyph,
 						       hb_glyph_extents_t *extents,
 						       void *user_data);
+
+/**
+ * hb_font_get_glyph_contour_point_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @point_index: The contour-point index to query
+ * @x: (out): The X value retrieved for the contour point
+ * @y: (out): The Y value retrieved for the contour point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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 #hb_position_t output parameter.
+ * 
+ * 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,
 							     hb_codepoint_t glyph, unsigned int point_index,
 							     hb_position_t *x, hb_position_t *y,
 							     void *user_data);
 
 
+/**
+ * hb_font_get_glyph_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @name: (out) (array length=size): Name string retrieved for the glyph ID
+ * @size: Length of the glyph-name string retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * 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
+ *
+ **/
 typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
 						    hb_codepoint_t glyph,
 						    char *name, unsigned int size,
 						    void *user_data);
+
+/**
+ * hb_font_get_glyph_from_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @name: (array length=len): The name string to query
+ * @len: The length of the name queried
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the glyph ID that corresponds to a glyph-name
+ * string. 
+ * 
+ * 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,
 							 const char *name, int len, /* -1 means nul-terminated */
 							 hb_codepoint_t *glyph,
@@ -187,12 +516,12 @@
 
 /**
  * hb_font_funcs_set_font_h_extents_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_font_h_extents_func_t.
  *
  * Since: 1.1.2
  **/
@@ -203,12 +532,12 @@
 
 /**
  * hb_font_funcs_set_font_v_extents_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_font_v_extents_func_t.
  *
  * Since: 1.1.2
  **/
@@ -219,12 +548,12 @@
 
 /**
  * hb_font_funcs_set_nominal_glyph_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_nominal_glyph_func_t.
  *
  * Since: 1.2.3
  **/
@@ -235,12 +564,12 @@
 
 /**
  * hb_font_funcs_set_nominal_glyphs_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_nominal_glyphs_func_t.
  *
  * Since: 2.0.0
  **/
@@ -251,12 +580,12 @@
 
 /**
  * hb_font_funcs_set_variation_glyph_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_variation_glyph_func_t.
  *
  * Since: 1.2.3
  **/
@@ -267,12 +596,12 @@
 
 /**
  * hb_font_funcs_set_glyph_h_advance_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_h_advance_func_t.
  *
  * Since: 0.9.2
  **/
@@ -283,12 +612,12 @@
 
 /**
  * hb_font_funcs_set_glyph_v_advance_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_v_advance_func_t.
  *
  * Since: 0.9.2
  **/
@@ -299,12 +628,12 @@
 
 /**
  * hb_font_funcs_set_glyph_h_advances_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_h_advances_func_t.
  *
  * Since: 1.8.6
  **/
@@ -315,12 +644,12 @@
 
 /**
  * hb_font_funcs_set_glyph_v_advances_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_v_advances_func_t.
  *
  * Since: 1.8.6
  **/
@@ -331,12 +660,12 @@
 
 /**
  * hb_font_funcs_set_glyph_h_origin_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_h_origin_func_t.
  *
  * Since: 0.9.2
  **/
@@ -347,12 +676,12 @@
 
 /**
  * hb_font_funcs_set_glyph_v_origin_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_v_origin_func_t.
  *
  * Since: 0.9.2
  **/
@@ -363,12 +692,12 @@
 
 /**
  * hb_font_funcs_set_glyph_h_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_h_kerning_func_t.
  *
  * Since: 0.9.2
  **/
@@ -379,12 +708,12 @@
 
 /**
  * hb_font_funcs_set_glyph_extents_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_extents_func_t.
  *
  * Since: 0.9.2
  **/
@@ -395,12 +724,12 @@
 
 /**
  * hb_font_funcs_set_glyph_contour_point_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_contour_point_func_t.
  *
  * Since: 0.9.2
  **/
@@ -411,12 +740,12 @@
 
 /**
  * hb_font_funcs_set_glyph_name_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_name_func_t.
  *
  * Since: 0.9.2
  **/
@@ -427,12 +756,12 @@
 
 /**
  * hb_font_funcs_set_glyph_from_name_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @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_from_name_func_t.
  *
  * Since: 0.9.2
  **/
@@ -704,6 +1033,12 @@
 			       const float *coords,
 			       unsigned int coords_length);
 
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN const float *
+hb_font_get_var_coords_design (hb_font_t *font,
+			       unsigned int *length);
+#endif
+
 HB_EXTERN void
 hb_font_set_var_coords_normalized (hb_font_t *font,
 				   const int *coords, /* 2.14 normalized */
@@ -717,6 +1052,12 @@
 hb_font_set_var_named_instance (hb_font_t *font,
 				unsigned 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_END_DECLS
 
 #endif /* HB_FONT_H */
diff --git a/src/hb-font.hh b/src/hb-font.hh
index b1e8e64..1b7f445 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -120,6 +120,7 @@
   /* Font variation coordinates. */
   unsigned int num_coords;
   int *coords;
+  float *design_coords;
 
   hb_font_funcs_t   *klass;
   void              *user_data;
@@ -216,9 +217,10 @@
   }
 
   hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
-			       hb_codepoint_t *glyph)
+			       hb_codepoint_t *glyph,
+			       hb_codepoint_t not_found = 0)
   {
-    *glyph = 0;
+    *glyph = not_found;
     return klass->get.f.nominal_glyph (this, user_data,
 				       unicode, glyph,
 				       klass->user_data.nominal_glyph);
@@ -237,9 +239,10 @@
   }
 
   hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
-				 hb_codepoint_t *glyph)
+				 hb_codepoint_t *glyph,
+				 hb_codepoint_t not_found = 0)
   {
-    *glyph = 0;
+    *glyph = not_found;
     return klass->get.f.variation_glyph (this, user_data,
 					 unicode, variation_selector, glyph,
 					 klass->user_data.variation_glyph);
@@ -286,7 +289,7 @@
   }
 
   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
-			        hb_position_t *x, hb_position_t *y)
+				hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
     return klass->get.f.glyph_h_origin (this, user_data,
@@ -338,7 +341,7 @@
   }
 
   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
-					    hb_position_t *x, hb_position_t *y)
+				     hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
     return klass->get.f.glyph_contour_point (this, user_data,
@@ -617,9 +620,7 @@
   }
 
   hb_position_t em_mult (int16_t v, int64_t mult)
-  {
-    return (hb_position_t) ((v * mult) >> 16);
-  }
+  { 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)
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index e526bf4..97a2c82 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -48,8 +48,13 @@
  * @short_description: FreeType integration
  * @include: hb-ft.h
  *
- * Functions for using HarfBuzz with the FreeType library to provide face and
+ * Functions for using HarfBuzz with the FreeType library.
+ *
+ * HarfBuzz supports using FreeType to provide face and
  * font data.
+ *
+ * <note>Note that FreeType is not thread-safe, therefore these
+ * functions are not thread-safe either.</note>
  **/
 
 
@@ -79,17 +84,15 @@
   bool symbol; /* Whether selected cmap is symbol cmap. */
   bool unref; /* Whether to destroy ft_face when done. */
 
-  mutable hb_atomic_int_t cached_x_scale;
+  mutable int cached_x_scale;
   mutable hb_advance_cache_t advance_cache;
 };
 
 static hb_ft_font_t *
 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 {
-  hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
-
-  if (unlikely (!ft_font))
-    return nullptr;
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t));
+  if (unlikely (!ft_font)) return nullptr;
 
   ft_font->lock.init ();
   ft_font->ft_face = ft_face;
@@ -98,7 +101,7 @@
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_x_scale.set_relaxed (0);
+  ft_font->cached_x_scale = 0;
   ft_font->advance_cache.init ();
 
   return ft_font;
@@ -122,15 +125,18 @@
 
   ft_font->lock.fini ();
 
-  free (ft_font);
+  hb_free (ft_font);
 }
 
 /**
  * hb_ft_font_set_load_flags:
- * @font:
- * @load_flags:
+ * @font: #hb_font_t to work upon
+ * @load_flags: The FreeType load flags to set
  *
+ * Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
  *
+ * For more information, see 
+ * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
  * Since: 1.0.5
  **/
@@ -140,7 +146,7 @@
   if (hb_object_is_immutable (font))
     return;
 
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
@@ -150,17 +156,21 @@
 
 /**
  * hb_ft_font_get_load_flags:
- * @font:
+ * @font: #hb_font_t to work upon
  *
+ * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
  *
+ * For more information, see 
+ * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
- * Return value:
+ * Return value: FT_Load_Glyph flags found
+ *
  * Since: 1.0.5
  **/
 int
 hb_ft_font_get_load_flags (hb_font_t *font)
 {
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
     return 0;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -168,10 +178,21 @@
   return ft_font->load_flags;
 }
 
+/**
+ * hb_ft_font_get_face:
+ * @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
+ *
+ * Since: 0.9.2
+ **/
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
     return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -179,6 +200,47 @@
   return ft_font->ft_face;
 }
 
+/**
+ * hb_ft_font_lock_face:
+ * @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().
+ *
+ * Return value: (nullable): the FT_Face associated with @font or %NULL
+ * Since: 2.6.5
+ **/
+FT_Face
+hb_ft_font_lock_face (hb_font_t *font)
+{
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
+    return nullptr;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  ft_font->lock.lock ();
+
+  return ft_font->ft_face;
+}
+
+/**
+ * hb_ft_font_unlock_face:
+ * @font: #hb_font_t to work upon
+ *
+ * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
+ *
+ * Since: 2.6.5
+ **/
+void
+hb_ft_font_unlock_face (hb_font_t *font)
+{
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
+    return;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  ft_font->lock.unlock ();
+}
 
 
 static hb_bool_t
@@ -273,10 +335,10 @@
   int load_flags = ft_font->load_flags;
   int mult = font->x_scale < 0 ? -1 : +1;
 
-  if (font->x_scale != ft_font->cached_x_scale.get ())
+  if (font->x_scale != ft_font->cached_x_scale)
   {
     ft_font->advance_cache.clear ();
-    ft_font->cached_x_scale.set (font->x_scale);
+    ft_font->cached_x_scale = font->x_scale;
   }
 
   for (unsigned int i = 0; i < count; i++)
@@ -499,9 +561,7 @@
   return true;
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ft_funcs ();
-#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>
 {
@@ -529,21 +589,17 @@
 
     hb_font_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ft_funcs);
-#endif
+    hb_atexit (free_static_ft_funcs);
 
     return funcs;
   }
 } static_ft_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ft_funcs ()
 {
   static_ft_funcs.free_instance ();
 }
-#endif
 
 static hb_font_funcs_t *
 _hb_ft_get_font_funcs ()
@@ -556,9 +612,12 @@
 {
   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 
+  hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
+  if (unlikely (!ft_font)) return;
+
   hb_font_set_funcs (font,
 		     _hb_ft_get_font_funcs (),
-		     _hb_ft_font_create (ft_face, symbol, unref),
+		     ft_font,
 		     _hb_ft_font_destroy);
 }
 
@@ -577,30 +636,40 @@
   if (error)
     return nullptr;
 
-  buffer = (FT_Byte *) malloc (length);
+  buffer = (FT_Byte *) hb_malloc (length);
   if (!buffer)
     return nullptr;
 
   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
   if (error)
   {
-    free (buffer);
+    hb_free (buffer);
     return nullptr;
   }
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
-			 buffer, free);
+			 buffer, hb_free);
 }
 
 /**
  * hb_ft_face_create:
- * @ft_face: (destroy destroy) (scope notified):
- * @destroy:
+ * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
+ * @destroy: (nullable): A callback to call when the face object is not needed anymore
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * This variant of the function does not provide any life-cycle management.
  *
- * Return value: (transfer full):
+ * Most client programs should use hb_ft_face_create_referenced()
+ * (or, perhaps, hb_ft_face_create_cached()) instead. 
+ *
+ * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
+ * then it is the client program's responsibility to destroy @ft_face 
+ * after the #hb_face_t face object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -630,11 +699,20 @@
 
 /**
  * hb_ft_face_create_referenced:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * 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
+ * #hb_face_t face object remains alive. Also calls FT_Done_Face()
+ * when the #hb_face_t face object is destroyed.
  *
- * Return value: (transfer full):
+ * Use this version unless you know you have good reasons not to.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.38
  **/
 hb_face_t *
@@ -652,11 +730,21 @@
 
 /**
  * hb_ft_face_create_cached:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * 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
+ * #hb_face_t returned to them, and that #hb_face_t will be correctly
+ * reference counted.
  *
- * Return value: (transfer full):
+ * However, client programs are still responsible for destroying
+ * @ft_face after the last #hb_face_t face object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -674,15 +762,34 @@
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 }
 
-
 /**
  * hb_ft_font_create:
- * @ft_face: (destroy destroy) (scope notified):
- * @destroy:
+ * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
+ * @destroy: (nullable): A callback to call when the font object is not needed anymore
  *
+ * Creates an #hb_font_t font object from the specified FT_Face.
  *
+ * <note>Note: You must set the face size on @ft_face before calling
+ * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
+ * access `size` member of FT_Face unconditionally.</note>
  *
- * Return value: (transfer full):
+ * This variant of the function does not provide any life-cycle management.
+ *
+ * Most client programs should use hb_ft_font_create_referenced()
+ * instead. 
+ *
+ * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
+ * then it is the client program's responsibility to destroy @ft_face 
+ * after the #hb_font_t font object has been destroyed.
+ *
+ * HarfBuzz will use the @destroy callback on the #hb_font_t font object 
+ * if it is supplied when you use this function. However, even if @destroy
+ * is provided, it is the client program's responsibility to destroy @ft_face,
+ * and it is the client program's responsibility to ensure that @ft_face is
+ * destroyed only after the #hb_font_t font object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_font_t font object
+ *
  * Since: 0.9.2
  **/
 hb_font_t *
@@ -700,6 +807,16 @@
   return font;
 }
 
+/**
+ * hb_ft_font_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Refreshes the state of @font when the underlying FT_Face has changed.
+ * This function should be called after changing the size or
+ * variation-axis settings on the FT_Face.
+ *
+ * Since: 1.0.5
+ **/
 void
 hb_ft_font_changed (hb_font_t *font)
 {
@@ -707,6 +824,7 @@
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
   FT_Face ft_face = ft_font->ft_face;
 
   hb_font_set_scale (font,
@@ -718,12 +836,12 @@
 		    ft_face->size->metrics.y_ppem);
 #endif
 
-#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
   FT_MM_Var *mm_var = nullptr;
   if (!FT_Get_MM_Var (ft_face, &mm_var))
   {
-    FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
-    int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
+    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
+    int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
     if (coords && ft_coords)
     {
       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
@@ -742,12 +860,12 @@
 	  hb_font_set_var_coords_normalized (font, nullptr, 0);
       }
     }
-    free (coords);
-    free (ft_coords);
+    hb_free (coords);
+    hb_free (ft_coords);
 #ifdef HAVE_FT_DONE_MM_VAR
     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
 #else
-    free (mm_var);
+    hb_free (mm_var);
 #endif
   }
 #endif
@@ -755,11 +873,23 @@
 
 /**
  * hb_ft_font_create_referenced:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_font_t font object from the specified FT_Face.
  *
+ * <note>Note: You must set the face size on @ft_face before calling
+ * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
+ * and will access `size` member of FT_Face unconditionally.</note>
  *
- * Return value: (transfer full):
+ * This is the preferred variant of the hb_ft_font_create*
+ * function family, because it calls FT_Reference_Face() on @ft_face,
+ * ensuring that @ft_face remains alive as long as the resulting
+ * #hb_font_t font object remains alive.
+ *
+ * Use this version unless you know you have good reasons not to.
+ *
+ * Return value: (transfer full): the new #hb_font_t font object
+ *
  * Since: 0.9.38
  **/
 hb_font_t *
@@ -769,9 +899,7 @@
   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ft_library ();
-#endif
+static inline void free_static_ft_library ();
 
 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
 							     hb_ft_library_lazy_loader_t>
@@ -782,9 +910,7 @@
     if (FT_Init_FreeType (&l))
       return nullptr;
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ft_library);
-#endif
+    hb_atexit (free_static_ft_library);
 
     return l;
   }
@@ -798,13 +924,11 @@
   }
 } static_ft_library;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ft_library ()
 {
   static_ft_library.free_instance ();
 }
-#endif
 
 static FT_Library
 get_ft_library ()
@@ -818,6 +942,28 @@
   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 }
 
+/**
+ * hb_ft_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified
+ * #hb_font_t font object to use FreeType font functions.
+ *
+ * In particular, you can use this function to configure an
+ * existing #hb_face_t face object for use with FreeType font
+ * functions even if that #hb_face_t face object was initially
+ * 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()
+ * is preconfigured for FreeType font functions and does not
+ * require this function to be used.
+ *
+ * <note>Note: Internally, this function creates an FT_Face.
+* </note>
+ *
+ * Since: 1.0.5
+ **/
 void
 hb_ft_font_set_funcs (hb_font_t *font)
 {
@@ -857,18 +1003,18 @@
     FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
-#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
+#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 *) calloc (num_coords, sizeof (FT_Fixed));
+    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);
-      free (ft_coords);
+      hb_free (ft_coords);
     }
   }
 #endif
diff --git a/src/hb-ft.h b/src/hb-ft.h
index 94013ee..bf07115 100644
--- a/src/hb-ft.h
+++ b/src/hb-ft.h
@@ -110,6 +110,12 @@
 HB_EXTERN FT_Face
 hb_ft_font_get_face (hb_font_t *font);
 
+HB_EXTERN FT_Face
+hb_ft_font_lock_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_ft_font_unlock_face (hb_font_t *font);
+
 HB_EXTERN void
 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
 
diff --git a/src/hb-gdi.cc b/src/hb-gdi.cc
index f6306ef..8e7589b 100644
--- a/src/hb-gdi.cc
+++ b/src/hb-gdi.cc
@@ -28,6 +28,16 @@
 
 #include "hb-gdi.h"
 
+
+/**
+ * SECTION:hb-gdi
+ * @title: hb-gdi
+ * @short_description: GDI integration
+ * @include: hb-gdi.h
+ *
+ * Functions for using HarfBuzz with GDI fonts.
+ **/
+
 static hb_blob_t *
 _hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
@@ -40,16 +50,16 @@
   length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
   if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
 
-  buffer = (char *) malloc (length);
+  buffer = (char *) hb_malloc (length);
   if (unlikely (!buffer)) goto fail_with_releasedc;
   length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
   if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
   ReleaseDC (nullptr, hdc);
 
-  return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
+  return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free);
 
 fail_with_releasedc_and_free:
-  free (buffer);
+  hb_free (buffer);
 fail_with_releasedc:
   ReleaseDC (nullptr, hdc);
 fail:
@@ -60,6 +70,8 @@
  * hb_gdi_face_create:
  * @hfont: a HFONT object.
  *
+ * Constructs a new face object from the specified GDI HFONT.
+ *
  * Return value: #hb_face_t object corresponding to the given input
  *
  * Since: 2.6.0
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index db02b67..8ddc7eb 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -41,166 +41,46 @@
  * @short_description: GLib integration
  * @include: hb-glib.h
  *
- * Functions for using HarfBuzz with the GLib library to provide Unicode data.
+ * Functions for using HarfBuzz with the GLib library.
+ *
+ * HarfBuzz supports using GLib to provide Unicode data, by attaching
+ * GLib functions to the virtual methods in a #hb_unicode_funcs_t function
+ * structure.
  **/
 
 
-#if !GLIB_CHECK_VERSION(2,29,14)
-static const hb_script_t
-glib_script_to_script[] =
-{
-  HB_SCRIPT_COMMON,
-  HB_SCRIPT_INHERITED,
-  HB_SCRIPT_ARABIC,
-  HB_SCRIPT_ARMENIAN,
-  HB_SCRIPT_BENGALI,
-  HB_SCRIPT_BOPOMOFO,
-  HB_SCRIPT_CHEROKEE,
-  HB_SCRIPT_COPTIC,
-  HB_SCRIPT_CYRILLIC,
-  HB_SCRIPT_DESERET,
-  HB_SCRIPT_DEVANAGARI,
-  HB_SCRIPT_ETHIOPIC,
-  HB_SCRIPT_GEORGIAN,
-  HB_SCRIPT_GOTHIC,
-  HB_SCRIPT_GREEK,
-  HB_SCRIPT_GUJARATI,
-  HB_SCRIPT_GURMUKHI,
-  HB_SCRIPT_HAN,
-  HB_SCRIPT_HANGUL,
-  HB_SCRIPT_HEBREW,
-  HB_SCRIPT_HIRAGANA,
-  HB_SCRIPT_KANNADA,
-  HB_SCRIPT_KATAKANA,
-  HB_SCRIPT_KHMER,
-  HB_SCRIPT_LAO,
-  HB_SCRIPT_LATIN,
-  HB_SCRIPT_MALAYALAM,
-  HB_SCRIPT_MONGOLIAN,
-  HB_SCRIPT_MYANMAR,
-  HB_SCRIPT_OGHAM,
-  HB_SCRIPT_OLD_ITALIC,
-  HB_SCRIPT_ORIYA,
-  HB_SCRIPT_RUNIC,
-  HB_SCRIPT_SINHALA,
-  HB_SCRIPT_SYRIAC,
-  HB_SCRIPT_TAMIL,
-  HB_SCRIPT_TELUGU,
-  HB_SCRIPT_THAANA,
-  HB_SCRIPT_THAI,
-  HB_SCRIPT_TIBETAN,
-  HB_SCRIPT_CANADIAN_SYLLABICS,
-  HB_SCRIPT_YI,
-  HB_SCRIPT_TAGALOG,
-  HB_SCRIPT_HANUNOO,
-  HB_SCRIPT_BUHID,
-  HB_SCRIPT_TAGBANWA,
-
-  /* Unicode-4.0 additions */
-  HB_SCRIPT_BRAILLE,
-  HB_SCRIPT_CYPRIOT,
-  HB_SCRIPT_LIMBU,
-  HB_SCRIPT_OSMANYA,
-  HB_SCRIPT_SHAVIAN,
-  HB_SCRIPT_LINEAR_B,
-  HB_SCRIPT_TAI_LE,
-  HB_SCRIPT_UGARITIC,
-
-  /* Unicode-4.1 additions */
-  HB_SCRIPT_NEW_TAI_LUE,
-  HB_SCRIPT_BUGINESE,
-  HB_SCRIPT_GLAGOLITIC,
-  HB_SCRIPT_TIFINAGH,
-  HB_SCRIPT_SYLOTI_NAGRI,
-  HB_SCRIPT_OLD_PERSIAN,
-  HB_SCRIPT_KHAROSHTHI,
-
-  /* Unicode-5.0 additions */
-  HB_SCRIPT_UNKNOWN,
-  HB_SCRIPT_BALINESE,
-  HB_SCRIPT_CUNEIFORM,
-  HB_SCRIPT_PHOENICIAN,
-  HB_SCRIPT_PHAGS_PA,
-  HB_SCRIPT_NKO,
-
-  /* Unicode-5.1 additions */
-  HB_SCRIPT_KAYAH_LI,
-  HB_SCRIPT_LEPCHA,
-  HB_SCRIPT_REJANG,
-  HB_SCRIPT_SUNDANESE,
-  HB_SCRIPT_SAURASHTRA,
-  HB_SCRIPT_CHAM,
-  HB_SCRIPT_OL_CHIKI,
-  HB_SCRIPT_VAI,
-  HB_SCRIPT_CARIAN,
-  HB_SCRIPT_LYCIAN,
-  HB_SCRIPT_LYDIAN,
-
-  /* Unicode-5.2 additions */
-  HB_SCRIPT_AVESTAN,
-  HB_SCRIPT_BAMUM,
-  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
-  HB_SCRIPT_IMPERIAL_ARAMAIC,
-  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
-  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
-  HB_SCRIPT_JAVANESE,
-  HB_SCRIPT_KAITHI,
-  HB_SCRIPT_TAI_THAM,
-  HB_SCRIPT_LISU,
-  HB_SCRIPT_MEETEI_MAYEK,
-  HB_SCRIPT_OLD_SOUTH_ARABIAN,
-  HB_SCRIPT_OLD_TURKIC,
-  HB_SCRIPT_SAMARITAN,
-  HB_SCRIPT_TAI_VIET,
-
-  /* Unicode-6.0 additions */
-  HB_SCRIPT_BATAK,
-  HB_SCRIPT_BRAHMI,
-  HB_SCRIPT_MANDAIC,
-
-  /* Unicode-6.1 additions */
-  HB_SCRIPT_CHAKMA,
-  HB_SCRIPT_MEROITIC_CURSIVE,
-  HB_SCRIPT_MEROITIC_HIEROGLYPHS,
-  HB_SCRIPT_MIAO,
-  HB_SCRIPT_SHARADA,
-  HB_SCRIPT_SORA_SOMPENG,
-  HB_SCRIPT_TAKRI
-};
-#endif
-
+/**
+ * hb_glib_script_to_script:
+ * @script: The GUnicodeScript identifier to query
+ *
+ * Fetches the #hb_script_t script that corresponds to the
+ * specified GUnicodeScript identifier.
+ *
+ * Return value: the #hb_script_t script found
+ *
+ * Since: 0.9.38
+ **/
 hb_script_t
 hb_glib_script_to_script (GUnicodeScript script)
 {
-#if GLIB_CHECK_VERSION(2,29,14)
   return (hb_script_t) g_unicode_script_to_iso15924 (script);
-#else
-  if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script)))
-    return glib_script_to_script[script];
-
-  if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE))
-    return HB_SCRIPT_INVALID;
-
-  return HB_SCRIPT_UNKNOWN;
-#endif
 }
 
+/**
+ * hb_glib_script_from_script:
+ * @script: The #hb_script_t to query
+ *
+ * Fetches the GUnicodeScript identifier that corresponds to the
+ * specified #hb_script_t script.
+ *
+ * Return value: the GUnicodeScript identifier found
+ *
+ * Since: 0.9.38
+ **/
 GUnicodeScript
 hb_glib_script_from_script (hb_script_t script)
 {
-#if GLIB_CHECK_VERSION(2,29,14)
   return g_unicode_script_from_iso15924 (script);
-#else
-  unsigned int count = ARRAY_LENGTH (glib_script_to_script);
-  for (unsigned int i = 0; i < count; i++)
-    if (glib_script_to_script[i] == script)
-      return (GUnicodeScript) i;
-
-  if (unlikely (script == HB_SCRIPT_INVALID))
-    return G_UNICODE_SCRIPT_INVALID_CODE;
-
-  return G_UNICODE_SCRIPT_UNKNOWN;
-#endif
 }
 
 
@@ -338,9 +218,7 @@
 }
 
 
-#if HB_USE_ATEXIT
-static void free_static_glib_funcs ();
-#endif
+static inline void free_static_glib_funcs ();
 
 static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
 {
@@ -357,22 +235,28 @@
 
     hb_unicode_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_glib_funcs);
-#endif
+    hb_atexit (free_static_glib_funcs);
 
     return funcs;
   }
 } static_glib_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_glib_funcs ()
 {
   static_glib_funcs.free_instance ();
 }
-#endif
 
+/**
+ * hb_glib_get_unicode_funcs:
+ *
+ * Fetches a Unicode-functions structure that is populated
+ * with the appropriate GLib function for each method.
+ *
+ * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure
+ *
+ * Since: 0.9.38
+ **/
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs ()
 {
@@ -391,6 +275,12 @@
 
 /**
  * hb_glib_blob_create:
+ * @gbytes: the GBytes structure to work upon
+ *
+ * Creates an #hb_blob_t blob from the specified
+ * GBytes data structure.
+ *
+ * Return value: (transfer full): the new #hb_blob_t blob object
  *
  * Since: 0.9.38
  **/
diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl
index 17f1ade..87a11dd 100644
--- a/src/hb-gobject-enums.cc.tmpl
+++ b/src/hb-gobject-enums.cc.tmpl
@@ -1,6 +1,6 @@
 /*** BEGIN file-header ***/
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright (C) 2011  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -43,7 +43,7 @@
 /*** END file-header ***/
 
 /*** BEGIN file-production ***/
-/* enumerations from "@filename@" */
+/* enumerations from "@basename@" */
 /*** END file-production ***/
 
 /*** BEGIN file-tail ***/
diff --git a/src/hb-gobject-enums.h.tmpl b/src/hb-gobject-enums.h.tmpl
index 7ef9dfc..a846786 100644
--- a/src/hb-gobject-enums.h.tmpl
+++ b/src/hb-gobject-enums.h.tmpl
@@ -1,6 +1,6 @@
 /*** BEGIN file-header ***/
 /*
- * Copyright © 2013  Google, Inc.
+ * Copyright (C) 2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -25,7 +25,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_GOBJECT_H_IN
+#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-gobject.h> instead."
 #endif
 
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 7f4922e..540b11f 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -32,11 +32,20 @@
 /**
  * SECTION:hb-gobject
  * @title: hb-gobject
- * @short_description: GObject integration
+ * @short_description: GObject integration support
  * @include: hb-gobject.h
  *
- * Functions for using HarfBuzz with the GObject library to provide
+ * Support for using HarfBuzz with the GObject library to provide
  * type data.
+ *
+ * The types and functions listed here are solely a linkage between
+ * HarfBuzz's public data types and the GTypes used by the GObject framework.
+ * HarfBuzz uses GObject introspection to generate its Python bindings 
+ * (and potentially other language bindings); client programs should never need
+ * to access the GObject-integration mechanics.
+ *
+ * For client programs using the GNOME and GTK software stack, please see the
+ * GLib and FreeType integration pages.
  **/
 
 
@@ -71,12 +80,12 @@
 #define HB_DEFINE_VALUE_TYPE(name) \
 	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
 	{ \
-	  hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
+	  hb_##name##_t *c = (hb_##name##_t *) hb_calloc (1, sizeof (hb_##name##_t)); \
 	  if (unlikely (!c)) return nullptr; \
 	  *c = *l; \
 	  return c; \
 	} \
-	static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
+	static void _hb_##name##_destroy (hb_##name##_t *l) { hb_free (l); } \
 	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
 
 HB_DEFINE_OBJECT_TYPE (buffer)
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
index 800beed..63467f8 100644
--- a/src/hb-gobject-structs.h
+++ b/src/hb-gobject-structs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright (C) 2011  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_GOBJECT_H_IN
+#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-gobject.h> instead."
 #endif
 
@@ -40,47 +40,22 @@
 
 /* Object types */
 
-/**
- * hb_gobject_blob_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_blob_get_type (void);
 #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
 
-/**
- * hb_gobject_buffer_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_buffer_get_type (void);
 #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
 
-/**
- * hb_gobject_face_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_face_get_type (void);
 #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
 
-/**
- * hb_gobject_font_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_font_get_type (void);
 #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
 
-/**
- * hb_gobject_font_funcs_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_font_funcs_get_type (void);
 #define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
@@ -97,11 +72,6 @@
 hb_gobject_shape_plan_get_type (void);
 #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
 
-/**
- * hb_gobject_unicode_funcs_get_type:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN GType
 hb_gobject_unicode_funcs_get_type (void);
 #define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
diff --git a/src/hb-gobject.h b/src/hb-gobject.h
index ea1bd25..8891aa0 100644
--- a/src/hb-gobject.h
+++ b/src/hb-gobject.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright (C) 2011  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index f0f2f8c..209207f 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -45,7 +45,11 @@
  * @short_description: Graphite2 integration
  * @include: hb-graphite2.h
  *
- * Functions for using HarfBuzz with the Graphite2 fonts.
+ * Functions for using HarfBuzz with fonts that include Graphite features.
+ * 
+ * For Graphite features to work, you must be sure that HarfBuzz was compiled
+ * with the `graphite2` shaping engine enabled. Currently, the default is to
+ * not enable `graphite2` shaping.
  **/
 
 
@@ -84,7 +88,7 @@
   {
     blob = face_data->face->reference_table (tag);
 
-    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
+    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) hb_calloc (1, sizeof (hb_graphite2_tablelist_t));
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
       return nullptr;
@@ -119,15 +123,16 @@
   }
   hb_blob_destroy (silf_blob);
 
-  hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
+  hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) hb_calloc (1, sizeof (hb_graphite2_face_data_t));
   if (unlikely (!data))
     return nullptr;
 
   data->face = face;
-  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
+  const gr_face_ops ops = {sizeof(gr_face_ops), &hb_graphite2_get_table, NULL};
+  data->grface = gr_make_face_with_ops (data, &ops, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
-    free (data);
+    hb_free (data);
     return nullptr;
   }
 
@@ -144,15 +149,23 @@
     hb_graphite2_tablelist_t *old = tlist;
     hb_blob_destroy (tlist->blob);
     tlist = tlist->next;
-    free (old);
+    hb_free (old);
   }
 
   gr_face_destroy (data->grface);
 
-  free (data);
+  hb_free (data);
 }
 
-/*
+/**
+ * hb_graphite2_face_get_gr_face:
+ * @face: @hb_face_t to query
+ *
+ * Fetches the Graphite2 gr_face corresponding to the specified
+ * #hb_face_t face object.
+ *
+ * Return value: the gr_face found
+ *
  * Since: 0.9.10
  */
 gr_face *
@@ -183,6 +196,11 @@
 #ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_graphite2_font_get_gr_font:
+ * @font: An #hb_font_t
+ *
+ * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ *
+ * Return value: (nullable): Graphite2 font associated with @font.
  *
  * Since: 0.9.10
  * Deprecated: 1.4.2
@@ -272,7 +290,7 @@
     return true;
   }
 
-  buffer->ensure (glyph_count);
+  (void) buffer->ensure (glyph_count);
   scratch = buffer->get_scratch_buffer (&scratch_size);
   while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
 	  DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
@@ -376,7 +394,7 @@
   buffer->len = glyph_count;
 
   /* Positioning. */
-  unsigned int currclus = (unsigned int) -1;
+  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))
diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h
index 1720191..f299da9 100644
--- a/src/hb-graphite2.h
+++ b/src/hb-graphite2.h
@@ -32,7 +32,15 @@
 
 HB_BEGIN_DECLS
 
-
+/**
+ * HB_GRAPHITE2_TAG_SILF:
+ *
+ * The #hb_tag_t tag for the `Silf` table, which holds Graphite
+ * features. 
+ *
+ * For more information, see http://graphite.sil.org/
+ *
+ **/
 #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
 
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 985ff02..e46401f 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -54,7 +54,21 @@
  * @short_description: ICU integration
  * @include: hb-icu.h
  *
- * Functions for using HarfBuzz with the ICU library to provide Unicode data.
+ * Functions for using HarfBuzz with the International Components for Unicode
+ * (ICU) library. HarfBuzz supports using ICU to provide Unicode data, by attaching
+ * ICU functions to the virtual methods in a #hb_unicode_funcs_t function
+ * structure.
+ **/
+
+/**
+ * hb_icu_script_to_script:
+ * @script: The UScriptCode identifier to query
+ *
+ * Fetches the #hb_script_t script that corresponds to the
+ * specified UScriptCode identifier.
+ *
+ * Return value: the #hb_script_t script found
+ *
  **/
 
 hb_script_t
@@ -66,6 +80,16 @@
   return hb_script_from_string (uscript_getShortName (script), -1);
 }
 
+/**
+ * hb_icu_script_from_script:
+ * @script: The #hb_script_t script to query
+ *
+ * Fetches the UScriptCode identifier that corresponds to the
+ * specified #hb_script_t script.
+ *
+ * Return value: the UScriptCode identifier found
+ *
+ **/
 UScriptCode
 hb_icu_script_from_script (hb_script_t script)
 {
@@ -168,45 +192,13 @@
 			hb_codepoint_t      a,
 			hb_codepoint_t      b,
 			hb_codepoint_t     *ab,
-			void               *user_data HB_UNUSED)
+			void               *user_data)
 {
-#if U_ICU_VERSION_MAJOR_NUM >= 49
-  {
-    const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
-    UChar32 ret = unorm2_composePair (normalizer, a, b);
-    if (ret < 0) return false;
-    *ab = ret;
-    return true;
-  }
-#endif
-
-  /* We don't ifdef-out the fallback code such that compiler always
-   * sees it and makes sure it's compilable. */
-
-  UChar utf16[4], normalized[5];
-  unsigned int len;
-  hb_bool_t ret, err;
-  UErrorCode icu_err;
-
-  len = 0;
-  err = false;
-  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
-  if (err) return false;
-  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
-  if (err) return false;
-
-  icu_err = U_ZERO_ERROR;
-  len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
-  if (U_FAILURE (icu_err))
-    return false;
-  if (u_countChar32 (normalized, len) == 1) {
-    U16_GET_UNSAFE (normalized, 0, *ab);
-    ret = true;
-  } else {
-    ret = false;
-  }
-
-  return ret;
+  const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
+  UChar32 ret = unorm2_composePair (normalizer, a, b);
+  if (ret < 0) return false;
+  *ab = ret;
+  return true;
 }
 
 static hb_bool_t
@@ -214,114 +206,43 @@
 			  hb_codepoint_t      ab,
 			  hb_codepoint_t     *a,
 			  hb_codepoint_t     *b,
-			  void               *user_data HB_UNUSED)
+			  void               *user_data)
 {
-#if U_ICU_VERSION_MAJOR_NUM >= 49
+  const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
+  UChar decomposed[4];
+  int len;
+  UErrorCode icu_err = U_ZERO_ERROR;
+  len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
+				    ARRAY_LENGTH (decomposed), &icu_err);
+  if (U_FAILURE (icu_err) || len < 0) return false;
+
+  len = u_countChar32 (decomposed, len);
+  if (len == 1)
   {
-    const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
-    UChar decomposed[4];
-    int len;
-    UErrorCode icu_err = U_ZERO_ERROR;
-    len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
-				      ARRAY_LENGTH (decomposed), &icu_err);
-    if (U_FAILURE (icu_err) || len < 0) return false;
-
-    len = u_countChar32 (decomposed, len);
-    if (len == 1) {
-      U16_GET_UNSAFE (decomposed, 0, *a);
-      *b = 0;
-      return *a != ab;
-    } else if (len == 2) {
-      len = 0;
-      U16_NEXT_UNSAFE (decomposed, len, *a);
-      U16_NEXT_UNSAFE (decomposed, len, *b);
-    }
-    return true;
-  }
-#endif
-
-  /* We don't ifdef-out the fallback code such that compiler always
-   * sees it and makes sure it's compilable. */
-
-  UChar utf16[2], normalized[2 * 19/*HB_UNICODE_MAX_DECOMPOSITION_LEN*/ + 1];
-  unsigned int len;
-  hb_bool_t ret, err;
-  UErrorCode icu_err;
-
-  /* This function is a monster! Maybe it wasn't a good idea adding a
-   * pairwise decompose API... */
-  /* Watchout for the dragons.  Err, watchout for macros changing len. */
-
-  len = 0;
-  err = false;
-  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
-  if (err) return false;
-
-  icu_err = U_ZERO_ERROR;
-  len = unorm2_normalize (unorm2_getNFDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
-  if (U_FAILURE (icu_err))
-    return false;
-
-  len = u_countChar32 (normalized, len);
-
-  if (len == 1) {
-    U16_GET_UNSAFE (normalized, 0, *a);
+    U16_GET_UNSAFE (decomposed, 0, *a);
     *b = 0;
-    ret = *a != ab;
-  } else if (len == 2) {
-    len = 0;
-    U16_NEXT_UNSAFE (normalized, len, *a);
-    U16_NEXT_UNSAFE (normalized, len, *b);
-
-    /* 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 :-(. */
-    UChar recomposed[20];
-    icu_err = U_ZERO_ERROR;
-    unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
-    if (U_FAILURE (icu_err))
-      return false;
-    hb_codepoint_t c;
-    U16_GET_UNSAFE (recomposed, 0, c);
-    if (c != *a && c != ab) {
-      *a = c;
-      *b = 0;
-    }
-    ret = true;
-  } else {
-    /* If decomposed to more than two characters, take the last one,
-     * and recompose the rest to get the first component. */
-    U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
-    UChar recomposed[18 * 2];
-    icu_err = U_ZERO_ERROR;
-    len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
-    if (U_FAILURE (icu_err))
-      return false;
-    /* We expect that recomposed has exactly one character now. */
-    if (unlikely (u_countChar32 (recomposed, len) != 1))
-      return false;
-    U16_GET_UNSAFE (recomposed, 0, *a);
-    ret = true;
+    return *a != ab;
   }
-
-  return ret;
+  else if (len == 2)
+  {
+    len = 0;
+    U16_NEXT_UNSAFE (decomposed, len, *a);
+    U16_NEXT_UNSAFE (decomposed, len, *b);
+  }
+  return true;
 }
 
 
-#if HB_USE_ATEXIT
-static void free_static_icu_funcs ();
-#endif
+static inline void free_static_icu_funcs ();
 
 static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
 {
   static hb_unicode_funcs_t *create ()
   {
     void *user_data = nullptr;
-#if U_ICU_VERSION_MAJOR_NUM >= 49
     UErrorCode icu_err = U_ZERO_ERROR;
     user_data = (void *) unorm2_getNFCInstance (&icu_err);
     assert (user_data);
-#endif
 
     hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
 
@@ -334,22 +255,28 @@
 
     hb_unicode_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_icu_funcs);
-#endif
+    hb_atexit (free_static_icu_funcs);
 
     return funcs;
   }
 } static_icu_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_icu_funcs ()
 {
   static_icu_funcs.free_instance ();
 }
-#endif
 
+/**
+ * hb_icu_get_unicode_funcs:
+ *
+ * Fetches a Unicode-functions structure that is populated
+ * with the appropriate ICU function for each method.
+ *
+ * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure
+ *
+ * Since: 0.9.38
+ **/
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs ()
 {
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index 981c5c2..87b8ed8 100644
--- a/src/hb-iter.hh
+++ b/src/hb-iter.hh
@@ -46,7 +46,7 @@
  * TODO Document more.
  *
  * If iterator implementation implements operator!=, then can be
- * used in range-based for loop.  That comes free if the iterator
+ * 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
@@ -162,7 +162,7 @@
 {
   template <typename T> hb_iter_type<T>
   operator () (T&& c) const
-  { return hb_deref (hb_forward<T> (c)).iter (); }
+  { return hb_deref (std::forward<T> (c)).iter (); }
 
   /* Specialization for C arrays. */
 
@@ -353,7 +353,7 @@
 template <typename Lhs, typename Rhs,
 	  hb_requires (hb_is_iterator (Lhs))>
 static inline auto
-operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
+operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (std::forward<Rhs> (rhs) (std::forward<Lhs> (lhs)))
 
 /* hb_map(), hb_filter(), hb_reduce() */
 
@@ -674,8 +674,8 @@
   template <typename S2 = S>
   auto
   inc (hb_type_identity<S2> s, hb_priority<1>)
-    -> hb_void_t<decltype (hb_invoke (hb_forward<S2> (s), hb_declval<T&> ()))>
-  { v = hb_invoke (hb_forward<S2> (s), v); }
+    -> hb_void_t<decltype (hb_invoke (std::forward<S2> (s), hb_declval<T&> ()))>
+  { v = hb_invoke (std::forward<S2> (s), v); }
 
   void
   inc (S s, hb_priority<0>)
@@ -874,7 +874,7 @@
 		    Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+      if (!hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
 	return false;
     return true;
   }
@@ -891,7 +891,7 @@
 		    Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+      if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
 	return true;
     return false;
   }
@@ -908,7 +908,7 @@
 		    Proj&& f = hb_identity) const
   {
     for (auto it = hb_iter (c); it; ++it)
-      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+      if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it)))
 	return false;
     return true;
   }
@@ -922,7 +922,7 @@
 template <typename C, typename V,
 	  hb_requires (hb_is_iterable (C))>
 inline void
-hb_fill (C& c, const V &v)
+hb_fill (C&& c, const V &v)
 {
   for (auto i = hb_iter (c); i; i++)
     *i = v;
diff --git a/src/hb-kern.hh b/src/hb-kern.hh
index 99d533c..3f952fe 100644
--- a/src/hb-kern.hh
+++ b/src/hb-kern.hh
@@ -52,8 +52,7 @@
     OT::hb_ot_apply_context_t c (1, font, buffer);
     c.set_lookup_mask (kern_mask);
     c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
-    OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
-    skippy_iter.init (&c);
+    auto &skippy_iter = c.iter_input;
 
     bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
     unsigned int count = buffer->len;
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 15535d7..010c257 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -41,22 +41,6 @@
  * Casts
  */
 
-/* Cast to struct T, reference to reference */
-template<typename Type, typename TObject>
-static inline const Type& CastR(const TObject &X)
-{ return reinterpret_cast<const Type&> (X); }
-template<typename Type, typename TObject>
-static inline Type& CastR(TObject &X)
-{ return reinterpret_cast<Type&> (X); }
-
-/* Cast to struct T, pointer to pointer */
-template<typename Type, typename TObject>
-static inline const Type* CastP(const TObject *X)
-{ return reinterpret_cast<const Type*> (X); }
-template<typename Type, typename TObject>
-static inline Type* CastP(TObject *X)
-{ return reinterpret_cast<Type*> (X); }
-
 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
  * location pointed to by P plus Ofs bytes. */
 template<typename Type>
@@ -70,7 +54,7 @@
 {
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
-  return * reinterpret_cast<Type*> ((char *) P + offset);
+  return * reinterpret_cast<const Type*> ((const char *) P + offset);
 #pragma GCC diagnostic pop
 }
 template<typename Type>
@@ -96,6 +80,11 @@
  * Size checking
  */
 
+/* Size signifying variable-sized array */
+#ifndef HB_VAR_ARRAY
+#define HB_VAR_ARRAY 1
+#endif
+
 /* Check _assertion in a method environment */
 #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
   void _instance_assertion_on_line_##_line () const \
@@ -135,7 +124,7 @@
 
 #define DEFINE_SIZE_ARRAY(size, array) \
   DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + HB_VAR_ARRAY * sizeof ((array)[0])) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \
   static constexpr unsigned null_size = (size); \
   static constexpr unsigned min_size = (size)
 
@@ -250,17 +239,17 @@
   static Returned* convert (Stored *p) { return p; }
 
   /* By default null/init/fini the object. */
-  static const Stored* get_null () { return &Null(Stored); }
+  static const Stored* get_null () { return &Null (Stored); }
   static Stored *create (Data *data)
   {
-    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
     if (likely (p))
       p->init (data);
     return p;
   }
   static Stored *create ()
   {
-    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
     if (likely (p))
       p->init ();
     return p;
@@ -268,7 +257,7 @@
   static void destroy (Stored *p)
   {
     p->fini ();
-    free (p);
+    hb_free (p);
   }
 
 //  private:
diff --git a/src/hb-map.cc b/src/hb-map.cc
index a2c770c..9f1ac42 100644
--- a/src/hb-map.cc
+++ b/src/hb-map.cc
@@ -42,7 +42,9 @@
 /**
  * hb_map_create: (Xconstructor)
  *
- * Return value: (transfer full):
+ * Creates a new, initially empty map.
+ *
+ * Return value: (transfer full): The new #hb_map_t
  *
  * Since: 1.7.7
  **/
@@ -62,21 +64,25 @@
 /**
  * hb_map_get_empty:
  *
- * Return value: (transfer full):
+ * Fetches the singleton empty #hb_map_t.
+ *
+ * Return value: (transfer full): The empty #hb_map_t
  *
  * Since: 1.7.7
  **/
 hb_map_t *
 hb_map_get_empty ()
 {
-  return const_cast<hb_map_t *> (&Null(hb_map_t));
+  return const_cast<hb_map_t *> (&Null (hb_map_t));
 }
 
 /**
  * hb_map_reference: (skip)
- * @map: a map.
+ * @map: A map
  *
- * Return value: (transfer full):
+ * Increases the reference count on a map.
+ *
+ * Return value: (transfer full): The map
  *
  * Since: 1.7.7
  **/
@@ -88,7 +94,11 @@
 
 /**
  * hb_map_destroy: (skip)
- * @map: a map.
+ * @map: A map
+ *
+ * Decreases the reference count on a map. When
+ * the reference count reaches zero, the map is
+ * destroyed, freeing all memory.
  *
  * Since: 1.7.7
  **/
@@ -99,18 +109,20 @@
 
   map->fini_shallow ();
 
-  free (map);
+  hb_free (map);
 }
 
 /**
  * hb_map_set_user_data: (skip)
- * @map: a map.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @map: A map
+ * @key: The user-data key to set
+ * @data: A pointer to the user data to set
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
  *
- * Return value:
+ * Attaches a user-data key/data pair to the specified map.
+ *
+ * Return value: %true if success, %false otherwise
  *
  * Since: 1.7.7
  **/
@@ -126,10 +138,13 @@
 
 /**
  * hb_map_get_user_data: (skip)
- * @map: a map.
- * @key:
+ * @map: A map
+ * @key: The user-data key to query
  *
- * Return value: (transfer none):
+ * Fetches the user data associated with the specified key,
+ * attached to the specified map.
+ *
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 1.7.7
  **/
@@ -143,11 +158,11 @@
 
 /**
  * hb_map_allocation_successful:
- * @map: a map.
+ * @map: A map
  *
+ * Tests whether memory allocation for a set was successful.
  *
- *
- * Return value:
+ * Return value: %true if allocation succeeded, %false otherwise
  *
  * Since: 1.7.7
  **/
@@ -160,11 +175,11 @@
 
 /**
  * hb_map_set:
- * @map: a map.
- * @key:
- * @value:
+ * @map: A map
+ * @key: The key to store in the map
+ * @value: The value to store for @key
  *
- *
+ * Stores @key:@value in the map.
  *
  * Since: 1.7.7
  **/
@@ -173,15 +188,16 @@
 	    hb_codepoint_t  key,
 	    hb_codepoint_t  value)
 {
+  /* Immutable-safe. */
   map->set (key, value);
 }
 
 /**
  * hb_map_get:
- * @map: a map.
- * @key:
+ * @map: A map
+ * @key: The key to query
  *
- *
+ * Fetches the value stored for @key in @map.
  *
  * Since: 1.7.7
  **/
@@ -194,10 +210,10 @@
 
 /**
  * hb_map_del:
- * @map: a map.
- * @key:
+ * @map: A map
+ * @key: The key to delete
  *
- *
+ * Removes @key and its stored value from @map.
  *
  * Since: 1.7.7
  **/
@@ -205,15 +221,18 @@
 hb_map_del (hb_map_t       *map,
 	    hb_codepoint_t  key)
 {
+  /* Immutable-safe. */
   map->del (key);
 }
 
 /**
  * hb_map_has:
- * @map: a map.
- * @key:
+ * @map: A map
+ * @key: The key to query
  *
+ * Tests whether @key is an element of @map.
  *
+ * Return value: %true if @key is found in @map, %false otherwise
  *
  * Since: 1.7.7
  **/
@@ -227,9 +246,9 @@
 
 /**
  * hb_map_clear:
- * @map: a map.
+ * @map: A map
  *
- *
+ * Clears out the contents of @map.
  *
  * Since: 1.7.7
  **/
@@ -241,9 +260,11 @@
 
 /**
  * hb_map_is_empty:
- * @map: a map.
+ * @map: A map
  *
+ * Tests whether @map is empty (contains no elements).
  *
+ * Return value: %true if @map is empty
  *
  * Since: 1.7.7
  **/
@@ -255,9 +276,11 @@
 
 /**
  * hb_map_get_population:
- * @map: a map.
+ * @map: A map
  *
+ * Returns the number of key-value pairs in the map.
  *
+ * Return value: The population of @map
  *
  * Since: 1.7.7
  **/
diff --git a/src/hb-map.h b/src/hb-map.h
index b77843c..6a45a7b 100644
--- a/src/hb-map.h
+++ b/src/hb-map.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,11 +36,21 @@
 HB_BEGIN_DECLS
 
 
-/*
+/**
+ * HB_MAP_VALUE_INVALID:
+ *
+ * Unset #hb_map_t value.
+ *
  * Since: 1.7.7
  */
 #define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
 
+/**
+ * hb_map_t:
+ *
+ * Data type for holding integer-to-integer hash maps.
+ *
+ **/
 typedef struct hb_map_t hb_map_t;
 
 
diff --git a/src/hb-map.hh b/src/hb-map.hh
index 8c8db4d..bb4a0eb 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -35,16 +35,35 @@
  */
 
 template <typename K, typename V,
-	  K kINVALID = hb_is_pointer (K) ? 0 : hb_is_signed (K) ? hb_int_min (K) : (K) -1,
-	  V vINVALID = hb_is_pointer (V) ? 0 : hb_is_signed (V) ? hb_int_min (V) : (V) -1>
+	  K kINVALID = hb_is_pointer (K) ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1,
+	  V vINVALID = hb_is_pointer (V) ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1>
 struct hb_hashmap_t
 {
-  HB_DELETE_COPY_ASSIGN (hb_hashmap_t);
+  static constexpr K INVALID_KEY   = kINVALID;
+  static constexpr V INVALID_VALUE = vINVALID;
+
   hb_hashmap_t ()  { init (); }
   ~hb_hashmap_t () { fini (); }
 
-  static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
-  static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
+  hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { 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= (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 ()
+  {
+    for (auto&& item : lst)
+      set (item.first, item.second);
+  }
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
+  {
+    hb_copy (o, *this);
+  }
+
+  static_assert (std::is_integral<K>::value || hb_is_pointer (K), "");
+  static_assert (std::is_integral<V>::value || hb_is_pointer (V), "");
 
   struct item_t
   {
@@ -54,7 +73,7 @@
 
     void clear () { key = kINVALID; value = vINVALID; hash = 0; }
 
-    bool operator == (K o) { return hb_deref (key) == hb_deref (o); }
+    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    { return key == kINVALID; }
     bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
@@ -70,6 +89,16 @@
   unsigned int prime;
   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);
+    hb_swap (a.occupancy, b.occupancy);
+    hb_swap (a.mask, b.mask);
+    hb_swap (a.prime, b.prime);
+    hb_swap (a.items, b.items);
+  }
   void init_shallow ()
   {
     successful = true;
@@ -85,7 +114,7 @@
   }
   void fini_shallow ()
   {
-    free (items);
+    hb_free (items);
     items = nullptr;
     population = occupancy = 0;
   }
@@ -97,8 +126,6 @@
 
   void reset ()
   {
-    if (unlikely (hb_object_is_immutable (this)))
-      return;
     successful = true;
     clear ();
   }
@@ -111,15 +138,14 @@
 
     unsigned int power = hb_bit_storage (population * 2 + 8);
     unsigned int new_size = 1u << power;
-    item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
+    item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
     if (unlikely (!new_items))
     {
       successful = false;
       return false;
     }
-    + hb_iter (new_items, new_size)
-    | hb_apply (&item_t::clear)
-    ;
+    for (auto &_ : hb_iter (new_items, new_size))
+      _.clear ();
 
     unsigned int old_size = mask + 1;
     item_t *old_items = items;
@@ -135,18 +161,16 @@
       for (unsigned int i = 0; i < old_size; i++)
 	if (old_items[i].is_real ())
 	  set_with_hash (old_items[i].key,
-                         old_items[i].hash,
-                         old_items[i].value);
+			 old_items[i].hash,
+			 std::move (old_items[i].value));
 
-    free (old_items);
+    hb_free (old_items);
 
     return true;
   }
 
-  void set (K key, V value)
-  {
-    set_with_hash (key, hb_hash (key), value);
-  }
+  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)); }
 
   V get (K key) const
   {
@@ -172,17 +196,17 @@
 
   void clear ()
   {
-    if (unlikely (hb_object_is_immutable (this)))
-      return;
+    if (unlikely (!successful)) return;
+
     if (items)
-      + hb_iter (items, mask + 1)
-      | hb_apply (&item_t::clear)
-      ;
+      for (auto &_ : hb_iter (items, mask + 1))
+	_.clear ();
 
     population = occupancy = 0;
   }
 
   bool is_empty () const { return population == 0; }
+  explicit operator bool () const { return !is_empty (); }
 
   unsigned int get_population () const { return population; }
 
@@ -211,25 +235,26 @@
   )
 
   /* Sink interface. */
-  hb_hashmap_t<K, V, kINVALID, vINVALID>& operator << (const hb_pair_t<K, V>& v)
+  hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
   { set (v.first, v.second); return *this; }
 
   protected:
 
-  void set_with_hash (K key, uint32_t hash, V value)
+  template <typename VV>
+  bool set_with_hash (K key, uint32_t hash, VV&& value)
   {
-    if (unlikely (!successful)) return;
-    if (unlikely (key == kINVALID)) return;
-    if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
+    if (unlikely (!successful)) return false;
+    if (unlikely (key == kINVALID)) return true;
+    if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
     unsigned int i = bucket_for_hash (key, hash);
 
     if (value == vINVALID && items[i].key != key)
-      return; /* Trying to delete non-existent key. */
+      return true; /* Trying to delete non-existent key. */
 
     if (!items[i].is_unused ())
     {
       occupancy--;
-      if (items[i].is_tombstone ())
+      if (!items[i].is_tombstone ())
 	population--;
     }
 
@@ -240,6 +265,8 @@
     occupancy++;
     if (!items[i].is_tombstone ())
       population++;
+
+    return true;
   }
 
   unsigned int bucket_for (K key) const
@@ -322,7 +349,22 @@
 struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
 			       hb_codepoint_t,
 			       HB_MAP_VALUE_INVALID,
-			       HB_MAP_VALUE_INVALID> {};
+			       HB_MAP_VALUE_INVALID>
+{
+  using hashmap = hb_hashmap_t<hb_codepoint_t,
+			       hb_codepoint_t,
+			       HB_MAP_VALUE_INVALID,
+			       HB_MAP_VALUE_INVALID>;
 
+  hb_map_t () = default;
+  ~hb_map_t () = default;
+  hb_map_t (hb_map_t& o) = default;
+  hb_map_t& operator= (const hb_map_t& other) = default;
+  hb_map_t& operator= (hb_map_t&& other) = default;
+  hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_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 */
diff --git a/src/hb-meta.hh b/src/hb-meta.hh
index 2dfaeb7..0ea5774 100644
--- a/src/hb-meta.hh
+++ b/src/hb-meta.hh
@@ -29,6 +29,9 @@
 
 #include "hb.hh"
 
+#include <type_traits>
+#include <utility>
+
 
 /*
  * C++ template meta-programming & fundamentals used with them.
@@ -49,6 +52,10 @@
 using hb_true_type = hb_bool_constant<true>;
 using hb_false_type = hb_bool_constant<false>;
 
+/* Static-assert as expression. */
+template <bool cond> struct static_assert_expr;
+template <> struct static_assert_expr<true> : hb_false_type {};
+#define static_assert_expr(C) static_assert_expr<C>::value
 
 /* Basic type SFINAE. */
 
@@ -97,14 +104,14 @@
 template <typename T> static inline T hb_declval ();
 #define hb_declval(T) (hb_declval<T> ())
 
-template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
 template <typename T> using hb_add_const = const T;
 #define hb_is_const(T) hb_match_const<T>::value
-template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
-template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_true_type	{};
+template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
 template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
 template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
@@ -113,8 +120,8 @@
 template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
 template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
 #define hb_is_reference(T) hb_match_reference<T>::value
-template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
 template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
 template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
@@ -125,40 +132,7 @@
 /* TODO Add feature-parity to std::decay. */
 template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
 
-
-template<bool B, class T, class F>
-struct _hb_conditional { typedef T type; };
-template<class T, class F>
-struct _hb_conditional<false, T, F> { typedef F type; };
-template<bool B, class T, class F>
-using hb_conditional = typename _hb_conditional<B, T, F>::type;
-
-
-template <typename From, typename To>
-struct hb_is_convertible
-{
-  private:
-  static constexpr bool   from_void = hb_is_same (void, hb_decay<From>);
-  static constexpr bool     to_void = hb_is_same (void, hb_decay<To>  );
-  static constexpr bool either_void = from_void || to_void;
-  static constexpr bool   both_void = from_void && to_void;
-
-  static hb_true_type impl2 (hb_conditional<to_void, int, To>);
-
-  template <typename T>
-  static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
-  template <typename T>
-  static hb_false_type impl (hb_priority<0>);
-  public:
-  static constexpr bool value = both_void ||
-		       (!either_void &&
-			decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
-};
-#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value
-
-template <typename Base, typename Derived>
-using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
-#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value
+#define hb_is_convertible(From,To) std::is_convertible<From, To>::value
 
 template <typename From, typename To>
 using hb_is_cr_convertible = hb_bool_constant<
@@ -168,20 +142,11 @@
 >;
 #define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
 
-/* std::move and std::forward */
-
-template <typename T>
-static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
-
-template <typename T>
-static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
-template <typename T>
-static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
 
 struct
 {
   template <typename T> constexpr auto
-  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+  operator () (T&& v) const HB_AUTO_RETURN (std::forward<T> (v))
 
   template <typename T> constexpr auto
   operator () (T *v) const HB_AUTO_RETURN (*v)
@@ -191,7 +156,7 @@
 struct
 {
   template <typename T> constexpr auto
-  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+  operator () (T&& v) const HB_AUTO_RETURN (std::forward<T> (v))
 
   template <typename T> constexpr auto
   operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
@@ -220,49 +185,7 @@
 };
 
 
-template <typename T>
-using hb_is_integral = hb_bool_constant<
-  hb_is_same (hb_decay<T>, char) ||
-  hb_is_same (hb_decay<T>, signed char) ||
-  hb_is_same (hb_decay<T>, unsigned char) ||
-  hb_is_same (hb_decay<T>, signed int) ||
-  hb_is_same (hb_decay<T>, unsigned int) ||
-  hb_is_same (hb_decay<T>, signed short) ||
-  hb_is_same (hb_decay<T>, unsigned short) ||
-  hb_is_same (hb_decay<T>, signed long) ||
-  hb_is_same (hb_decay<T>, unsigned long) ||
-  hb_is_same (hb_decay<T>, signed long long) ||
-  hb_is_same (hb_decay<T>, unsigned long long) ||
-  false
->;
-#define hb_is_integral(T) hb_is_integral<T>::value
-template <typename T>
-using hb_is_floating_point = hb_bool_constant<
-  hb_is_same (hb_decay<T>, float) ||
-  hb_is_same (hb_decay<T>, double) ||
-  hb_is_same (hb_decay<T>, long double) ||
-  false
->;
-#define hb_is_floating_point(T) hb_is_floating_point<T>::value
-template <typename T>
-using hb_is_arithmetic = hb_bool_constant<
-  hb_is_integral (T) ||
-  hb_is_floating_point (T) ||
-  false
->;
-#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
-
-
-template <typename T>
-using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
-				    hb_bool_constant<(T) -1 < (T) 0>,
-				    hb_false_type>;
-#define hb_is_signed(T) hb_is_signed<T>::value
-template <typename T>
-using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
-				      hb_bool_constant<(T) 0 < (T) -1>,
-				      hb_false_type>;
-#define hb_is_unsigned(T) hb_is_unsigned<T>::value
+/* Type traits */
 
 template <typename T> struct hb_int_min;
 template <> struct hb_int_min<char>			: hb_integral_constant<char,			CHAR_MIN>	{};
@@ -276,6 +199,7 @@
 template <> struct hb_int_min<unsigned long>		: hb_integral_constant<unsigned long,		0>		{};
 template <> struct hb_int_min<signed long long>		: hb_integral_constant<signed long long,	LLONG_MIN>	{};
 template <> struct hb_int_min<unsigned long long>	: hb_integral_constant<unsigned long long,	0>		{};
+template <typename T> struct hb_int_min<T *>		: hb_integral_constant<T *,			nullptr>	{};
 #define hb_int_min(T) hb_int_min<T>::value
 template <typename T> struct hb_int_max;
 template <> struct hb_int_max<char>			: hb_integral_constant<char,			CHAR_MAX>	{};
@@ -292,109 +216,26 @@
 #define hb_int_max(T) hb_int_max<T>::value
 
 
+/* Class traits. */
+
+#define HB_DELETE_COPY_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
+#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
+  TypeName() = delete; \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
+
+/* hb_unwrap_type (T)
+ * If T has no T::type, returns T. Otherwise calls itself on T::type recursively.
+ */
 
 template <typename T, typename>
-struct _hb_is_destructible : hb_false_type {};
+struct _hb_unwrap_type : hb_type_identity_t<T> {};
 template <typename T>
-struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
+struct _hb_unwrap_type<T, hb_void_t<typename T::type>> : _hb_unwrap_type<typename T::type, void> {};
 template <typename T>
-using hb_is_destructible = _hb_is_destructible<T, void>;
-#define hb_is_destructible(T) hb_is_destructible<T>::value
-
-template <typename T, typename, typename ...Ts>
-struct _hb_is_constructible : hb_false_type {};
-template <typename T, typename ...Ts>
-struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
-template <typename T, typename ...Ts>
-using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
-#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
-
-template <typename T>
-using hb_is_default_constructible = hb_is_constructible<T>;
-#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
-
-template <typename T>
-using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
-#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
-
-template <typename T>
-using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
-#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
-
-template <typename T, typename U, typename>
-struct _hb_is_assignable : hb_false_type {};
-template <typename T, typename U>
-struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
-template <typename T, typename U>
-using hb_is_assignable = _hb_is_assignable<T, U, void>;
-#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value
-
-template <typename T>
-using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
-					       hb_add_lvalue_reference<hb_add_const<T>>>;
-#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
-
-template <typename T>
-using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
-					       hb_add_rvalue_reference<T>>;
-#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
-
-/* Trivial versions. */
-
-template <typename T> union hb_trivial { T value; };
-
-/* Don't know how to do the following. */
-template <typename T>
-using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
-#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
-
-/* Don't know how to do the following. */
-//template <typename T, typename ...Ts>
-//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
-//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
-
-template <typename T>
-using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
-#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
-
-template <typename T>
-using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
-#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
-
-template <typename T>
-using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
-#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
-
-/* Don't know how to do the following. */
-//template <typename T, typename U>
-//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
-//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
-
-template <typename T>
-using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
-#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
-
-template <typename T>
-using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
-#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
-
-template <typename T>
-using hb_is_trivially_copyable= hb_bool_constant<
-  hb_is_trivially_destructible (T) &&
-  (!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
-  (!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
-  (!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
-  (!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
-  true
->;
-#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
-
-template <typename T>
-using hb_is_trivial= hb_bool_constant<
-  hb_is_trivially_copyable (T) &&
-  hb_is_trivially_default_constructible (T)
->;
-#define hb_is_trivial(T) hb_is_trivial<T>::value
-
+using hb_unwrap_type = _hb_unwrap_type<T, void>;
+#define hb_unwrap_type(T) typename hb_unwrap_type<T>::type
 
 #endif /* HB_META_HH */
diff --git a/src/hb-ms-feature-ranges.cc b/src/hb-ms-feature-ranges.cc
new file mode 100644
index 0000000..6d09b25
--- /dev/null
+++ b/src/hb-ms-feature-ranges.cc
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2011,2012,2013  Google, Inc.
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ms-feature-ranges.hh"
+
+bool
+hb_ms_setup_features (const hb_feature_t                *features,
+		      unsigned int                       num_features,
+		      hb_vector_t<hb_ms_feature_t>      &feature_records, /* OUT */
+		      hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
+{
+  feature_records.shrink(0);
+  range_records.shrink(0);
+
+  /* Sort features by start/end events. */
+  hb_vector_t<hb_ms_feature_event_t> feature_events;
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    hb_ms_active_feature_t feature;
+    feature.fea.tag_le = hb_uint32_swap (features[i].tag);
+    feature.fea.value = features[i].value;
+    feature.order = i;
+
+    hb_ms_feature_event_t *event;
+
+    event = feature_events.push ();
+    event->index = features[i].start;
+    event->start = true;
+    event->feature = feature;
+
+    event = feature_events.push ();
+    event->index = features[i].end;
+    event->start = false;
+    event->feature = feature;
+  }
+  feature_events.qsort ();
+  /* Add a strategic final event. */
+  {
+    hb_ms_active_feature_t feature;
+    feature.fea.tag_le = 0;
+    feature.fea.value = 0;
+    feature.order = num_features + 1;
+
+    auto *event = feature_events.push ();
+    event->index = 0; /* This value does magic. */
+    event->start = false;
+    event->feature = feature;
+  }
+
+  /* Scan events and save features for each range. */
+  hb_vector_t<hb_ms_active_feature_t> active_features;
+  unsigned int last_index = 0;
+  for (unsigned int i = 0; i < feature_events.length; i++)
+  {
+    auto *event = &feature_events[i];
+
+    if (event->index != last_index)
+    {
+      /* Save a snapshot of active features and the range. */
+      auto *range = range_records.push ();
+      auto offset = feature_records.length;
+
+      active_features.qsort ();
+      for (unsigned int j = 0; j < active_features.length; j++)
+      {
+        if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
+        {
+          feature_records.push (active_features[j].fea);
+        }
+        else
+        {
+          /* Overrides value for existing feature. */
+          feature_records[feature_records.length - 1].value = active_features[j].fea.value;
+        }
+      }
+
+      /* Will convert to pointer after all is ready, since feature_records.array
+       * may move as we grow it. */
+      range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
+      range->features.num_features = feature_records.length - offset;
+      range->index_first = last_index;
+      range->index_last  = event->index - 1;
+
+      last_index = event->index;
+    }
+
+    if (event->start)
+    {
+      active_features.push (event->feature);
+    }
+    else
+    {
+      auto *feature = active_features.find (&event->feature);
+      if (feature)
+        active_features.remove (feature - active_features.arrayZ);
+    }
+  }
+
+  if (!range_records.length) /* No active feature found. */
+    num_features = 0;
+
+  /* Fixup the pointers. */
+  for (unsigned int i = 0; i < range_records.length; i++)
+  {
+    auto *range = &range_records[i];
+    range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
+  }
+
+  return !!num_features;
+}
+
+void
+hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t>      &feature_records,
+			   hb_vector_t<hb_ms_range_record_t> &range_records,
+			   unsigned int                       chars_offset,
+			   unsigned int                       chars_len,
+			   uint16_t                          *log_clusters,
+			   hb_vector_t<hb_ms_features_t*>    &range_features, /* OUT */
+			   hb_vector_t<uint32_t>             &range_counts /* OUT */)
+{
+  range_features.shrink (0);
+  range_counts.shrink (0);
+
+  auto *last_range = &range_records[0];
+  for (unsigned int i = chars_offset; i < chars_len; i++)
+  {
+    auto *range = last_range;
+    while (log_clusters[i] < range->index_first)
+      range--;
+    while (log_clusters[i] > range->index_last)
+      range++;
+    if (!range_features.length ||
+        &range->features != range_features[range_features.length - 1])
+    {
+      auto **features = range_features.push ();
+      auto *c = range_counts.push ();
+      if (unlikely (!features || !c))
+      {
+        range_features.shrink (0);
+        range_counts.shrink (0);
+        break;
+      }
+      *features = &range->features;
+      *c = 1;
+    }
+    else
+    {
+      range_counts[range_counts.length - 1]++;
+    }
+
+    last_range = range;
+  }
+}
diff --git a/src/hb-ms-feature-ranges.hh b/src/hb-ms-feature-ranges.hh
new file mode 100644
index 0000000..401d1e1
--- /dev/null
+++ b/src/hb-ms-feature-ranges.hh
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2011,2012,2013  Google, Inc.
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_MS_FEATURE_RANGES_HH
+#define HB_MS_FEATURE_RANGES_HH
+
+#include "hb.hh"
+
+typedef struct hb_ms_feature_t {
+  uint32_t tag_le;
+  uint32_t value;
+} hb_ms_feature_t;
+
+typedef struct hb_ms_features_t {
+  hb_ms_feature_t *features;
+  uint32_t         num_features;
+} hb_ms_features_t;
+
+struct hb_ms_active_feature_t {
+  hb_ms_feature_t fea;
+  unsigned int order;
+
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
+    const auto *a = (const hb_ms_active_feature_t *) pa;
+    const auto *b = (const hb_ms_active_feature_t *) pb;
+    return a->fea.tag_le < b->fea.tag_le ? -1 : a->fea.tag_le > b->fea.tag_le ? 1 :
+	   a->order < b->order ? -1 : a->order > b->order ? 1 :
+	   a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 :
+	   0;
+  }
+  bool operator== (const hb_ms_active_feature_t *f)
+  { return cmp (this, f) == 0; }
+};
+
+struct hb_ms_feature_event_t {
+  unsigned int index;
+  bool start;
+  hb_ms_active_feature_t feature;
+
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
+  {
+    const auto *a = (const hb_ms_feature_event_t *) pa;
+    const auto *b = (const hb_ms_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 :
+	   hb_ms_active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct hb_ms_range_record_t {
+  hb_ms_features_t features;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+HB_INTERNAL bool
+hb_ms_setup_features (const hb_feature_t                *features,
+		      unsigned int                       num_features,
+		      hb_vector_t<hb_ms_feature_t>      &feature_records, /* OUT */
+		      hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */);
+
+
+HB_INTERNAL void
+hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t>      &feature_records,
+			   hb_vector_t<hb_ms_range_record_t> &range_records,
+			   unsigned int                       chars_offset,
+			   unsigned int                       chars_len,
+			   uint16_t                          *log_clusters,
+			   hb_vector_t<hb_ms_features_t*>    &range_features, /* OUT */
+			   hb_vector_t<uint32_t>             &range_counts /* OUT */);
+
+#endif /* HB_MS_FEATURE_RANGES_HH */
diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh
index e7f8b1c..6914b22 100644
--- a/src/hb-mutex.hh
+++ b/src/hb-mutex.hh
@@ -39,8 +39,7 @@
 
 /* We need external help for these */
 
-#if defined(HB_MUTEX_IMPL_INIT) \
- && defined(hb_mutex_impl_init) \
+#if defined(hb_mutex_impl_init) \
  && defined(hb_mutex_impl_lock) \
  && defined(hb_mutex_impl_unlock) \
  && defined(hb_mutex_impl_finish)
@@ -48,23 +47,20 @@
 /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
 
 
-#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
+#elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
 
 #include <pthread.h>
 typedef pthread_mutex_t hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
 #define hb_mutex_impl_init(M)	pthread_mutex_init (M, nullptr)
 #define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
 #define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
 #define hb_mutex_impl_finish(M)	pthread_mutex_destroy (M)
 
 
-#elif !defined(HB_NO_MT) && defined(_WIN32)
+#elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && defined(_WIN32)
 
-#include <windows.h>
 typedef CRITICAL_SECTION hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	{0}
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #define hb_mutex_impl_init(M)	InitializeCriticalSectionEx (M, 0, 0)
 #else
 #define hb_mutex_impl_init(M)	InitializeCriticalSection (M)
@@ -74,52 +70,40 @@
 #define hb_mutex_impl_finish(M)	DeleteCriticalSection (M)
 
 
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+#elif !defined(HB_NO_MT)
 
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
-# include <sched.h>
-# define HB_SCHED_YIELD() sched_yield ()
-#else
-# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
-#endif
-
-/* This actually is not a totally awful implementation. */
-typedef volatile int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	0
-#define hb_mutex_impl_init(M)	*(M) = 0
-#define hb_mutex_impl_lock(M)	HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
-#define hb_mutex_impl_unlock(M)	__sync_lock_release (M)
-#define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
+#include <mutex>
+typedef std::mutex              hb_mutex_impl_t;
+#define hb_mutex_impl_init(M)   HB_STMT_START { new (M) hb_mutex_impl_t; } HB_STMT_END
+#define hb_mutex_impl_lock(M)   (M)->lock ()
+#define hb_mutex_impl_unlock(M) (M)->unlock ()
+#define hb_mutex_impl_finish(M) HB_STMT_START { (M)->~hb_mutex_impl_t(); } HB_STMT_END
 
 
-#elif defined(HB_NO_MT)
+#else /* defined(HB_NO_MT) */
 
 typedef int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	0
 #define hb_mutex_impl_init(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_lock(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_unlock(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
 
 
-#else
-
-#error "Could not find any system to define mutex macros."
-#error "Check hb-mutex.hh for possible resolutions."
-
 #endif
 
 
-#define HB_MUTEX_INIT		{HB_MUTEX_IMPL_INIT}
-
 struct hb_mutex_t
 {
-  hb_mutex_impl_t m;
+  /* Create space for, but do not initialize m. */
+  alignas(hb_mutex_impl_t) char m[sizeof (hb_mutex_impl_t)];
 
-  void init   () { hb_mutex_impl_init   (&m); }
-  void lock   () { hb_mutex_impl_lock   (&m); }
-  void unlock () { hb_mutex_impl_unlock (&m); }
-  void fini ()   { hb_mutex_impl_finish (&m); }
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  void init   () { hb_mutex_impl_init   ((hb_mutex_impl_t *) m); }
+  void lock   () { hb_mutex_impl_lock   ((hb_mutex_impl_t *) m); }
+  void unlock () { hb_mutex_impl_unlock ((hb_mutex_impl_t *) m); }
+  void fini   () { hb_mutex_impl_finish ((hb_mutex_impl_t *) m); }
+#pragma GCC diagnostic pop
 };
 
 struct hb_lock_t
diff --git a/src/hb-null.hh b/src/hb-null.hh
index d457820..db38a4d 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -39,8 +39,11 @@
 
 #define HB_NULL_POOL_SIZE 384
 
-/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
- * otherwise return sizeof(T). */
+/* 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).
+ *
+ * The main purpose of this is to let structs communicate that they are not nullable,
+ * by defining min_size but *not* null_size. */
 
 /* The hard way...
  * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
@@ -49,8 +52,9 @@
 template <typename T, typename>
 struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
-
+struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>>
+	: hb_integral_constant<unsigned,
+			       (sizeof (T) > T::null_size ? sizeof (T) : T::null_size)> {};
 template <typename T>
 using hb_null_size = _hb_null_size<T, void>;
 #define hb_null_size(T) hb_null_size<T>::value
@@ -68,6 +72,14 @@
 using hb_static_size = _hb_static_size<T, void>;
 #define hb_static_size(T) hb_static_size<T>::value
 
+template <typename T, typename>
+struct _hb_min_size : hb_integral_constant<unsigned, sizeof (T)> {};
+template <typename T>
+struct _hb_min_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::min_size> {};
+template <typename T>
+using hb_min_size = _hb_min_size<T, void>;
+#define hb_min_size(T) hb_min_size<T>::value
+
 
 /*
  * Null()
@@ -104,7 +116,7 @@
 	  } \
 	}; \
 	namespace Namespace { \
-	static_assert (true, "Just so we take semicolon after.")
+	static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
 	const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
 
@@ -117,7 +129,7 @@
 	    return _hb_Null_##Type; \
 	  } \
 	}; \
-	static_assert (true, "Just so we take semicolon after.")
+	static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_INSTANCE(Type) \
 	const Type _hb_Null_##Type
 
@@ -135,7 +147,7 @@
 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, &Null (Type), sizeof (*obj));
   return *obj;
 }
 template <typename QType>
@@ -148,11 +160,11 @@
 
 template <typename Type>
 struct CrapOrNullHelper {
-  static Type & get () { return Crap(Type); }
+  static Type & get () { return Crap (Type); }
 };
 template <typename Type>
 struct CrapOrNullHelper<const Type> {
-  static const Type & get () { return Null(Type); }
+  static const Type & get () { return Null (Type); }
 };
 #define CrapOrNull(Type) CrapOrNullHelper<Type>::get ()
 
@@ -174,9 +186,10 @@
   /* 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 *> (&Null (T)); }
   T * get_raw () const { return v; }
 
+  private:
   T *v;
 };
 
diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh
index c78c850..1a9dbba 100644
--- a/src/hb-number-parser.hh
+++ b/src/hb-number-parser.hh
@@ -30,10 +30,8 @@
 
 #include "hb.hh"
 
-#include <float.h>
 
-
-#line 37 "hb-number-parser.hh"
+#line 35 "hb-number-parser.hh"
 static const unsigned char _double_parser_trans_keys[] = {
 	0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 
 	46u, 101u, 0
@@ -93,12 +91,12 @@
 static const int double_parser_en_main = 1;
 
 
-#line 70 "hb-number-parser.rl"
+#line 68 "hb-number-parser.rl"
 
 
 /* Works only for n < 512 */
 static inline double
-_pow10 (unsigned int exponent)
+_pow10 (unsigned exponent)
 {
   static const double _powers_of_10[] =
   {
@@ -112,38 +110,37 @@
     100.,
     10.
   };
-  unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
+  unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
   double result = 1;
   for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
     if (exponent & mask) result *= *power;
   return result;
 }
 
+/* a variant of strtod that also gets end of buffer in its second argument */
 static inline double
-strtod_rl (const char *buf, char **end_ptr)
+strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 {
-  const char *p, *pe;
   double value = 0;
   double frac = 0;
   double frac_count = 0;
-  unsigned int exp = 0;
+  unsigned exp = 0;
   bool neg = false, exp_neg = false, exp_overflow = false;
-  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
-  const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
-  p = buf;
-  pe = p + strlen (p);
+  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
+  const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
 
+  const char *pe = *end_ptr;
   while (p < pe && ISSPACE (*p))
     p++;
 
   int cs;
   
-#line 142 "hb-number-parser.hh"
+#line 139 "hb-number-parser.hh"
 	{
 	cs = double_parser_start;
 	}
 
-#line 147 "hb-number-parser.hh"
+#line 144 "hb-number-parser.hh"
 	{
 	int _slen;
 	int _trans;
@@ -169,21 +166,21 @@
 
 	switch ( _double_parser_trans_actions[_trans] ) {
 	case 1:
-#line 39 "hb-number-parser.rl"
+#line 37 "hb-number-parser.rl"
 	{ neg = true; }
 	break;
 	case 4:
-#line 40 "hb-number-parser.rl"
+#line 38 "hb-number-parser.rl"
 	{ exp_neg = true; }
 	break;
 	case 2:
-#line 42 "hb-number-parser.rl"
+#line 40 "hb-number-parser.rl"
 	{
 	value = value * 10. + ((*p) - '0');
 }
 	break;
 	case 3:
-#line 45 "hb-number-parser.rl"
+#line 43 "hb-number-parser.rl"
 	{
 	if (likely (frac <= MAX_FRACT / 10))
 	{
@@ -193,7 +190,7 @@
 }
 	break;
 	case 5:
-#line 52 "hb-number-parser.rl"
+#line 50 "hb-number-parser.rl"
 	{
 	if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
 	  exp = exp * 10 + ((*p) - '0');
@@ -201,7 +198,7 @@
 	  exp_overflow = true;
 }
 	break;
-#line 205 "hb-number-parser.hh"
+#line 202 "hb-number-parser.hh"
 	}
 
 _again:
@@ -213,10 +210,10 @@
 	_out: {}
 	}
 
-#line 116 "hb-number-parser.rl"
+#line 113 "hb-number-parser.rl"
 
 
-  *end_ptr = (char *) p;
+  *end_ptr = p;
 
   if (frac_count) value += frac / _pow10 (frac_count);
   if (neg) value *= -1.;
diff --git a/src/hb-number-parser.rl b/src/hb-number-parser.rl
index 8445fa2..c6c4a3b 100644
--- a/src/hb-number-parser.rl
+++ b/src/hb-number-parser.rl
@@ -28,8 +28,6 @@
 
 #include "hb.hh"
 
-#include <float.h>
-
 %%{
 
 machine double_parser;
@@ -71,7 +69,7 @@
 
 /* Works only for n < 512 */
 static inline double
-_pow10 (unsigned int exponent)
+_pow10 (unsigned exponent)
 {
   static const double _powers_of_10[] =
   {
@@ -85,27 +83,26 @@
     100.,
     10.
   };
-  unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
+  unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
   double result = 1;
   for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
     if (exponent & mask) result *= *power;
   return result;
 }
 
+/* a variant of strtod that also gets end of buffer in its second argument */
 static inline double
-strtod_rl (const char *buf, char **end_ptr)
+strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 {
-  const char *p, *pe;
   double value = 0;
   double frac = 0;
   double frac_count = 0;
-  unsigned int exp = 0;
+  unsigned exp = 0;
   bool neg = false, exp_neg = false, exp_overflow = false;
-  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
-  const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
-  p = buf;
-  pe = p + strlen (p);
+  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
+  const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
 
+  const char *pe = *end_ptr;
   while (p < pe && ISSPACE (*p))
     p++;
 
@@ -115,7 +112,7 @@
     write exec;
   }%%
 
-  *end_ptr = (char *) p;
+  *end_ptr = p;
 
   if (frac_count) value += frac / _pow10 (frac_count);
   if (neg) value *= -1.;
diff --git a/src/hb-number.cc b/src/hb-number.cc
index 4f84d4a..6e4f3f7 100644
--- a/src/hb-number.cc
+++ b/src/hb-number.cc
@@ -25,21 +25,16 @@
 
 #include "hb.hh"
 #include "hb-machinery.hh"
+#include "hb-number.hh"
 #include "hb-number-parser.hh"
 
-#include <locale.h>
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h>
-#endif
-
 template<typename T, typename Func>
 static bool
 _parse_number (const char **pp, const char *end, T *pv,
 	       bool whole_buffer, Func f)
 {
   char buf[32];
-  unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1,
-			     (unsigned int) (end - *pp));
+  unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp));
   strncpy (buf, *pp, len);
   buf[len] = '\0';
 
@@ -50,7 +45,8 @@
   *pv = f (p, &pend);
   if (unlikely (errno || p == pend ||
 		/* Check if consumed whole buffer if is requested */
-		(whole_buffer && pend - p != end - *pp))) return false;
+		(whole_buffer && pend - p != end - *pp)))
+    return false;
 
   *pp += pend - p;
   return true;
@@ -65,83 +61,20 @@
 }
 
 bool
-hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
+hb_parse_uint (const char **pp, const char *end, unsigned *pv,
 	       bool whole_buffer, int base)
 {
-  return _parse_number<unsigned int> (pp, end, pv, whole_buffer,
-				      [base] (const char *p, char **end)
-				      { return strtoul (p, end, base); });
+  return _parse_number<unsigned> (pp, end, pv, whole_buffer,
+				  [base] (const char *p, char **end)
+				  { return strtoul (p, end, base); });
 }
 
-
-#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T locale_t
-#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
-#define HB_FREE_LOCALE(loc) freelocale (loc)
-#elif defined(_MSC_VER)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T _locale_t
-#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
-#define HB_FREE_LOCALE(loc) _free_locale (loc)
-#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
-#endif
-
-#ifdef USE_XLOCALE
-
-#if HB_USE_ATEXIT
-static void free_static_C_locale ();
-#endif
-
-static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<HB_LOCALE_T>,
-							  hb_C_locale_lazy_loader_t>
-{
-  static HB_LOCALE_T create ()
-  {
-    HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
-
-#if HB_USE_ATEXIT
-    atexit (free_static_C_locale);
-#endif
-
-    return C_locale;
-  }
-  static void destroy (HB_LOCALE_T p)
-  {
-    HB_FREE_LOCALE (p);
-  }
-  static HB_LOCALE_T get_null ()
-  {
-    return nullptr;
-  }
-} static_C_locale;
-
-#if HB_USE_ATEXIT
-static
-void free_static_C_locale ()
-{
-  static_C_locale.free_instance ();
-}
-#endif
-
-static HB_LOCALE_T
-get_C_locale ()
-{
-  return static_C_locale.get_unconst ();
-}
-#endif /* USE_XLOCALE */
-
 bool
-hb_parse_double (const char **pp, const char *end, double *pv,
-		 bool whole_buffer)
+hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer)
 {
-  return _parse_number<double> (pp, end, pv, whole_buffer,
-				[] (const char *p, char **end)
-				{
-#ifdef USE_XLOCALE
-				  return strtod_l (p, end, get_C_locale ());
-#else
-				  return strtod_rl (p, end);
-#endif
-				});
+  const char *pend = end;
+  *pv = strtod_rl (*pp, &pend);
+  if (unlikely (*pp == pend)) return false;
+  *pp = pend;
+  return !whole_buffer || end == pend;
 }
diff --git a/src/hb-object.hh b/src/hb-object.hh
index c470532..0e15cb1 100644
--- a/src/hb-object.hh
+++ b/src/hb-object.hh
@@ -140,10 +140,6 @@
  * Reference-count.
  */
 
-#define HB_REFERENCE_COUNT_INERT_VALUE 0
-#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
-#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)}
-
 struct hb_reference_count_t
 {
   mutable hb_atomic_int_t ref_count;
@@ -152,9 +148,9 @@
   int get_relaxed () const { return ref_count.get_relaxed (); }
   int inc () const { return ref_count.inc (); }
   int dec () const { return ref_count.dec (); }
-  void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
+  void fini () { ref_count.set_relaxed (-0x0000DEAD); }
 
-  bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
+  bool is_inert () const { return !ref_count.get_relaxed (); }
   bool is_valid () const { return ref_count.get_relaxed () > 0; }
 };
 
@@ -168,8 +164,8 @@
     void *data;
     hb_destroy_func_t destroy;
 
-    bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
-    bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
+    bool operator == (const hb_user_data_key_t *other_key) const { return key == other_key; }
+    bool operator == (const hb_user_data_item_t &other) const { return key == other.key; }
 
     void fini () { if (destroy) destroy (data); }
   };
@@ -197,15 +193,12 @@
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  mutable hb_atomic_int_t writable;
+  mutable hb_atomic_int_t writable = 0;
   hb_atomic_ptr_t<hb_user_data_array_t> user_data;
+
+  bool is_inert () const { return !ref_count.get_relaxed (); }
 };
-#define HB_OBJECT_HEADER_STATIC \
-	{ \
-	  HB_REFERENCE_COUNT_INIT, \
-	  HB_ATOMIC_INT_INIT (false), \
-	  HB_ATOMIC_PTR_INIT (nullptr) \
-	}
+#define HB_OBJECT_HEADER_STATIC {}
 
 
 /*
@@ -224,7 +217,7 @@
 template <typename Type>
 static inline Type *hb_object_create ()
 {
-  Type *obj = (Type *) calloc (1, sizeof (Type));
+  Type *obj = (Type *) hb_calloc (1, sizeof (Type));
 
   if (unlikely (!obj))
     return obj;
@@ -241,11 +234,6 @@
   obj->header.user_data.init ();
 }
 template <typename Type>
-static inline bool hb_object_is_inert (const Type *obj)
-{
-  return unlikely (obj->header.ref_count.is_inert ());
-}
-template <typename Type>
 static inline bool hb_object_is_valid (const Type *obj)
 {
   return likely (obj->header.ref_count.is_valid ());
@@ -264,7 +252,7 @@
 static inline Type *hb_object_reference (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return obj;
   assert (hb_object_is_valid (obj));
   obj->header.ref_count.inc ();
@@ -274,7 +262,7 @@
 static inline bool hb_object_destroy (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
   if (obj->header.ref_count.dec () != 1)
@@ -291,7 +279,7 @@
   if (user_data)
   {
     user_data->fini ();
-    free (user_data);
+    hb_free (user_data);
     user_data = nullptr;
   }
 }
@@ -302,7 +290,7 @@
 					    hb_destroy_func_t   destroy,
 					    hb_bool_t           replace)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
 
@@ -310,14 +298,14 @@
   hb_user_data_array_t *user_data = obj->header.user_data.get ();
   if (unlikely (!user_data))
   {
-    user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1);
+    user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
     if (unlikely (!user_data))
       return false;
     user_data->init ();
     if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
     {
       user_data->fini ();
-      free (user_data);
+      hb_free (user_data);
       goto retry;
     }
   }
@@ -329,7 +317,7 @@
 static inline void *hb_object_get_user_data (Type               *obj,
 					     hb_user_data_key_t *key)
 {
-  if (unlikely (!obj || hb_object_is_inert (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 ();
diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh
index cb1fdf1..6eee582 100644
--- a/src/hb-open-file.hh
+++ b/src/hb-open-file.hh
@@ -35,7 +35,6 @@
 
 namespace OT {
 
-
 /*
  *
  * The OpenType Font File
@@ -48,7 +47,7 @@
  */
 
 struct OpenTypeFontFile;
-struct OffsetTable;
+struct OpenTypeOffsetTable;
 struct TTCHeader;
 
 
@@ -78,7 +77,7 @@
   DEFINE_SIZE_STATIC (16);
 } OpenTypeTable;
 
-typedef struct OffsetTable
+typedef struct OpenTypeOffsetTable
 {
   friend struct OpenTypeFontFile;
 
@@ -91,15 +90,10 @@
   {
     if (table_count)
     {
-      if (start_offset >= tables.len)
-	*table_count = 0;
-      else
-	*table_count = hb_min (*table_count, tables.len - start_offset);
-
-      const TableRecord *sub_tables = tables.arrayZ + start_offset;
-      unsigned int count = *table_count;
-      for (unsigned int i = 0; i < count; i++)
-	table_tags[i] = sub_tables[i].tag;
+      + tables.sub_array (start_offset, table_count)
+      | hb_map (&TableRecord::tag)
+      | hb_sink (hb_array (table_tags, *table_count))
+      ;
     }
     return tables.len;
   }
@@ -107,7 +101,13 @@
   {
     Tag t;
     t = tag;
-    return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+    /* Use lfind for small fonts; there are fonts that have unsorted table entries;
+     * those tend to work in other tools, so tolerate them.
+     * https://github.com/harfbuzz/harfbuzz/issues/3065 */
+    if (tables.len < 16)
+      return tables.lfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+    else
+      return tables.bfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
   }
   const TableRecord& get_table_by_tag (hb_tag_t tag) const
   {
@@ -118,44 +118,53 @@
 
   public:
 
-  template <typename item_t>
+  template <typename Iterator,
+	    hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
   bool serialize (hb_serialize_context_t *c,
 		  hb_tag_t sfnt_tag,
-		  hb_array_t<item_t> items)
+		  Iterator it)
   {
     TRACE_SERIALIZE (this);
     /* Alloc 12 for the OTHeader. */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     /* Write sfntVersion (bytes 0..3). */
     sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
-    if (unlikely (!tables.serialize (c, items.length))) return_trace (false);
+    unsigned num_items = it.len ();
+    if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
 
     const char *dir_end = (const char *) c->head;
     HBUINT32 *checksum_adjustment = nullptr;
 
     /* Write OffsetTables, alloc for and write actual table blobs. */
-    for (unsigned int i = 0; i < tables.len; i++)
+    unsigned i = 0;
+    for (hb_pair_t<hb_tag_t, hb_blob_t*> entry : it)
     {
-      TableRecord &rec = tables.arrayZ[i];
-      hb_blob_t *blob = items[i].blob;
-      rec.tag = items[i].tag;
-      rec.length = blob->length;
-      rec.offset.serialize (c, this);
+      hb_blob_t *blob = entry.second;
+      unsigned len = blob->length;
 
       /* Allocate room for the table and copy it. */
-      char *start = (char *) c->allocate_size<void> (rec.length);
+      char *start = (char *) c->allocate_size<void> (len);
       if (unlikely (!start)) return false;
 
-      if (likely (rec.length))
-	memcpy (start, blob->data, rec.length);
+      TableRecord &rec = tables.arrayZ[i];
+      rec.tag = entry.first;
+      rec.length = len;
+      rec.offset = 0;
+      if (unlikely (!c->check_assign (rec.offset,
+				      (unsigned) ((char *) start - (char *) this),
+				      HB_SERIALIZE_ERROR_OFFSET_OVERFLOW)))
+        return_trace (false);
+
+      if (likely (len))
+	memcpy (start, blob->data, len);
 
       /* 4-byte alignment. */
       c->align (4);
       const char *end = (const char *) c->head;
 
-      if (items[i].tag == HB_OT_TAG_head &&
+      if (entry.first == HB_OT_TAG_head &&
 	  (unsigned) (end - start) >= head::static_size)
       {
 	head *h = (head *) start;
@@ -164,6 +173,7 @@
       }
 
       rec.checkSum.set_for_data (start, end - start);
+      i++;
     }
 
     tables.qsort ();
@@ -175,7 +185,7 @@
       /* The following line is a slower version of the following block. */
       //checksum.set_for_data (this, (const char *) c->head - (const char *) this);
       checksum.set_for_data (this, dir_end - (const char *) this);
-      for (unsigned int i = 0; i < items.length; i++)
+      for (unsigned int i = 0; i < num_items; i++)
       {
 	TableRecord &rec = tables.arrayZ[i];
 	checksum = checksum + rec.checkSum;
@@ -223,7 +233,7 @@
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  LArrayOf<LOffsetTo<OffsetTable>>
+  Array32Of<Offset32To<OpenTypeOffsetTable>>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
@@ -249,7 +259,7 @@
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
     case 1: return u.version1.get_face (i);
-    default:return Null(OpenTypeFontFace);
+    default:return Null (OpenTypeFontFace);
     }
   }
 
@@ -284,7 +294,7 @@
 struct ResourceRecord
 {
   const OpenTypeFontFace & get_face (const void *data_base) const
-  { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); }
+  { return * reinterpret_cast<const OpenTypeFontFace *> ((data_base+offset).arrayZ); }
 
   bool sanitize (hb_sanitize_context_t *c,
 		 const void *data_base) const
@@ -300,7 +310,7 @@
   HBINT16	nameOffset;	/* Offset from beginning of resource name list
 				 * to resource name, -1 means there is none. */
   HBUINT8	attrs;		/* Resource attributes */
-  NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24>
+  NNOffset24To<Array32Of<HBUINT8>>
 		offset;		/* Offset from beginning of data block to
 				 * data for this resource */
   HBUINT32	reserved;	/* Reserved for handle to resource */
@@ -335,7 +345,7 @@
   protected:
   Tag		tag;		/* Resource type. */
   HBUINT16	resCountM1;	/* Number of resources minus 1. */
-  NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
+  NNOffset16To<UnsizedArrayOf<ResourceRecord>>
 		resourcesZ;	/* Offset from beginning of resource type list
 				 * to reference item list for this type. */
   public:
@@ -391,7 +401,7 @@
   HBUINT32	reserved1;	/* Reserved for handle to next resource map */
   HBUINT16	resreved2;	/* Reserved for file reference number */
   HBUINT16	attrs;		/* Resource fork attribute */
-  NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
+  NNOffset16To<ArrayOfM1<ResourceTypeRecord>>
 		typeList;	/* Offset from beginning of map to
 				 * resource type list */
   Offset16	nameList;	/* Offset from beginning of map to
@@ -423,10 +433,10 @@
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		data;		/* Offset from beginning of resource fork
 				 * to resource data */
-  LNNOffsetTo<ResourceMap >
+  NNOffset32To<ResourceMap >
 		map;		/* Offset from beginning of resource fork
 				 * to resource map */
   HBUINT32	dataLen;	/* Length of resource data */
@@ -478,18 +488,19 @@
     case TrueTypeTag:	return u.fontFace;
     case TTCTag:	return u.ttcHeader.get_face (i);
     case DFontTag:	return u.rfHeader.get_face (i, base_offset);
-    default:		return Null(OpenTypeFontFace);
+    default:		return Null (OpenTypeFontFace);
     }
   }
 
-  template <typename item_t>
+  template <typename Iterator,
+	    hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
   bool serialize_single (hb_serialize_context_t *c,
 			 hb_tag_t sfnt_tag,
-			 hb_array_t<item_t> items)
+			 Iterator items)
   {
     TRACE_SERIALIZE (this);
     assert (sfnt_tag != TTCTag);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     return_trace (u.fontFace.serialize (c, sfnt_tag, items));
   }
 
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index af242ec..7e52417 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -53,14 +53,19 @@
  */
 
 /* Integer types in big-endian order and no alignment requirement */
-template <typename Type, unsigned int Size>
+template <typename Type,
+	  unsigned int Size = sizeof (Type)>
 struct IntType
 {
   typedef Type type;
-  typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
 
-  IntType& operator = (wide_type i) { v = i; return *this; }
-  operator wide_type () const { return v; }
+  IntType () = default;
+  explicit constexpr IntType (Type V) : v {V} {}
+  IntType& operator = (Type i) { v = i; return *this; }
+  /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
+   * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
+  operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; }
+
   bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
   bool operator != (const IntType &o) const { return !(*this == o); }
 
@@ -73,14 +78,28 @@
 
   HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
   { return b->cmp (*a); }
-  template <typename Type2>
+  HB_INTERNAL static int cmp (const void *a, const void *b)
+  {
+    IntType *pa = (IntType *) a;
+    IntType *pb = (IntType *) b;
+
+    return pb->cmp (*pa);
+  }
+  template <typename Type2,
+	    hb_enable_if (std::is_integral<Type2>::value &&
+			  sizeof (Type2) < sizeof (int) &&
+			  sizeof (Type) < sizeof (int))>
   int cmp (Type2 a) const
   {
     Type b = v;
-    if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
-      return (int) a - (int) b;
-    else
-      return a < b ? -1 : a == b ? 0 : +1;
+    return (int) a - (int) b;
+  }
+  template <typename Type2,
+	    hb_enable_if (hb_is_convertible (Type2, Type))>
+  int cmp (Type2 a) const
+  {
+    Type b = v;
+    return a < b ? -1 : a == b ? 0 : +1;
   }
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -93,16 +112,25 @@
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef IntType<uint8_t,  1> HBUINT8;	/* 8-bit unsigned integer. */
-typedef IntType<int8_t,   1> HBINT8;	/* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> HBUINT16;	/* 16-bit unsigned integer. */
-typedef IntType<int16_t,  2> HBINT16;	/* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> HBUINT32;	/* 32-bit unsigned integer. */
-typedef IntType<int32_t,  4> HBINT32;	/* 32-bit signed integer. */
+typedef IntType<uint8_t>  HBUINT8;	/* 8-bit unsigned integer. */
+typedef IntType<int8_t>   HBINT8;	/* 8-bit signed integer. */
+typedef IntType<uint16_t> HBUINT16;	/* 16-bit unsigned integer. */
+typedef IntType<int16_t>  HBINT16;	/* 16-bit signed integer. */
+typedef IntType<uint32_t> HBUINT32;	/* 32-bit unsigned integer. */
+typedef IntType<int32_t>  HBINT32;	/* 32-bit signed integer. */
 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
  * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
 typedef IntType<uint32_t, 3> HBUINT24;	/* 24-bit unsigned integer. */
 
+/* 15-bit unsigned number; top bit used for extension. */
+struct HBUINT15 : HBUINT16
+{
+  /* TODO Flesh out; actually mask top bit. */
+  HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; }
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
 typedef HBINT16 FWORD;
 
@@ -156,16 +184,16 @@
 {
   Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
-  operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
-  operator char* ()             { return reinterpret_cast<char *> (&this->v); }
+  operator const char* () const { return reinterpret_cast<const char *> (this); }
+  operator char* ()             { return reinterpret_cast<char *> (this); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-struct HBGlyphID : HBUINT16
+struct HBGlyphID16 : HBUINT16
 {
-  HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+  HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
 
 /* Script/language-system/feature index */
@@ -177,6 +205,12 @@
 
 typedef Index NameID;
 
+struct VarIdx : HBUINT32 {
+  static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
+  VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
+};
+DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
+
 /* Offset, Null offset = 0 */
 template <typename Type, bool has_null=true>
 struct Offset : Type
@@ -187,18 +221,12 @@
 
   bool is_null () const { return has_null && 0 == *this; }
 
-  void *serialize (hb_serialize_context_t *c, const void *base)
-  {
-    void *t = c->start_embed<void> ();
-    c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
-    return t;
-  }
-
   public:
   DEFINE_SIZE_STATIC (sizeof (Type));
 };
 
 typedef Offset<HBUINT16> Offset16;
+typedef Offset<HBUINT24> Offset24;
 typedef Offset<HBUINT32> Offset32;
 
 
@@ -268,7 +296,7 @@
   static       Type *get_crap () { return &Crap (Type); }
 };
 
-template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
+template <typename Type, typename OffsetType, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
   HB_DELETE_COPY_ASSIGN (OffsetTo);
@@ -300,17 +328,10 @@
 	    hb_enable_if (hb_is_convertible (Base, void *))>
   friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
 
-  Type& serialize (hb_serialize_context_t *c, const void *base)
-  {
-    return * (Type *) Offset<OffsetType>::serialize (c, base);
-  }
 
   template <typename ...Ts>
-  bool serialize_subset (hb_subset_context_t *c,
-			 const OffsetTo& src,
-			 const void *src_base,
-			 const void *dst_base,
-			 Ts&&... ds)
+  bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
+			 const void *src_base, Ts&&... ds)
   {
     *this = 0;
     if (src.is_null ())
@@ -320,22 +341,41 @@
 
     s->push ();
 
-    bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
+    bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...);
 
     if (ret || !has_null)
-      s->add_link (*this, s->pop_pack (), dst_base);
+      s->add_link (*this, s->pop_pack ());
     else
       s->pop_discard ();
 
     return ret;
   }
 
-  /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
+
   template <typename ...Ts>
-  bool serialize_copy (hb_serialize_context_t *c,
-		       const OffsetTo& src,
-		       const void *src_base,
-		       const void *dst_base,
+  bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
+  {
+    *this = 0;
+
+    Type* obj = c->push<Type> ();
+    bool ret = obj->serialize (c, std::forward<Ts> (ds)...);
+
+    if (ret)
+      c->add_link (*this, c->pop_pack ());
+    else
+      c->pop_discard ();
+
+    return ret;
+  }
+
+  /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
+  /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
+   * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
+   */
+  template <typename ...Ts>
+  bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
+		       const void *src_base, unsigned dst_bias,
+		       hb_serialize_context_t::whence_t whence,
 		       Ts&&... ds)
   {
     *this = 0;
@@ -344,19 +384,23 @@
 
     c->push ();
 
-    bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
+    bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...);
 
-    c->add_link (*this, c->pop_pack (), dst_base);
+    c->add_link (*this, c->pop_pack (), whence, dst_bias);
 
     return ret;
   }
 
+  bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
+		       const void *src_base, unsigned dst_bias = 0)
+  { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
+
   bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
     if (unlikely (this->is_null ())) return_trace (true);
-    if (unlikely (!c->check_range (base, *this))) return_trace (false);
+    if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
     return_trace (true);
   }
 
@@ -366,7 +410,7 @@
     TRACE_SANITIZE (this);
     return_trace (sanitize_shallow (c, base) &&
 		  (this->is_null () ||
-		   c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
+		   c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
 		   neuter (c)));
   }
 
@@ -379,12 +423,14 @@
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
 /* Partial specializations. */
-template <typename Type, bool has_null=true>
-using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
-template <typename Type, typename OffsetType=HBUINT16>
-using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
-template <typename Type>
-using LNNOffsetTo = LOffsetTo<Type, false>;
+template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
+template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
+template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
+
+template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
+template <typename Type> using NNOffset16To = Offset16To<Type, false>;
+template <typename Type> using NNOffset24To = Offset24To<Type, false>;
+template <typename Type> using NNOffset32To = Offset32To<Type, false>;
 
 
 /*
@@ -423,8 +469,6 @@
   { return hb_array (arrayZ, len); }
   hb_array_t<const Type> as_array (unsigned int len) const
   { return hb_array (arrayZ, len); }
-  operator hb_array_t<      Type> ()       { return as_array (); }
-  operator hb_array_t<const Type> () const { return as_array (); }
 
   template <typename T>
   Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
@@ -432,6 +476,11 @@
   template <typename T>
   const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
   { return *as_array (len).lsearch (x, &not_found); }
+  template <typename T>
+  bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
+  { return as_array (len).lfind (x, i, not_found, to_store); }
 
   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array (len).qsort (start, end); }
@@ -439,7 +488,7 @@
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend (*this, items_len))) return_trace (false);
+    if (unlikely (!c->extend (this, items_len))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
@@ -469,9 +518,9 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+      if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -490,11 +539,11 @@
 
 /* Unsized array of offset's */
 template <typename Type, typename OffsetType, bool has_null=true>
-using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
+using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
 template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
+struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
 {
   const Type& operator [] (int i_) const
   {
@@ -515,8 +564,8 @@
   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
-		   ::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
+    return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
+		   ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
   }
 };
 
@@ -539,14 +588,14 @@
   { return *as_array (len).bsearch (x, &not_found); }
   template <typename T>
   bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
-		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-		     unsigned int to_store = (unsigned int) -1) const
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
   { return as_array (len).bfind (x, i, not_found, to_store); }
 };
 
 
 /* An array with a number of elements. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
 struct ArrayOf
 {
   typedef Type item_t;
@@ -594,17 +643,32 @@
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
   { return as_array ().sub_array (start_offset, count); }
 
-  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  template <typename T>
+  Type &lsearch (const T &x, Type &not_found = Crap (Type))
+  { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  bool lfind (const T &x, unsigned int *i = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      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); }
+
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    c->check_assign (len, items_len);
-    if (unlikely (!c->extend (*this))) return_trace (false);
+    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);
     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 ();
@@ -620,7 +684,7 @@
   {
     TRACE_SERIALIZE (this);
     len++;
-    if (unlikely (!len || !c->extend (*this)))
+    if (unlikely (!len || !c->extend (this)))
     {
       len--;
       return_trace (nullptr);
@@ -633,7 +697,7 @@
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
     if (unlikely (!c->extend_min (out))) return_trace (nullptr);
-    c->check_assign (out->len, len);
+    c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
     if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
     return_trace (out);
   }
@@ -643,24 +707,14 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+      if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
 
-  template <typename T>
-  Type &lsearch (const T &x, Type &not_found = Crap (Type))
-  { return *as_array ().lsearch (x, &not_found); }
-  template <typename T>
-  const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
-  { return *as_array ().lsearch (x, &not_found); }
-
-  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
-  { as_array ().qsort (start, end); }
-
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -673,21 +727,18 @@
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
-template <typename Type>
-using LArrayOf = ArrayOf<Type, HBUINT32>;
+template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
 /* Array of Offset's */
-template <typename Type>
-using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
-template <typename Type>
-using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
-template <typename Type>
-using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
+template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
+template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
+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 OffsetListOf : OffsetArrayOf<Type>
+struct List16OfOffset16To : Array16OfOffset16To<Type>
 {
   const Type& operator [] (int i_) const
   {
@@ -705,7 +756,7 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+    struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
@@ -717,7 +768,7 @@
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
+    return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
   }
 };
 
@@ -760,9 +811,9 @@
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    c->check_assign (lenP1, items_len + 1);
-    if (unlikely (!c->extend (*this))) return_trace (false);
+    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);
     return_trace (true);
   }
   template <typename Iterator,
@@ -784,10 +835,10 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+      if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -833,9 +884,10 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
     unsigned int count = lenM1 + 1;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+      if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -856,7 +908,7 @@
 };
 
 /* An array with sorted elements.  Supports binary searching. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
   hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
@@ -902,11 +954,14 @@
   { return *as_array ().bsearch (x, &not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
+template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
+
 /*
  * Binary-search arrays
  */
@@ -1015,10 +1070,10 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
+      if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -1026,18 +1081,15 @@
   template <typename T>
   const Type *bsearch (const T &key) const
   {
-    unsigned int size = header.unitSize;
-    int min = 0, max = (int) get_length () - 1;
-    while (min <= max)
-    {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
-      int c = p->cmp (key);
-      if (c < 0) max = mid - 1;
-      else if (c > 0) min = mid + 1;
-      else return p;
-    }
-    return nullptr;
+    unsigned pos;
+    return hb_bsearch_impl (&pos,
+			    key,
+			    (const void *) bytesZ,
+			    get_length (),
+			    header.unitSize,
+			    _hb_cmp_method<T, Type>)
+	   ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
+	   : nullptr;
   }
 
   private:
diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh
index 6735c74..180c87c 100644
--- a/src/hb-ot-cff-common.hh
+++ b/src/hb-ot-cff-common.hh
@@ -38,6 +38,9 @@
 
 #define CFF_UNDEF_CODE  0xFFFFFFFF
 
+using objidx_t = hb_serialize_context_t::objidx_t;
+using whence_t = hb_serialize_context_t::whence_t;
+
 /* utility macro */
 template<typename Type>
 static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
@@ -89,11 +92,14 @@
   unsigned int offset_array_size () const
   { return calculate_offset_array_size (offSize, count); }
 
-  static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count,
-						 unsigned int dataSize)
+  CFFIndex *copy (hb_serialize_context_t *c) const
   {
-    if (count == 0) return COUNT::static_size;
-    return min_size + calculate_offset_array_size (offSize_, count) + dataSize;
+    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)
@@ -101,7 +107,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size ();
     CFFIndex *dest = c->allocate_size<CFFIndex> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -114,13 +120,13 @@
     if (byteArray.length == 0)
     {
       COUNT *dest = c->allocate_min<COUNT> ();
-      if (unlikely (dest == nullptr)) return_trace (false);
+      if (unlikely (!dest)) return_trace (false);
       *dest = 0;
     }
     else
     {
       /* serialize CFFIndex header */
-      if (unlikely (!c->extend_min (*this))) return_trace (false);
+      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))))
@@ -139,10 +145,9 @@
       /* serialize data */
       for (unsigned int i = 0; i < byteArray.length; i++)
       {
-      	const byte_str_t &bs = byteArray[i];
-	unsigned char  *dest = c->allocate_size<unsigned char> (bs.length);
-	if (unlikely (dest == nullptr))
-	  return_trace (false);
+	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);
       }
     }
@@ -163,6 +168,71 @@
     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)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned total = + it | hb_reduce (hb_add, 0);
+    unsigned off_size = calcOffSize (total);
+
+    /* serialize CFFIndex header */
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    this->count = it.len ();
+    this->offSize = off_size;
+    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
+      return_trace (false);
+
+    /* serialize indices */
+    unsigned int offset = 1;
+    unsigned int i = 0;
+    for (unsigned _ : +it)
+    {
+      CFFIndex<COUNT>::set_offset_at (i++, offset);
+      offset += _;
+    }
+    CFFIndex<COUNT>::set_offset_at (i, offset);
+
+    return_trace (true);
+  }
+
   void set_offset_at (unsigned int index, unsigned int offset)
   {
     HBUINT8 *p = offsets + offSize * index + offSize;
@@ -189,7 +259,7 @@
   unsigned int length_at (unsigned int index) const
   {
     if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
-	          (offset_at (index + 1) > offset_at (count))))
+		  (offset_at (index + 1) > offset_at (count))))
       return 0;
     return offset_at (index + 1) - offset_at (index);
   }
@@ -237,7 +307,8 @@
   public:
   COUNT		count;		/* Number of object data. Note there are (count+1) offsets */
   HBUINT8	offSize;	/* The byte size of each offset in the offsets array. */
-  HBUINT8	offsets[HB_VAR_ARRAY];	/* The array of (count + 1) offsets into objects array (1-base). */
+  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);
@@ -250,7 +321,7 @@
   {
     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);
+    return Null (byte_str_t);
   }
 
   template <typename DATA, typename PARAM1, typename PARAM2>
@@ -264,7 +335,7 @@
   {
     TRACE_SERIALIZE (this);
     /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     this->count = dataArrayLen;
     this->offSize = offSize_;
     if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
@@ -284,85 +355,41 @@
     for (unsigned int i = 0; i < dataArrayLen; i++)
     {
       TYPE *dest = c->start_embed<TYPE> ();
-      if (unlikely (dest == nullptr ||
-		    !dest->serialize (c, dataArray[i], param1, param2)))
+      if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
 	return_trace (false);
     }
     return_trace (true);
   }
-
-  /* in parallel to above */
-  template <typename DATA, typename PARAM>
-  static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
-						 const DATA *dataArray,
-						 unsigned int dataArrayLen,
-						 hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
-						 const PARAM &param)
-  {
-    /* determine offset size */
-    unsigned int totalDataSize = 0;
-    for (unsigned int i = 0; i < dataArrayLen; i++)
-    {
-      unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
-      dataSizeArray[i] = dataSize;
-      totalDataSize += dataSize;
-    }
-    offSize_ = calcOffSize (totalDataSize);
-
-    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
-  }
 };
 
 /* Top Dict, Font Dict, Private Dict */
 struct Dict : UnsizedByteStr
 {
-  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
+  template <typename DICTVAL, typename OP_SERIALIZER, typename ...Ts>
   bool serialize (hb_serialize_context_t *c,
 		  const DICTVAL &dictval,
 		  OP_SERIALIZER& opszr,
-		  PARAM& param)
+		  Ts&&... ds)
   {
     TRACE_SERIALIZE (this);
     for (unsigned int i = 0; i < dictval.get_count (); i++)
-      if (unlikely (!opszr.serialize (c, dictval[i], param)))
+      if (unlikely (!opszr.serialize (c, dictval[i], std::forward<Ts> (ds)...)))
 	return_trace (false);
 
     return_trace (true);
   }
 
-  /* in parallel to above */
-  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
-  static unsigned int calculate_serialized_size (const DICTVAL &dictval,
-						 OP_SERIALIZER& opszr,
-						 PARAM& param)
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dictval.get_count (); i++)
-      size += opszr.calculate_serialized_size (dictval[i], param);
-    return size;
-  }
-
-  template <typename DICTVAL, typename OP_SERIALIZER>
-  static unsigned int calculate_serialized_size (const DICTVAL &dictval,
-						 OP_SERIALIZER& opszr)
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dictval.get_count (); i++)
-      size += opszr.calculate_serialized_size (dictval[i]);
-    return size;
-  }
-
-  template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
+  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<INTTYPE, minVal, maxVal> (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));
-    if (unlikely (p == nullptr)) return_trace (false);
+    if (unlikely (!p)) return_trace (false);
     if (Is_OpCode_ESC (op))
     {
       *p = OpCode_escape;
@@ -373,17 +400,28 @@
     return_trace (true);
   }
 
-  static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
+  template <typename V>
+  static bool serialize_int4_op (hb_serialize_context_t *c, op_code_t op, V value)
+  { return serialize_int_op<HBINT32> (c, op, value, OpCode_longintdict); }
 
-  static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
+  template <typename V>
+  static bool serialize_int2_op (hb_serialize_context_t *c, op_code_t op, V value)
+  { return serialize_int_op<HBINT16> (c, op, value, OpCode_shortint); }
 
-  static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_uint4_op (c, op, value); }
+  template <typename T, int int_op>
+  static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence)
+  {
+    T &ofs = *(T *) (c->head + OpCode_Size (int_op));
+    if (unlikely (!serialize_int_op<T> (c, op, 0, int_op))) return false;
+    c->add_link (ofs, link, whence);
+    return true;
+  }
 
-  static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_uint2_op (c, op, value); }
+  static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
+  { return serialize_link_op<HBINT32, OpCode_longintdict> (c, op, link, whence); }
+
+  static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
+  { return serialize_link_op<HBINT16, OpCode_shortint> (c, op, link, whence); }
 };
 
 struct TopDict : Dict {};
@@ -392,105 +430,39 @@
 
 struct table_info_t
 {
-  void init () { offSize = offset = size = 0; }
+  void init () { offset = size = 0; link = 0; }
 
   unsigned int    offset;
   unsigned int    size;
-  unsigned int    offSize;
+  objidx_t	  link;
 };
 
 template <typename COUNT>
 struct FDArray : CFFIndexOf<COUNT, FontDict>
 {
-  /* used by CFF1 */
-  template <typename DICTVAL, typename OP_SERIALIZER>
+  template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
   bool serialize (hb_serialize_context_t *c,
-		  unsigned int offSize_,
-		  const hb_vector_t<DICTVAL> &fontDicts,
+		  Iterator it,
 		  OP_SERIALIZER& opszr)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count = fontDicts.length;
-    this->offSize = offSize_;
-    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
-      return_trace (false);
 
-    /* serialize font dict offsets */
-    unsigned int offset = 1;
-    unsigned int fid = 0;
-    for (; fid < fontDicts.length; fid++)
-    {
-      CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-      offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
-    }
-    CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-
-    /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.length; i++)
+    /* serialize INDEX data */
+    hb_vector_t<unsigned> sizes;
+    c->push ();
+    + it
+    | hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
     {
       FontDict *dict = c->start_embed<FontDict> ();
-      if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
-	return_trace (false);
-    }
-    return_trace (true);
-  }
+		dict->serialize (c, _.first, opszr, _.second);
+		return c->head - (const char*)dict;
+	      })
+    | hb_sink (sizes)
+    ;
+    c->pop_pack (false);
 
-  /* used by CFF2 */
-  template <typename DICTVAL, typename OP_SERIALIZER>
-  bool serialize (hb_serialize_context_t *c,
-		  unsigned int offSize_,
-		  const hb_vector_t<DICTVAL> &fontDicts,
-		  unsigned int fdCount,
-		  const hb_inc_bimap_t &fdmap,
-		  OP_SERIALIZER& opszr,
-		  const hb_vector_t<table_info_t> &privateInfos)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count = fdCount;
-    this->offSize = offSize_;
-    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
-      return_trace (false);
-
-    /* serialize font dict offsets */
-    unsigned int  offset = 1;
-    unsigned int  fid = 0;
-    for (unsigned i = 0; i < fontDicts.length; i++)
-      if (fdmap.has (i))
-      {
-      	if (unlikely (fid >= fdCount)) return_trace (false);
-	CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
-	offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
-      }
-    CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-
-    /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.length; i++)
-      if (fdmap.has (i))
-      {
-	FontDict *dict = c->start_embed<FontDict> ();
-	if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
-	  return_trace (false);
-      }
-    return_trace (true);
-  }
-
-  /* in parallel to above */
-  template <typename OP_SERIALIZER, typename DICTVAL>
-  static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
-						 const hb_vector_t<DICTVAL> &fontDicts,
-						 unsigned int fdCount,
-						 const hb_inc_bimap_t &fdmap,
-						 OP_SERIALIZER& opszr)
-  {
-    unsigned int dictsSize = 0;
-    for (unsigned int i = 0; i < fontDicts.len; i++)
-      if (fdmap.has (i))
-	dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
-
-    offSize_ = calcOffSize (dictsSize);
-    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
+    /* serialize INDEX header */
+    return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
   }
 };
 
@@ -544,7 +516,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) ||
-    		  (nRanges () == 0) || ranges[0].first != 0))
+		  (nRanges () == 0) || ranges[0].first != 0))
       return_trace (false);
 
     for (unsigned int i = 1; i < nRanges (); i++)
@@ -588,14 +560,11 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     FDSelect *dest = c->allocate_size<FDSelect> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (unsigned int num_glyphs) const
-  { return get_size (num_glyphs); }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
     switch (format)
diff --git a/src/hb-ot-cff1-std-str.hh b/src/hb-ot-cff1-std-str.hh
new file mode 100644
index 0000000..65d56ae
--- /dev/null
+++ b/src/hb-ot-cff1-std-str.hh
@@ -0,0 +1,425 @@
+/*
+ * Copyright © 2019  Adobe, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_OT_CFF1_STD_STR_HH
+#if 0 /* Make checks happy. */
+#define HB_OT_CFF1_STD_STR_HH
+#include "hb.hh"
+#endif
+
+_S(".notdef")
+_S("space")
+_S("exclam")
+_S("quotedbl")
+_S("numbersign")
+_S("dollar")
+_S("percent")
+_S("ampersand")
+_S("quoteright")
+_S("parenleft")
+_S("parenright")
+_S("asterisk")
+_S("plus")
+_S("comma")
+_S("hyphen")
+_S("period")
+_S("slash")
+_S("zero")
+_S("one")
+_S("two")
+_S("three")
+_S("four")
+_S("five")
+_S("six")
+_S("seven")
+_S("eight")
+_S("nine")
+_S("colon")
+_S("semicolon")
+_S("less")
+_S("equal")
+_S("greater")
+_S("question")
+_S("at")
+_S("A")
+_S("B")
+_S("C")
+_S("D")
+_S("E")
+_S("F")
+_S("G")
+_S("H")
+_S("I")
+_S("J")
+_S("K")
+_S("L")
+_S("M")
+_S("N")
+_S("O")
+_S("P")
+_S("Q")
+_S("R")
+_S("S")
+_S("T")
+_S("U")
+_S("V")
+_S("W")
+_S("X")
+_S("Y")
+_S("Z")
+_S("bracketleft")
+_S("backslash")
+_S("bracketright")
+_S("asciicircum")
+_S("underscore")
+_S("quoteleft")
+_S("a")
+_S("b")
+_S("c")
+_S("d")
+_S("e")
+_S("f")
+_S("g")
+_S("h")
+_S("i")
+_S("j")
+_S("k")
+_S("l")
+_S("m")
+_S("n")
+_S("o")
+_S("p")
+_S("q")
+_S("r")
+_S("s")
+_S("t")
+_S("u")
+_S("v")
+_S("w")
+_S("x")
+_S("y")
+_S("z")
+_S("braceleft")
+_S("bar")
+_S("braceright")
+_S("asciitilde")
+_S("exclamdown")
+_S("cent")
+_S("sterling")
+_S("fraction")
+_S("yen")
+_S("florin")
+_S("section")
+_S("currency")
+_S("quotesingle")
+_S("quotedblleft")
+_S("guillemotleft")
+_S("guilsinglleft")
+_S("guilsinglright")
+_S("fi")
+_S("fl")
+_S("endash")
+_S("dagger")
+_S("daggerdbl")
+_S("periodcentered")
+_S("paragraph")
+_S("bullet")
+_S("quotesinglbase")
+_S("quotedblbase")
+_S("quotedblright")
+_S("guillemotright")
+_S("ellipsis")
+_S("perthousand")
+_S("questiondown")
+_S("grave")
+_S("acute")
+_S("circumflex")
+_S("tilde")
+_S("macron")
+_S("breve")
+_S("dotaccent")
+_S("dieresis")
+_S("ring")
+_S("cedilla")
+_S("hungarumlaut")
+_S("ogonek")
+_S("caron")
+_S("emdash")
+_S("AE")
+_S("ordfeminine")
+_S("Lslash")
+_S("Oslash")
+_S("OE")
+_S("ordmasculine")
+_S("ae")
+_S("dotlessi")
+_S("lslash")
+_S("oslash")
+_S("oe")
+_S("germandbls")
+_S("onesuperior")
+_S("logicalnot")
+_S("mu")
+_S("trademark")
+_S("Eth")
+_S("onehalf")
+_S("plusminus")
+_S("Thorn")
+_S("onequarter")
+_S("divide")
+_S("brokenbar")
+_S("degree")
+_S("thorn")
+_S("threequarters")
+_S("twosuperior")
+_S("registered")
+_S("minus")
+_S("eth")
+_S("multiply")
+_S("threesuperior")
+_S("copyright")
+_S("Aacute")
+_S("Acircumflex")
+_S("Adieresis")
+_S("Agrave")
+_S("Aring")
+_S("Atilde")
+_S("Ccedilla")
+_S("Eacute")
+_S("Ecircumflex")
+_S("Edieresis")
+_S("Egrave")
+_S("Iacute")
+_S("Icircumflex")
+_S("Idieresis")
+_S("Igrave")
+_S("Ntilde")
+_S("Oacute")
+_S("Ocircumflex")
+_S("Odieresis")
+_S("Ograve")
+_S("Otilde")
+_S("Scaron")
+_S("Uacute")
+_S("Ucircumflex")
+_S("Udieresis")
+_S("Ugrave")
+_S("Yacute")
+_S("Ydieresis")
+_S("Zcaron")
+_S("aacute")
+_S("acircumflex")
+_S("adieresis")
+_S("agrave")
+_S("aring")
+_S("atilde")
+_S("ccedilla")
+_S("eacute")
+_S("ecircumflex")
+_S("edieresis")
+_S("egrave")
+_S("iacute")
+_S("icircumflex")
+_S("idieresis")
+_S("igrave")
+_S("ntilde")
+_S("oacute")
+_S("ocircumflex")
+_S("odieresis")
+_S("ograve")
+_S("otilde")
+_S("scaron")
+_S("uacute")
+_S("ucircumflex")
+_S("udieresis")
+_S("ugrave")
+_S("yacute")
+_S("ydieresis")
+_S("zcaron")
+_S("exclamsmall")
+_S("Hungarumlautsmall")
+_S("dollaroldstyle")
+_S("dollarsuperior")
+_S("ampersandsmall")
+_S("Acutesmall")
+_S("parenleftsuperior")
+_S("parenrightsuperior")
+_S("twodotenleader")
+_S("onedotenleader")
+_S("zerooldstyle")
+_S("oneoldstyle")
+_S("twooldstyle")
+_S("threeoldstyle")
+_S("fouroldstyle")
+_S("fiveoldstyle")
+_S("sixoldstyle")
+_S("sevenoldstyle")
+_S("eightoldstyle")
+_S("nineoldstyle")
+_S("commasuperior")
+_S("threequartersemdash")
+_S("periodsuperior")
+_S("questionsmall")
+_S("asuperior")
+_S("bsuperior")
+_S("centsuperior")
+_S("dsuperior")
+_S("esuperior")
+_S("isuperior")
+_S("lsuperior")
+_S("msuperior")
+_S("nsuperior")
+_S("osuperior")
+_S("rsuperior")
+_S("ssuperior")
+_S("tsuperior")
+_S("ff")
+_S("ffi")
+_S("ffl")
+_S("parenleftinferior")
+_S("parenrightinferior")
+_S("Circumflexsmall")
+_S("hyphensuperior")
+_S("Gravesmall")
+_S("Asmall")
+_S("Bsmall")
+_S("Csmall")
+_S("Dsmall")
+_S("Esmall")
+_S("Fsmall")
+_S("Gsmall")
+_S("Hsmall")
+_S("Ismall")
+_S("Jsmall")
+_S("Ksmall")
+_S("Lsmall")
+_S("Msmall")
+_S("Nsmall")
+_S("Osmall")
+_S("Psmall")
+_S("Qsmall")
+_S("Rsmall")
+_S("Ssmall")
+_S("Tsmall")
+_S("Usmall")
+_S("Vsmall")
+_S("Wsmall")
+_S("Xsmall")
+_S("Ysmall")
+_S("Zsmall")
+_S("colonmonetary")
+_S("onefitted")
+_S("rupiah")
+_S("Tildesmall")
+_S("exclamdownsmall")
+_S("centoldstyle")
+_S("Lslashsmall")
+_S("Scaronsmall")
+_S("Zcaronsmall")
+_S("Dieresissmall")
+_S("Brevesmall")
+_S("Caronsmall")
+_S("Dotaccentsmall")
+_S("Macronsmall")
+_S("figuredash")
+_S("hypheninferior")
+_S("Ogoneksmall")
+_S("Ringsmall")
+_S("Cedillasmall")
+_S("questiondownsmall")
+_S("oneeighth")
+_S("threeeighths")
+_S("fiveeighths")
+_S("seveneighths")
+_S("onethird")
+_S("twothirds")
+_S("zerosuperior")
+_S("foursuperior")
+_S("fivesuperior")
+_S("sixsuperior")
+_S("sevensuperior")
+_S("eightsuperior")
+_S("ninesuperior")
+_S("zeroinferior")
+_S("oneinferior")
+_S("twoinferior")
+_S("threeinferior")
+_S("fourinferior")
+_S("fiveinferior")
+_S("sixinferior")
+_S("seveninferior")
+_S("eightinferior")
+_S("nineinferior")
+_S("centinferior")
+_S("dollarinferior")
+_S("periodinferior")
+_S("commainferior")
+_S("Agravesmall")
+_S("Aacutesmall")
+_S("Acircumflexsmall")
+_S("Atildesmall")
+_S("Adieresissmall")
+_S("Aringsmall")
+_S("AEsmall")
+_S("Ccedillasmall")
+_S("Egravesmall")
+_S("Eacutesmall")
+_S("Ecircumflexsmall")
+_S("Edieresissmall")
+_S("Igravesmall")
+_S("Iacutesmall")
+_S("Icircumflexsmall")
+_S("Idieresissmall")
+_S("Ethsmall")
+_S("Ntildesmall")
+_S("Ogravesmall")
+_S("Oacutesmall")
+_S("Ocircumflexsmall")
+_S("Otildesmall")
+_S("Odieresissmall")
+_S("OEsmall")
+_S("Oslashsmall")
+_S("Ugravesmall")
+_S("Uacutesmall")
+_S("Ucircumflexsmall")
+_S("Udieresissmall")
+_S("Yacutesmall")
+_S("Thornsmall")
+_S("Ydieresissmall")
+_S("001.000")
+_S("001.001")
+_S("001.002")
+_S("001.003")
+_S("Black")
+_S("Bold")
+_S("Book")
+_S("Light")
+_S("Medium")
+_S("Regular")
+_S("Roman")
+_S("Semibold")
+
+#endif /* HB_OT_CFF1_STD_STR_HH */
diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc
index 55abd11..3298fa3 100644
--- a/src/hb-ot-cff1-table.cc
+++ b/src/hb-ot-cff1-table.cc
@@ -28,11 +28,25 @@
 
 #ifndef HB_NO_CFF
 
+#include "hb-draw.hh"
+#include "hb-algs.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-cff1-interp-cs.hh"
 
 using namespace CFF;
 
+struct sid_to_gid_t
+{
+  uint16_t  sid;
+  uint8_t   gid;
+
+  int cmp (uint16_t a) const
+  {
+    if (a == sid) return 0;
+    return (a < sid) ? -1 : 1;
+  }
+};
+
 /* SID to code */
 static const uint8_t standard_encoding_to_code [] =
 {
@@ -104,6 +118,80 @@
   340,  341,  342,  343,  344,  345,  346
 };
 
+/* SID to glyph ID */
+static const sid_to_gid_t expert_charset_sid_to_gid [] =
+{
+    { 1, 1 },     { 13, 12 },   { 14, 13 },   { 15, 14 },
+    { 27, 26 },   { 28, 27 },   { 99, 15 },   { 109, 46 },
+    { 110, 47 },  { 150, 111 }, { 155, 101 }, { 158, 100 },
+    { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 },
+    { 230, 3 },   { 231, 4 },   { 232, 5 },   { 233, 6 },
+    { 234, 7 },   { 235, 8 },   { 236, 9 },   { 237, 10 },
+    { 238, 11 },  { 239, 16 },  { 240, 17 },  { 241, 18 },
+    { 242, 19 },  { 243, 20 },  { 244, 21 },  { 245, 22 },
+    { 246, 23 },  { 247, 24 },  { 248, 25 },  { 249, 28 },
+    { 250, 29 },  { 251, 30 },  { 252, 31 },  { 253, 32 },
+    { 254, 33 },  { 255, 34 },  { 256, 35 },  { 257, 36 },
+    { 258, 37 },  { 259, 38 },  { 260, 39 },  { 261, 40 },
+    { 262, 41 },  { 263, 42 },  { 264, 43 },  { 265, 44 },
+    { 266, 45 },  { 267, 48 },  { 268, 49 },  { 269, 50 },
+    { 270, 51 },  { 271, 52 },  { 272, 53 },  { 273, 54 },
+    { 274, 55 },  { 275, 56 },  { 276, 57 },  { 277, 58 },
+    { 278, 59 },  { 279, 60 },  { 280, 61 },  { 281, 62 },
+    { 282, 63 },  { 283, 64 },  { 284, 65 },  { 285, 66 },
+    { 286, 67 },  { 287, 68 },  { 288, 69 },  { 289, 70 },
+    { 290, 71 },  { 291, 72 },  { 292, 73 },  { 293, 74 },
+    { 294, 75 },  { 295, 76 },  { 296, 77 },  { 297, 78 },
+    { 298, 79 },  { 299, 80 },  { 300, 81 },  { 301, 82 },
+    { 302, 83 },  { 303, 84 },  { 304, 85 },  { 305, 86 },
+    { 306, 87 },  { 307, 88 },  { 308, 89 },  { 309, 90 },
+    { 310, 91 },  { 311, 92 },  { 312, 93 },  { 313, 94 },
+    { 314, 95 },  { 315, 96 },  { 316, 97 },  { 317, 98 },
+    { 318, 99 },  { 319, 103 }, { 320, 104 }, { 321, 105 },
+    { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 },
+    { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 },
+    { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 },
+    { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 },
+    { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 },
+    { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 },
+    { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 },
+    { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 },
+    { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 },
+    { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 },
+    { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 },
+    { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 },
+    { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 },
+    { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 },
+    { 378, 165 }
+};
+
+/* SID to glyph ID */
+static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
+{
+  { 1, 1 },       { 13, 8 },      { 14, 9 },      { 15, 10 },
+  { 27, 22 },     { 28, 23 },     { 99, 11 },     { 109, 41 },
+  { 110, 42 },    { 150, 64 },    { 155, 55 },    { 158, 54 },
+  { 163, 56 },    { 164, 65 },    { 169, 66 },    { 231, 2 },
+  { 232, 3 },     { 235, 4 },     { 236, 5 },     { 237, 6 },
+  { 238, 7 },     { 239, 12 },    { 240, 13 },    { 241, 14 },
+  { 242, 15 },    { 243, 16 },    { 244, 17 },    { 245, 18 },
+  { 246, 19 },    { 247, 20 },    { 248, 21 },    { 249, 24 },
+  { 250, 25 },    { 251, 26 },    { 253, 27 },    { 254, 28 },
+  { 255, 29 },    { 256, 30 },    { 257, 31 },    { 258, 32 },
+  { 259, 33 },    { 260, 34 },    { 261, 35 },    { 262, 36 },
+  { 263, 37 },    { 264, 38 },    { 265, 39 },    { 266, 40 },
+  { 267, 43 },    { 268, 44 },    { 269, 45 },    { 270, 46 },
+  { 272, 47 },    { 300, 48 },    { 301, 49 },    { 302, 50 },
+  { 305, 51 },    { 314, 52 },    { 315, 53 },    { 320, 57 },
+  { 321, 58 },    { 322, 59 },    { 323, 60 },    { 324, 61 },
+  { 325, 62 },    { 326, 63 },    { 327, 67 },    { 328, 68 },
+  { 329, 69 },    { 330, 70 },    { 331, 71 },    { 332, 72 },
+  { 333, 73 },    { 334, 74 },    { 335, 75 },    { 336, 76 },
+  { 337, 77 },    { 338, 78 },    { 339, 79 },    { 340, 80 },
+  { 341, 81 },    { 342, 82 },    { 343, 83 },    { 344, 84 },
+  { 345, 85 },    { 346, 86 }
+};
+
 /* code to SID */
 static const uint8_t standard_encoding_to_sid [] =
 {
@@ -157,6 +245,18 @@
     return 0;
 }
 
+hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
+{
+  const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
+  return pair ? pair->gid : 0;
+}
+
+hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
+{
+  const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
+  return pair ? pair->gid : 0;
+}
+
 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
 {
   if (code < ARRAY_LENGTH (standard_encoding_to_sid))
@@ -326,7 +426,7 @@
   else
   {
     extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
-    extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
+    extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing;
   }
   if (bounds.min.y >= bounds.max.y)
   {
@@ -336,12 +436,136 @@
   else
   {
     extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
-    extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
+    extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing;
   }
 
   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_)
+  {
+    draw_helper = &draw_helper_;
+    cff = cff_;
+    font = font_;
+    delta = delta_;
+  }
+
+  void move_to (const point_t &p)
+  {
+    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 ()));
+  }
+
+  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 ()));
+  }
+
+  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
+  {
+    point_t point1 = p1, point2 = p2, point3 = p3;
+    if (delta)
+    {
+      point1.move (*delta);
+      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 ()));
+  }
+
+  void end_path () { draw_helper->end_path (); }
+
+  hb_font_t *font;
+  draw_helper_t *draw_helper;
+  point_t *delta;
+
+  const OT::cff1::accelerator_t *cff;
+};
+
+struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
+{
+  static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
+  {
+    param.move_to (pt);
+    env.moveto (pt);
+  }
+
+  static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
+  {
+    param.line_to (pt1);
+    env.moveto (pt1);
+  }
+
+  static void curve (cff1_cs_interp_env_t &env, cff1_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);
+  }
+};
+
+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);
+
+struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
+{
+  static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
+  {
+    /* End previous path */
+    param.end_path ();
+
+    unsigned int n = env.argStack.get_count ();
+    point_t delta;
+    delta.x = env.argStack[n-4];
+    delta.y = env.argStack[n-3];
+    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
+    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
+
+    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))))
+      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)
+{
+  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);
+  if (unlikely (!interp.interpret (param))) return false;
+
+  /* Let's end the path specially since it is called inside seac also */
+  param.end_path ();
+
+  return true;
+}
+
+bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) 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);
+}
+#endif
+
 struct get_seac_param_t
 {
   void init (const OT::cff1::accelerator_t *_cff)
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index ad20651..5dd183e 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -27,15 +27,21 @@
 #ifndef HB_OT_CFF1_TABLE_HH
 #define HB_OT_CFF1_TABLE_HH
 
-#include "hb-ot-head-table.hh"
 #include "hb-ot-cff-common.hh"
 #include "hb-subset-cff1.hh"
+#include "hb-draw.hh"
+
+#define HB_STRING_ARRAY_NAME cff1_std_strings
+#define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh"
+#include "hb-string-array.hh"
+#undef HB_STRING_ARRAY_LIST
+#undef HB_STRING_ARRAY_NAME
 
 namespace CFF {
 
 /*
  * CFF -- Compact Font Format (CFF)
- * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
+ * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
  */
 #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
 
@@ -49,7 +55,6 @@
 
 typedef CFFIndex<HBUINT16> CFF1Index;
 typedef CFF1Index          CFF1CharStrings;
-typedef FDArray<HBUINT16>  CFF1FDArray;
 typedef Subrs<HBUINT16>    CFF1Subrs;
 
 struct CFF1FDSelect : FDSelect {};
@@ -169,7 +174,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size ();
     Encoding *dest = c->allocate_size<Encoding> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -182,14 +187,14 @@
 		  const hb_vector_t<code_pair_t>& supp_codes)
   {
     TRACE_SERIALIZE (this);
-    Encoding *dest = c->extend_min (*this);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    Encoding *dest = c->extend_min (this);
+    if (unlikely (!dest)) return_trace (false);
     dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
     switch (format) {
     case 0:
     {
       Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count);
-      if (unlikely (fmt0 == nullptr)) return_trace (false);
+      if (unlikely (!fmt0)) return_trace (false);
       fmt0->nCodes () = enc_count;
       unsigned int glyph = 0;
       for (unsigned int i = 0; i < code_ranges.length; i++)
@@ -206,7 +211,7 @@
     case 1:
     {
       Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length);
-      if (unlikely (fmt1 == nullptr)) return_trace (false);
+      if (unlikely (!fmt1)) return_trace (false);
       fmt1->nRanges () = code_ranges.length;
       for (unsigned int i = 0; i < code_ranges.length; i++)
       {
@@ -223,7 +228,7 @@
     if (supp_codes.length)
     {
       CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length);
-      if (unlikely (suppData == nullptr)) return_trace (false);
+      if (unlikely (!suppData)) return_trace (false);
       suppData->nSups () = supp_codes.length;
       for (unsigned int i = 0; i < supp_codes.length; i++)
       {
@@ -235,23 +240,6 @@
     return_trace (true);
   }
 
-  /* parallel to above: calculate the size of a subset Encoding */
-  static unsigned int calculate_serialized_size (uint8_t format,
-						 unsigned int enc_count,
-						 unsigned int supp_count)
-  {
-    unsigned int size = min_size;
-    switch (format)
-    {
-    case 0: size += Encoding0::min_size + HBUINT8::static_size * enc_count; break;
-    case 1: size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; break;
-    default:return 0;
-    }
-    if (supp_count > 0)
-      size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count;
-    return size;
-  }
-
   unsigned int get_size () const
   {
     unsigned int size = min_size;
@@ -414,7 +402,7 @@
     for (unsigned int i = 0;; i++)
     {
       if (glyph >= num_glyphs)
-      	return 0;
+	return 0;
       if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft))
 	return glyph + (sid - ranges[i].first);
       glyph += (ranges[i].nLeft + 1);
@@ -457,7 +445,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     Charset *dest = c->allocate_size<Charset> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -469,15 +457,15 @@
 		  const hb_vector_t<code_pair_t>& sid_ranges)
   {
     TRACE_SERIALIZE (this);
-    Charset *dest = c->extend_min (*this);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    Charset *dest = c->extend_min (this);
+    if (unlikely (!dest)) return_trace (false);
     dest->format = format;
     switch (format)
     {
     case 0:
     {
       Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
-      if (unlikely (fmt0 == nullptr)) return_trace (false);
+      if (unlikely (!fmt0)) return_trace (false);
       unsigned int glyph = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
@@ -491,10 +479,10 @@
     case 1:
     {
       Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
-      if (unlikely (fmt1 == nullptr)) return_trace (false);
+      if (unlikely (!fmt1)) return_trace (false);
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-      	if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
+	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;
@@ -505,10 +493,10 @@
     case 2:
     {
       Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
-      if (unlikely (fmt2 == nullptr)) return_trace (false);
+      if (unlikely (!fmt2)) return_trace (false);
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
-      	if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
+	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;
@@ -520,19 +508,6 @@
     return_trace (true);
   }
 
-  /* parallel to above: calculate the size of a subset Charset */
-  static unsigned int calculate_serialized_size (uint8_t format,
-						 unsigned int count)
-  {
-    switch (format)
-    {
-    case 0: return min_size + Charset0::min_size + HBUINT16::static_size * (count - 1);
-    case 1: return min_size + Charset1::min_size + Charset1_Range::static_size * count;
-    case 2: return min_size + Charset2::min_size + Charset2_Range::static_size * count;
-    default:return 0;
-    }
-  }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
     switch (format)
@@ -544,8 +519,9 @@
     }
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
   {
+    if (unlikely (glyph >= num_glyphs)) return 0;
     switch (format)
     {
     case 0: return u.format0.get_sid (glyph);
@@ -594,7 +570,7 @@
 struct CFF1StringIndex : CFF1Index
 {
   bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
-		  unsigned int offSize_, const hb_inc_bimap_t &sidmap)
+		  const hb_inc_bimap_t &sidmap)
   {
     TRACE_SERIALIZE (this);
     if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
@@ -612,30 +588,14 @@
     for (unsigned int i = 0; i < strings.count; i++)
     {
       hb_codepoint_t  j = sidmap[i];
-      if (j != CFF_UNDEF_CODE)
+      if (j != HB_MAP_VALUE_INVALID)
 	bytesArray[j] = strings[i];
     }
 
-    bool result = CFF1Index::serialize (c, offSize_, bytesArray);
+    bool result = CFF1Index::serialize (c, bytesArray);
     bytesArray.fini ();
     return_trace (result);
   }
-
-  /* in parallel to above */
-  unsigned int calculate_serialized_size (unsigned int &offSize_ /*OUT*/, const hb_inc_bimap_t &sidmap) const
-  {
-    offSize_ = 0;
-    if ((count == 0) || (sidmap.get_population () == 0))
-      return count.static_size;
-
-    unsigned int dataSize = 0;
-    for (unsigned int i = 0; i < count; i++)
-      if (sidmap[i] != CFF_UNDEF_CODE)
-	dataSize += length_at (i);
-
-    offSize_ = calcOffSize(dataSize);
-    return CFF1Index::calculate_serialized_size (offSize_, sidmap.get_population (), dataSize);
-  }
 };
 
 struct cff1_top_dict_interp_env_t : num_interp_env_t
@@ -738,7 +698,7 @@
   unsigned int    EncodingOffset;
   unsigned int    CharsetOffset;
   unsigned int    FDSelectOffset;
-  table_info_t       privateDictInfo;
+  table_info_t    privateDictInfo;
 };
 
 struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
@@ -753,6 +713,7 @@
       case OpCode_Notice:
       case OpCode_Copyright:
       case OpCode_FullName:
+      case OpCode_FontName:
       case OpCode_FamilyName:
       case OpCode_Weight:
       case OpCode_PostScript:
@@ -880,21 +841,10 @@
   {
     dict_values_t<VAL>::init ();
     subrsOffset = 0;
-    localSubrs = &Null(CFF1Subrs);
+    localSubrs = &Null (CFF1Subrs);
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
-      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
-	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
-      else
-	size += dict_values_t<VAL>::get_value (i).str.length;
-    return size;
-  }
-
   unsigned int      subrsOffset;
   const CFF1Subrs    *localSubrs;
 };
@@ -997,6 +947,37 @@
 typedef CFF1Index CFF1NameIndex;
 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
 
+struct cff1_font_dict_values_mod_t
+{
+  cff1_font_dict_values_mod_t() { init (); }
+
+  void init () { init ( &Null (cff1_font_dict_values_t), CFF_UNDEF_SID ); }
+
+  void init (const cff1_font_dict_values_t *base_,
+	     unsigned int fontName_)
+  {
+    base = base_;
+    fontName = fontName_;
+    privateDictInfo.init ();
+  }
+
+  unsigned get_count () const { return base->get_count (); }
+
+  const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
+
+  const cff1_font_dict_values_t    *base;
+  table_info_t		   privateDictInfo;
+  unsigned int		fontName;
+};
+
+struct CFF1FDArray : FDArray<HBUINT16>
+{
+  /* FDArray::serialize() requires this partial specialization to compile */
+  template <typename ITER, typename OP_SERIALIZER>
+  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
+  { return FDArray<HBUINT16>::serialize<cff1_font_dict_values_mod_t, cff1_font_dict_values_mod_t> (c, it, opszr); }
+};
+
 } /* namespace CFF */
 
 namespace OT {
@@ -1031,7 +1012,7 @@
 
       const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
 
-      if (cff == &Null(OT::cff1))
+      if (cff == &Null (OT::cff1))
       { fini (); return; }
 
       nameIndex = &cff->nameIndex (cff);
@@ -1052,7 +1033,7 @@
       }
 
       if (is_predef_charset ())
-	charset = &Null(Charset);
+	charset = &Null (Charset);
       else
       {
 	charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
@@ -1064,16 +1045,30 @@
       {
 	fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
 	fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
-	if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
-	    (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
+	if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
+	    (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
 	{ fini (); return; }
 
 	fdCount = fdArray->count;
       }
       else
       {
-	fdArray = &Null(CFF1FDArray);
-	fdSelect = &Null(CFF1FDSelect);
+	fdArray = &Null (CFF1FDArray);
+	fdSelect = &Null (CFF1FDSelect);
+      }
+
+      encoding = &Null (Encoding);
+      if (is_CID ())
+      {
+	if (unlikely (charset == &Null (Charset))) { fini (); return; }
+      }
+      else
+      {
+	if (!is_predef_encoding ())
+	{
+	  encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
+	  if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+	}
       }
 
       stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
@@ -1086,14 +1081,15 @@
 
       charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
 
-      if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
+      if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
       { fini (); return; }
 
       num_glyphs = charStrings->count;
       if (num_glyphs != sc.get_num_glyphs ())
       { fini (); return; }
 
-      privateDicts.resize (fdCount);
+      if (unlikely (!privateDicts.resize (fdCount)))
+      { fini (); return; }
       for (unsigned int i = 0; i < fdCount; i++)
 	privateDicts[i].init ();
 
@@ -1104,14 +1100,14 @@
 	{
 	  byte_str_t fontDictStr = (*fdArray)[i];
 	  if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
-	  cff1_font_dict_values_t  *font;
+	  cff1_font_dict_values_t *font;
 	  cff1_font_dict_interpreter_t font_interp;
 	  font_interp.env.init (fontDictStr);
 	  font = fontDicts.push ();
-	  if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; }
+	  if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; }
 	  font->init ();
 	  if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
-	  PRIVDICTVAL  *priv = &privateDicts[i];
+	  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;
@@ -1120,15 +1116,15 @@
 	  if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
 	  priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-	  if (priv->localSubrs != &Null(CFF1Subrs) &&
+	  if (priv->localSubrs != &Null (CFF1Subrs) &&
 	      unlikely (!priv->localSubrs->sanitize (&sc)))
 	  { fini (); return; }
 	}
       }
       else  /* non-CID */
       {
-	cff1_top_dict_values_t  *font = &topDict;
-	PRIVDICTVAL  *priv = &privateDicts[0];
+	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; }
@@ -1138,7 +1134,7 @@
 	if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
 	priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-	if (priv->localSubrs != &Null(CFF1Subrs) &&
+	if (priv->localSubrs != &Null (CFF1Subrs) &&
 	    unlikely (!priv->localSubrs->sanitize (&sc)))
 	{ fini (); return; }
       }
@@ -1154,7 +1150,7 @@
       blob = nullptr;
     }
 
-    bool is_valid () const { return blob != nullptr; }
+    bool is_valid () const { return blob; }
     bool   is_CID () const { return topDict.is_CID (); }
 
     bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; }
@@ -1165,69 +1161,18 @@
       if (unlikely (sid == CFF_UNDEF_SID))
 	return 0;
 
-      if (charset != &Null(Charset))
+      if (charset != &Null (Charset))
 	return charset->get_glyph (sid, num_glyphs);
       else if ((topDict.CharsetOffset == ISOAdobeCharset)
 	      && (code <= 228 /*zcaron*/)) return sid;
       return 0;
     }
 
-    protected:
-    hb_blob_t	       *blob;
-    hb_sanitize_context_t   sc;
-
-    public:
-    const Charset	   *charset;
-    const CFF1NameIndex     *nameIndex;
-    const CFF1TopDictIndex  *topDictIndex;
-    const CFF1StringIndex   *stringIndex;
-    const CFF1Subrs	 *globalSubrs;
-    const CFF1CharStrings   *charStrings;
-    const CFF1FDArray       *fdArray;
-    const CFF1FDSelect      *fdSelect;
-    unsigned int	    fdCount;
-
-    cff1_top_dict_values_t       topDict;
-    hb_vector_t<cff1_font_dict_values_t>   fontDicts;
-    hb_vector_t<PRIVDICTVAL>	  privateDicts;
-
-    unsigned int	    num_glyphs;
-  };
-
-  struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
-  {
-    HB_INTERNAL bool get_extents (hb_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;
-  };
-
-  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t>
-  {
-    void init (hb_face_t *face)
-    {
-      SUPER::init (face);
-      if (blob == nullptr) return;
-
-      const OT::cff1 *cff = this->blob->as<OT::cff1> ();
-      encoding = &Null(Encoding);
-      if (is_CID ())
-      {
-	if (unlikely (charset == &Null(Charset))) { fini (); return; }
-      }
-      else
-      {
-	if (!is_predef_encoding ())
-	{
-	  encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
-	  if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
-	}
-      }
-    }
-
     bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
 
     hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
     {
-      if (encoding != &Null(Encoding))
+      if (encoding != &Null (Encoding))
 	return encoding->get_code (glyph);
       else
       {
@@ -1251,20 +1196,20 @@
 
     hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
     {
-      if (charset != &Null(Charset))
-	return charset->get_sid (glyph);
+      if (charset != &Null (Charset))
+	return charset->get_sid (glyph, num_glyphs);
       else
       {
 	hb_codepoint_t sid = 0;
 	switch (topDict.CharsetOffset)
 	{
-	  case  ISOAdobeCharset:
+	  case ISOAdobeCharset:
 	    if (glyph <= 228 /*zcaron*/) sid = glyph;
 	    break;
-	  case  ExpertCharset:
+	  case ExpertCharset:
 	    sid = lookup_expert_charset_for_sid (glyph);
 	    break;
-	  case  ExpertSubsetCharset:
+	  case ExpertSubsetCharset:
 	      sid = lookup_expert_subset_charset_for_sid (glyph);
 	    break;
 	  default:
@@ -1274,40 +1219,179 @@
       }
     }
 
-    const Encoding	  *encoding;
+    hb_codepoint_t sid_to_glyph (hb_codepoint_t sid) const
+    {
+      if (charset != &Null (Charset))
+	return charset->get_glyph (sid, num_glyphs);
+      else
+      {
+	hb_codepoint_t glyph = 0;
+	switch (topDict.CharsetOffset)
+	{
+	  case ISOAdobeCharset:
+	    if (sid <= 228 /*zcaron*/) glyph = sid;
+	    break;
+	  case ExpertCharset:
+	    glyph = lookup_expert_charset_for_glyph (sid);
+	    break;
+	  case ExpertSubsetCharset:
+	    glyph = lookup_expert_subset_charset_for_glyph (sid);
+	    break;
+	  default:
+	    break;
+	}
+	return glyph;
+      }
+    }
 
-    private:
-    typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER;
+    protected:
+    hb_blob_t	           *blob;
+    hb_sanitize_context_t   sc;
+
+    public:
+    const Encoding	    *encoding;
+    const Charset	    *charset;
+    const CFF1NameIndex     *nameIndex;
+    const CFF1TopDictIndex  *topDictIndex;
+    const CFF1StringIndex   *stringIndex;
+    const CFF1Subrs	    *globalSubrs;
+    const CFF1CharStrings   *charStrings;
+    const CFF1FDArray       *fdArray;
+    const CFF1FDSelect      *fdSelect;
+    unsigned int	     fdCount;
+
+    cff1_top_dict_values_t   topDict;
+    hb_vector_t<cff1_font_dict_values_t>
+			     fontDicts;
+    hb_vector_t<PRIVDICTVAL> privateDicts;
+
+    unsigned int	     num_glyphs;
   };
 
-  bool subset (hb_subset_plan_t *plan) const
+  struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
   {
-    hb_blob_t *cff_prime = nullptr;
+    void init (hb_face_t *face)
+    {
+      SUPER::init (face);
 
-    bool success = true;
-    if (hb_subset_cff1 (plan, &cff_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime);
-      hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
-      success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
-      hb_blob_destroy (head_blob);
-    } else {
-      success = false;
+      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 ();
     }
-    hb_blob_destroy (cff_prime);
 
-    return success;
-  }
+    void fini ()
+    {
+      glyph_names.fini ();
+
+      SUPER::fini ();
+    }
+
+    bool get_glyph_name (hb_codepoint_t glyph,
+			 char *buf, unsigned int buf_len) const
+    {
+      if (!buf) return true;
+      if (unlikely (!is_valid ())) return false;
+      if (is_CID()) return false;
+      hb_codepoint_t sid = glyph_to_sid (glyph);
+      const char *str;
+      size_t str_len;
+      if (sid < cff1_std_strings_length)
+      {
+	hb_bytes_t byte_str = cff1_std_strings (sid);
+	str = byte_str.arrayZ;
+	str_len = byte_str.length;
+      }
+      else
+      {
+	byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
+	str = (const char *)ubyte_str.arrayZ;
+	str_len = ubyte_str.length;
+      }
+      if (!str_len) return false;
+      unsigned int len = hb_min (buf_len - 1, str_len);
+      strncpy (buf, (const char*)str, len);
+      buf[len] = '\0';
+      return true;
+    }
+
+    bool get_glyph_from_name (const char *name, int len,
+			      hb_codepoint_t *glyph) const
+    {
+      if (len < 0) len = strlen (name);
+      if (unlikely (!len)) return false;
+
+      gname_t key = { hb_bytes_t (name, len), 0 };
+      const gname_t *gname = glyph_names.bsearch (key);
+      if (!gname) return false;
+      hb_codepoint_t gid = sid_to_glyph (gname->sid);
+      if (!gid && gname->sid) return false;
+      *glyph = gid;
+      return true;
+    }
+
+    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
+
+    private:
+    struct gname_t
+    {
+      hb_bytes_t	name;
+      uint16_t		sid;
+
+      static int cmp (const void *a_, const void *b_)
+      {
+	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);
+	int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen);
+	if (ret) return ret;
+	return a->name.length - b->name.length;
+      }
+
+      int cmp (const gname_t &a) const { return cmp (&a, this); }
+    };
+
+    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> {};
+
+  bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
 
   protected:
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph);
   HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph);
+  HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_glyph (hb_codepoint_t sid);
+  HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code);
 
   public:
   FixedVersion<HBUINT8> version;	  /* Version of CFF table. set to 0x0100u */
-  OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
+  NNOffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
   HBUINT8	       offSize;	  /* offset size (unused?) */
 
   public:
diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc
index a2242b7..879b7cd 100644
--- a/src/hb-ot-cff2-table.cc
+++ b/src/hb-ot-cff2-table.cc
@@ -30,6 +30,7 @@
 
 #include "hb-ot-cff2-table.hh"
 #include "hb-cff2-interp-cs.hh"
+#include "hb-draw.hh"
 
 using namespace CFF;
 
@@ -126,7 +127,7 @@
   else
   {
     extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
-    extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
+    extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing;
   }
   if (param.min_y >= param.max_y)
   {
@@ -136,11 +137,79 @@
   else
   {
     extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
-    extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
+    extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing;
   }
 
   return true;
 }
 
+#ifdef HB_EXPERIMENTAL_API
+struct cff2_path_param_t
+{
+  cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+  {
+    draw_helper = &draw_helper_;
+    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 ())); }
+
+  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 ())); }
+
+  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 ()));
+  }
+
+  protected:
+  draw_helper_t *draw_helper;
+  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>
+{
+  static void moveto (cff2_cs_interp_env_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)
+  {
+    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)
+  {
+    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> {};
+
+bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+{
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
+  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);
+  if (unlikely (!interp.interpret (param))) return false;
+  return true;
+}
+#endif
 
 #endif
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index 8646cde..829217f 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -27,9 +27,9 @@
 #ifndef HB_OT_CFF2_TABLE_HH
 #define HB_OT_CFF2_TABLE_HH
 
-#include "hb-ot-head-table.hh"
 #include "hb-ot-cff-common.hh"
 #include "hb-subset-cff2.hh"
+#include "hb-draw.hh"
 
 namespace CFF {
 
@@ -43,7 +43,6 @@
 template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
 
 typedef CFF2Index         CFF2CharStrings;
-typedef FDArray<HBUINT32> CFF2FDArray;
 typedef Subrs<HBUINT32>   CFF2Subrs;
 
 typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
@@ -56,14 +55,11 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (unsigned int num_glyphs) const
-  { return get_size (num_glyphs); }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
     switch (format)
@@ -127,7 +123,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size_ = varStore->get_size ();
     CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, varStore, size_);
     return_trace (true);
   }
@@ -150,26 +146,6 @@
   }
   void fini () { top_dict_values_t<>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < get_count (); i++)
-    {
-      op_code_t op = get_value (i).op;
-      switch (op)
-      {
-	case OpCode_vstore:
-	case OpCode_FDSelect:
-	  size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
-	  break;
-	default:
-	  size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i));
-	  break;
-      }
-    }
-    return size;
-  }
-
   unsigned int  vstoreOffset;
   unsigned int  FDSelectOffset;
 };
@@ -256,22 +232,11 @@
   {
     dict_values_t<VAL>::init ();
     subrsOffset = 0;
-    localSubrs = &Null(CFF2Subrs);
+    localSubrs = &Null (CFF2Subrs);
     ivs = 0;
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
-      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
-	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
-      else
-	size += dict_values_t<VAL>::get_value (i).str.length;
-    return size;
-  }
-
   unsigned int      subrsOffset;
   const CFF2Subrs   *localSubrs;
   unsigned int      ivs;
@@ -404,6 +369,14 @@
 typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
 typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
 
+struct CFF2FDArray : FDArray<HBUINT32>
+{
+  /* FDArray::serialize does not compile without this partial specialization */
+  template <typename ITER, typename OP_SERIALIZER>
+  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
+  { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
+};
+
 } /* namespace CFF */
 
 namespace OT {
@@ -438,7 +411,7 @@
 
       const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
 
-      if (cff2 == &Null(OT::cff2))
+      if (cff2 == &Null (OT::cff2))
       { fini (); return; }
 
       { /* parse top dict */
@@ -456,11 +429,11 @@
       fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
       fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
 
-      if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
-	  (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
-	  (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
-	  (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
-	  (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
+      if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
+	  (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
+	  (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
+	  (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
+	  (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
       { fini (); return; }
 
       num_glyphs = charStrings->count;
@@ -468,7 +441,8 @@
       { fini (); return; }
 
       fdCount = fdArray->count;
-      privateDicts.resize (fdCount);
+      if (!privateDicts.resize (fdCount))
+      { fini (); return; }
 
       /* parse font dicts and gather private dicts */
       for (unsigned int i = 0; i < fdCount; i++)
@@ -479,7 +453,7 @@
 	cff2_font_dict_interpreter_t font_interp;
 	font_interp.env.init (fontDictStr);
 	font = fontDicts.push ();
-	if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; }
+	if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; }
 	font->init ();
 	if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 
@@ -491,7 +465,7 @@
 	if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
 
 	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
-	if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
+	if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
 	  unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
 	{ fini (); return; }
       }
@@ -507,7 +481,7 @@
       blob = nullptr;
     }
 
-    bool is_valid () const { return blob != nullptr; }
+    bool is_valid () const { return blob; }
 
     protected:
     hb_blob_t			*blob;
@@ -533,27 +507,14 @@
     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
   };
 
   typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
 
-  bool subset (hb_subset_plan_t *plan) const
-  {
-    hb_blob_t *cff2_prime = nullptr;
-
-    bool success = true;
-    if (hb_subset_cff2 (plan, &cff2_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
-      hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
-      success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
-      hb_blob_destroy (head_blob);
-    } else {
-      success = false;
-    }
-    hb_blob_destroy (cff2_prime);
-
-    return success;
-  }
+  bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
 
   public:
   FixedVersion<HBUINT8>		version;	/* Version of CFF2 table. set to 0x0200u */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 9ebd8e4..c8a2af1 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -49,6 +49,12 @@
     *glyph = gid;
     return true;
   }
+
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   void collect_unicodes (hb_set_t *out) const
   {
     for (unsigned int i = 0; i < 256; i++)
@@ -56,6 +62,18 @@
 	out->add (i);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    for (unsigned i = 0; i < 256; i++)
+      if (glyphIdArray[i])
+      {
+	hb_codepoint_t glyph = glyphIdArray[i];
+	unicodes->add (i);
+	mapping->set (i, glyph);
+      }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -83,18 +101,16 @@
     HBUINT16 *endCode = c->start_embed<HBUINT16> ();
     hb_codepoint_t prev_endcp = 0xFFFF;
 
-    + it
-    | hb_apply ([&] (const hb_item_type<Iterator> _)
-		{
-		  if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
-		  {
-		    HBUINT16 end_code;
-		    end_code = prev_endcp;
-		    c->copy<HBUINT16> (end_code);
-		  }
-		  prev_endcp = _.first;
-		})
-    ;
+    for (const auto& _ : +it)
+    {
+      if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
+      {
+	HBUINT16 end_code;
+	end_code = prev_endcp;
+	c->copy<HBUINT16> (end_code);
+      }
+      prev_endcp = _.first;
+    }
 
     {
       // last endCode
@@ -121,19 +137,17 @@
     HBUINT16 *startCode = c->start_embed<HBUINT16> ();
     hb_codepoint_t prev_cp = 0xFFFF;
 
-    + it
-    | hb_apply ([&] (const hb_item_type<Iterator> _)
-		{
-		  if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
-		  {
-		    HBUINT16 start_code;
-		    start_code = _.first;
-		    c->copy<HBUINT16> (start_code);
-		  }
+    for (const auto& _ : +it)
+    {
+      if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
+      {
+	HBUINT16 start_code;
+	start_code = _.first;
+	c->copy<HBUINT16> (start_code);
+      }
 
-		  prev_cp = _.first;
-		})
-    ;
+      prev_cp = _.first;
+    }
 
     // There must be a final entry with end_code == 0xFFFF.
     if (it.len () == 0 || prev_cp != 0xFFFF)
@@ -149,10 +163,10 @@
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   HBINT16* serialize_idDelta_array (hb_serialize_context_t *c,
-				     Iterator it,
-				     HBUINT16 *endCode,
-				     HBUINT16 *startCode,
-				     unsigned segcount)
+				    Iterator it,
+				    HBUINT16 *endCode,
+				    HBUINT16 *startCode,
+				    unsigned segcount)
   {
     unsigned i = 0;
     hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF;
@@ -162,30 +176,28 @@
     if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
       return nullptr;
 
-    + it
-    | hb_apply ([&] (const hb_item_type<Iterator> _)
-		{
-		  if (_.first == startCode[i])
-		  {
-		    use_delta = true;
-		    start_gid = _.second;
-		  }
-		  else if (_.second != last_gid + 1) use_delta = false;
+    for (const auto& _ : +it)
+    {
+      if (_.first == startCode[i])
+      {
+	use_delta = true;
+	start_gid = _.second;
+      }
+      else if (_.second != last_gid + 1) use_delta = false;
 
-		  if (_.first == endCode[i])
-		  {
-		    HBINT16 delta;
-		    if (use_delta) delta = (int)start_gid - (int)startCode[i];
-		    else delta = 0;
-		    c->copy<HBINT16> (delta);
+      if (_.first == endCode[i])
+      {
+	HBINT16 delta;
+	if (use_delta) delta = (int)start_gid - (int)startCode[i];
+	else delta = 0;
+	c->copy<HBINT16> (delta);
 
-		    i++;
-		  }
+	i++;
+      }
 
-		  last_gid = _.second;
-		  last_cp = _.first;
-		})
-    ;
+      last_gid = _.second;
+      last_cp = _.first;
+    }
 
     if (it.len () == 0 || last_cp != 0xFFFF)
     {
@@ -206,29 +218,24 @@
 					 HBINT16 *idDelta,
 					 unsigned segcount)
   {
+    hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
+    + it | hb_sink (cp_to_gid);
+
     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;
 
-    + hb_range (segcount)
-    | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
-    | hb_apply ([&] (const unsigned i)
-		{
-		  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
-
-		  + it
-		  | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
-		  | hb_apply ([&] (const hb_item_type<Iterator> _)
-			      {
-				HBUINT16 glyID;
-				glyID = _.second;
-				c->copy<HBUINT16> (glyID);
-			      })
-		  ;
-
-
-		})
-    ;
+    for (unsigned i : + hb_range (segcount)
+             | 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++)
+      {
+        HBUINT16 gid;
+        gid = cp_to_gid[cp];
+        c->copy<HBUINT16> (gid);
+      }
+    }
 
     return idRangeOffset;
   }
@@ -238,12 +245,20 @@
   void serialize (hb_serialize_context_t *c,
 		  Iterator it)
   {
+    auto format4_iter =
+    + it
+    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+		 { return _.first <= 0xFFFF; })
+    ;
+
+    if (format4_iter.len () == 0) return;
+
     unsigned table_initpos = c->length ();
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
     this->format = 4;
 
     //serialize endCode[]
-    HBUINT16 *endCode = serialize_endcode_array (c, it);
+    HBUINT16 *endCode = serialize_endcode_array (c, format4_iter);
     if (unlikely (!endCode)) return;
 
     unsigned segcount = (c->length () - min_size) / HBUINT16::static_size;
@@ -252,17 +267,27 @@
     if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding.
 
    // serialize startCode[]
-    HBUINT16 *startCode = serialize_startcode_array (c, it);
+    HBUINT16 *startCode = serialize_startcode_array (c, format4_iter);
     if (unlikely (!startCode)) return;
 
     //serialize idDelta[]
-    HBINT16 *idDelta = serialize_idDelta_array (c, it, endCode, startCode, segcount);
+    HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount);
     if (unlikely (!idDelta)) return;
 
-    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, it, endCode, startCode, idDelta, segcount);
+    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return;
 
-    if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return;
+    this->length = c->length () - table_initpos;
+    if ((long long) this->length != (long long) c->length () - table_initpos)
+    {
+      // Length overflowed. Discard the current object before setting the error condition, otherwise
+      // discard is a noop which prevents the higher level code from reverting the serializer to the
+      // pre-error state in cmap4 overflow handling code.
+      c->pop_discard ();
+      c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return;
+    }
+
     this->segCountX2 = segcount * 2;
     this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
     this->searchRange = 2 * (1u << this->entrySelector);
@@ -271,6 +296,11 @@
 		       : 0;
   }
 
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   struct accelerator_t
   {
     accelerator_t () {}
@@ -291,27 +321,28 @@
 
     bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
     {
-      /* Custom two-array bsearch. */
-      int min = 0, max = (int) this->segCount - 1;
-      const HBUINT16 *startCount = this->startCount;
-      const HBUINT16 *endCount = this->endCount;
-      unsigned int i;
-      while (min <= max)
+      struct CustomRange
       {
-	int mid = ((unsigned int) min + (unsigned int) max) / 2;
-	if (codepoint < startCount[mid])
-	  max = mid - 1;
-	else if (codepoint > endCount[mid])
-	  min = mid + 1;
-	else
+	int cmp (hb_codepoint_t k,
+		 unsigned distance) const
 	{
-	  i = mid;
-	  goto found;
+	  if (k > last) return +1;
+	  if (k < (&last)[distance]) return -1;
+	  return 0;
 	}
-      }
-      return false;
+	HBUINT16 last;
+      };
 
-    found:
+      const HBUINT16 *found = hb_bsearch (codepoint,
+					  this->endCount,
+					  this->segCount,
+					  2,
+					  _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
+					  this->segCount + 1);
+      if (!found)
+	return false;
+      unsigned int i = found - endCount;
+
       hb_codepoint_t gid;
       unsigned int rangeOffset = this->idRangeOffset[i];
       if (rangeOffset == 0)
@@ -333,8 +364,10 @@
       *glyph = gid;
       return true;
     }
+
     HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
     { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
+
     void collect_unicodes (hb_set_t *out) const
     {
       unsigned int count = this->segCount;
@@ -371,6 +404,45 @@
       }
     }
 
+    void collect_mapping (hb_set_t *unicodes, /* OUT */
+			  hb_map_t *mapping /* OUT */) const
+    {
+      unsigned count = this->segCount;
+      if (count && this->startCount[count - 1] == 0xFFFFu)
+	count--; /* Skip sentinel segment. */
+      for (unsigned i = 0; i < count; i++)
+      {
+	hb_codepoint_t start = this->startCount[i];
+	hb_codepoint_t end = this->endCount[i];
+	unsigned rangeOffset = this->idRangeOffset[i];
+	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;
+	    unicodes->add (codepoint);
+	    mapping->set (codepoint, gid);
+	  }
+	}
+	else
+	{
+	  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+	  {
+	    unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+	    if (unlikely (index >= this->glyphIdArrayLength))
+	      break;
+	    hb_codepoint_t gid = this->glyphIdArray[index];
+	    if (unlikely (!gid))
+	      continue;
+	    unicodes->add (codepoint);
+	    mapping->set (codepoint, gid);
+	  }
+	}
+      }
+    }
+
     const HBUINT16 *endCount;
     const HBUINT16 *startCount;
     const HBUINT16 *idDelta;
@@ -391,6 +463,13 @@
     accel.collect_unicodes (out);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    accelerator_t accel (this);
+    accel.collect_mapping (unicodes, mapping);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -403,8 +482,8 @@
        * If that is the case, just change the value to truncate
        * the subtable at the end of the blob. */
       uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
-					    (uintptr_t) (c->end -
-							 (char *) this));
+					       (uintptr_t) (c->end -
+							    (char *) this));
       if (!c->try_set (&length, new_length))
 	return_trace (false);
     }
@@ -484,6 +563,12 @@
     *glyph = gid;
     return true;
   }
+
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   void collect_unicodes (hb_set_t *out) const
   {
     hb_codepoint_t start = startCharCode;
@@ -493,6 +578,21 @@
 	out->add (start + i);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    hb_codepoint_t start_cp = startCharCode;
+    unsigned count = glyphIdArray.len;
+    for (unsigned i = 0; i < count; i++)
+      if (glyphIdArray[i])
+      {
+	hb_codepoint_t unicode = start_cp + i;
+	hb_codepoint_t glyphid = glyphIdArray[i];
+	unicodes->add (unicode);
+	mapping->set (unicode, glyphid);
+      }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -504,7 +604,7 @@
   UINT		length;		/* Byte length of this subtable. */
   UINT		language;	/* Ignore. */
   UINT		startCharCode;	/* First character code covered. */
-  ArrayOf<HBGlyphID, UINT>
+  ArrayOf<HBGlyphID16, UINT>
 		glyphIdArray;	/* Array of glyph index values for character
 				 * codes in the range. */
   public:
@@ -528,19 +628,60 @@
     return true;
   }
 
-  void collect_unicodes (hb_set_t *out) const
+  unsigned get_language () const
+  {
+    return language;
+  }
+
+  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
   {
     for (unsigned int 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);
-      for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+      hb_codepoint_t gid = this->groups[i].glyphID;
+      if (!gid)
       {
-	hb_codepoint_t gid = T::group_get_glyph (this->groups[i], codepoint);
-	if (unlikely (!gid))
-	  continue;
-	out->add (codepoint);
+	/* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
+	if (! T::group_get_glyph (this->groups[i], end)) continue;
+	start++;
+	gid++;
+      }
+      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
+      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
+	end = start + (hb_codepoint_t) num_glyphs - gid;
+
+      out->add_range (start, end);
+    }
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping, /* OUT */
+			unsigned num_glyphs) const
+  {
+    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);
+      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;
+	start++;
+	gid++;
+      }
+      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
+      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
+	end = start + (hb_codepoint_t) num_glyphs - gid;
+
+      for (unsigned cp = start; cp <= end; cp++)
+      {
+	unicodes->add (cp);
+	mapping->set (cp, gid);
+	gid++;
       }
     }
   }
@@ -556,7 +697,7 @@
   HBUINT16	reserved;	/* Reserved; set to 0. */
   HBUINT32	length;		/* Byte length of this subtable. */
   HBUINT32	language;	/* Ignore. */
-  SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
+  SortedArray32Of<CmapSubtableLongGroup>
 		groups;		/* Groupings. */
   public:
   DEFINE_SIZE_ARRAY (16, groups);
@@ -577,38 +718,34 @@
   {
     if (it.len () == 0) return;
     unsigned table_initpos = c->length ();
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
 
     hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
     hb_codepoint_t glyphID = 0;
 
-    + it
-    | hb_apply ([&] (const hb_item_type<Iterator> _)
-	      {
-		if (startCharCode == 0xFFFF)
-		{
-		  startCharCode = _.first;
-		  endCharCode = _.first;
-		  glyphID = _.second;
-		}
-		else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
-		{
-		  CmapSubtableLongGroup  grouprecord;
-		  grouprecord.startCharCode = startCharCode;
-		  grouprecord.endCharCode = endCharCode;
-		  grouprecord.glyphID = glyphID;
-		  c->copy<CmapSubtableLongGroup> (grouprecord);
+    for (const auto& _ : +it)
+    {
+      if (startCharCode == 0xFFFF)
+      {
+	startCharCode = _.first;
+	endCharCode = _.first;
+	glyphID = _.second;
+      }
+      else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
+      {
+	CmapSubtableLongGroup  grouprecord;
+	grouprecord.startCharCode = startCharCode;
+	grouprecord.endCharCode = endCharCode;
+	grouprecord.glyphID = glyphID;
+	c->copy<CmapSubtableLongGroup> (grouprecord);
 
-		  startCharCode = _.first;
-		  endCharCode = _.first;
-		  glyphID = _.second;
-		}
-		else
-		{
-		  endCharCode = _.first;
-		}
-	      })
-    ;
+	startCharCode = _.first;
+	endCharCode = _.first;
+	glyphID = _.second;
+      }
+      else
+	endCharCode = _.first;
+    }
 
     CmapSubtableLongGroup record;
     record.startCharCode = startCharCode;
@@ -674,7 +811,7 @@
   DEFINE_SIZE_STATIC (4);
 };
 
-struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
+struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
 {
   void collect_unicodes (hb_set_t *out) const
   {
@@ -683,7 +820,7 @@
     {
       hb_codepoint_t first = arrayZ[i].startUnicodeValue;
       hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
-				 (hb_codepoint_t) HB_UNICODE_MAX);
+				    (hb_codepoint_t) HB_UNICODE_MAX);
       out->add_range (first, last);
     }
   }
@@ -740,7 +877,9 @@
     }
     else
     {
-      if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
+      if (unlikely (!c->check_assign (out->len,
+                                      (c->length () - init_len) / UnicodeValueRange::static_size,
+                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
       return out;
     }
   }
@@ -761,18 +900,29 @@
   }
 
   HBUINT24	unicodeValue;	/* Base Unicode value of the UVS */
-  HBGlyphID	glyphID;	/* Glyph ID of the UVS */
+  HBGlyphID16	glyphID;	/* Glyph ID of the UVS */
   public:
   DEFINE_SIZE_STATIC (5);
 };
 
-struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
+struct NonDefaultUVS : SortedArray32Of<UVSMapping>
 {
   void collect_unicodes (hb_set_t *out) const
   {
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      out->add (arrayZ[i].glyphID);
+    for (const auto& a : as_array ())
+      out->add (a.unicodeValue);
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    for (const auto& a : as_array ())
+    {
+      hb_codepoint_t unicode = a.unicodeValue;
+      hb_codepoint_t glyphid = a.glyphID;
+      unicodes->add (unicode);
+      mapping->set (unicode, glyphid);
+    }
   }
 
   void closure_glyphs (const hb_set_t      *unicodes,
@@ -787,7 +937,7 @@
 
   NonDefaultUVS* copy (hb_serialize_context_t *c,
 		       const hb_set_t *unicodes,
-		       const hb_set_t *glyphs,
+		       const hb_set_t *glyphs_requested,
 		       const hb_map_t *glyph_map) const
   {
     NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
@@ -797,7 +947,7 @@
     + as_array ()
     | hb_filter ([&] (const UVSMapping& _)
 		 {
-		   return unicodes->has (_.unicodeValue) || glyphs->has (_.glyphID);
+		   return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
 		 })
     ;
 
@@ -839,12 +989,34 @@
     return GLYPH_VARIANT_NOT_FOUND;
   }
 
+  VariationSelectorRecord(const VariationSelectorRecord& other)
+  {
+    *this = other;
+  }
+
+  void operator= (const VariationSelectorRecord& other)
+  {
+    varSelector = other.varSelector;
+    HBUINT32 offset = other.defaultUVS;
+    defaultUVS = offset;
+    offset = other.nonDefaultUVS;
+    nonDefaultUVS = offset;
+  }
+
   void collect_unicodes (hb_set_t *out, const void *base) const
   {
     (base+defaultUVS).collect_unicodes (out);
     (base+nonDefaultUVS).collect_unicodes (out);
   }
 
+  void collect_mapping (const void *base,
+			hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    (base+defaultUVS).collect_unicodes (unicodes);
+    (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
+  }
+
   int cmp (const hb_codepoint_t &variation_selector) const
   { return varSelector.cmp (variation_selector); }
 
@@ -856,56 +1028,49 @@
 		  nonDefaultUVS.sanitize (c, base));
   }
 
-  VariationSelectorRecord* copy (hb_serialize_context_t *c,
-				 const hb_set_t *unicodes,
-				 const hb_set_t *glyphs,
-				 const hb_map_t *glyph_map,
-				 const void *src_base,
-				 const void *dst_base) const
+  hb_pair_t<unsigned, unsigned>
+  copy (hb_serialize_context_t *c,
+	const hb_set_t *unicodes,
+	const hb_set_t *glyphs_requested,
+	const hb_map_t *glyph_map,
+	const void *base) const
   {
     auto snap = c->snapshot ();
     auto *out = c->embed<VariationSelectorRecord> (*this);
-    if (unlikely (!out)) return nullptr;
+    if (unlikely (!out)) return hb_pair (0, 0);
 
     out->defaultUVS = 0;
     out->nonDefaultUVS = 0;
 
-    bool drop = true;
-
-    if (defaultUVS != 0)
-    {
-      c->push ();
-      if (c->copy (src_base+defaultUVS, unicodes))
-      {
-	c->add_link (out->defaultUVS, c->pop_pack (), dst_base);
-	drop = false;
-      }
-      else c->pop_discard ();
-    }
-
+    unsigned non_default_uvs_objidx = 0;
     if (nonDefaultUVS != 0)
     {
       c->push ();
-      if (c->copy (src_base+nonDefaultUVS, unicodes, glyphs, glyph_map))
-      {
-	c->add_link (out->nonDefaultUVS, c->pop_pack (), dst_base);
-	drop = false;
-      }
+      if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
+	non_default_uvs_objidx = c->pop_pack ();
       else c->pop_discard ();
     }
 
-    if (drop)
+    unsigned default_uvs_objidx = 0;
+    if (defaultUVS != 0)
     {
-      c->revert (snap);
-      return nullptr;
+      c->push ();
+      if (c->copy (base+defaultUVS, unicodes))
+	default_uvs_objidx = c->pop_pack ();
+      else c->pop_discard ();
     }
-    else return out;
+
+
+    if (!default_uvs_objidx && !non_default_uvs_objidx)
+      c->revert (snap);
+
+    return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
   }
 
   HBUINT24	varSelector;	/* Variation selector. */
-  LOffsetTo<DefaultUVS>
+  Offset32To<DefaultUVS>
 		defaultUVS;	/* Offset to Default UVS Table.  May be 0. */
-  LOffsetTo<NonDefaultUVS>
+  Offset32To<NonDefaultUVS>
 		nonDefaultUVS;	/* Offset to Non-Default UVS Table.  May be 0. */
   public:
   DEFINE_SIZE_STATIC (11);
@@ -920,9 +1085,8 @@
 
   void collect_variation_selectors (hb_set_t *out) const
   {
-    unsigned int count = record.len;
-    for (unsigned int i = 0; i < count; i++)
-      out->add (record.arrayZ[i].varSelector);
+    for (const auto& a : record.as_array ())
+      out->add (a.varSelector);
   }
   void collect_variation_unicodes (hb_codepoint_t variation_selector,
 				   hb_set_t *out) const
@@ -930,28 +1094,83 @@
 
   void serialize (hb_serialize_context_t *c,
 		  const hb_set_t *unicodes,
-		  const hb_set_t *glyphs,
+		  const hb_set_t *glyphs_requested,
 		  const hb_map_t *glyph_map,
-		  const void *src_base)
+		  const void *base)
   {
     auto snap = c->snapshot ();
     unsigned table_initpos = c->length ();
     const char* init_tail = c->tail;
 
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
     this->format = 14;
 
-    const CmapSubtableFormat14 *src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (src_base);
-    for (const VariationSelectorRecord& _ : src_tbl->record)
-      c->copy (_, unicodes, glyphs, glyph_map, src_base, this);
+    auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
+
+    /*
+     * Some versions of OTS require that offsets are in order. Due to the use
+     * of push()/pop_pack() serializing the variation records in order results
+     * in the offsets being in reverse order (first record has the largest
+     * offset). While this is perfectly valid, it will cause some versions of
+     * OTS to consider this table bad.
+     *
+     * So to prevent this issue we serialize the variation records in reverse
+     * order, so that the offsets are ordered from small to large. Since
+     * variation records are supposed to be in increasing order of varSelector
+     * we then have to reverse the order of the written variation selector
+     * records after everything is finalized.
+     */
+    hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
+    for (int i = src_tbl->record.len - 1; i >= 0; i--)
+    {
+      hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
+      if (result.first || result.second)
+	obj_indices.push (result);
+    }
 
     if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
-      c->revert (snap);
-    else
     {
-      int tail_len = init_tail - c->tail;
-      c->check_assign (this->length, c->length () - table_initpos + tail_len);
-      c->check_assign (this->record.len, (c->length () - table_initpos - CmapSubtableFormat14::min_size) / VariationSelectorRecord::static_size);
+      c->revert (snap);
+      return;
+    }
+
+    if (unlikely (!c->check_success (!obj_indices.in_error ())))
+      return;
+
+    int tail_len = init_tail - c->tail;
+    c->check_assign (this->length, c->length () - table_initpos + tail_len,
+                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
+    c->check_assign (this->record.len,
+		     (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
+		     VariationSelectorRecord::static_size,
+                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    /* Correct the incorrect write order by reversing the order of the variation
+       records array. */
+    _reverse_variation_records ();
+
+    /* Now that records are in the right order, we can set up the offsets. */
+    _add_links_to_variation_records (c, obj_indices);
+  }
+
+  void _reverse_variation_records ()
+  {
+    record.as_array ().reverse ();
+  }
+
+  void _add_links_to_variation_records (hb_serialize_context_t *c,
+					const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
+  {
+    for (unsigned i = 0; i < obj_indices.length; i++)
+    {
+      /*
+       * Since the record array has been reversed (see comments in copy())
+       * but obj_indices has not been, the indices at obj_indices[i]
+       * are for the variation record at record[j].
+       */
+      int j = obj_indices.length - 1 - i;
+      c->add_link (record[j].defaultUVS, obj_indices[i].first);
+      c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
     }
   }
 
@@ -966,6 +1185,19 @@
     ;
   }
 
+  void collect_unicodes (hb_set_t *out) const
+  {
+    for (const VariationSelectorRecord& _ : record)
+      _.collect_unicodes (out, this);
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping /* OUT */) const
+  {
+    for (const VariationSelectorRecord& _ : record)
+      _.collect_mapping (this, unicodes, mapping);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -976,7 +1208,7 @@
   protected:
   HBUINT16	format;		/* Format number is set to 14. */
   HBUINT32	length;		/* Byte length of this subtable. */
-  SortedArrayOf<VariationSelectorRecord, HBUINT32>
+  SortedArray32Of<VariationSelectorRecord>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
@@ -1001,32 +1233,62 @@
     default: return false;
     }
   }
-  void collect_unicodes (hb_set_t *out) const
+  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
   {
     switch (u.format) {
     case  0: u.format0 .collect_unicodes (out); return;
     case  4: u.format4 .collect_unicodes (out); return;
     case  6: u.format6 .collect_unicodes (out); return;
     case 10: u.format10.collect_unicodes (out); return;
-    case 12: u.format12.collect_unicodes (out); return;
-    case 13: u.format13.collect_unicodes (out); return;
+    case 12: u.format12.collect_unicodes (out, num_glyphs); return;
+    case 13: u.format13.collect_unicodes (out, num_glyphs); return;
     case 14:
     default: return;
     }
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+			hb_map_t *mapping, /* OUT */
+			unsigned num_glyphs = UINT_MAX) const
+  {
+    switch (u.format) {
+    case  0: u.format0 .collect_mapping (unicodes, mapping); return;
+    case  4: u.format4 .collect_mapping (unicodes, mapping); return;
+    case  6: u.format6 .collect_mapping (unicodes, mapping); return;
+    case 10: u.format10.collect_mapping (unicodes, mapping); return;
+    case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case 14:
+    default: return;
+    }
+  }
+
+  unsigned get_language () const
+  {
+    switch (u.format) {
+    case  0: return u.format0 .get_language ();
+    case  4: return u.format4 .get_language ();
+    case  6: return u.format6 .get_language ();
+    case 10: return u.format10.get_language ();
+    case 12: return u.format12.get_language ();
+    case 13: return u.format13.get_language ();
+    case 14:
+    default: return 0;
+    }
+  }
+
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
 		  Iterator it,
 		  unsigned format,
 		  const hb_subset_plan_t *plan,
-		  const void *src_base)
+		  const void *base)
   {
     switch (format) {
-    case  4: u.format4.serialize (c, it);  return;
-    case 12: u.format12.serialize (c, it); return;
-    case 14: u.format14.serialize (c, plan->unicodes, plan->_glyphset, plan->glyph_map, src_base); return;
+    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);
     default: return;
     }
   }
@@ -1087,8 +1349,7 @@
   EncodingRecord* copy (hb_serialize_context_t *c,
 			Iterator it,
 			unsigned format,
-			const void *src_base,
-			const void *dst_base,
+			const void *base,
 			const hb_subset_plan_t *plan,
 			/* INOUT */ unsigned *objidx) const
   {
@@ -1102,7 +1363,7 @@
     {
       CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
       unsigned origin_length = c->length ();
-      cmapsubtable->serialize (c, it, format, plan, &(src_base+subtable));
+      cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
       if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
       else c->pop_discard ();
     }
@@ -1113,13 +1374,13 @@
       return_trace (nullptr);
     }
 
-    c->add_link (out->subtable, *objidx, dst_base);
+    c->add_link (out->subtable, *objidx);
     return_trace (out);
   }
 
   HBUINT16	platformID;	/* Platform ID. */
   HBUINT16	encodingID;	/* Platform-specific encoding ID. */
-  LOffsetTo<CmapSubtable>
+  Offset32To<CmapSubtable>
 		subtable;	/* Byte offset from beginning of table to the subtable for this encoding. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -1130,28 +1391,113 @@
   static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
   template<typename Iterator, typename EncodingRecIter,
-	   hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
+	   hb_requires (hb_is_iterator (EncodingRecIter))>
+  bool serialize (hb_serialize_context_t *c,
 		  Iterator it,
 		  EncodingRecIter encodingrec_iter,
-		  const void *src_base,
-		  const hb_subset_plan_t *plan)
+		  const void *base,
+		  const hb_subset_plan_t *plan,
+                  bool drop_format_4 = false)
   {
-    if (unlikely (!c->extend_min ((*this))))  return;
+    if (unlikely (!c->extend_min ((*this))))  return false;
     this->version = 0;
 
     unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
+    auto snap = c->snapshot ();
 
     for (const EncodingRecord& _ : encodingrec_iter)
     {
-      unsigned format = (src_base+_.subtable).u.format;
+      if (c->in_error ())
+        return false;
 
-      if (format == 4) c->copy (_, it, 4u, src_base, this, plan, &format4objidx);
-      else if (format == 12) c->copy (_, it, 12u, src_base, this, plan, &format12objidx);
-      else if (format == 14) c->copy (_, it, 14u, src_base, this, plan, &format14objidx);
+      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);
+
+      if (!drop_format_4 && format == 4)
+      {
+        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.
+          c->revert (snap);
+          return serialize (c, it,
+                            encodingrec_iter,
+                            base,
+                            plan,
+                            true);
+        }
+      }
+
+      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);
+      }
+      else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
+    }
+    c->check_assign(this->encodingRecord.len,
+                    (c->length () - cmap::min_size)/EncodingRecord::static_size,
+                    HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    // Fail if format 4 was dropped and there is no cmap12.
+    return !drop_format_4 || format12objidx;
+  }
+
+  template<typename Iterator, typename EncodingRecordIterator,
+      hb_requires (hb_is_iterator (Iterator)),
+      hb_requires (hb_is_iterator (EncodingRecordIterator))>
+  bool _can_drop (const EncodingRecord& cmap12,
+                  const hb_set_t& cmap12_unicodes,
+                  const void* base,
+                  Iterator subset_unicodes,
+                  EncodingRecordIterator encoding_records)
+  {
+    for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
+    {
+      if (cp >= 0x10000) return false;
     }
 
-    c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
+    unsigned target_platform;
+    unsigned target_encoding;
+    unsigned target_language = (base+cmap12.subtable).get_language ();
+
+    if (cmap12.platformID == 0 && cmap12.encodingID == 4)
+    {
+      target_platform = 0;
+      target_encoding = 3;
+    } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
+      target_platform = 3;
+      target_encoding = 1;
+    } else {
+      return false;
+    }
+
+    for (const auto& _ : encoding_records)
+    {
+      if (_.platformID != target_platform
+          || _.encodingID != target_encoding
+          || (base+_.subtable).get_language() != target_language)
+        continue;
+
+      hb_set_t sibling_unicodes;
+      (base+_.subtable).collect_unicodes (&sibling_unicodes);
+
+      auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
+      auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
+      for (; cmap12 && sibling; cmap12++, sibling++)
+      {
+        unsigned a = *cmap12;
+        unsigned b = *sibling;
+        if (a != b) return false;
+      }
+
+      return !cmap12 && !sibling;
+    }
+
+    return false;
   }
 
   void closure_glyphs (const hb_set_t      *unicodes,
@@ -1187,7 +1533,6 @@
 		})
     ;
 
-
     if (unlikely (!encodingrec_iter.len ())) return_trace (false);
 
     const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
@@ -1205,7 +1550,7 @@
       else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
     }
 
-    if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false);
+    if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
     if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
 
     auto it =
@@ -1220,8 +1565,7 @@
 		 { return (_.second != HB_MAP_VALUE_INVALID); })
     ;
 
-    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
-    return_trace (true);
+    return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -1339,8 +1683,11 @@
       return get_nominal_glyph (unicode, glyph);
     }
 
-    void collect_unicodes (hb_set_t *out) const
-    { subtable->collect_unicodes (out); }
+    void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
+    { subtable->collect_unicodes (out, num_glyphs); }
+    void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
+			  unsigned num_glyphs = UINT_MAX) const
+    { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
     void collect_variation_selectors (hb_set_t *out) const
     { subtable_uvs->collect_variation_selectors (out); }
     void collect_variation_unicodes (hb_codepoint_t variation_selector,
@@ -1413,7 +1760,7 @@
   }
 
   const EncodingRecord *find_encodingrec (unsigned int platform_id,
-				    unsigned int encoding_id) const
+					  unsigned int encoding_id) const
   {
     EncodingRecord key;
     key.platformID = platform_id;
@@ -1445,9 +1792,9 @@
   }
 
   protected:
-  HBUINT16		version;	/* Table version number (0). */
-  SortedArrayOf<EncodingRecord>
-			encodingRecord;	/* Encoding tables. */
+  HBUINT16	version;	/* Table version number (0). */
+  SortedArray16Of<EncodingRecord>
+		encodingRecord;	/* Encoding tables. */
   public:
   DEFINE_SIZE_ARRAY (4, encodingRecord);
 };
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 3498d3b..1445991 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -21,7 +21,7 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Seigo Nonaka
+ * Google Author(s): Seigo Nonaka, Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_CBDT_TABLE_HH
@@ -43,6 +43,35 @@
 
 namespace OT {
 
+struct cblc_bitmap_size_subset_context_t
+{
+  const char *cbdt;
+  unsigned int cbdt_length;
+  hb_vector_t<char> *cbdt_prime;
+  unsigned int size;		/* INOUT
+				 *  Input: old size of IndexSubtable
+				 *  Output: new size of IndexSubtable
+				 */
+  unsigned int num_tables;	/* INOUT
+				 *  Input: old number of subtables.
+				 *  Output: new number of subtables.
+				 */
+  hb_codepoint_t start_glyph;	/* OUT */
+  hb_codepoint_t end_glyph;	/* OUT */
+};
+
+static inline bool
+_copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
+		    const void        *data,
+		    unsigned           length)
+{
+  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);
+  cbdt_prime->length = new_len;
+  return true;
+}
+
 struct SmallGlyphMetrics
 {
   bool sanitize (hb_sanitize_context_t *c) const
@@ -56,7 +85,7 @@
     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 (-height);
+    extents->height = font->em_scale_y (-static_cast<int>(height));
   }
 
   HBUINT8	height;
@@ -65,7 +94,7 @@
   HBINT8	bearingY;
   HBUINT8	advance;
   public:
-  DEFINE_SIZE_STATIC(5);
+  DEFINE_SIZE_STATIC (5);
 };
 
 struct BigGlyphMetrics : SmallGlyphMetrics
@@ -74,7 +103,7 @@
   HBINT8	vertBearingY;
   HBUINT8	vertAdvance;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 struct SBitLineMetrics
@@ -98,7 +127,7 @@
   HBINT8	padding1;
   HBINT8	padding2;
   public:
-  DEFINE_SIZE_STATIC(12);
+  DEFINE_SIZE_STATIC (12);
 };
 
 
@@ -118,7 +147,7 @@
   HBUINT16	imageFormat;
   HBUINT32	imageDataOffset;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 template <typename OffsetType>
@@ -143,11 +172,23 @@
     return true;
   }
 
+  bool add_offset (hb_serialize_context_t *c,
+		   unsigned int offset,
+		   unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+    Offset<OffsetType> embedded_offset;
+    embedded_offset = offset;
+    *size += sizeof (OffsetType);
+    auto *o = c->embed (embedded_offset);
+    return_trace ((bool) o);
+  }
+
   IndexSubtableHeader	header;
   UnsizedArrayOf<Offset<OffsetType>>
- 			offsetArrayZ;
+			offsetArrayZ;
   public:
-  DEFINE_SIZE_ARRAY(8, offsetArrayZ);
+  DEFINE_SIZE_ARRAY (8, offsetArrayZ);
 };
 
 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
@@ -159,35 +200,153 @@
   {
     TRACE_SANITIZE (this);
     if (!u.header.sanitize (c)) return_trace (false);
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 1: return_trace (u.format1.sanitize (c, glyph_count));
     case 3: return_trace (u.format3.sanitize (c, glyph_count));
     default:return_trace (true);
     }
   }
 
+  bool
+  finish_subtable (hb_serialize_context_t *c,
+		   unsigned int cbdt_prime_len,
+		   unsigned int num_glyphs,
+		   unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
+    switch (u.header.indexFormat)
+    {
+    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
+    case 3: {
+      if (!u.format3.add_offset (c, local_offset, size))
+	return_trace (false);
+      if (!(num_glyphs & 0x01))  // Pad to 32-bit alignment if needed.
+	return_trace (u.format3.add_offset (c, 0, size));
+      return_trace (true);
+    }
+    // TODO: implement 2, 4, 5.
+    case 2: case 4:  // No-op.
+    case 5:  // Pad to 32-bit aligned.
+    default: return_trace (false);
+    }
+  }
+
+  bool
+  fill_missing_glyphs (hb_serialize_context_t *c,
+		       unsigned int cbdt_prime_len,
+		       unsigned int num_missing,
+		       unsigned int *size /* OUT (accumulated) */,
+		       unsigned int *num_glyphs /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
+    switch (u.header.indexFormat)
+    {
+    case 1: {
+      for (unsigned int i = 0; i < num_missing; i++)
+      {
+	if (unlikely (!u.format1.add_offset (c, local_offset, size)))
+	  return_trace (false);
+	*num_glyphs += 1;
+      }
+      return_trace (true);
+    }
+    case 3: {
+      for (unsigned int i = 0; i < num_missing; i++)
+      {
+	if (unlikely (!u.format3.add_offset (c, local_offset, size)))
+	  return_trace (false);
+	*num_glyphs += 1;
+      }
+      return_trace (true);
+    }
+    // TODO: implement 2, 4, 5.
+    case 2:  // Add empty space in cbdt_prime?.
+    case 4: case 5:  // No-op as sparse is supported.
+    default: return_trace (false);
+    }
+  }
+
+  bool
+  copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx,
+		     const char *cbdt, unsigned int cbdt_length,
+		     hb_vector_t<char> *cbdt_prime /* INOUT */,
+		     IndexSubtable *subtable_prime /* INOUT */,
+		     unsigned int *size /* OUT (accumulated) */) const
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int offset, length, format;
+    if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false);
+    if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false);
+
+    auto *header_prime = subtable_prime->get_header ();
+    unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset;
+    if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false);
+
+    return_trace (subtable_prime->add_offset (c, new_local_offset, size));
+  }
+
+  bool
+  add_offset (hb_serialize_context_t *c, unsigned int local_offset,
+	      unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.header.indexFormat)
+    {
+    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
+    case 3: return_trace (u.format3.add_offset (c, local_offset, size));
+    // TODO: Implement tables 2, 4, 5
+    case 2:  // Should be a no-op.
+    case 4: case 5:  // Handle sparse cases.
+    default: return_trace (false);
+    }
+  }
+
   bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
   {
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 2: case 5: /* TODO */
     case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
     default:return (false);
     }
   }
 
-  bool get_image_data (unsigned int idx,
-		       unsigned int *offset,
-		       unsigned int *length,
-		       unsigned int *format) const
+  bool
+  get_image_data (unsigned int idx, unsigned int *offset,
+		  unsigned int *length, unsigned int *format) const
   {
     *format = u.header.imageFormat;
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 1: return u.format1.get_image_data (idx, offset, length);
     case 3: return u.format3.get_image_data (idx, offset, length);
     default: return false;
     }
   }
 
+  const IndexSubtableHeader* get_header () const { return &u.header; }
+
+  void populate_header (unsigned index_format,
+			unsigned image_format,
+			unsigned int image_data_offset,
+			unsigned int *size)
+  {
+    u.header.indexFormat = index_format;
+    u.header.imageFormat = image_format;
+    u.header.imageDataOffset = image_data_offset;
+    switch (u.header.indexFormat)
+    {
+    case 1: *size += IndexSubtableFormat1::min_size; break;
+    case 3: *size += IndexSubtableFormat3::min_size; break;
+    }
+  }
+
   protected:
   union {
   IndexSubtableHeader	header;
@@ -209,12 +368,135 @@
 		  offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
   }
 
-  bool get_extents (hb_glyph_extents_t *extents,
-		    const void *base) const
+  const IndexSubtable* get_subtable (const void *base) const
   {
-    return (base+offsetToSubtable).get_extents (extents);
+    return &(base+offsetToSubtable);
   }
 
+  bool add_new_subtable (hb_subset_context_t* c,
+			 cblc_bitmap_size_subset_context_t *bitmap_size_context,
+			 IndexSubtableRecord *record,
+			 const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
+			 const void *base,
+			 unsigned int *start /* INOUT */) const
+  {
+    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);
+    auto *old_header = old_subtable->get_header ();
+
+    subtable->populate_header (old_header->indexFormat,
+			       old_header->imageFormat,
+			       bitmap_size_context->cbdt_prime->length,
+			       &bitmap_size_context->size);
+
+    unsigned int num_glyphs = 0;
+    bool early_exit = false;
+    for (unsigned int i = *start; i < lookup->length; i++)
+    {
+      hb_codepoint_t new_gid = (*lookup)[i].first;
+      const IndexSubtableRecord *next_record = (*lookup)[i].second;
+      const IndexSubtable *next_subtable = next_record->get_subtable (base);
+      auto *next_header = next_subtable->get_header ();
+      if (next_header != old_header)
+      {
+	*start = i;
+	early_exit = true;
+	break;
+      }
+      unsigned int num_missing = record->add_glyph_for_subset (new_gid);
+      if (unlikely (!subtable->fill_missing_glyphs (c->serializer,
+						    bitmap_size_context->cbdt_prime->length,
+						    num_missing,
+						    &bitmap_size_context->size,
+						    &num_glyphs)))
+	return_trace (false);
+
+      hb_codepoint_t old_gid = 0;
+      c->plan->old_gid_for_new_gid (new_gid, &old_gid);
+      if (old_gid < next_record->firstGlyphIndex)
+	return_trace (false);
+
+      unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex;
+      if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer,
+						       old_idx,
+						       bitmap_size_context->cbdt,
+						       bitmap_size_context->cbdt_length,
+						       bitmap_size_context->cbdt_prime,
+						       subtable,
+						       &bitmap_size_context->size)))
+	return_trace (false);
+      num_glyphs += 1;
+    }
+    if (!early_exit)
+      *start = lookup->length;
+    if (unlikely (!subtable->finish_subtable (c->serializer,
+					      bitmap_size_context->cbdt_prime->length,
+					      num_glyphs,
+					      &bitmap_size_context->size)))
+      return_trace (false);
+    return_trace (true);
+  }
+
+  bool add_new_record (hb_subset_context_t *c,
+		       cblc_bitmap_size_subset_context_t *bitmap_size_context,
+		       const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
+		       const void *base,
+		       unsigned int *start, /* INOUT */
+		       hb_vector_t<IndexSubtableRecord>* records /* INOUT */) const
+  {
+    TRACE_SERIALIZE (this);
+    auto snap = c->serializer->snapshot ();
+    unsigned int old_size = bitmap_size_context->size;
+    unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;
+
+    // Set to invalid state to indicate filling glyphs is not yet started.
+    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;
+    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)))
+    {
+      c->serializer->pop_discard ();
+      c->serializer->revert (snap);
+      bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length);
+      bitmap_size_context->size = old_size;
+      records->resize (records->length - 1);
+      return_trace (false);
+    }
+
+    bitmap_size_context->num_tables += 1;
+    return_trace (true);
+  }
+
+  unsigned int add_glyph_for_subset (hb_codepoint_t gid)
+  {
+    if (firstGlyphIndex > lastGlyphIndex)
+    {
+      firstGlyphIndex = gid;
+      lastGlyphIndex = gid;
+      return 0;
+    }
+    // TODO maybe assert? this shouldn't occur.
+    if (lastGlyphIndex > gid)
+      return 0;
+    unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1);
+    lastGlyphIndex = gid;
+    return num_missing;
+  }
+
+  bool get_extents (hb_glyph_extents_t *extents, const void *base) const
+  { return (base+offsetToSubtable).get_extents (extents); }
+
   bool get_image_data (unsigned int  gid,
 		       const void   *base,
 		       unsigned int *offset,
@@ -226,11 +508,11 @@
 						   offset, length, format);
   }
 
-  HBGlyphID			firstGlyphIndex;
-  HBGlyphID			lastGlyphIndex;
-  LOffsetTo<IndexSubtable>	offsetToSubtable;
+  HBGlyphID16			firstGlyphIndex;
+  HBGlyphID16			lastGlyphIndex;
+  Offset32To<IndexSubtable>	offsetToSubtable;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 struct IndexSubtableArray
@@ -243,6 +525,79 @@
     return_trace (indexSubtablesZ.sanitize (c, count, this));
   }
 
+  void
+  build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context,
+		hb_vector_t<hb_pair_t<hb_codepoint_t,
+		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++)
+    {
+      hb_codepoint_t old_gid;
+      if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
+
+      const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables);
+      if (unlikely (!record)) continue;
+
+      // Don't add gaps to the lookup. The best way to determine if a glyph is a
+      // gap is that it has no image data.
+      unsigned int offset, length, format;
+      if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue;
+
+      lookup->push (hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*> (new_gid, record));
+
+      if (!start_glyph_is_set)
+      {
+	bitmap_size_context->start_glyph = new_gid;
+	start_glyph_is_set = true;
+      }
+
+      bitmap_size_context->end_glyph = new_gid;
+    }
+  }
+
+  bool
+  subset (hb_subset_context_t *c,
+	  cblc_bitmap_size_subset_context_t *bitmap_size_context) const
+  {
+    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)))
+      return false;
+
+    bitmap_size_context->size = 0;
+    bitmap_size_context->num_tables = 0;
+    hb_vector_t<IndexSubtableRecord> records;
+    for (unsigned int start = 0; start < lookup.length;)
+    {
+      if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records)))
+      {
+	// Discard any leftover pushes to the serializer from successful records.
+	for (unsigned int i = 0; i < records.length; i++)
+	  c->serializer->pop_discard ();
+	return_trace (false);
+      }
+    }
+
+    /* Workaround to ensure offset ordering is from least to greatest when
+     * resolving links. */
+    hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
+    for (unsigned int i = 0; i < records.length; i++)
+      objidxs.push (c->serializer->pop_pack ());
+    for (unsigned int i = 0; i < records.length; i++)
+    {
+      IndexSubtableRecord* record = c->serializer->embed (records[i]);
+      if (unlikely (!record)) return_trace (false);
+      c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]);
+    }
+    return_trace (true);
+  }
+
   public:
   const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
   {
@@ -274,30 +629,64 @@
 		  vertical.sanitize (c));
   }
 
-  const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
-					 const void *base,
-					 const void **out_base) const
+  const IndexSubtableRecord *
+  find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const
   {
     *out_base = &(base+indexSubtableArrayOffset);
     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
   }
 
+  bool
+  subset (hb_subset_context_t *c, const void *base,
+	  const char *cbdt, unsigned int cbdt_length,
+	  hb_vector_t<char> *cbdt_prime /* INOUT */) const
+  {
+    TRACE_SUBSET (this);
+    auto *out_table = c->serializer->embed (this);
+    if (unlikely (!out_table)) return_trace (false);
+
+    cblc_bitmap_size_subset_context_t bitmap_size_context;
+    bitmap_size_context.cbdt = cbdt;
+    bitmap_size_context.cbdt_length = cbdt_length;
+    bitmap_size_context.cbdt_prime = cbdt_prime;
+    bitmap_size_context.size = indexTablesSize;
+    bitmap_size_context.num_tables = numberOfIndexSubtables;
+    bitmap_size_context.start_glyph = 1;
+    bitmap_size_context.end_glyph = 0;
+
+    if (!out_table->indexSubtableArrayOffset.serialize_subset (c,
+							       indexSubtableArrayOffset,
+							       base,
+							       &bitmap_size_context))
+      return_trace (false);
+    if (!bitmap_size_context.size ||
+	!bitmap_size_context.num_tables ||
+	bitmap_size_context.start_glyph > bitmap_size_context.end_glyph)
+      return_trace (false);
+
+    out_table->indexTablesSize = bitmap_size_context.size;
+    out_table->numberOfIndexSubtables = bitmap_size_context.num_tables;
+    out_table->startGlyphIndex = bitmap_size_context.start_glyph;
+    out_table->endGlyphIndex = bitmap_size_context.end_glyph;
+    return_trace (true);
+  }
+
   protected:
-  LNNOffsetTo<IndexSubtableArray>
+  NNOffset32To<IndexSubtableArray>
 			indexSubtableArrayOffset;
   HBUINT32		indexTablesSize;
   HBUINT32		numberOfIndexSubtables;
   HBUINT32		colorRef;
   SBitLineMetrics	horizontal;
   SBitLineMetrics	vertical;
-  HBGlyphID		startGlyphIndex;
-  HBGlyphID		endGlyphIndex;
+  HBGlyphID16		startGlyphIndex;
+  HBGlyphID16		endGlyphIndex;
   HBUINT8		ppemX;
   HBUINT8		ppemY;
   HBUINT8		bitDepth;
   HBINT8		flags;
   public:
-  DEFINE_SIZE_STATIC(48);
+  DEFINE_SIZE_STATIC (48);
 };
 
 
@@ -308,24 +697,24 @@
 struct GlyphBitmapDataFormat17
 {
   SmallGlyphMetrics	glyphMetrics;
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
-  DEFINE_SIZE_ARRAY(9, data);
+  DEFINE_SIZE_ARRAY (9, data);
 };
 
 struct GlyphBitmapDataFormat18
 {
   BigGlyphMetrics	glyphMetrics;
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
-  DEFINE_SIZE_ARRAY(12, data);
+  DEFINE_SIZE_ARRAY (12, data);
 };
 
 struct GlyphBitmapDataFormat19
 {
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
-  DEFINE_SIZE_ARRAY(4, data);
+  DEFINE_SIZE_ARRAY (4, data);
 };
 
 struct CBLC
@@ -342,12 +731,50 @@
 		  sizeTables.sanitize (c, this));
   }
 
+  static bool
+  sink_cbdt (hb_subset_context_t *c, hb_vector_t<char>* cbdt_prime)
+  {
+    hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ,
+						 cbdt_prime->length,
+						 HB_MEMORY_MODE_WRITABLE,
+						 cbdt_prime->arrayZ,
+						 hb_free);
+    cbdt_prime->init ();  // Leak arrayZ to the blob.
+    bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
+    hb_blob_destroy (cbdt_prime_blob);
+    return ret;
+  }
+
+  bool
+  subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table,
+		     const char *cbdt /* IN */, unsigned int cbdt_length,
+		     CBLC *cblc_prime /* INOUT */, hb_vector_t<char> *cbdt_prime /* INOUT */) const
+  {
+    TRACE_SUBSET (this);
+    cblc_prime->sizeTables.len++;
+
+    auto snap = c->serializer->snapshot ();
+    auto cbdt_prime_len = cbdt_prime->length;
+
+    if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime))
+    {
+      cblc_prime->sizeTables.len--;
+      c->serializer->revert (snap);
+      cbdt_prime->shrink (cbdt_prime_len);
+      return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  // Implemented in cc file as it depends on definition of CBDT.
+  HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+
   protected:
   const BitmapSizeTable &choose_strike (hb_font_t *font) const
   {
     unsigned count = sizeTables.len;
     if (unlikely (!count))
-      return Null(BitmapSizeTable);
+      return Null (BitmapSizeTable);
 
     unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
     if (!requested_ppem)
@@ -371,9 +798,9 @@
 
   protected:
   FixedVersion<>		version;
-  LArrayOf<BitmapSizeTable>	sizeTables;
+  Array32Of<BitmapSizeTable>	sizeTables;
   public:
-  DEFINE_SIZE_ARRAY(8, sizeTables);
+  DEFINE_SIZE_ARRAY (8, sizeTables);
 };
 
 struct CBDT
@@ -384,8 +811,8 @@
   {
     void init (hb_face_t *face)
     {
-      cblc = hb_sanitize_context_t().reference_table<CBLC> (face);
-      cbdt = hb_sanitize_context_t().reference_table<CBDT> (face);
+      cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
+      cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);
 
       upem = hb_face_get_upem (face);
     }
@@ -396,8 +823,8 @@
       this->cbdt.destroy ();
     }
 
-    bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
-		      hb_glyph_extents_t *extents) const
+    bool
+    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -412,33 +839,27 @@
       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 	return false;
 
-      {
-	unsigned int cbdt_len = cbdt.get_length ();
-	if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
-	  return false;
+      unsigned int cbdt_len = cbdt.get_length ();
+      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+	return false;
 
-	switch (image_format)
-	{
-	  case 17: {
-	    if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
-	      return false;
-	    const GlyphBitmapDataFormat17& glyphFormat17 =
-		StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	    glyphFormat17.glyphMetrics.get_extents (font, extents);
-	    break;
-	  }
-	  case 18: {
-	    if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
-	      return false;
-	    const GlyphBitmapDataFormat18& glyphFormat18 =
-		StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-	    glyphFormat18.glyphMetrics.get_extents (font, extents);
-	    break;
-	  }
-	  default:
-	    // TODO: Support other image formats.
-	    return false;
-	}
+      switch (image_format)
+      {
+      case 17: {
+	if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
+	  return false;
+	auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+	glyphFormat17.glyphMetrics.get_extents (font, extents);
+	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);
+	break;
+      }
+      default: return false; /* TODO: Support other image formats. */
       }
 
       /* Convert to font units. */
@@ -452,8 +873,8 @@
       return true;
     }
 
-    hb_blob_t* reference_png (hb_font_t      *font,
-			      hb_codepoint_t  glyph) const
+    hb_blob_t*
+    reference_png (hb_font_t *font, hb_codepoint_t glyph) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -465,44 +886,41 @@
       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 	return hb_blob_get_empty ();
 
+      unsigned int cbdt_len = cbdt.get_length ();
+      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+	return hb_blob_get_empty ();
+
+      switch (image_format)
       {
-	unsigned int cbdt_len = cbdt.get_length ();
-	if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+      case 17:
+      {
+	if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
 	  return hb_blob_get_empty ();
-
-	switch (image_format)
-	{
-	  case 17: {
-	    if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
-	      return hb_blob_get_empty ();
-	    const GlyphBitmapDataFormat17& glyphFormat17 =
-	      StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	    return hb_blob_create_sub_blob (cbdt.get_blob (),
-					    image_offset + GlyphBitmapDataFormat17::min_size,
-					    glyphFormat17.data.len);
-	  }
-	  case 18: {
-	    if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
-	      return hb_blob_get_empty ();
-	    const GlyphBitmapDataFormat18& glyphFormat18 =
-	      StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-	    return hb_blob_create_sub_blob (cbdt.get_blob (),
-					    image_offset + GlyphBitmapDataFormat18::min_size,
-					    glyphFormat18.data.len);
-	  }
-	  case 19: {
-	    if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
-	      return hb_blob_get_empty ();
-	    const GlyphBitmapDataFormat19& glyphFormat19 =
-	      StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
-	    return hb_blob_create_sub_blob (cbdt.get_blob (),
-					    image_offset + GlyphBitmapDataFormat19::min_size,
-					    glyphFormat19.data.len);
-	  }
-	}
+	auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+	return hb_blob_create_sub_blob (cbdt.get_blob (),
+					image_offset + GlyphBitmapDataFormat17::min_size,
+					glyphFormat17.data.len);
       }
-
-      return hb_blob_get_empty ();
+      case 18:
+      {
+	if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
+	  return hb_blob_get_empty ();
+	auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
+	return hb_blob_create_sub_blob (cbdt.get_blob (),
+					image_offset + GlyphBitmapDataFormat18::min_size,
+					glyphFormat18.data.len);
+      }
+      case 19:
+      {
+	if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
+	  return hb_blob_get_empty ();
+	auto &glyphFormat19 = StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
+	return hb_blob_create_sub_blob (cbdt.get_blob (),
+					image_offset + GlyphBitmapDataFormat19::min_size,
+					glyphFormat19.data.len);
+      }
+      default: return hb_blob_get_empty (); /* TODO: Support other image formats. */
+      }
     }
 
     bool has_data () const { return cbdt.get_length (); }
@@ -525,9 +943,41 @@
   FixedVersion<>		version;
   UnsizedArrayOf<HBUINT8>	dataZ;
   public:
-  DEFINE_SIZE_ARRAY(4, dataZ);
+  DEFINE_SIZE_ARRAY (4, dataZ);
 };
 
+inline bool
+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);
+  if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
+  cblc_prime->version = version;
+
+  hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table<CBDT> (c->plan->source);
+  unsigned int cbdt_length;
+  CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length);
+  if (unlikely (cbdt_length < CBDT::min_size))
+  {
+    hb_blob_destroy (cbdt_blob);
+    return_trace (false);
+  }
+  _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size);
+
+  for (const BitmapSizeTable& table : + sizeTables.iter ())
+    subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime);
+
+  hb_blob_destroy (cbdt_blob);
+
+  return_trace (CBLC::sink_cbdt (c, &cbdt_prime));
+}
+
 struct CBDT_accelerator_t : CBDT::accelerator_t {};
 
 } /* namespace OT */
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index e2ed7c6..03476fa 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2020  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,12 +21,16 @@
  * 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): Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_COLR_TABLE_HH
 #define HB_OT_COLOR_COLR_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-var-common.hh"
 
 /*
  * COLR -- Color
@@ -33,9 +38,78 @@
  */
 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
 
+#ifndef COLRV1_MAX_NESTING_LEVEL
+#define COLRV1_MAX_NESTING_LEVEL	100
+#endif
+
+#ifndef COLRV1_ENABLE_SUBSETTING
+#define COLRV1_ENABLE_SUBSETTING 1
+#endif
 
 namespace OT {
 
+struct COLR;
+struct hb_colrv1_closure_context_t :
+       hb_dispatch_context_t<hb_colrv1_closure_context_t>
+{
+  template <typename T>
+  return_t dispatch (const T &obj)
+  {
+    if (unlikely (nesting_level_left == 0))
+      return hb_empty_t ();
+
+    if (paint_visited (&obj))
+      return hb_empty_t ();
+
+    nesting_level_left--;
+    obj.closurev1 (this);
+    nesting_level_left++;
+    return hb_empty_t ();
+  }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  bool paint_visited (const void *paint)
+  {
+    hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
+     if (visited_paint.has (delta))
+      return true;
+
+    visited_paint.add (delta);
+    return false;
+  }
+
+  const COLR* get_colr_table () const
+  { return reinterpret_cast<const COLR *> (base); }
+
+  void add_glyph (unsigned glyph_id)
+  { glyphs->add (glyph_id); }
+
+  void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
+  { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
+
+  void add_palette_index (unsigned palette_index)
+  { palette_indices->add (palette_index); }
+
+  public:
+  const void *base;
+  hb_set_t visited_paint;
+  hb_set_t *glyphs;
+  hb_set_t *layer_indices;
+  hb_set_t *palette_indices;
+  unsigned nesting_level_left;
+
+  hb_colrv1_closure_context_t (const void *base_,
+                               hb_set_t *glyphs_,
+                               hb_set_t *layer_indices_,
+                               hb_set_t *palette_indices_,
+                               unsigned nesting_level_left_ = COLRV1_MAX_NESTING_LEVEL) :
+                          base (base_),
+                          glyphs (glyphs_),
+                          layer_indices (layer_indices_),
+                          palette_indices (palette_indices_),
+                          nesting_level_left (nesting_level_left_)
+  {}
+};
 
 struct LayerRecord
 {
@@ -47,8 +121,8 @@
     return_trace (c->check_struct (this));
   }
 
-  protected:
-  HBGlyphID	glyphId;	/* Glyph ID of layer glyph */
+  public:
+  HBGlyphID16	glyphId;	/* Glyph ID of layer glyph */
   Index		colorIdx;	/* Index value to use with a
 				 * selected color palette.
 				 * An index value of 0xFFFF
@@ -75,7 +149,7 @@
   }
 
   public:
-  HBGlyphID	glyphId;	/* Glyph ID of reference glyph */
+  HBGlyphID16	glyphId;	/* Glyph ID of reference glyph */
   HBUINT16	firstLayerIdx;	/* Index (from beginning of
 				 * the Layer Records) to the
 				 * layer record. There will be
@@ -87,6 +161,1076 @@
   DEFINE_SIZE_STATIC (6);
 };
 
+template <typename T>
+struct Variable
+{
+  Variable<T>* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (this));
+  }
+
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { value.closurev1 (c); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    if (!value.subset (c)) return_trace (false);
+    return_trace (c->serializer->embed (varIdxBase));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  protected:
+  T      value;
+  VarIdx varIdxBase;
+  public:
+  DEFINE_SIZE_STATIC (4 + T::static_size);
+};
+
+template <typename T>
+struct NoVariable
+{
+  NoVariable<T>* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (this));
+  }
+
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { value.closurev1 (c); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (value.subset (c));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && value.sanitize (c));
+  }
+
+  T      value;
+  public:
+  DEFINE_SIZE_STATIC (T::static_size);
+};
+
+// Color structures
+
+struct ColorStop
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { c->add_palette_index (paletteIndex); }
+
+  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 (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  F2DOT14	stopOffset;
+  HBUINT16	paletteIndex;
+  F2DOT14	alpha;
+  public:
+  DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
+};
+
+struct Extend : HBUINT8
+{
+  enum {
+    EXTEND_PAD     = 0,
+    EXTEND_REPEAT  = 1,
+    EXTEND_REFLECT = 2,
+  };
+  public:
+  DEFINE_SIZE_STATIC (1);
+};
+
+template <template<typename> class Var>
+struct ColorLine
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  {
+    for (const auto &stop : stops.iter ())
+      stop.closurev1 (c);
+  }
+
+  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 (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);
+    if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
+
+    for (const auto& stop : stops.iter ())
+    {
+      if (!stop.subset (c)) return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  stops.sanitize (c));
+  }
+
+  Extend	extend;
+  Array16Of<Var<ColorStop>>	stops;
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (3, stops);
+};
+
+// Composition modes
+
+// Compositing modes are taken from https://www.w3.org/TR/compositing-1/
+// NOTE: a brief audit of major implementations suggests most support most
+// or all of the specified modes.
+struct CompositeMode : HBUINT8
+{
+  enum {
+    // Porter-Duff modes
+    // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
+    COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
+    COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
+    COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
+    COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
+    COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
+    COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
+    COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
+    COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
+    COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
+    COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
+    COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
+    COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
+    COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
+
+    // Blend modes
+    // https://www.w3.org/TR/compositing-1/#blending
+    COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
+    COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
+    COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
+    COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
+    COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
+    COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
+    COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
+    COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
+    COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
+    COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
+    COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
+
+    // Modes that, uniquely, do not operate on components
+    // https://www.w3.org/TR/compositing-1/#blendingnonseparable
+    COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
+    COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
+    COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
+    COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
+  };
+  public:
+  DEFINE_SIZE_STATIC (1);
+};
+
+struct Affine2x3
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBFixed xx;
+  HBFixed yx;
+  HBFixed xy;
+  HBFixed yy;
+  HBFixed dx;
+  HBFixed dy;
+  public:
+  DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
+};
+
+struct PaintColrLayers
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8	format; /* format = 1 */
+  HBUINT8	numLayers;
+  HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct PaintSolid
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { c->add_palette_index (paletteIndex); }
+
+  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 (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
+  HBUINT16	paletteIndex;
+  F2DOT14	alpha;
+  public:
+  DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintLinearGradient
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { (this+colorLine).closurev1 (c); }
+
+  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->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
+                                            * table) to ColorLine subtable. */
+  FWORD			x0;
+  FWORD			y0;
+  FWORD			x1;
+  FWORD			y1;
+  FWORD			x2;
+  FWORD			y2;
+  public:
+  DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintRadialGradient
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { (this+colorLine).closurev1 (c); }
+
+  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->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
+                                            * table) to ColorLine subtable. */
+  FWORD			x0;
+  FWORD			y0;
+  UFWORD		radius0;
+  FWORD			x1;
+  FWORD			y1;
+  UFWORD		radius1;
+  public:
+  DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintSweepGradient
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { (this+colorLine).closurev1 (c); }
+
+  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->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
+                                            * table) to ColorLine subtable. */
+  FWORD			centerX;
+  FWORD			centerY;
+  F2DOT14		startAngle;
+  F2DOT14		endAngle;
+  public:
+  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
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
+                                       HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    return_trace (out->paint.serialize_subset (c, paint, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && paint.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 10 */
+  Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
+  HBUINT16		gid;
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct PaintColrGlyph
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8	format; /* format = 11 */
+  HBUINT16	gid;
+  public:
+  DEFINE_SIZE_STATIC (3);
+};
+
+template <template<typename> class Var>
+struct PaintTransform
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  bool subset (hb_subset_context_t *c) 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));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  src.sanitize (c, this) &&
+                  transform.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 12(noVar) or 13 (Var) */
+  Offset24To<Paint>		src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
+  Offset24To<Var<Affine2x3>>	transform;
+  public:
+  DEFINE_SIZE_STATIC (7);
+};
+
+struct PaintTranslate
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
+  FWORD		dx;
+  FWORD		dy;
+  public:
+  DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
+};
+
+struct PaintScale
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
+  F2DOT14		scaleX;
+  F2DOT14		scaleY;
+  public:
+  DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
+};
+
+struct PaintScaleAroundCenter
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 18 (noVar) or 19(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
+  F2DOT14	scaleX;
+  F2DOT14	scaleY;
+  FWORD		centerX;
+  FWORD		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
+};
+
+struct PaintScaleUniform
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 20 (noVar) or 21(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
+  F2DOT14		scale;
+  public:
+  DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
+};
+
+struct PaintScaleUniformAroundCenter
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 22 (noVar) or 23(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
+  F2DOT14	scale;
+  FWORD		centerX;
+  FWORD		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
+};
+
+struct PaintRotate
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 24 (noVar) or 25(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
+  F2DOT14		angle;
+  public:
+  DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
+};
+
+struct PaintRotateAroundCenter
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 26 (noVar) or 27(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
+  F2DOT14	angle;
+  FWORD		centerX;
+  FWORD		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
+};
+
+struct PaintSkew
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 28(noVar) or 29 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
+  F2DOT14		xSkewAngle;
+  F2DOT14		ySkewAngle;
+  public:
+  DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
+};
+
+struct PaintSkewAroundCenter
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 30(noVar) or 31 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
+  F2DOT14	xSkewAngle;
+  F2DOT14	ySkewAngle;
+  FWORD		centerX;
+  FWORD		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
+};
+
+struct PaintComposite
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  bool subset (hb_subset_context_t *c) 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 sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  src.sanitize (c, this) &&
+                  backdrop.sanitize (c, this));
+  }
+
+  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 */
+  Offset24To<Paint>	backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct ClipBoxFormat1
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  HBUINT8	format; /* format = 1(noVar) or 2(Var)*/
+  FWORD		xMin;
+  FWORD		yMin;
+  FWORD		xMax;
+  FWORD		yMax;
+  public:
+  DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
+};
+
+struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {};
+
+struct ClipBox
+{
+  ClipBox* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (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);
+    }
+  }
+
+  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 {
+  HBUINT8		format;         /* Format identifier */
+  ClipBoxFormat1	format1;
+  ClipBoxFormat2	format2;
+  } u;
+};
+
+struct ClipRecord
+{
+  ClipRecord* copy (hb_serialize_context_t *c, const void *base) 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);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
+  }
+
+  public:
+  HBUINT16		startGlyphID;  // first gid clip applies to
+  HBUINT16		endGlyphID;    // last gid clip applies to, inclusive
+  Offset24To<ClipBox>	clipBox;   // Box or VarBox
+  public:
+  DEFINE_SIZE_STATIC (7);
+};
+
+struct ClipList
+{
+  unsigned serialize_clip_records (hb_serialize_context_t *c,
+                                   const hb_set_t& gids,
+                                   const hb_map_t& gid_offset_map) const
+  {
+    TRACE_SERIALIZE (this);
+    if (gids.is_empty () ||
+        gid_offset_map.get_population () != gids.get_population ())
+      return_trace (0);
+
+    unsigned count  = 0;
+
+    hb_codepoint_t start_gid= gids.get_min ();
+    hb_codepoint_t prev_gid = start_gid;
+
+    unsigned offset = gid_offset_map.get (start_gid);
+    unsigned prev_offset = offset;
+    for (const hb_codepoint_t _ : gids.iter ())
+    {
+      if (_ == start_gid) continue;
+      
+      offset = gid_offset_map.get (_);
+      if (_ == prev_gid + 1 &&  offset == prev_offset)
+      {
+        prev_gid = _;
+        continue;
+      }
+
+      ClipRecord record;
+      record.startGlyphID = start_gid;
+      record.endGlyphID = prev_gid;
+      record.clipBox = prev_offset;
+
+      if (!c->copy (record, this)) return_trace (0);
+      count++;
+
+      start_gid = _;
+      prev_gid = _;
+      prev_offset = offset;
+    }
+
+    //last one
+    {
+      ClipRecord record;
+      record.startGlyphID = start_gid;
+      record.endGlyphID = prev_gid;
+      record.clipBox = prev_offset;
+      if (!c->copy (record, this)) return_trace (0);
+      count++;
+    }
+    return_trace (count);
+  }
+
+  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);
+    if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+    const hb_set_t& glyphset = *c->plan->_glyphset;
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+    
+    hb_map_t new_gid_offset_map;
+    hb_set_t new_gids;
+    for (const ClipRecord& record : clips.iter ())
+    {
+      unsigned start_gid = record.startGlyphID;
+      unsigned end_gid = record.endGlyphID;
+      for (unsigned gid = start_gid; gid <= end_gid; gid++)
+      {
+        if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
+        unsigned new_gid = glyph_map.get (gid);
+        new_gid_offset_map.set (new_gid, record.clipBox);
+        new_gids.add (new_gid);
+      }
+    }
+
+    unsigned count = serialize_clip_records (c->serializer, 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));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && clips.sanitize (c, this));
+  }
+
+  HBUINT8			format;  // Set to 1.
+  Array32Of<ClipRecord>		clips;  // Clip records, sorted by startGlyphID
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (5, clips);
+};
+
+struct Paint
+{
+  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.paintformat1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
+    case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
+    case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
+    case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
+    case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
+    case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
+    case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
+    case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
+    case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
+    case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
+    case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
+    case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
+    case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
+    case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
+    case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
+    case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
+    case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
+    case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
+    case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
+    case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
+    case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
+    case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
+    case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
+    case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
+    case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
+    case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
+    case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
+    case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  HBUINT8					format;
+  PaintColrLayers				paintformat1;
+  PaintSolid					paintformat2;
+  Variable<PaintSolid>				paintformat3;
+  PaintLinearGradient<NoVariable>		paintformat4;
+  Variable<PaintLinearGradient<Variable>>	paintformat5;
+  PaintRadialGradient<NoVariable>		paintformat6;
+  Variable<PaintRadialGradient<Variable>>	paintformat7;
+  PaintSweepGradient<NoVariable>		paintformat8;
+  Variable<PaintSweepGradient<Variable>>	paintformat9;
+  PaintGlyph					paintformat10;
+  PaintColrGlyph				paintformat11;
+  PaintTransform<NoVariable>			paintformat12;
+  PaintTransform<Variable>			paintformat13;
+  PaintTranslate				paintformat14;
+  Variable<PaintTranslate>			paintformat15;
+  PaintScale					paintformat16;
+  Variable<PaintScale>				paintformat17;
+  PaintScaleAroundCenter			paintformat18;
+  Variable<PaintScaleAroundCenter>		paintformat19;
+  PaintScaleUniform				paintformat20;
+  Variable<PaintScaleUniform>			paintformat21;
+  PaintScaleUniformAroundCenter			paintformat22;
+  Variable<PaintScaleUniformAroundCenter>	paintformat23;
+  PaintRotate					paintformat24;
+  Variable<PaintRotate>				paintformat25;
+  PaintRotateAroundCenter			paintformat26;
+  Variable<PaintRotateAroundCenter>		paintformat27;
+  PaintSkew					paintformat28;
+  Variable<PaintSkew>				paintformat29;
+  PaintSkewAroundCenter				paintformat30;
+  Variable<PaintSkewAroundCenter>		paintformat31;
+  PaintComposite				paintformat32;
+  } u;
+};
+
+struct BaseGlyphPaintRecord
+{
+  int cmp (hb_codepoint_t g) const
+  { 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
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = s->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
+                          HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    return_trace (out->paint.serialize_subset (c, paint, src_base));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
+  }
+
+  public:
+  HBGlyphID16		glyphId;    /* Glyph ID of reference glyph */
+  Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
+                                     * Typically PaintColrLayers */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
+{
+  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);
+    const hb_set_t* glyphset = c->plan->_glyphset;
+
+    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++;
+      else return_trace (false);
+    }
+
+    return_trace (out->len != 0);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
+  }
+};
+
+struct LayerList : Array32OfOffset32To<Paint>
+{
+  const Paint& get_paint (unsigned i) const
+  { return this+(*this)[i]; }
+
+  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);
+
+    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);
+    }
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
+  }
+};
+
 struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@@ -112,24 +1256,265 @@
     return glyph_layers.length;
   }
 
+  struct accelerator_t
+  {
+    accelerator_t () {}
+    ~accelerator_t () { fini (); }
+
+    void init (hb_face_t *face)
+    { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
+
+    void fini () { this->colr.destroy (); }
+
+    bool is_valid () { return colr.get_blob ()->length; }
+
+    void closure_glyphs (hb_codepoint_t glyph,
+			 hb_set_t *related_ids /* OUT */) const
+    { colr->closure_glyphs (glyph, related_ids); }
+
+    void closure_V0palette_indices (const hb_set_t *glyphs,
+				    hb_set_t *palettes /* OUT */) const
+    { colr->closure_V0palette_indices (glyphs, palettes); }
+
+    void closure_forV1 (hb_set_t *glyphset,
+                        hb_set_t *layer_indices,
+                        hb_set_t *palette_indices) const
+    { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
+
+    private:
+    hb_blob_ptr_t<COLR> colr;
+  };
+
+  void closure_glyphs (hb_codepoint_t glyph,
+		       hb_set_t *related_ids /* OUT */) const
+  {
+    const BaseGlyphRecord *record = get_base_glyph_record (glyph);
+    if (!record) return;
+
+    auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
+								       record->numLayers);
+    if (!glyph_layers.length) return;
+    related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
+  }
+
+  void closure_V0palette_indices (const hb_set_t *glyphs,
+				  hb_set_t *palettes /* OUT */) const
+  {
+    if (!numBaseGlyphs || !numLayers) return;
+    hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
+    hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
+
+    for (const BaseGlyphRecord record : baseGlyphs)
+    {
+      if (!glyphs->has (record.glyphId)) continue;
+      hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
+                                                                   record.numLayers);
+      for (const LayerRecord layer : glyph_layers)
+        palettes->add (layer.colorIdx);
+    }
+  }
+
+  void closure_forV1 (hb_set_t *glyphset,
+                      hb_set_t *layer_indices,
+                      hb_set_t *palette_indices) const
+  {
+    if (version != 1) return;
+    hb_set_t visited_glyphs;
+
+    hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
+    const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
+
+    for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
+    {
+      unsigned gid = baseglyph_paintrecord.glyphId;
+      if (!glyphset->has (gid)) continue;
+
+      const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
+      paint.dispatch (&c);
+    }
+    hb_set_union (glyphset, &visited_glyphs);
+  }
+
+  const LayerList& get_layerList () const
+  { return (this+layerList); }
+
+  const BaseGlyphList& get_baseglyphList () const
+  { return (this+baseGlyphList); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-			  (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
-			  (this+layersZ).sanitize (c, numLayers)));
+    return_trace (c->check_struct (this) &&
+                  (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
+                  (this+layersZ).sanitize (c, numLayers) &&
+                  (version == 0 ||
+		   (COLRV1_ENABLE_SUBSETTING && version == 1 &&
+		    baseGlyphList.sanitize (c, this) &&
+		    layerList.sanitize (c, this) &&
+		    clipList.sanitize (c, this) &&
+		    varIdxMap.sanitize (c, this) &&
+		    varStore.sanitize (c, this))));
+  }
+
+  template<typename BaseIterator, typename LayerIterator,
+	   hb_requires (hb_is_iterator (BaseIterator)),
+	   hb_requires (hb_is_iterator (LayerIterator))>
+  bool serialize_V0 (hb_serialize_context_t *c,
+		     unsigned version,
+		     BaseIterator base_it,
+		     LayerIterator layer_it)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (base_it.len () != layer_it.len ()))
+      return_trace (false);
+
+    this->version = version;
+    numLayers = 0;
+    numBaseGlyphs = base_it.len ();
+    if (numBaseGlyphs == 0)
+    {
+      baseGlyphsZ = 0;
+      layersZ = 0;
+      return_trace (true);
+    }
+
+    c->push ();
+    for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
+    {
+      auto* record = c->embed (_);
+      if (unlikely (!record)) return_trace (false);
+      record->firstLayerIdx = numLayers;
+      numLayers += record->numLayers;
+    }
+    c->add_link (baseGlyphsZ, c->pop_pack ());
+
+    c->push ();
+    for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
+      _.as_array ().copy (c);
+
+    c->add_link (layersZ, c->pop_pack ());
+
+    return_trace (true);
+  }
+
+  const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
+  {
+    if ((unsigned int) gid == 0) // Ignore notdef.
+      return nullptr;
+    const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
+    if ((record && (hb_codepoint_t) record->glyphId != gid))
+      record = nullptr;
+    return record;
+  }
+
+  const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
+  {
+    const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
+    if ((record && (hb_codepoint_t) record->glyphId != gid))
+      record = nullptr;
+    return record;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+
+    auto base_it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
+			      {
+				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+
+				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
+				if (unlikely (!old_record))
+				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
+
+				BaseGlyphRecord new_record = {};
+				new_record.glyphId = new_gid;
+				new_record.numLayers = old_record->numLayers;
+				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
+			      })
+    | hb_filter (hb_first)
+    | hb_map_retains_sorting (hb_second)
+    ;
+
+    auto layer_it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map (reverse_glyph_map)
+    | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
+			      {
+				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
+				hb_vector_t<LayerRecord> out_layers;
+
+				if (unlikely (!old_record ||
+					      old_record->firstLayerIdx >= numLayers ||
+					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
+				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
+
+				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
+											     old_record->numLayers);
+				out_layers.resize (layers.length);
+				for (unsigned int i = 0; i < layers.length; i++) {
+				  out_layers[i] = layers[i];
+				  hb_codepoint_t new_gid = 0;
+				  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);
+				}
+
+				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
+			      })
+    | hb_filter (hb_first)
+    | hb_map_retains_sorting (hb_second)
+    ;
+
+    if (version == 0 && (!base_it || !layer_it))
+      return_trace (false);
+
+    COLR *colr_prime = c->serializer->start_embed<COLR> ();
+    if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
+
+    if (version == 0)
+    return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
+
+    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))
+    {
+      if (c->serializer->in_error ()) return_trace (false);
+      //no more COLRv1 glyphs: downgrade to version 0
+      c->serializer->revert (snap);
+      return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
+    }
+
+    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->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
+    //TODO: subset varStore once it's implemented in fonttools
+    return_trace (true);
   }
 
   protected:
   HBUINT16	version;	/* Table version number (starts at 0). */
   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
-  LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
+  NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
 		baseGlyphsZ;	/* Offset to Base Glyph records. */
-  LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
+  NNOffset32To<UnsizedArrayOf<LayerRecord>>
 		layersZ;	/* Offset to Layer Records. */
   HBUINT16	numLayers;	/* Number of Layer Records. */
+  // Version-1 additions
+  Offset32To<BaseGlyphList>		baseGlyphList;
+  Offset32To<LayerList>			layerList;
+  Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
+  Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
+  Offset32To<VariationStore>		varStore;
   public:
-  DEFINE_SIZE_STATIC (14);
+  DEFINE_SIZE_MIN (14);
 };
 
 } /* namespace OT */
diff --git a/src/hb-ot-color-colrv1-closure.hh b/src/hb-ot-color-colrv1-closure.hh
new file mode 100644
index 0000000..ca85ba6
--- /dev/null
+++ b/src/hb-ot-color-colrv1-closure.hh
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ * 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.
+ *
+ */
+
+#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
+#define HB_OT_COLR_COLRV1_CLOSURE_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-color-colr-table.hh"
+
+/*
+ * COLR -- Color
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+ */
+namespace OT {
+
+HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  c->add_layer_indices (firstLayerIndex, numLayers);
+  const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
+  for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+  {
+    const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i];
+    paint.dispatch (c);
+  }
+}
+
+HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  c->add_glyph (gid);
+  (this+paint).dispatch (c);
+}
+
+HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  const COLR *colr_table = c->get_colr_table ();
+  const BaseGlyphPaintRecord* baseglyph_paintrecord = colr_table->get_base_glyph_paintrecord (gid);
+  if (!baseglyph_paintrecord) return;
+  c->add_glyph (gid);
+
+  const BaseGlyphList &baseglyph_list = colr_table->get_baseglyphList ();
+  (&baseglyph_list+baseglyph_paintrecord->paint).dispatch (c);
+}
+
+template <template<typename> class Var>
+HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
+{ (this+src).dispatch (c); }
+
+HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+  (this+backdrop).dispatch (c);
+}
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index 1b3c7fc..a9deeba 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/src/hb-ot-color-cpal-table.hh
@@ -39,7 +39,6 @@
  */
 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
 
-
 namespace OT {
 
 
@@ -74,6 +73,44 @@
   }
 
   public:
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned palette_count,
+                  unsigned color_count,
+                  const void *base,
+                  const hb_map_t *color_index_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->allocate_size<CPALV1Tail> (static_size);
+    if (unlikely (!out)) return_trace (false);
+
+    out->paletteFlagsZ = 0;
+    if (paletteFlagsZ)
+      out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+
+    out->paletteLabelsZ = 0;
+    if (paletteLabelsZ)
+      out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+
+    const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
+    if (colorLabelsZ)
+    {
+      c->push ();
+      for (const auto _ : colorLabels)
+      {
+        if (!color_index_map->has (_)) continue;
+        NameID new_color_idx;
+        new_color_idx = color_index_map->get (_);
+        if (!c->copy<NameID> (new_color_idx))
+        {
+          c->pop_discard ();
+          return_trace (false);
+        }
+      }
+      c->add_link (out->colorLabelsZ, c->pop_pack ());
+    }
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c,
 		 const void *base,
 		 unsigned int palette_count,
@@ -87,15 +124,17 @@
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
+  // TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
+  //                     here. Currently they are needed since UnsizedArrayOf doesn't define null_size
+  NNOffset32To<UnsizedArrayOf<HBUINT32>>
 		paletteFlagsZ;		/* Offset from the beginning of CPAL table to
 					 * the Palette Type Array. Set to 0 if no array
 					 * is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID>>
+  NNOffset32To<UnsizedArrayOf<NameID>>
 		paletteLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the palette labels array. Set to 0 if no
 					 * array is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID>>
+  NNOffset32To<UnsizedArrayOf<NameID>>
 		colorLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the color labels array. Set to 0
 					 * if no array is provided. */
@@ -142,12 +181,9 @@
 								       numColors);
     if (color_count)
     {
-      hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
-      /* Always return numColors colors per palette even if it has out-of-bounds start index. */
-      unsigned int count = hb_min ((unsigned) hb_max ((int) (numColors - start_offset), 0), *color_count);
-      *color_count = count;
-      for (unsigned int i = 0; i < count; i++)
-	colors[i] = segment_colors[i]; /* Bound-checked read. */
+      + palette_colors.sub_array (start_offset, color_count)
+      | hb_sink (hb_array (colors, *color_count))
+      ;
     }
     return numColors;
   }
@@ -155,11 +191,89 @@
   private:
   const CPALV1Tail& v1 () const
   {
-    if (version == 0) return Null(CPALV1Tail);
+    if (version == 0) return Null (CPALV1Tail);
     return StructAfter<CPALV1Tail> (*this);
   }
 
   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
+  {
+    TRACE_SERIALIZE (this);
+
+    for (const auto idx : color_record_indices)
+    {
+      HBUINT16 new_idx;
+      if (idx == 0) new_idx = 0;
+      else new_idx = color_record_index_map.get (idx);
+      if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
+    }
+
+    c->push ();
+    for (const auto _ : retained_color_record_indices.iter ())
+    {
+      if (!c->copy<BGRAColor> (color_records[_]))
+      {
+        c->pop_discard ();
+        return_trace (false);
+      }
+    }
+    c->add_link (colorRecordsZ, c->pop_pack ());
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    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;
+    for (const auto _ : color_index_map->keys ())
+    {
+      if (_ == 0xFFFF) continue;
+      retained_color_indices.add (_);
+    }
+    if (retained_color_indices.is_empty ()) return_trace (false);
+
+    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;
+
+    unsigned record_count = 0;
+    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++;
+      }
+    }
+
+    out->numColorRecords = record_count;
+    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))
+      return_trace (false);
+
+    if (version == 1)
+      return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -176,7 +290,7 @@
   HBUINT16	numPalettes;		/* Number of palettes in the table. */
   HBUINT16	numColorRecords;	/* Total number of color records, combined for
 					 * all palettes. */
-  LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
+  NNOffset32To<UnsizedArrayOf<BGRAColor>>
 		colorRecordsZ;		/* Offset from the beginning of CPAL table to
 					 * the first ColorRecord. */
   UnsizedArrayOf<HBUINT16>
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index 35d3fd5..d2911f1 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2020  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,12 +21,15 @@
  * 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): Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_SBIX_TABLE_HH
 #define HB_OT_COLOR_SBIX_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
 
 /*
  * sbix -- Standard Bitmap Graphics
@@ -40,6 +44,20 @@
 
 struct SBIXGlyph
 {
+  SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const
+  {
+    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;
+    new_glyph->yOffset = yOffset;
+    new_glyph->graphicType = graphicType;
+    data.copy (c, data_length);
+    return_trace (new_glyph);
+  }
+
   HBINT16	xOffset;	/* The horizontal (x-axis) offset from the left
 				 * edge of the graphic to the glyph’s origin.
 				 * That is, the x-coordinate of the point on the
@@ -62,6 +80,9 @@
 
 struct SBIXStrike
 {
+  static unsigned int get_size (unsigned num_glyphs)
+  { return min_size + num_glyphs * HBUINT32::static_size; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -116,12 +137,55 @@
     return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
   }
 
+  bool subset (hb_subset_context_t *c, unsigned int available_len) const
+  {
+    TRACE_SUBSET (this);
+    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;
+    out->resolution = resolution;
+    HBUINT32 head;
+    head = get_size (num_output_glyphs + 1);
+
+    bool has_glyphs = false;
+    for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++)
+    {
+      hb_codepoint_t old_gid;
+      if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) ||
+	  unlikely (imageOffsetsZ[old_gid].is_null () ||
+		    imageOffsetsZ[old_gid + 1].is_null () ||
+		    imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] ||
+		    imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) ||
+		    (unsigned int) imageOffsetsZ[old_gid + 1] > available_len)
+      {
+	out->imageOffsetsZ[new_gid] = head;
+	continue;
+      }
+      has_glyphs = true;
+      unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid];
+      unsigned int glyph_data_length = delta - SBIXGlyph::min_size;
+      if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length))
+	return_trace (false);
+      out->imageOffsetsZ[new_gid] = head;
+      head += delta;
+    }
+    if (has_glyphs)
+      out->imageOffsetsZ[num_output_glyphs] = head;
+    else
+      c->serializer->revert (snap);
+    return_trace (has_glyphs);
+  }
+
   public:
   HBUINT16	ppem;		/* The PPEM size for which this strike was designed. */
   HBUINT16	resolution;	/* The device pixel density (in PPI) for which this
 				 * strike was designed. (E.g., 96 PPI, 192 PPI.) */
   protected:
-  UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
+  UnsizedArrayOf<Offset32To<SBIXGlyph>>
 		imageOffsetsZ;	/* Offset from the beginning of the strike data header
 				 * to bitmap data for an individual glyph ID. */
   public:
@@ -140,7 +204,7 @@
   {
     void init (hb_face_t *face)
     {
-      table = hb_sanitize_context_t().reference_table<sbix> (face);
+      table = hb_sanitize_context_t ().reference_table<sbix> (face);
       num_glyphs = face->get_num_glyphs ();
     }
     void fini () { table.destroy (); }
@@ -173,7 +237,7 @@
     {
       unsigned count = table->strikes.len;
       if (unlikely (!count))
-	return Null(SBIXStrike);
+	return Null (SBIXStrike);
 
       unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
       if (!requested_ppem)
@@ -237,7 +301,7 @@
       extents->x_bearing = x_offset;
       extents->y_bearing = png.IHDR.height + y_offset;
       extents->width     = png.IHDR.width;
-      extents->height    = -png.IHDR.height;
+      extents->height    = -1 * png.IHDR.height;
 
       /* Convert to font units. */
       if (strike_ppem)
@@ -275,11 +339,68 @@
 			  strikes.sanitize (c, this)));
   }
 
+  bool
+  add_strike (hb_subset_context_t *c, unsigned i) const
+  {
+    if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i])
+      return false;
+
+    return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]);
+  }
+
+  bool serialize_strike_offsets (hb_subset_context_t *c) const
+  {
+    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;
+    hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
+    for (int i = strikes.len - 1; i >= 0; --i)
+    {
+      auto* o = out->serialize_append (c->serializer);
+      if (unlikely (!o)) return_trace (false);
+      *o = 0;
+      auto snap = c->serializer->snapshot ();
+      c->serializer->push ();
+      bool ret = add_strike (c, i);
+      if (!ret)
+      {
+	c->serializer->pop_discard ();
+	out->pop ();
+	c->serializer->revert (snap);
+      }
+      else
+      {
+	objidxs.push (c->serializer->pop_pack ());
+	new_strikes.push (o);
+      }
+    }
+    for (unsigned int i = 0; i < new_strikes.length; ++i)
+      c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]);
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t* c) const
+  {
+    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);
+
+    return_trace (serialize_strike_offsets (c));
+  }
+
   protected:
   HBUINT16	version;	/* Table version number — set to 1 */
   HBUINT16	flags;		/* Bit 0: Set to 1. Bit 1: Draw outlines.
 				 * Bits 2 to 15: reserved (set to 0). */
-  LOffsetLArrayOf<SBIXStrike>
+  Array32OfOffset32To<SBIXStrike>
 		strikes;	/* Offsets from the beginning of the 'sbix'
 				 * table to data for each individual bitmap strike. */
   public:
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 926d61e..e022ef4 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -62,7 +62,7 @@
 				 * this index entry. */
   HBUINT16	endGlyphID;	/* The last glyph ID in the range described by
 				 * this index entry. Must be >= startGlyphID. */
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		svgDoc;		/* Offset from the beginning of the SVG Document Index
 				 * to an SVG document. Must be non-zero. */
   HBUINT32	svgDocLength;	/* Length of the SVG document.
@@ -80,7 +80,7 @@
   struct accelerator_t
   {
     void init (hb_face_t *face)
-    { table = hb_sanitize_context_t().reference_table<SVG> (face); }
+    { table = hb_sanitize_context_t ().reference_table<SVG> (face); }
     void fini () { table.destroy (); }
 
     hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
@@ -107,7 +107,7 @@
 
   protected:
   HBUINT16	version;	/* Table version (starting at 0). */
-  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
+  Offset32To<SortedArray16Of<SVGDocumentIndexEntry>>
 		svgDocEntries;	/* Offset (relative to the start of the SVG table) to the
 				 * SVG Documents Index. Must be non-zero. */
 				/* Array of SVG Document Index Entries. */
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 0e7203a..4170b71 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -37,9 +37,6 @@
 #include "hb-ot-color-sbix-table.hh"
 #include "hb-ot-color-svg-table.hh"
 
-#include <stdlib.h>
-#include <string.h>
-
 
 /**
  * SECTION:hb-ot-color
@@ -64,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
  */
@@ -195,7 +192,7 @@
  *
  * Tests whether a face includes any `COLR` color layers.
  *
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 2.1.0
  */
@@ -242,7 +239,7 @@
  *
  * 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
  */
@@ -280,7 +277,7 @@
  *
  * 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
  */
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
index 63ef20a..c23ce4d 100644
--- a/src/hb-ot-color.h
+++ b/src/hb-ot-color.h
@@ -26,7 +26,7 @@
  * Google Author(s): Sascha Brawer, Behdad Esfahbod
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -66,6 +66,8 @@
  * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
  *   palette is appropriate to use when displaying the font on a dark background such as black.
  *
+ * Flags that describe the properties of color palette.
+ *
  * Since: 2.1.0
  */
 typedef enum { /*< flags >*/
@@ -95,13 +97,14 @@
 
 /**
  * hb_ot_color_layer_t:
+ * @glyph: the glyph ID of the layer
+ * @color_index: the palette color index of the layer
  *
  * Pairs of glyph and color index.
  *
  * Since: 2.1.0
  **/
-typedef struct hb_ot_color_layer_t
-{
+typedef struct hb_ot_color_layer_t {
   hb_codepoint_t glyph;
   unsigned int   color_index;
 } hb_ot_color_layer_t;
diff --git a/src/hb-ot-deprecated.h b/src/hb-ot-deprecated.h
index bc72f8a..ce6b6fe 100644
--- a/src/hb-ot-deprecated.h
+++ b/src/hb-ot-deprecated.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -41,6 +41,13 @@
 
 
 /* https://github.com/harfbuzz/harfbuzz/issues/1734 */
+/**
+ * HB_MATH_GLYPH_PART_FLAG_EXTENDER:
+ *
+ * Use #HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER instead.
+ *
+ * Deprecated: 2.5.1
+ */
 #define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
 
 
@@ -71,6 +78,8 @@
 /**
  * HB_OT_VAR_NO_AXIS_INDEX:
  *
+ * Do not use.
+ *
  * Since: 1.4.2
  * Deprecated: 2.2.0
  */
@@ -78,12 +87,18 @@
 
 /**
  * hb_ot_var_axis_t:
+ * @tag: axis tag
+ * @name_id: axis name identifier
+ * @min_value: minimum value of the axis
+ * @default_value: default value of the axis
+ * @max_value: maximum value of the axis
+ *
+ * Use #hb_ot_var_axis_info_t instead.
  *
  * Since: 1.4.2
  * Deprecated: 2.2.0
  */
-typedef struct hb_ot_var_axis_t
-{
+typedef struct hb_ot_var_axis_t {
   hb_tag_t tag;
   hb_ot_name_id_t name_id;
   float min_value;
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh
index 6fa9baf..ffbbb1b 100644
--- a/src/hb-ot-face-table-list.hh
+++ b/src/hb-ot-face-table-list.hh
@@ -40,7 +40,7 @@
 
 /* This lists font tables that the hb_face_t will contain and lazily
  * load.  Don't add a table unless it's used though.  This is not
- * exactly free. */
+ * exactly zero-cost. */
 
 /* v--- Add new tables in the right place here. */
 
@@ -53,13 +53,13 @@
 HB_OT_TABLE (OT, hhea)
 HB_OT_ACCELERATOR (OT, hmtx)
 HB_OT_TABLE (OT, OS2)
-#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS)
+#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
 HB_OT_ACCELERATOR (OT, post)
 #endif
 #ifndef HB_NO_NAME
 HB_OT_ACCELERATOR (OT, name)
 #endif
-#ifndef HB_NO_STAT
+#ifndef HB_NO_STYLE
 HB_OT_TABLE (OT, STAT)
 #endif
 #ifndef HB_NO_META
@@ -113,7 +113,6 @@
 HB_OT_TABLE (AAT, kerx)
 HB_OT_TABLE (AAT, ankr)
 HB_OT_TABLE (AAT, trak)
-HB_OT_TABLE (AAT, lcar)
 HB_OT_TABLE (AAT, ltag)
 HB_OT_TABLE (AAT, feat)
 // HB_OT_TABLE (AAT, opbd)
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 96f94e4..5c044c1 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -183,22 +183,21 @@
 			 void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  bool ret = false;
 
 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
-  if (!ret) ret = ot_face->sbix->get_extents (font, glyph, extents);
+  if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
 #endif
-  if (!ret) ret = ot_face->glyf->get_extents (font, glyph, extents);
+  if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
 #ifndef HB_NO_OT_FONT_CFF
-  if (!ret) ret = ot_face->cff1->get_extents (font, glyph, extents);
-  if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents);
+  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 (!ret) ret = ot_face->CBDT->get_extents (font, glyph, extents);
+  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
 #endif
 
   // TODO Hook up side-bearings variations.
-  return ret;
+  return false;
 }
 
 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
@@ -210,7 +209,11 @@
 		      void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  return ot_face->post->get_glyph_name (glyph, name, size);
+  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;
+#endif
+  return false;
 }
 static hb_bool_t
 hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
@@ -220,7 +223,11 @@
 			   void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  return ot_face->post->get_glyph_from_name (name, len, glyph);
+  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;
+#endif
+  return false;
 }
 #endif
 
@@ -246,9 +253,7 @@
 	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ot_funcs ();
-#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>
 {
@@ -274,21 +279,17 @@
 
     hb_font_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ot_funcs);
-#endif
+    hb_atexit (free_static_ot_funcs);
 
     return funcs;
   }
 } static_ot_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ot_funcs ()
 {
   static_ot_funcs.free_instance ();
 }
-#endif
 
 static hb_font_funcs_t *
 _hb_ot_get_font_funcs ()
@@ -299,6 +300,9 @@
 
 /**
  * hb_ot_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Sets the font functions to use when working with @font. 
  *
  * Since: 0.9.28
  **/
diff --git a/src/hb-ot-font.h b/src/hb-ot-font.h
index 80eaa54..e7959d1 100644
--- a/src/hb-ot-font.h
+++ b/src/hb-ot-font.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh
index 94fff58..f2a9cad 100644
--- a/src/hb-ot-gasp-table.hh
+++ b/src/hb-ot-gasp-table.hh
@@ -48,8 +48,8 @@
   }
 
   public:
-  HBUINT16 	rangeMaxPPEM;	/* Upper limit of range, in PPEM */
-  HBUINT16 	rangeGaspBehavior;
+  HBUINT16	rangeMaxPPEM;	/* Upper limit of range, in PPEM */
+  HBUINT16	rangeGaspBehavior;
 				/* Flags describing desired rasterizer behavior. */
   public:
   DEFINE_SIZE_STATIC (4);
@@ -71,7 +71,7 @@
 
   protected:
   HBUINT16	version;	/* Version number (set to 1) */
-  ArrayOf<GaspRange>
+  Array16Of<GaspRange>
 		gaspRanges;	/* Number of records to follow
 				 * Sorted by ppem */
   public:
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 571e50e..6b419ea 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -34,8 +34,7 @@
 #include "hb-ot-head-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-var-gvar-table.hh"
-
-#include <float.h>
+#include "hb-draw.hh"
 
 namespace OT {
 
@@ -46,6 +45,10 @@
  */
 #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
 {
@@ -92,11 +95,14 @@
   static bool
   _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
   {
-    unsigned max_offset = + padded_offsets | hb_reduce(hb_add, 0);
+    unsigned max_offset =
+    + padded_offsets
+    | hb_reduce (hb_add, 0)
+    ;
     unsigned num_offsets = padded_offsets.len () + 1;
     bool use_short_loca = max_offset < 0x1FFFF;
     unsigned entry_size = use_short_loca ? 2 : 4;
-    char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
+    char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
 
     if (unlikely (!loca_prime_data)) return false;
 
@@ -105,18 +111,18 @@
 	       entry_size, num_offsets, max_offset, entry_size * num_offsets);
 
     if (use_short_loca)
-      _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets));
+      _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));
+      _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,
-					    free);
+    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);
+	       && _add_head_and_set_loca_version (plan, use_short_loca);
 
     hb_blob_destroy (loca_blob);
     return result;
@@ -148,7 +154,19 @@
 		  const hb_subset_plan_t *plan)
   {
     TRACE_SERIALIZE (this);
+    unsigned init_len = c->length ();
     for (const auto &_ : it) _.serialize (c, 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);
   }
 
@@ -172,7 +190,7 @@
     | hb_map (&SubsetGlyph::padded_size)
     ;
 
-    if (c->serializer->in_error ()) return_trace (false);
+    if (unlikely (c->serializer->in_error ())) return_trace (false);
     return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
 								    padded_offsets)));
   }
@@ -195,10 +213,15 @@
 		if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
 		  return subset_glyph;
 
-		subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
-		if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
-		else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
-
+		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)
@@ -227,22 +250,24 @@
 
   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
+      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;
@@ -261,6 +286,18 @@
       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
@@ -349,9 +386,9 @@
       return tx || ty;
     }
 
-    public:
+    protected:
     HBUINT16	flags;
-    HBGlyphID	glyphIndex;
+    HBGlyphID16	glyphIndex;
     public:
     DEFINE_SIZE_MIN (4);
   };
@@ -360,47 +397,87 @@
   {
     typedef const CompositeGlyphChain *__item_t__;
     composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
-      glyph (glyph_), current (current_)
-    { if (!in_range (current)) current = nullptr; }
-    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
+        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->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; }
+      if (!current->has_more ()) { current = nullptr; return; }
 
-      const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
-							 CompositeGlyphChain> (*current);
-      if (!in_range (possible)) { current = nullptr; return; }
-      current = possible;
+      set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
     }
     bool operator != (const composite_iter_t& o) const
     { return glyph != o.glyph || current != o.current; }
 
-    bool in_range (const CompositeGlyphChain *composite) const
+
+    void set_next (const CompositeGlyphChain *composite)
     {
-      return glyph.in_range (composite, CompositeGlyphChain::min_size)
-	  && glyph.in_range (composite, composite->get_size ());
+      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, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+      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 (font->face->table.hmtx->get_side_bearing (gid));
+	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));
@@ -445,23 +522,11 @@
 	return instructionLength;
       }
 
-      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_RESERVED1 = 0x40,
-	FLAG_RESERVED2 = 0x80
-      };
-
       const Glyph trim_padding () const
       {
 	/* based on FontTools _g_l_y_f.py::trim */
-	const char *glyph = bytes.arrayZ;
-	const char *glyph_end = glyph + bytes.length;
+	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 ();
 
@@ -470,7 +535,6 @@
 	unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
 
 	glyph += 2 + num_instructions;
-	if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
 
 	unsigned int coord_bytes = 0;
 	unsigned int coords_with_flags = 0;
@@ -519,70 +583,64 @@
 	dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
       }
 
-      struct x_setter_t
+      void set_overlaps_flag ()
       {
-	void set (contour_point_t &point, float v) const { point.x = v; }
-	bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; }
-	bool is_same  (uint8_t flag) const { return flag & FLAG_X_SAME; }
-      };
+        if (unlikely (!header.numberOfContours)) return;
 
-      struct y_setter_t
-      {
-	void set (contour_point_t &point, float v) const { point.y = v; }
-	bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; }
-	bool is_same  (uint8_t flag) const { return flag & FLAG_Y_SAME; }
-      };
+        unsigned flags_offset = length (instructions_length ());
+        if (unlikely (length (flags_offset + 1) > bytes.length)) return;
 
-      template <typename T>
+	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)
+			       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)
       {
-	T coord_setter;
 	float v = 0;
-	for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++)
+	for (unsigned i = 0; i < points_.length; i++)
 	{
 	  uint8_t flag = points_[i].flag;
-	  if (coord_setter.is_short (flag))
+	  if (flag & short_flag)
 	  {
-	    if (unlikely (!bytes.in_range (p))) return false;
-	    if (coord_setter.is_same (flag))
+	    if (unlikely (!bytes.check_range (p))) return false;
+	    if (flag & same_flag)
 	      v += *p++;
 	    else
 	      v -= *p++;
 	  }
 	  else
 	  {
-	    if (!coord_setter.is_same (flag))
+	    if (!(flag & same_flag))
 	    {
-	      if (unlikely (!bytes.in_range ((const HBUINT16 *) p))) return false;
+	      if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false;
 	      v += *(const HBINT16 *) p;
 	      p += HBINT16::static_size;
 	    }
 	  }
-	  coord_setter.set (points_[i], v);
+	  setter (points_[i], v);
 	}
 	return true;
       }
 
       bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
-			       hb_vector_t<unsigned int> &end_points_ /* OUT */,
-			       const bool phantom_only=false) const
+			       bool phantom_only = false) const
       {
 	const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
 	int num_contours = header.numberOfContours;
-	if (unlikely (!bytes.in_range (&endPtsOfContours[num_contours + 1]))) return false;
+	if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
 	unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
 
-	points_.resize (num_points + PHANTOM_COUNT);
+	points_.resize (num_points);
 	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
 	if (phantom_only) return true;
 
-	/* Read simple glyph points if !phantom_only */
-	end_points_.resize (num_contours);
-
 	for (int i = 0; i < num_contours; i++)
-	  end_points_[i] = endPtsOfContours[i];
+	  points_[endPtsOfContours[i]].is_end_point = true;
 
 	/* Skip instructions */
 	const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
@@ -591,12 +649,12 @@
 	/* Read flags */
 	for (unsigned int i = 0; i < num_points; i++)
 	{
-	  if (unlikely (!bytes.in_range (p))) return false;
+	  if (unlikely (!bytes.check_range (p))) return false;
 	  uint8_t flag = *p++;
 	  points_[i].flag = flag;
 	  if (flag & FLAG_REPEAT)
 	  {
-	    if (unlikely (!bytes.in_range (p))) return false;
+	    if (unlikely (!bytes.check_range (p))) return false;
 	    unsigned int repeat_count = *p++;
 	    while ((repeat_count-- > 0) && (++i < num_points))
 	      points_[i].flag = flag;
@@ -604,8 +662,10 @@
 	}
 
 	/* Read x & y coordinates */
-	return (read_points<x_setter_t> (p, points_, bytes) &&
-		read_points<y_setter_t> (p, points_, bytes));
+	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);
       }
     };
 
@@ -628,7 +688,7 @@
 	  last = &item;
 	if (unlikely (!last)) return 0;
 
-	if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS)
+	if (last->has_instructions ())
 	  start = (char *) last - &bytes + last->get_size ();
 	if (unlikely (start > end)) return 0;
 	return end - start;
@@ -638,40 +698,25 @@
        * If removing hints it falls out of that. */
       const Glyph trim_padding () const { return Glyph (bytes); }
 
-      /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */
       void drop_hints ()
       {
 	for (const auto &_ : get_iterator ())
-	  *const_cast<OT::HBUINT16 *> (&_.flags) = (uint16_t) _.flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS;
+	  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)); }
 
-      bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
-			       hb_vector_t<unsigned int> &end_points_ /* OUT */,
-			       const bool phantom_only=false) const
+      void set_overlaps_flag ()
       {
-	/* add one pseudo point for each component in composite glyph */
-	unsigned int num_points = hb_len (get_iterator ());
-	points_.resize (num_points + PHANTOM_COUNT);
-	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
-	return true;
+        const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
+                .set_overlaps_flag ();
       }
     };
 
     enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
 
-    enum phantom_point_index_t
-    {
-      PHANTOM_LEFT   = 0,
-      PHANTOM_RIGHT  = 1,
-      PHANTOM_TOP    = 2,
-      PHANTOM_BOTTOM = 3,
-      PHANTOM_COUNT  = 4
-    };
-
     public:
     composite_iter_t get_composite_iterator () const
     {
@@ -697,6 +742,15 @@
       }
     }
 
+    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) {
@@ -706,167 +760,67 @@
       }
     }
 
-    /* for a simple glyph, return contour end points, flags, along with coordinate points
-     * for a composite glyph, return pseudo component points
-     * in both cases points trailed with four phantom points
-     */
-    bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
-			     hb_vector_t<unsigned int> &end_points_ /* OUT */,
-			     const bool phantom_only=false) const
-    {
-      switch (type) {
-      case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only);
-      case SIMPLE:    return SimpleGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only);
-      default:
-	/* empty glyph */
-	points_.resize (PHANTOM_COUNT);
-	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
-	return true;
-      }
-    }
-
-    bool is_simple_glyph ()    const { return type == SIMPLE; }
-    bool is_composite_glyph () const { return type == COMPOSITE; }
-
-    bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
-    {
-      if (type == EMPTY) return true; /* Empty glyph; zero extents. */
-      return header->get_extents (font, gid, extents);
-    }
-
-    hb_bytes_t get_bytes ()          const { return bytes; }
-    const GlyphHeader &get_header () const { return *header; }
-
-    Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) :
-      bytes (bytes_), 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;
-    const GlyphHeader *header;
-    unsigned type;
-  };
-
-  struct accelerator_t
-  {
-    void init (hb_face_t *face_)
-    {
-      short_offset = false;
-      num_glyphs = 0;
-      loca_table = nullptr;
-      glyf_table = nullptr;
-      face = face_;
-      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);
-
-      num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
-    }
-
-    void fini ()
-    {
-      loca_table.destroy ();
-      glyf_table.destroy ();
-    }
-
-    enum phantom_point_index_t
-    {
-      PHANTOM_LEFT   = 0,
-      PHANTOM_RIGHT  = 1,
-      PHANTOM_TOP    = 2,
-      PHANTOM_BOTTOM = 3,
-      PHANTOM_COUNT  = 4
-    };
-
-    protected:
-
-    void init_phantom_points (hb_codepoint_t gid, hb_array_t<contour_point_t> &phantoms /* IN/OUT */) const
-    {
-      const Glyph &glyph = glyph_for_gid (gid);
-      int h_delta = (int) glyph.get_header ().xMin - face->table.hmtx->get_side_bearing (gid);
-      int v_orig  = (int) glyph.get_header ().yMax + face->table.vmtx->get_side_bearing (gid);
-      unsigned int h_adv = face->table.hmtx->get_advance (gid);
-      unsigned int v_adv = face->table.vmtx->get_advance (gid);
-
-      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;
-    }
-
-    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 - min_x);
-	extents->y_bearing = font->em_scalef_y (max_y);
-	extents->height = font->em_scalef_y (min_y - max_y);
-      }
-
-      protected:
-      float min_x, min_y, max_x, max_y;
-    };
-
-#ifndef HB_NO_VAR
     /* Note: Recursively calls itself.
      * all_points includes phantom points
      */
-    bool get_points_var (hb_codepoint_t gid,
-			 const int *coords, unsigned int coord_count,
-			 contour_point_vector_t &all_points /* OUT */,
-			 unsigned int depth = 0) const
+    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;
+      if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
       contour_point_vector_t points;
-      hb_vector_t<unsigned int> end_points;
-      const Glyph &glyph = glyph_for_gid (gid);
-      if (unlikely (!glyph.get_contour_points (points, end_points))) return false;
-      hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
-      init_phantom_points (gid, phantoms);
-      if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array (), end_points.as_array ()))) return false;
 
-      unsigned int comp_index = 0;
-      if (glyph.is_simple_glyph ())
-	all_points.extend (points.as_array ());
-      else if (glyph.is_composite_glyph ())
+      switch (type) {
+      case COMPOSITE:
       {
-	for (auto &item : glyph.get_composite_iterator ())
+	/* 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 + glyf_accelerator.vmtx->get_side_bearing (gid);
+	unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
+	unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid);
+	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 (!get_points_var (item.glyphIndex, coords, coord_count,
-					 comp_points, depth))
-			|| comp_points.length < PHANTOM_COUNT)
+	  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 */
@@ -877,7 +831,7 @@
 	  /* Apply component transformation & translation */
 	  item.transform_points (comp_points);
 
-	  /* Apply translatation from gvar */
+	  /* Apply translation from gvar */
 	  comp_points.translate (points[comp_index]);
 
 	  if (item.is_anchored ())
@@ -900,110 +854,232 @@
 	}
 
 	all_points.extend (phantoms);
+      } break;
+      default:
+	all_points.extend (phantoms);
       }
-      else return false;
+
+      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_points_bearing_applied (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const
+    bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
+		      hb_glyph_extents_t *extents) const
     {
-      if (unlikely (!get_points_var (gid, font->coords, font->num_coords, all_points) ||
-		    all_points.length < PHANTOM_COUNT)) return false;
+      if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+      return header->get_extents (font, glyf_accelerator, gid, extents);
+    }
 
-      /* Undocumented rasterizer behavior:
-       * Shift points horizontally by the updated left side bearing
-       */
-      contour_point_t delta;
-      delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f);
-      if (delta.x) all_points.translate (delta);
-      return true;
+    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;
+  };
 
-    bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t gid,
-				       hb_glyph_extents_t *extents=nullptr /* OUT */,
-				       contour_point_vector_t *phantoms=nullptr /* OUT */) const
+  struct accelerator_t
+  {
+    void init (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;
+      vmtx = nullptr;
+      face = face_;
+      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;
+      vmtx = face->table.vmtx;
+
+      num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+      num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
+    }
+
+    void fini ()
+    {
+      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;
-      if (!unlikely (get_points_bearing_applied (font, gid, all_points))) return false;
-      if (extents)
+
+      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 ())
       {
-	contour_bounds_t bounds;
-	for (unsigned int i = 0; i + PHANTOM_COUNT < all_points.length; i++)
-	  bounds.add (all_points[i]);
-	bounds.get_extents (font, extents);
+	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 int i = 0; i < PHANTOM_COUNT; i++)
-	  (*phantoms)[i] = all_points[all_points.length - PHANTOM_COUNT + i];
+	for (unsigned i = 0; i < PHANTOM_COUNT; ++i)
+	  phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i];
+
       return true;
     }
 
-    bool get_var_metrics (hb_font_t *font, hb_codepoint_t gid,
-			  contour_point_vector_t &phantoms) const
-    { return get_var_extents_and_phantoms (font, gid, nullptr, &phantoms); }
+#ifndef HB_NO_VAR
+    struct points_aggregator_t
+    {
+      hb_font_t *font;
+      hb_glyph_extents_t *extents;
+      contour_point_t *phantoms;
 
-    bool get_extents_var (hb_font_t *font, hb_codepoint_t gid,
-			  hb_glyph_extents_t *extents) const
-    { return get_var_extents_and_phantoms (font, gid, extents); }
-#endif
+      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:
-#ifndef HB_NO_VAR
-    unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t gid,
-				  bool is_vertical) const
+    unsigned
+    get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
     {
-      bool success = false;
-      contour_point_vector_t phantoms;
-      phantoms.resize (PHANTOM_COUNT);
+      if (unlikely (gid >= num_glyphs)) return 0;
 
-      if (likely (font->num_coords == face->table.gvar->get_axis_count ()))
-	success = get_var_metrics (font, gid, phantoms);
+      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 is_vertical ? face->table.vmtx->get_advance (gid) : face->table.hmtx->get_advance (gid);
+	return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid);
 
-      if (is_vertical)
-	return roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y);
-      else
-	return roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x);
+      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_vector_t phantoms;
-      phantoms.resize (PHANTOM_COUNT);
 
-      if (unlikely (!get_var_extents_and_phantoms (font, gid, &extents, &phantoms)))
-	return is_vertical ? face->table.vmtx->get_side_bearing (gid) : face->table.hmtx->get_side_bearing (gid);
+      contour_point_t phantoms[PHANTOM_COUNT];
+      if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
+	return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid);
 
-      return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x);
+      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
     {
-#ifndef HB_NO_VAR
-      unsigned int coord_count;
-      const int *coords = hb_font_get_var_coords_normalized (font, &coord_count);
-      if (coords && coord_count > 0 && coord_count == face->table.gvar->get_axis_count ())
-	return get_extents_var (font, gid, extents);
-#endif
-
       if (unlikely (gid >= num_glyphs)) return false;
 
-      return glyph_for_gid (gid).get_extents (font, gid, extents);
+#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
     {
-      unsigned int start_offset, end_offset;
       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;
@@ -1021,24 +1097,161 @@
 	return Glyph ();
 
       Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
-			       end_offset - start_offset));
+			       end_offset - start_offset), gid);
       return needs_padding_removal ? glyph.trim_padding () : glyph;
     }
 
-    void
-    add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
-			  unsigned int depth = 0) const
+    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;
+      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;
+      if (gids_to_retain->has (gid)) return operation_count;
 
       gids_to_retain->add (gid);
 
-      for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
-        add_gid_and_children (item.glyphIndex, gids_to_retain, depth);
+      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;
+    const vmtx_accelerator_t *vmtx;
+
     private:
     bool short_offset;
     unsigned int num_glyphs;
@@ -1063,7 +1276,7 @@
       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 = padding ();
-      DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length  + pad_length, pad_length);
+      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;
@@ -1073,17 +1286,21 @@
 	pad_length--;
       }
 
-      if (!unlikely (dest_glyph.length)) return_trace (true);
+      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 (_.glyphIndex, &new_gid))
-	  ((OT::glyf::CompositeGlyphChain *) &_)->glyphIndex = new_gid;
+	if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid))
+	  const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
       }
 
-      if (plan->drop_hints) Glyph (dest_glyph).drop_hints ();
+      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);
     }
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 96c1d1f..dea2b7e 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -52,7 +52,7 @@
 
     unsigned length = it.len ();
 
-    if (unlikely (!c->extend (*this, length)))  return_trace (false);
+    if (unlikely (!c->extend (this, length)))  return_trace (false);
 
     this->pixelSize = pixelSize;
     this->maxWidth =
@@ -107,13 +107,10 @@
     this->numRecords = it.len ();
     this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
 
-    + it
-    | hb_apply ([c] (const hb_item_type<Iterator>& _) {
-		  c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
-		})
-    ;
+    for (const hb_item_type<Iterator>& _ : +it)
+      c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
 
-    return_trace (c->successful);
+    return_trace (c->successful ());
   }
 
 
@@ -134,10 +131,10 @@
 	  auto row =
 	    + hb_range (c->plan->num_output_glyphs ())
 	    | hb_map (c->plan->reverse_glyph_map)
-	    | hb_map ([=] (hb_codepoint_t _)
+	    | hb_map ([this, c, device_record] (hb_codepoint_t _)
 		      {
 			if (c->plan->is_empty_glyph (_))
-			  return Null(HBUINT8);
+			  return Null (HBUINT8);
 			return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
 		      })
 	    ;
@@ -164,10 +161,12 @@
   }
 
   protected:
-  HBUINT16		version;		/* Table version number (0) */
-  HBUINT16		numRecords;		/* Number of device records. */
-  HBUINT32		sizeDeviceRecord;	/* Size of a device record, 32-bit aligned. */
-  DeviceRecord		firstDeviceRecord;	/* Array of device records. */
+  HBUINT16	version;	/* Table version number (0) */
+  HBUINT16	numRecords;	/* Number of device records. */
+  HBUINT32	sizeDeviceRecord;
+				/* Size of a device record, 32-bit aligned. */
+  DeviceRecord	firstDeviceRecord;
+				/* Array of device records. */
   public:
   DEFINE_SIZE_MIN (8);
 };
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 3c0bb3d..20991aa 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -43,7 +43,7 @@
 
 struct head
 {
-  friend struct OffsetTable;
+  friend struct OpenTypeOffsetTable;
 
   static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
 
@@ -54,18 +54,32 @@
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
+  bool serialize (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace ((bool) c->embed (this));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (serialize (c->serializer));
+  }
+
   enum mac_style_flag_t {
     BOLD	= 1u<<0,
     ITALIC	= 1u<<1,
     UNDERLINE	= 1u<<2,
     OUTLINE	= 1u<<3,
     SHADOW	= 1u<<4,
-    CONDENSED	= 1u<<5
+    CONDENSED	= 1u<<5,
+    EXPANDED	= 1u<<6,
   };
 
   bool is_bold () const      { return macStyle & BOLD; }
   bool is_italic () const    { return macStyle & ITALIC; }
   bool is_condensed () const { return macStyle & CONDENSED; }
+  bool is_expanded () const  { return macStyle & EXPANDED; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index 778b6c5..d9c9bd3 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -54,35 +54,38 @@
   }
 
   public:
-  FixedVersion<>version;		/* 0x00010000u for version 1.0. */
-  FWORD		ascender;		/* Typographic ascent. */
-  FWORD		descender;		/* Typographic descent. */
-  FWORD		lineGap;		/* Typographic line gap. */
-  UFWORD	advanceMax;		/* Maximum advance width/height value in
-					 * metrics table. */
-  FWORD		minLeadingBearing;	/* Minimum left/top sidebearing value in
-					 * metrics table. */
-  FWORD		minTrailingBearing;	/* Minimum right/bottom sidebearing value;
-					 * calculated as Min(aw - lsb -
-					 * (xMax - xMin)) for horizontal. */
-  FWORD		maxExtent;		/* horizontal: Max(lsb + (xMax - xMin)),
-					 * vertical: minLeadingBearing+(yMax-yMin). */
-  HBINT16		caretSlopeRise;		/* Used to calculate the slope of the
-					 * cursor (rise/run); 1 for vertical caret,
-					 * 0 for horizontal.*/
-  HBINT16		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
-  HBINT16		caretOffset;		/* The amount by which a slanted
-					 * highlight on a glyph needs
-					 * to be shifted to produce the
-					 * best appearance. Set to 0 for
-					 * non-slanted fonts. */
-  HBINT16		reserved1;		/* Set to 0. */
-  HBINT16		reserved2;		/* Set to 0. */
-  HBINT16		reserved3;		/* Set to 0. */
-  HBINT16		reserved4;		/* Set to 0. */
-  HBINT16		metricDataFormat;	/* 0 for current format. */
-  HBUINT16	numberOfLongMetrics;	/* Number of LongMetric entries in metric
-					 * table. */
+  FixedVersion<>version;	/* 0x00010000u for version 1.0. */
+  FWORD		ascender;	/* Typographic ascent. */
+  FWORD		descender;	/* Typographic descent. */
+  FWORD		lineGap;	/* Typographic line gap. */
+  UFWORD	advanceMax;	/* Maximum advance width/height value in
+				 * metrics table. */
+  FWORD		minLeadingBearing;
+				/* Minimum left/top sidebearing value in
+				 * metrics table. */
+  FWORD		minTrailingBearing;
+				/* Minimum right/bottom sidebearing value;
+				 * calculated as Min(aw - lsb -
+				 * (xMax - xMin)) for horizontal. */
+  FWORD		maxExtent;	/* horizontal: Max(lsb + (xMax - xMin)),
+				 * vertical: minLeadingBearing+(yMax-yMin). */
+  HBINT16	caretSlopeRise;	/* Used to calculate the slope of the
+				 * cursor (rise/run); 1 for vertical caret,
+				 * 0 for horizontal.*/
+  HBINT16	caretSlopeRun;	/* 0 for vertical caret, 1 for horizontal. */
+  HBINT16	caretOffset;	/* The amount by which a slanted
+				 * highlight on a glyph needs
+				 * to be shifted to produce the
+				 * best appearance. Set to 0 for
+				 * non-slanted fonts. */
+  HBINT16	reserved1;	/* Set to 0. */
+  HBINT16	reserved2;	/* Set to 0. */
+  HBINT16	reserved3;	/* Set to 0. */
+  HBINT16	reserved4;	/* Set to 0. */
+  HBINT16	metricDataFormat;/* 0 for current format. */
+  HBUINT16	numberOfLongMetrics;
+				/* Number of LongMetric entries in metric
+				 * table. */
   public:
   DEFINE_SIZE_STATIC (36);
 };
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index e20b372..4038329 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -101,25 +101,23 @@
 		  unsigned num_advances)
   {
     unsigned idx = 0;
-    + it
-    | hb_apply ([c, &idx, num_advances] (const hb_item_type<Iterator>& _)
-		{
-		  if (idx < num_advances)
-		  {
-		    LongMetric lm;
-		    lm.advance = _.first;
-		    lm.sb = _.second;
-		    if (unlikely (!c->embed<LongMetric> (&lm))) return;
-		  }
-		  else
-		  {
-		    FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
-		    if (unlikely (!sb)) return;
-		    *sb = _.second;
-		  }
-		  idx++;
-		})
-    ;
+    for (auto _ : it)
+    {
+      if (idx < num_advances)
+      {
+	LongMetric lm;
+	lm.advance = _.first;
+	lm.sb = _.second;
+	if (unlikely (!c->embed<LongMetric> (&lm))) return;
+      }
+      else
+      {
+	FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
+	if (unlikely (!sb)) return;
+	*sb = _.second;
+      }
+      idx++;
+    }
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -148,7 +146,7 @@
 
     _mtx.fini ();
 
-    if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
+    if (unlikely (c->serializer->in_error ()))
       return_trace (false);
 
     // Amend header num hmetrics
@@ -169,7 +167,7 @@
 
       num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
 
-      table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag);
+      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
 
       /* Cap num_metrics() and num_advances() based on table length. */
       unsigned int len = table.get_length ();
@@ -186,7 +184,7 @@
 	table = hb_blob_get_empty ();
       }
 
-      var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag);
+      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
     }
 
     void fini ()
@@ -216,7 +214,7 @@
 	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?!
+	return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
 
       return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
 #else
@@ -250,7 +248,7 @@
 	return advance;
 
       if (var_table.get_length ())
-	return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?!
+	return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
 
       return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
 #else
@@ -295,27 +293,29 @@
   };
 
   protected:
-  UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading
-					 * bearing values for each glyph. The
-					 * value numOfHMetrics comes from
-					 * the 'hhea' table. If the font is
-					 * monospaced, only one entry need
-					 * be in the array, but that entry is
-					 * required. The last entry applies to
-					 * all subsequent glyphs. */
-/*UnsizedArrayOf<FWORD>	leadingBearingX;*//* Here the advance is assumed
-					 * to be the same as the advance
-					 * for the last entry above. The
-					 * number of entries in this array is
-					 * derived from numGlyphs (from 'maxp'
-					 * table) minus numberOfLongMetrics.
-					 * This generally is used with a run
-					 * of monospaced glyphs (e.g., Kanji
-					 * fonts or Courier fonts). Only one
-					 * run is allowed and it must be at
-					 * the end. This allows a monospaced
-					 * font to vary the side bearing
-					 * values for each glyph. */
+  UnsizedArrayOf<LongMetric>
+		longMetricZ;	/* Paired advance width and leading
+				 * bearing values for each glyph. The
+				 * value numOfHMetrics comes from
+				 * the 'hhea' table. If the font is
+				 * monospaced, only one entry need
+				 * be in the array, but that entry is
+				 * required. The last entry applies to
+				 * all subsequent glyphs. */
+/*UnsizedArrayOf<FWORD>	leadingBearingX;*/
+				/* Here the advance is assumed
+				 * to be the same as the advance
+				 * for the last entry above. The
+				 * number of entries in this array is
+				 * derived from numGlyphs (from 'maxp'
+				 * table) minus numberOfLongMetrics.
+				 * This generally is used with a run
+				 * of monospaced glyphs (e.g., Kanji
+				 * fonts or Courier fonts). Only one
+				 * run is allowed and it must be at
+				 * the end. This allows a monospaced
+				 * font to vary the side bearing
+				 * values for each glyph. */
   public:
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index 36e5a35..ffa11bc 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -86,21 +86,26 @@
   }
 
   protected:
-  KernSubTableHeader	header;
-  HBUINT16		glyphCount;	/* The number of glyphs in this font. */
-  HBUINT8		kernValueCount;	/* The number of kerning values. */
-  HBUINT8		leftClassCount;	/* The number of left-hand classes. */
-  HBUINT8		rightClassCount;/* The number of right-hand classes. */
-  HBUINT8		flags;		/* Set to zero (reserved for future use). */
-  UnsizedArrayOf<FWORD>	kernValueZ;	/* The kerning values.
-					 * Length kernValueCount. */
+  KernSubTableHeader
+		header;
+  HBUINT16	glyphCount;	/* The number of glyphs in this font. */
+  HBUINT8	kernValueCount;	/* The number of kerning values. */
+  HBUINT8	leftClassCount;	/* The number of left-hand classes. */
+  HBUINT8	rightClassCount;/* The number of right-hand classes. */
+  HBUINT8	flags;		/* Set to zero (reserved for future use). */
+  UnsizedArrayOf<FWORD>
+		kernValueZ;	/* The kerning values.
+				 * Length kernValueCount. */
 #if 0
-  UnsizedArrayOf<HBUINT8>leftClass;	/* The left-hand classes.
-					 * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>rightClass;	/* The right-hand classes.
-					 * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>kernIndex;	/* The indices into the kernValue array.
-					 * Length leftClassCount * rightClassCount */
+  UnsizedArrayOf<HBUINT8>
+		leftClass;	/* The left-hand classes.
+				 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>
+		rightClass;	/* The right-hand classes.
+				 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>kernIndex;
+				/* The indices into the kernValue array.
+				 * Length leftClassCount * rightClassCount */
 #endif
   public:
   DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
@@ -129,11 +134,11 @@
     switch (subtable_type) {
     case 0:	return_trace (c->dispatch (u.format0));
 #ifndef HB_NO_AAT_SHAPE
-    case 1:	return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
+    case 1:	return_trace (u.header.apple ? c->dispatch (u.format1, std::forward<Ts> (ds)...) : c->default_return_value ());
 #endif
     case 2:	return_trace (c->dispatch (u.format2));
 #ifndef HB_NO_AAT_SHAPE
-    case 3:	return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
+    case 3:	return_trace (u.header.apple ? c->dispatch (u.format3, std::forward<Ts> (ds)...) : c->default_return_value ());
 #endif
     default:	return_trace (c->default_return_value ());
     }
@@ -246,8 +251,8 @@
   HBUINT8	coverage;	/* Coverage bits. */
   HBUINT8	format;		/* Subtable format. */
   HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts).
-			       * This value specifies which tuple this subtable covers.
-			       * Note: We don't implement. */
+				 * This value specifies which tuple this subtable covers.
+				 * Note: We don't implement. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
@@ -320,9 +325,9 @@
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:	return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
+    case 0:	return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...));
 #ifndef HB_NO_AAT_SHAPE
-    case 1:	return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
+    case 1:	return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...));
 #endif
     default:	return_trace (c->default_return_value ());
     }
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 02fe14f..eb4c3b4 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -73,7 +73,7 @@
   protected:
   HBUINT16	format;		/* Format identifier--format = 2 */
   FWORD		coordinate;	/* X or Y value, in design units */
-  HBGlyphID	referenceGlyph;	/* Glyph ID of control glyph */
+  HBGlyphID16	referenceGlyph;	/* Glyph ID of control glyph */
   HBUINT16	coordPoint;	/* Index of contour point on the
 				 * reference glyph */
   public:
@@ -103,7 +103,7 @@
   protected:
   HBUINT16	format;		/* Format identifier--format = 3 */
   FWORD		coordinate;	/* X or Y value, in design units */
-  OffsetTo<Device>
+  Offset16To<Device>
 		deviceTable;	/* Offset to Device table for X or
 				 * Y value, from beginning of
 				 * BaseCoord table (may be NULL). */
@@ -173,11 +173,11 @@
   protected:
   Tag		tag;		/* 4-byte feature identification tag--must
 				 * match feature tag in FeatureList */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		minCoord;	/* Offset to BaseCoord table that defines
 				 * the minimum extent value, from beginning
 				 * of MinMax table (may be NULL) */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		maxCoord;	/* Offset to BaseCoord table that defines
 				 * the maximum extent value, from beginning
 				 * of MinMax table (may be NULL) */
@@ -212,15 +212,15 @@
   }
 
   protected:
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		minCoord;	/* Offset to BaseCoord table that defines
 				 * minimum extent value, from the beginning
 				 * of MinMax table (may be NULL) */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		maxCoord;	/* Offset to BaseCoord table that defines
 				 * maximum extent value, from the beginning
 				 * of MinMax table (may be NULL) */
-  SortedArrayOf<FeatMinMaxRecord>
+  SortedArray16Of<FeatMinMaxRecord>
 		featMinMaxRecords;
 				/* Array of FeatMinMaxRecords, in alphabetical
 				 * order by featureTableTag */
@@ -247,7 +247,7 @@
   Index		defaultIndex;	/* Index number of default baseline for this
 				 * script — equals index position of baseline tag
 				 * in baselineTags array of the BaseTagList */
-  OffsetArrayOf<BaseCoord>
+  Array16OfOffset16To<BaseCoord>
 		baseCoords;	/* Number of BaseCoord tables defined — should equal
 				 * baseTagCount in the BaseTagList
 				 *
@@ -275,7 +275,7 @@
 
   protected:
   Tag		baseLangSysTag;	/* 4-byte language system identification tag */
-  OffsetTo<MinMax>
+  Offset16To<MinMax>
 		minMax;		/* Offset to MinMax table, from beginning
 				 * of BaseScript table */
   public:
@@ -305,13 +305,13 @@
   }
 
   protected:
-  OffsetTo<BaseValues>
+  Offset16To<BaseValues>
 		baseValues;	/* Offset to BaseValues table, from beginning
 				 * of BaseScript table (may be NULL) */
-  OffsetTo<MinMax>
+  Offset16To<MinMax>
 		defaultMinMax;	/* Offset to MinMax table, from beginning of
 				 * BaseScript table (may be NULL) */
-  SortedArrayOf<BaseLangSysRecord>
+  SortedArray16Of<BaseLangSysRecord>
 		baseLangSysRecords;
 				/* Number of BaseLangSysRecords
 				 * defined — may be zero (0) */
@@ -339,7 +339,7 @@
 
   protected:
   Tag		baseScriptTag;	/* 4-byte script identification tag */
-  OffsetTo<BaseScript>
+  Offset16To<BaseScript>
 		baseScript;	/* Offset to BaseScript table, from beginning
 				 * of BaseScriptList */
 
@@ -364,7 +364,7 @@
   }
 
   protected:
-  SortedArrayOf<BaseScriptRecord>
+  SortedArray16Of<BaseScriptRecord>
 			baseScriptRecords;
 
   public:
@@ -379,12 +379,20 @@
 		     const BaseCoord **coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ()) return false;
+    if (!base_script.has_data ())
+    {
+      *coord = nullptr;
+      return false;
+    }
 
     if (likely (coord))
     {
       unsigned int tag_index = 0;
-      (this+baseTagList).bfind (baseline_tag, &tag_index);
+      if (!(this+baseTagList).bfind (baseline_tag, &tag_index))
+      {
+        *coord = nullptr;
+        return false;
+      }
       *coord = &base_script.get_base_coord (tag_index);
     }
 
@@ -398,7 +406,11 @@
 		    const BaseCoord **max_coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (!base_script.has_data ()) return false;
+    if (!base_script.has_data ())
+    {
+      *min_coord = *max_coord = nullptr;
+      return false;
+    }
 
     base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
 
@@ -414,12 +426,12 @@
   }
 
   protected:
-  OffsetTo<SortedArrayOf<Tag>>
+  Offset16To<SortedArray16Of<Tag>>
 		baseTagList;	/* Offset to BaseTagList table, from beginning
 				 * of Axis table (may be NULL)
 				 * Array of 4-byte baseline identification tags — must
 				 * be in alphabetical order */
-  OffsetTo<BaseScriptList>
+  Offset16To<BaseScriptList>
 		baseScriptList;	/* Offset to BaseScriptList table, from beginning
 				 * of Axis table
 				 * Array of BaseScriptRecords, in alphabetical order
@@ -489,11 +501,11 @@
 
   protected:
   FixedVersion<>version;	/* Version of the BASE table */
-  OffsetTo<Axis>hAxis;		/* Offset to horizontal Axis table, from beginning
+  Offset16To<Axis>hAxis;		/* Offset to horizontal Axis table, from beginning
 				 * of BASE table (may be NULL) */
-  OffsetTo<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
+  Offset16To<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
 				 * of BASE table (may be NULL) */
-  LOffsetTo<VariationStore>
+  Offset32To<VariationStore>
 		varStore;	/* Offset to the table of Item Variation
 				 * Store--from beginning of BASE
 				 * header (may be NULL).  Introduced
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index fa08140..5d98278 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -60,6 +60,18 @@
 #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_INDICES
+#define HB_MAX_LOOKUP_INDICES	20000
+#endif
+
 
 namespace OT {
 
@@ -73,48 +85,206 @@
 
 template<typename Iterator>
 static inline void ClassDef_serialize (hb_serialize_context_t *c,
-                                       Iterator it);
+				       Iterator it);
 
 static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
-                                          const hb_set_t &glyphset,
-                                          const hb_map_t &gid_klass_map,
-                                          hb_sorted_vector_t<HBGlyphID> glyphs,
-                                          hb_sorted_vector_t<unsigned> klasses,
-                                          hb_map_t *klass_map /*INOUT*/);
+					  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*/);
 
 
+struct hb_prune_langsys_context_t
+{
+  hb_prune_langsys_context_t (const void         *table_,
+                              hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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) {}
+
+  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);
+  }
+
+  private:
+  template <typename T>
+  bool visited (const T *p, hb_set_t &visited_set)
+  {
+    hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
+     if (visited_set.has (delta))
+      return true;
+
+    visited_set.add (delta);
+    return false;
+  }
+
+  public:
+  const void *table;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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;
+};
+
+struct hb_subset_layout_context_t :
+  hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET>
+{
+  const char *get_name () { return "SUBSET_LAYOUT"; }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  bool visitScript ()
+  {
+    return script_count++ < HB_MAX_SCRIPTS;
+  }
+
+  bool visitLangSys ()
+  {
+    return langsys_count++ < HB_MAX_LANGSYS;
+  }
+
+  bool visitFeatureIndex (int count)
+  {
+    feature_index_count += count;
+    return feature_index_count < HB_MAX_FEATURE_INDICES;
+  }
+
+  bool visitLookupIndex()
+  {
+    lookup_index_count++;
+    return lookup_index_count < HB_MAX_LOOKUP_INDICES;
+  }
+
+  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 *, (unsigned)-1, nullptr> *script_langsys_map;
+  const hb_map_t *feature_index_map;
+  unsigned cur_script_index;
+
+  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 *, (unsigned)-1, nullptr> *script_langsys_map_,
+			      hb_map_t *feature_index_map_) :
+				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),
+				script_count (0),
+				langsys_count (0),
+				feature_index_count (0),
+				lookup_index_count (0)
+  {}
+
+  private:
+  unsigned script_count;
+  unsigned langsys_count;
+  unsigned feature_index_count;
+  unsigned lookup_index_count;
+};
+
+struct hb_collect_variation_indices_context_t :
+       hb_dispatch_context_t<hb_collect_variation_indices_context_t>
+{
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  hb_set_t *layout_variation_indices;
+  const hb_set_t *glyph_set;
+  const hb_map_t *gpos_lookups;
+
+  hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
+					  const hb_set_t *glyph_set_,
+					  const hb_map_t *gpos_lookups_) :
+					layout_variation_indices (layout_variation_indices_),
+					glyph_set (glyph_set_),
+					gpos_lookups (gpos_lookups_) {}
+};
+
 template<typename OutputArray>
 struct subset_offset_array_t
 {
-  subset_offset_array_t
-  (hb_subset_context_t *subset_context,
-   OutputArray& out,
-   const void *src_base,
-   const void *dest_base)
-      : _subset_context(subset_context), _out (out), _src_base (src_base), _dest_base (dest_base) {}
+  subset_offset_array_t (hb_subset_context_t *subset_context_,
+			 OutputArray& out_,
+			 const void *base_) : subset_context (subset_context_),
+					      out (out_), base (base_) {}
 
   template <typename T>
-  bool
-  operator ()
-  (T&& offset)
+  bool operator () (T&& offset)
   {
-    auto *o = _out.serialize_append (_subset_context->serializer);
+    auto snap = subset_context->serializer->snapshot ();
+    auto *o = out.serialize_append (subset_context->serializer);
     if (unlikely (!o)) return false;
-    auto snap = _subset_context->serializer->snapshot ();
-    bool ret = o->serialize_subset (_subset_context, offset, _src_base, _dest_base);
+    bool ret = o->serialize_subset (subset_context, offset, base);
     if (!ret)
     {
-      _out.pop ();
-      _subset_context->serializer->revert (snap);
+      out.pop ();
+      subset_context->serializer->revert (snap);
     }
     return ret;
   }
 
   private:
-  hb_subset_context_t *_subset_context;
-  OutputArray &_out;
-  const void *_src_base;
-  const void *_dest_base;
+  hb_subset_context_t *subset_context;
+  OutputArray &out;
+  const void *base;
+};
+
+
+template<typename OutputArray, typename Arg>
+struct subset_offset_array_arg_t
+{
+  subset_offset_array_arg_t (hb_subset_context_t *subset_context_,
+			     OutputArray& out_,
+			     const void *base_,
+			     Arg &&arg_) : subset_context (subset_context_), out (out_),
+					  base (base_), arg (arg_) {}
+
+  template <typename T>
+  bool operator () (T&& offset)
+  {
+    auto snap = subset_context->serializer->snapshot ();
+    auto *o = out.serialize_append (subset_context->serializer);
+    if (unlikely (!o)) return false;
+    bool ret = o->serialize_subset (subset_context, offset, base, arg);
+    if (!ret)
+    {
+      out.pop ();
+      subset_context->serializer->revert (snap);
+    }
+    return ret;
+  }
+
+  private:
+  hb_subset_context_t *subset_context;
+  OutputArray &out;
+  const void *base;
+  Arg &&arg;
 };
 
 /*
@@ -126,17 +296,93 @@
 {
   template<typename OutputArray>
   subset_offset_array_t<OutputArray>
-  operator ()
-  (hb_subset_context_t *subset_context,
-   OutputArray& out,
-   const void *src_base,
-   const void *dest_base) const
-  {
-    return subset_offset_array_t<OutputArray> (subset_context, out, src_base, dest_base);
-  }
+  operator () (hb_subset_context_t *subset_context, OutputArray& out,
+	       const void *base) const
+  { return subset_offset_array_t<OutputArray> (subset_context, out, base); }
+
+  /* Variant with one extra argument passed to serialize_subset */
+  template<typename OutputArray, typename Arg>
+  subset_offset_array_arg_t<OutputArray, Arg>
+  operator () (hb_subset_context_t *subset_context, OutputArray& out,
+	       const void *base, Arg &&arg) const
+  { return subset_offset_array_arg_t<OutputArray, Arg> (subset_context, out, base, arg); }
 }
 HB_FUNCOBJ (subset_offset_array);
 
+template<typename OutputArray>
+struct subset_record_array_t
+{
+  subset_record_array_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+			 const void *base_) : subset_layout_context (c_),
+					      out (out_), base (base_) {}
+
+  template <typename T>
+  void
+  operator () (T&& record)
+  {
+    auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+    bool ret = record.subset (subset_layout_context, base);
+    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;
+};
+
+/*
+ * Helper to subset a RecordList/record array. Subsets each Record in the array and
+ * discards the record if the subset operation returns false.
+ */
+struct
+{
+  template<typename OutputArray>
+  subset_record_array_t<OutputArray>
+  operator () (hb_subset_layout_context_t *c, OutputArray* out,
+	       const void *base) const
+  { return subset_record_array_t<OutputArray> (c, out, base); }
+}
+HB_FUNCOBJ (subset_record_array);
+
+
+template<typename OutputArray>
+struct serialize_math_record_array_t
+{
+  serialize_math_record_array_t (hb_serialize_context_t *serialize_context_,
+                         OutputArray& out_,
+                         const void *base_) : serialize_context (serialize_context_),
+                                              out (out_), base (base_) {}
+
+  template <typename T>
+  bool operator () (T&& record)
+  {
+    if (!serialize_context->copy (record, base)) return false;
+    out.len++;
+    return true;
+  }
+
+  private:
+  hb_serialize_context_t *serialize_context;
+  OutputArray &out;
+  const void *base;
+};
+
+/*
+ * Helper to serialize an array of MATH records.
+ */
+struct
+{
+  template<typename OutputArray>
+  serialize_math_record_array_t<OutputArray>
+  operator () (hb_serialize_context_t *serialize_context, OutputArray& out,
+               const void *base) const
+  { return serialize_math_record_array_t<OutputArray> (serialize_context, out, base); }
+
+}
+HB_FUNCOBJ (serialize_math_record_array);
+
 /*
  *
  * OpenType Layout Common Table Formats
@@ -153,31 +399,20 @@
   const void *list_base;
 };
 
-struct RecordList_subset_context_t {
-
-  RecordList_subset_context_t() : script_count (0), langsys_count (0)
-  {}
-
-  bool visitScript ()
-  {
-    return script_count++ < HB_MAX_SCRIPTS;
-  }
-
-  bool visitLangSys ()
-  {
-    return langsys_count++ < HB_MAX_LANGSYS;
-  }
-
-  private:
-  unsigned int script_count;
-  unsigned int langsys_count;
-};
-
 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);
@@ -186,7 +421,7 @@
   }
 
   Tag		tag;		/* 4-byte Tag identifier */
-  OffsetTo<Type>
+  Offset16To<Type>
 		offset;		/* Offset from beginning of object holding
 				 * the Record */
   public:
@@ -194,11 +429,11 @@
 };
 
 template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type>>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
 {
-  const OffsetTo<Type>& get_offset (unsigned int i) const
+  const Offset16To<Type>& get_offset (unsigned int i) const
   { return (*this)[i].offset; }
-  OffsetTo<Type>& get_offset (unsigned int i)
+  Offset16To<Type>& get_offset (unsigned int i)
   { return (*this)[i].offset; }
   const Tag& get_tag (unsigned int i) const
   { return (*this)[i].tag; }
@@ -206,17 +441,18 @@
 			 unsigned int *record_count /* IN/OUT */,
 			 hb_tag_t     *record_tags /* OUT */) const
   {
-    if (record_count) {
-      const Record<Type> *arr = this->sub_array (start_offset, record_count);
-      unsigned int count = *record_count;
-      for (unsigned int i = 0; i < count; i++)
-	record_tags[i] = arr[i].tag;
+    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_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+    return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
   }
 };
 
@@ -226,29 +462,16 @@
   const Type& operator [] (unsigned int i) const
   { return this+this->get_offset (i); }
 
-  bool subset (hb_subset_context_t *c) const
+  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);
 
-    RecordList_subset_context_t record_list_context;
-
-    unsigned int count = this->len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      auto *record = out->serialize_append (c->serializer);
-      if (unlikely (!record)) return false;
-      auto snap = c->serializer->snapshot ();
-      if (record->offset.serialize_subset (c, this->get_offset (i), this, out, &record_list_context))
-      {
-        record->tag = this->get_tag(i);
-        continue;
-      }
-      out->pop ();
-      c->serializer->revert (snap);
-    }
-
+    + this->iter ()
+    | hb_apply (subset_record_array (l, out, this))
+    ;
     return_trace (true);
   }
 
@@ -259,11 +482,55 @@
   }
 };
 
+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 < start ? -1 : g <= end ? 0 : +1; }
+  { return g < first ? -1 : g <= last ? 0 : +1; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -272,14 +539,14 @@
   }
 
   bool intersects (const hb_set_t *glyphs) const
-  { return glyphs->intersects (start, end); }
+  { return glyphs->intersects (first, last); }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
-  { return glyphs->add_range (start, end); }
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_range (first, last); }
 
-  HBGlyphID	start;		/* First GlyphID in the range */
-  HBGlyphID	end;		/* Last GlyphID in the range */
+  HBGlyphID16	first;		/* First GlyphID in the range */
+  HBGlyphID16	last;		/* Last GlyphID in the range */
   HBUINT16	value;		/* Value */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -287,32 +554,51 @@
 DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
 
 
-struct IndexArray : ArrayOf<Index>
+struct IndexArray : Array16Of<Index>
 {
+  bool intersects (const hb_map_t *indexes) const
+  { return hb_any (*this, indexes); }
+
+  template <typename Iterator,
+	    hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  hb_subset_layout_context_t *l,
+		  Iterator it)
+  {
+    if (!it) return;
+    if (unlikely (!c->extend_min ((*this)))) return;
+
+    for (const auto _ : it)
+    {
+      if (!l->visitLookupIndex()) break;
+
+      Index i;
+      i = _;
+      c->copy (i);
+      this->len++;
+    }
+  }
+
   unsigned int get_indexes (unsigned int start_offset,
 			    unsigned int *_count /* IN/OUT */,
 			    unsigned int *_indexes /* OUT */) const
   {
-    if (_count) {
-      const HBUINT16 *arr = this->sub_array (start_offset, _count);
-      unsigned int count = *_count;
-      for (unsigned int i = 0; i < count; i++)
-	_indexes[i] = arr[i];
+    if (_count)
+    {
+      + this->sub_array (start_offset, _count)
+      | hb_sink (hb_array (_indexes, *_count))
+      ;
     }
     return this->len;
   }
 
   void add_indexes_to (hb_set_t* output /* OUT */) const
   {
-    output->add_array (arrayZ, len);
+    output->add_array (as_array ());
   }
 };
 
 
-struct Script;
-struct LangSys;
-struct Feature;
-
 struct LangSys
 {
   unsigned int get_feature_count () const
@@ -340,6 +626,70 @@
     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)
+    ;
+
+    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 (c->visitedLangsys (this)) 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
   {
@@ -379,34 +729,90 @@
   bool has_default_lang_sys () const           { return defaultLangSys != 0; }
   const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
 
-  bool subset (hb_subset_context_t *c, RecordList_subset_context_t *record_list_context) const
+  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 ();
+      d.collect_features (c);
+
+      for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
+      {
+        const LangSys& l = this+_.first.offset;
+        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;
+        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 (!record_list_context->visitScript ()) return_trace (false);
+    if (!l->visitScript ()) return_trace (false);
 
     auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
 
-    out->defaultLangSys.serialize_copy (c->serializer, defaultLangSys, this, out);
-
-    for (const auto &src: langSys)
+    bool defaultLang = false;
+    if (has_default_lang_sys ())
     {
-      if (!record_list_context->visitLangSys ()) {
-        continue;
-      }
-
-      auto snap = c->serializer->snapshot ();
-      auto *lang_sys = c->serializer->embed (src);
-
-      if (likely(lang_sys)
-          && lang_sys->offset.serialize_copy (c->serializer, src.offset, this, out))
+      c->serializer->push ();
+      const LangSys& ls = this+defaultLangSys;
+      bool ret = ls.subset (c, l);
+      if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
       {
-        out->langSys.len++;
-        continue;
+	c->serializer->pop_discard ();
+	out->defaultLangSys = 0;
       }
-      c->serializer->revert (snap);
+      else
+      {
+	c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
+	defaultLang = true;
+      }
     }
-    return_trace (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,
@@ -417,7 +823,7 @@
   }
 
   protected:
-  OffsetTo<LangSys>
+  Offset16To<LangSys>
 		defaultLangSys;	/* Offset to DefaultLangSys table--from
 				 * beginning of Script table--may be Null */
   RecordArrayOf<LangSys>
@@ -427,7 +833,7 @@
   DEFINE_SIZE_ARRAY_SIZED (4, langSys);
 };
 
-typedef RecordListOf<Script> ScriptList;
+typedef RecordListOfScript ScriptList;
 
 
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
@@ -503,6 +909,12 @@
       return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   HBUINT16	designSize;	/* Represents the design size in 720/inch
 				 * units (decipoints).  The design size entry
 				 * must be non-zero.  When there is a design
@@ -553,6 +965,12 @@
     return_trace (c->check_struct (this));
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   HBUINT16	version;	/* (set to 0): This corresponds to a “minor”
 				 * version number. Additional data may be
 				 * added to the end of this Feature Parameters
@@ -579,6 +997,27 @@
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
 struct FeatureParamsCharacterVariants
 {
+  unsigned
+  get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const
+  {
+    if (char_count)
+    {
+      + characters.sub_array (start_offset, char_count)
+      | hb_sink (hb_array (chars, *char_count))
+      ;
+    }
+    return characters.len;
+  }
+
+  unsigned get_size () const
+  { return min_size + characters.len * HBUINT24::static_size; }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -609,7 +1048,7 @@
 					 * user-interface labels for the
 					 * feature parameters. (Must be zero
 					 * if numParameters is zero.) */
-  ArrayOf<HBUINT24>
+  Array16Of<HBUINT24>
 		characters;		/* Array of the Unicode Scalar Value
 					 * of the characters for which this
 					 * feature provides glyph variants.
@@ -635,6 +1074,19 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c, const Tag* tag) const
+  {
+    TRACE_SUBSET (this);
+    if (!tag) return_trace (false);
+    if (*tag == HB_TAG ('s','i','z','e'))
+      return_trace (u.size.subset (c));
+    if ((*tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return_trace (u.stylisticSet.subset (c));
+    if ((*tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return_trace (u.characterVariants.subset (c));
+    return_trace (false);
+  }
+
 #ifndef HB_NO_LAYOUT_FEATURE_PARAMS
   const FeatureParamsSize& get_size_params (hb_tag_t tag) const
   {
@@ -682,12 +1134,28 @@
   const FeatureParams &get_feature_params () const
   { return this+featureParams; }
 
-  bool subset (hb_subset_context_t *c, RecordList_subset_context_t *r) const
+  bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
+  { return lookupIndex.intersects (lookup_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->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    out->featureParams = 0; /* TODO(subset) FeatureParams. */
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    out->featureParams.serialize_subset (c, featureParams, this, tag);
+
+    auto it =
+    + hb_iter (lookupIndex)
+    | hb_filter (l->lookup_index_map)
+    | hb_map (l->lookup_index_map)
+    ;
+
+    out->lookupIndex.serialize (c->serializer, l, it);
+    // The decision to keep or drop this feature is already made before we get here
+    // so always retain it.
     return_trace (true);
   }
 
@@ -723,7 +1191,7 @@
       unsigned int new_offset_int = orig_offset -
 				    (((char *) this) - ((char *) closure->list_base));
 
-      OffsetTo<FeatureParams> new_offset;
+      Offset16To<FeatureParams> new_offset;
       /* Check that it would not overflow. */
       new_offset = new_offset_int;
       if (new_offset == new_offset_int &&
@@ -735,7 +1203,7 @@
     return_trace (true);
   }
 
-  OffsetTo<FeatureParams>
+  Offset16To<FeatureParams>
 		 featureParams;	/* Offset to Feature Parameters table (if one
 				 * has been defined for the feature), relative
 				 * to the beginning of the Feature Table; = Null
@@ -774,11 +1242,11 @@
   unsigned int get_subtable_count () const { return subTable.len; }
 
   template <typename TSubTable>
-  const OffsetArrayOf<TSubTable>& get_subtables () const
-  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
+  const Array16OfOffset16To<TSubTable>& get_subtables () const
+  { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); }
   template <typename TSubTable>
-  OffsetArrayOf<TSubTable>& get_subtables ()
-  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
+  Array16OfOffset16To<TSubTable>& get_subtables ()
+  { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); }
 
   template <typename TSubTable>
   const TSubTable& get_subtable (unsigned int i) const
@@ -818,7 +1286,7 @@
     TRACE_DISPATCH (this, lookup_type);
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
+      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...);
       if (c->stop_sublookup_iteration (r))
 	return_trace (r);
     }
@@ -831,13 +1299,13 @@
 		  unsigned int num_subtables)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     lookupType = lookup_type;
     lookupFlag = lookup_props & 0xFFFFu;
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      if (unlikely (!c->extend (*this))) return_trace (false);
+      if (unlikely (!c->extend (this))) return_trace (false);
       HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       markFilteringSet = lookup_props >> 16;
     }
@@ -848,19 +1316,27 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    out->lookupType = lookupType;
+    out->lookupFlag = lookupFlag;
 
-    /* Subset the actual subtables. */
-    /* TODO Drop empty ones, either by calling intersects() beforehand,
-     * or just dropping null offsets after. */
-    const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
-    OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
-    unsigned int count = subTable.len;
-    for (unsigned int i = 0; i < count; i++)
-      out_subtables[i].serialize_subset (c, subtables[i], this, out, get_type ());
+    const hb_set_t *glyphset = c->plan->glyphset_gsub ();
+    unsigned int lookup_type = get_type ();
+    + hb_iter (get_subtables <TSubTable> ())
+    | hb_filter ([this, glyphset, lookup_type] (const Offset16To<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
+    | hb_apply (subset_offset_array (c, out->get_subtables<TSubTable> (), this, lookup_type))
+    ;
 
-    return_trace (true);
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+    {
+      if (unlikely (!c->serializer->extend (out))) return_trace (false);
+      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
+      HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
+      outMarkFilteringSet = markFilteringSet;
+    }
+
+    return_trace (out->subTable.len);
   }
 
   template <typename TSubTable>
@@ -868,6 +1344,10 @@
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+
+    unsigned subtables = get_subtable_count ();
+    if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
+
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
@@ -890,8 +1370,7 @@
        * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
        */
       unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
-      unsigned int count = get_subtable_count ();
-      for (unsigned int i = 1; i < count; i++)
+      for (unsigned int i = 1; i < subtables; i++)
 	if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
 	  return_trace (false);
     }
@@ -901,7 +1380,7 @@
   private:
   HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
   HBUINT16	lookupFlag;		/* Lookup qualifiers */
-  ArrayOf<Offset16>
+  Array16Of<Offset16>
 		subTable;		/* Array of SubTables */
 /*HBUINT16	markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
@@ -910,7 +1389,33 @@
   DEFINE_SIZE_ARRAY (6, subTable);
 };
 
-typedef OffsetListOf<Lookup> LookupList;
+typedef List16OfOffset16To<Lookup> LookupList;
+
+template <typename TLookup>
+struct LookupOffsetList : List16OfOffset16To<TLookup>
+{
+  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));
+  }
+};
 
 
 /*
@@ -925,7 +1430,7 @@
   unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     unsigned int i;
-    glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED);
+    glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
     return i;
   }
 
@@ -946,18 +1451,25 @@
   bool intersects (const hb_set_t *glyphs) const
   {
     /* TODO Speed up, using hb_set_next() and bsearch()? */
-    unsigned int count = glyphArray.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (glyphs->has (glyphArray[i]))
+    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 add_coverage (set_t *glyphs) const
-  { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_sorted_array (glyphArray.as_array ()); }
 
   public:
   /* Older compilers need this to be public. */
@@ -979,7 +1491,7 @@
 
   protected:
   HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
-  SortedArrayOf<HBGlyphID>
+  SortedArray16Of<HBGlyphID16>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
@@ -993,9 +1505,9 @@
   unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     const RangeRecord &range = rangeRecord.bsearch (glyph_id);
-    return likely (range.start <= range.end) ?
-	   (unsigned int) range.value + (glyph_id - range.start) :
-	   NOT_COVERED;
+    return likely (range.first <= range.last)
+	 ? (unsigned int) range.value + (glyph_id - range.first)
+	 : NOT_COVERED;
   }
 
   template <typename Iterator,
@@ -1003,7 +1515,7 @@
   bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
 
     if (unlikely (!glyphs))
     {
@@ -1032,10 +1544,10 @@
       if (last + 1 != g)
       {
 	range++;
-	rangeRecord[range].start = g;
+	rangeRecord[range].first = g;
 	rangeRecord[range].value = count;
       }
-      rangeRecord[range].end = g;
+      rangeRecord[range].last = g;
       last = g;
       count++;
     }
@@ -1052,20 +1564,19 @@
   bool intersects (const hb_set_t *glyphs) const
   {
     /* TODO Speed up, using hb_set_next() and bsearch()? */
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (rangeRecord[i].intersects (glyphs))
+    /* 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
   {
-    unsigned int i;
-    unsigned int count = rangeRecord.len;
-    for (i = 0; i < count; i++) {
-      const RangeRecord &range = rangeRecord[i];
+    /* TODO(iter) Rewrite as dagger. */
+    for (const auto& range : rangeRecord.as_array ())
+    {
       if (range.value <= index &&
-	  index < (unsigned int) range.value + (range.end - range.start) &&
+	  index < (unsigned int) range.value + (range.last - range.first) &&
 	  range.intersects (glyphs))
 	return true;
       else if (index < range.value)
@@ -1074,12 +1585,22 @@
     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 add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+      if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
 	return false;
     return true;
   }
@@ -1093,8 +1614,8 @@
       c = &c_;
       coverage = 0;
       i = 0;
-      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
-      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
+      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;
@@ -1104,13 +1625,13 @@
     bool more () const { return i < c->rangeRecord.len; }
     void next ()
     {
-      if (j >= c->rangeRecord[i].end)
+      if (j >= c->rangeRecord[i].last)
       {
 	i++;
 	if (more ())
 	{
 	  unsigned int old = coverage;
-	  j = c->rangeRecord[i].start;
+	  j = c->rangeRecord[i].first;
 	  coverage = c->rangeRecord[i].value;
 	  if (unlikely (coverage != old + 1))
 	  {
@@ -1140,7 +1661,7 @@
 
   protected:
   HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
-  SortedArrayOf<RangeRecord>
+  SortedArray16Of<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
 				 * long */
@@ -1173,7 +1694,7 @@
   bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
 
     unsigned count = 0;
     unsigned num_ranges = 0;
@@ -1198,7 +1719,7 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto it =
@@ -1246,20 +1767,30 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     switch (u.format)
     {
-    case 1: return u.format1.add_coverage (glyphs);
-    case 2: return u.format2.add_coverage (glyphs);
+    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 ;
+    }
+  }
+
   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))
+    iter_t (const Coverage &c_ = Null (Coverage))
     {
       memset (this, 0, sizeof (*this));
       format = c_.u.format;
@@ -1333,22 +1864,28 @@
 template<typename Iterator>
 static inline void
 Coverage_serialize (hb_serialize_context_t *c,
-                    Iterator it)
+		    Iterator it)
 { c->start_embed<Coverage> ()->serialize (c, it); }
 
 static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
-                                          const hb_set_t &glyphset,
-                                          const hb_map_t &gid_klass_map,
-                                          hb_sorted_vector_t<HBGlyphID> glyphs,
-                                          hb_sorted_vector_t<unsigned> klasses,
-                                          hb_map_t *klass_map /*INOUT*/)
+					  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*/)
 {
-  bool has_no_match = glyphset.get_population () > gid_klass_map.get_population ();
-  
-  hb_map_t m;
-  if (!klass_map) klass_map = &m;
+  if (!klass_map)
+  {
+    ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter ()
+						   | hb_map (gid_klass_map)));
+    return;
+  }
 
-  if (has_no_match) klass_map->set (0, 0);
+  /* 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*/
+  if (!use_class_zero)
+    klass_map->set (0, 0);
+
   unsigned idx = klass_map->has (0) ? 1 : 0;
   for (const unsigned k: klasses.iter ())
   {
@@ -1356,17 +1893,16 @@
     klass_map->set (k, idx);
     idx++;
   }
-  
+
   auto it =
   + glyphs.iter ()
-  | hb_map_retains_sorting ([&] (const HBGlyphID& gid) -> hb_pair_t<hb_codepoint_t, HBUINT16>
-                            {
-                              HBUINT16 new_klass;
-                              new_klass = klass_map->get (gid_klass_map[gid]);
-                              return hb_pair ((hb_codepoint_t)gid, new_klass);
-                            })
+  | 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);
 }
@@ -1388,51 +1924,72 @@
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-                  Iterator it)
+		  Iterator it)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
 
     if (unlikely (!it))
     {
+      classFormat = 1;
       startGlyph = 0;
       classValue.len = 0;
       return_trace (true);
     }
 
-    startGlyph = (*it).first;
-    classValue.serialize (c, + it
-                             | hb_map (hb_second));
+    hb_codepoint_t glyph_min = (*it).first;
+    hb_codepoint_t glyph_max = + it
+			       | hb_map (hb_first)
+			       | hb_reduce (hb_max, 0u);
+    unsigned glyph_count = glyph_max - glyph_min + 1;
+
+    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)
+    {
+      unsigned idx = gid_klass_pair.first - glyph_min;
+      classValue[idx] = gid_klass_pair.second;
+    }
     return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c,
-               hb_map_t *klass_map = nullptr /*OUT*/) const
+	       hb_map_t *klass_map = nullptr /*OUT*/,
+               bool keep_empty_table = true,
+               bool use_class_zero = true,
+               const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-   
-    hb_sorted_vector_t<HBGlyphID> glyphs;
-    hb_sorted_vector_t<unsigned> orig_klasses;
+
+    hb_sorted_vector_t<HBGlyphID16> glyphs;
+    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))
+                                    | hb_filter (glyphset))
     {
+      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);
-      orig_klasses.push (klass);
+      orig_klasses.add (klass);
     }
 
-    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
-                                  glyphs, orig_klasses, klass_map);
-    return_trace ((bool) glyphs);
+    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);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1442,7 +1999,7 @@
   }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     unsigned int start = 0;
     unsigned int count = classValue.len;
@@ -1465,7 +2022,7 @@
   }
 
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned klass) const
   {
     unsigned int count = classValue.len;
     for (unsigned int i = 0; i < count; i++)
@@ -1483,7 +2040,7 @@
       if (classValue[iter - start]) return true;
     return false;
   }
-  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+  bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
   {
     unsigned int count = classValue.len;
     if (klass == 0)
@@ -1496,16 +2053,54 @@
       if (hb_set_next (glyphs, &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 (classValue[i] == klass && glyphs->has (startGlyph + i))
+      if (arr[i] == k && glyphs->has (startGlyph + i))
 	return true;
     return false;
   }
 
+  void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
+  {
+    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);
+
+      return;
+    }
+
+    for (unsigned i = 0; i < count; i++)
+      if (classValue[i] == klass && glyphs->has (startGlyph + i))
+        intersect_glyphs->add (startGlyph + i);
+  }
+
+  void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
+  {
+    if (glyphs->is_empty ()) return;
+    hb_codepoint_t end_glyph = startGlyph + classValue.len - 1;
+    if (glyphs->get_min () < startGlyph ||
+        glyphs->get_max () > end_glyph)
+      intersect_classes->add (0);
+
+    for (const auto& _ : + hb_enumerate (classValue))
+    {
+      hb_codepoint_t g = startGlyph + _.first;
+      if (glyphs->has (g))
+        intersect_classes->add (_.second);
+    }
+  }
+
   protected:
   HBUINT16	classFormat;	/* Format identifier--format = 1 */
-  HBGlyphID	startGlyph;	/* First GlyphID of the classValueArray */
-  ArrayOf<HBUINT16>
+  HBGlyphID16	startGlyph;	/* First GlyphID of the classValueArray */
+  Array16Of<HBUINT16>
 		classValue;	/* Array of Class Values--one per GlyphID */
   public:
   DEFINE_SIZE_ARRAY (6, classValue);
@@ -1524,13 +2119,14 @@
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-                  Iterator it)
+		  Iterator it)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
 
     if (unlikely (!it))
     {
+      classFormat = 2;
       rangeRecord.len = 0;
       return_trace (true);
     }
@@ -1540,8 +2136,8 @@
     unsigned prev_klass = (*it).second;
 
     RangeRecord range_rec;
-    range_rec.start = prev_gid;
-    range_rec.end = prev_gid;
+    range_rec.first = prev_gid;
+    range_rec.last = prev_gid;
     range_rec.value = prev_klass;
 
     RangeRecord *record = c->copy (range_rec);
@@ -1553,37 +2149,40 @@
       unsigned cur_klass = gid_klass_pair.second;
 
       if (cur_gid != prev_gid + 1 ||
-          cur_klass != prev_klass)
+	  cur_klass != prev_klass)
       {
-        if (unlikely (!record)) break;
-        record->end = prev_gid;
-        num_ranges++;
+	if (unlikely (!record)) break;
+	record->last = prev_gid;
+	num_ranges++;
 
-        range_rec.start = cur_gid;
-        range_rec.end = cur_gid;
-        range_rec.value = cur_klass;
+	range_rec.first = cur_gid;
+	range_rec.last = cur_gid;
+	range_rec.value = cur_klass;
 
-        record = c->copy (range_rec);
+	record = c->copy (range_rec);
       }
 
       prev_klass = cur_klass;
       prev_gid = cur_gid;
     }
 
-    if (likely (record)) record->end = prev_gid;
+    if (likely (record)) record->last = prev_gid;
     rangeRecord.len = num_ranges;
     return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c,
-               hb_map_t *klass_map = nullptr /*OUT*/) const
+	       hb_map_t *klass_map = nullptr /*OUT*/,
+               bool keep_empty_table = true,
+               bool use_class_zero = true,
+               const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
-    hb_sorted_vector_t<HBGlyphID> glyphs;
-    hb_sorted_vector_t<unsigned> orig_klasses;
+    hb_sorted_vector_t<HBGlyphID16> glyphs;
+    hb_set_t orig_klasses;
     hb_map_t gid_org_klass_map;
 
     unsigned count = rangeRecord.len;
@@ -1591,20 +2190,25 @@
     {
       unsigned klass = rangeRecord[i].value;
       if (!klass) continue;
-      hb_codepoint_t start = rangeRecord[i].start;
-      hb_codepoint_t end   = rangeRecord[i].end + 1;
+      hb_codepoint_t start = rangeRecord[i].first;
+      hb_codepoint_t end   = rangeRecord[i].last + 1;
       for (hb_codepoint_t g = start; g < end; g++)
       {
 	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);
-        orig_klasses.push (klass);
+	gid_org_klass_map.set (glyph_map[g], klass);
+	orig_klasses.add (klass);
       }
     }
 
-    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
-                                  glyphs, orig_klasses, klass_map);
-    return_trace ((bool) glyphs);
+    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);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1614,24 +2218,24 @@
   }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  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].add_coverage (glyphs)))
+	if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
 	  return false;
     return true;
   }
 
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned int klass) const
   {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
     {
       if (rangeRecord[i].value == klass)
-	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+	if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
 	  return false;
     }
     return true;
@@ -1642,11 +2246,14 @@
     /* TODO Speed up, using hb_set_next() and bsearch()? */
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
-      if (rangeRecord[i].intersects (glyphs))
+    {
+      const auto& range = rangeRecord[i];
+      if (range.intersects (glyphs) && range.value)
 	return true;
+    }
     return false;
   }
-  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+  bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
   {
     unsigned int count = rangeRecord.len;
     if (klass == 0)
@@ -1657,23 +2264,100 @@
       {
 	if (!hb_set_next (glyphs, &g))
 	  break;
-	if (g < rangeRecord[i].start)
+	if (g < rangeRecord[i].first)
 	  return true;
-	g = rangeRecord[i].end;
+	g = rangeRecord[i].last;
       }
       if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &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 (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
+      if (arr[i].value == k && arr[i].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++)
+      {
+        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);
+        }
+        g = rangeRecord[i].last;
+      }
+      while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+        intersect_glyphs->add (g);
+
+      return;
+    }
+
+    hb_codepoint_t g = HB_SET_VALUE_INVALID;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (rangeRecord[i].value != klass) continue;
+
+      if (g != HB_SET_VALUE_INVALID)
+      {
+        if (g >= rangeRecord[i].first &&
+            g <= rangeRecord[i].last)
+          intersect_glyphs->add (g);
+        if (g > rangeRecord[i].last)
+          continue;
+      }
+
+      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;
+      }
+    }
+  }
+
+  void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
+  {
+    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++)
+    {
+      if (!hb_set_next (glyphs, &g))
+        break;
+      if (g < rangeRecord[i].first)
+      {
+        intersect_classes->add (0);
+        break;
+      }
+      g = rangeRecord[i].last;
+    }
+    if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+      intersect_classes->add (0);
+
+    for (const RangeRecord& record : rangeRecord.iter ())
+      if (record.intersects (glyphs))
+        intersect_classes->add (record.value);
+  }
+
   protected:
   HBUINT16	classFormat;	/* Format identifier--format = 2 */
-  SortedArrayOf<RangeRecord>
+  SortedArray16Of<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
@@ -1702,36 +2386,40 @@
 
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
-  bool serialize (hb_serialize_context_t *c, Iterator it)
+  bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    auto it = + it_with_class_zero | hb_filter (hb_second);
 
     unsigned format = 2;
     if (likely (it))
     {
       hb_codepoint_t glyph_min = (*it).first;
-      hb_codepoint_t glyph_max = + it
-				 | hb_map (hb_first)
-                                 | hb_reduce (hb_max, 0u);
+      hb_codepoint_t glyph_max = glyph_min;
 
+      unsigned num_glyphs = 0;
       unsigned num_ranges = 1;
       hb_codepoint_t prev_gid = glyph_min;
       unsigned prev_klass = (*it).second;
 
       for (const auto gid_klass_pair : it)
       {
-        hb_codepoint_t cur_gid = gid_klass_pair.first;
-        unsigned cur_klass = gid_klass_pair.second;
-        if (cur_gid != prev_gid + 1 ||
-            cur_klass != prev_klass)
-          num_ranges++;
+	hb_codepoint_t cur_gid = gid_klass_pair.first;
+	unsigned cur_klass = gid_klass_pair.second;
+        num_glyphs++;
+	if (cur_gid == glyph_min) continue;
+        if (cur_gid > glyph_max) glyph_max = cur_gid;
+	if (cur_gid != prev_gid + 1 ||
+	    cur_klass != prev_klass)
+	  num_ranges++;
 
-        prev_gid = cur_gid;
-        prev_klass = cur_klass;
+	prev_gid = cur_gid;
+	prev_klass = cur_klass;
       }
 
-      if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3)
+      if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
 	format = 1;
     }
     u.format = format;
@@ -1745,12 +2433,15 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               hb_map_t *klass_map = nullptr /*OUT*/) const
+	       hb_map_t *klass_map = nullptr /*OUT*/,
+               bool keep_empty_table = true,
+               bool use_class_zero = true,
+               const Coverage* glyph_filter = nullptr) const
   {
     TRACE_SUBSET (this);
     switch (u.format) {
-    case 1: return_trace (u.format1.subset (c, klass_map));
-    case 2: return_trace (u.format2.subset (c, klass_map));
+    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));
     default:return_trace (false);
     }
   }
@@ -1769,11 +2460,11 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     switch (u.format) {
-    case 1: return u.format1.add_coverage (glyphs);
-    case 2: return u.format2.add_coverage (glyphs);
+    case 1: return u.format1.collect_coverage (glyphs);
+    case 2: return u.format2.collect_coverage (glyphs);
     default:return false;
     }
   }
@@ -1781,11 +2472,11 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned int klass) const
   {
     switch (u.format) {
-    case 1: return u.format1.add_class (glyphs, klass);
-    case 2: return u.format2.add_class (glyphs, klass);
+    case 1: return u.format1.collect_class (glyphs, klass);
+    case 2: return u.format2.collect_class (glyphs, klass);
     default:return false;
     }
   }
@@ -1807,6 +2498,25 @@
     }
   }
 
+  void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
+  {
+    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);
+    default:return;
+    }
+  }
+
+  void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.intersected_classes (glyphs, intersect_classes);
+    case 2: return u.format2.intersected_classes (glyphs, intersect_classes);
+    default:return;
+    }
+  }
+
+
   protected:
   union {
   HBUINT16		format;		/* Format identifier */
@@ -1819,7 +2529,7 @@
 
 template<typename Iterator>
 static inline void ClassDef_serialize (hb_serialize_context_t *c,
-                                       Iterator it)
+				       Iterator it)
 { c->start_embed<ClassDef> ()->serialize (c, it); }
 
 
@@ -1871,7 +2581,7 @@
 struct VarRegionList
 {
   float evaluate (unsigned int region_index,
-			 const int *coords, unsigned int coord_len) const
+		  const int *coords, unsigned int coord_len) const
   {
     if (unlikely (region_index >= regionCount))
       return 0.;
@@ -1894,30 +2604,35 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
+    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)
   {
     TRACE_SERIALIZE (this);
-    VarRegionList *out = c->allocate_min<VarRegionList> ();
-    if (unlikely (!out)) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     axisCount = src->axisCount;
     regionCount = region_map.get_population ();
-    if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false);
+    if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount,
+					     VarRegionAxis::static_size))) return_trace (false);
+    if (unlikely (!c->extend (this))) return_trace (false);
+    unsigned int region_count = src->regionCount;
     for (unsigned int r = 0; r < regionCount; r++)
-      memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * region_map.backward (r)], VarRegionAxis::static_size * axisCount);
+    {
+      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);
+    }
 
     return_trace (true);
   }
 
   unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
-  unsigned int get_region_count () const { return regionCount; }
 
-  protected:
+  public:
   HBUINT16	axisCount;
-  HBUINT16	regionCount;
+  HBUINT15	regionCount;
+  protected:
   UnsizedArrayOf<VarRegionAxis>
 		axesZ;
   public:
@@ -1933,11 +2648,14 @@
   { return shortCount + regionIndices.len; }
 
   unsigned int get_size () const
-  { return itemCount * get_row_size (); }
+  { return min_size
+	 - regionIndices.min_size + regionIndices.get_size ()
+	 + itemCount * get_row_size ();
+  }
 
   float get_delta (unsigned int inner,
-			  const int *coords, unsigned int coord_count,
-			  const VarRegionList &regions) const
+		   const int *coords, unsigned int coord_count,
+		   const VarRegionList &regions) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
@@ -1967,10 +2685,10 @@
    return delta;
   }
 
-  void get_scalars (int *coords, unsigned int coord_count,
-		    const VarRegionList &regions,
-		    float *scalars /*OUT */,
-		    unsigned int num_scalars) const
+  void get_region_scalars (const int *coords, unsigned int coord_count,
+			   const VarRegionList &regions,
+			   float *scalars /*OUT */,
+			   unsigned int num_scalars) const
   {
     unsigned count = hb_min (num_scalars, regionIndices.len);
     for (unsigned int i = 0; i < count; i++)
@@ -1996,7 +2714,7 @@
 		  const hb_bimap_t &region_map)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     itemCount = inner_map.get_next_value ();
 
     /* Optimize short count */
@@ -2031,16 +2749,14 @@
     for (r = 0; r < ri_count; r++)
       if (delta_sz[r])
       {
-      	ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
-      	new_ri_count++;
+	ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
+	new_ri_count++;
       }
 
     shortCount = new_short_count;
     regionIndices.len = new_ri_count;
 
-    unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount);
-    if (unlikely (!c->allocate_size<HBUINT8> (size)))
-      return_trace (false);
+    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]];
@@ -2055,16 +2771,16 @@
     return_trace (true);
   }
 
-  void collect_region_refs (hb_inc_bimap_t &region_map, const hb_inc_bimap_t &inner_map) const
+  void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
   {
     for (unsigned int r = 0; r < regionIndices.len; r++)
     {
       unsigned int region = regionIndices[r];
-      if (region_map.has (region)) continue;
+      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)
 	{
-	  region_map.add (region);
+	  region_indices.add (region);
 	  break;
 	}
     }
@@ -2099,7 +2815,7 @@
   protected:
   HBUINT16		itemCount;
   HBUINT16		shortCount;
-  ArrayOf<HBUINT16>	regionIndices;
+  Array16Of<HBUINT16>	regionIndices;
 /*UnsizedArrayOf<HBUINT8>bytesX;*/
   public:
   DEFINE_SIZE_ARRAY (6, regionIndices);
@@ -2107,6 +2823,7 @@
 
 struct VariationStore
 {
+  private:
   float get_delta (unsigned int outer, unsigned int inner,
 		   const int *coords, unsigned int coord_count) const
   {
@@ -2122,6 +2839,7 @@
 					     this+regions);
   }
 
+  public:
   float get_delta (unsigned int index,
 		   const int *coords, unsigned int coord_count) const
   {
@@ -2145,48 +2863,102 @@
 
   bool serialize (hb_serialize_context_t *c,
 		  const VariationStore *src,
-  		  const hb_array_t <hb_inc_bimap_t> &inner_maps)
+		  const hb_array_t <hb_inc_bimap_t> &inner_maps)
   {
     TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
     unsigned int set_count = 0;
     for (unsigned int i = 0; i < inner_maps.length; i++)
-      if (inner_maps[i].get_population () > 0) set_count++;
+      if (inner_maps[i].get_population ())
+	set_count++;
 
-    unsigned int size = min_size + HBUINT32::static_size * set_count;
-    if (unlikely (!c->allocate_size<HBUINT32> (size))) return_trace (false);
     format = 1;
 
-    hb_inc_bimap_t region_map;
-    for (unsigned int i = 0; i < inner_maps.length; i++)
-      (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]);
-    region_map.sort ();
+    const auto &src_regions = src+src->regions;
 
-    if (unlikely (!regions.serialize (c, this)
-		  .serialize (c, &(src+src->regions), region_map))) return_trace (false);
+    hb_set_t region_indices;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      (src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]);
+
+    if (region_indices.in_error ())
+      return_trace (false);
+
+    region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID);
+
+    /* TODO use constructor when our data-structures support that. */
+    hb_inc_bimap_t region_map;
+    + hb_iter (region_indices)
+    | hb_apply ([&region_map] (unsigned _) { region_map.add(_); })
+    ;
+    if (region_map.in_error())
+      return_trace (false);
+
+    if (unlikely (!regions.serialize_serialize (c, &src_regions, region_map)))
+      return_trace (false);
+
+    dataSets.len = set_count;
+    if (unlikely (!c->extend (dataSets))) return_trace (false);
 
     /* TODO: The following code could be simplified when
-     * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize ()
-     */
-    dataSets.len = set_count;
+     * List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */
     unsigned int set_index = 0;
     for (unsigned int i = 0; i < inner_maps.length; i++)
     {
-      if (inner_maps[i].get_population () == 0) continue;
-      if (unlikely (!dataSets[set_index++].serialize (c, this)
-		      .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
+      if (!inner_maps[i].get_population ()) continue;
+      if (unlikely (!dataSets[set_index++]
+		     .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
 	return_trace (false);
     }
 
     return_trace (true);
   }
 
-  unsigned int get_region_index_count (unsigned int ivs) const
-  { return (this+dataSets[ivs]).get_region_index_count (); }
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
 
-  void get_scalars (unsigned int ivs,
-		    int *coords, unsigned int coord_count,
-		    float *scalars /*OUT*/,
-		    unsigned int num_scalars) const
+    VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+    if (unlikely (!varstore_prime)) return_trace (false);
+
+    const hb_set_t *variation_indices = c->plan->layout_variation_indices;
+    if (variation_indices->is_empty ()) return_trace (false);
+
+    hb_vector_t<hb_inc_bimap_t> inner_maps;
+    inner_maps.resize ((unsigned) dataSets.len);
+    for (unsigned i = 0; i < inner_maps.length; i++)
+      inner_maps[i].init ();
+
+    for (unsigned idx : c->plan->layout_variation_indices->iter ())
+    {
+      uint16_t major = idx >> 16;
+      uint16_t minor = idx & 0xFFFF;
+
+      if (major >= inner_maps.length)
+      {
+	for (unsigned i = 0; i < inner_maps.length; i++)
+	  inner_maps[i].fini ();
+	return_trace (false);
+      }
+      inner_maps[major].add (minor);
+    }
+    varstore_prime->serialize (c->serializer, this, inner_maps.as_array ());
+
+    for (unsigned i = 0; i < inner_maps.length; i++)
+      inner_maps[i].fini ();
+
+    return_trace (
+        !c->serializer->in_error()
+        && varstore_prime->dataSets);
+  }
+
+  unsigned int get_region_index_count (unsigned int major) const
+  { return (this+dataSets[major]).get_region_index_count (); }
+
+  void get_region_scalars (unsigned int major,
+			   const int *coords, unsigned int coord_count,
+			   float *scalars /*OUT*/,
+			   unsigned int num_scalars) const
   {
 #ifdef HB_NO_VAR
     for (unsigned i = 0; i < num_scalars; i++)
@@ -2194,18 +2966,19 @@
     return;
 #endif
 
-    (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
-				      &scalars[0], num_scalars);
+    (this+dataSets[major]).get_region_scalars (coords, coord_count,
+					       this+regions,
+					       &scalars[0], num_scalars);
   }
 
   unsigned int get_sub_table_count () const { return dataSets.len; }
 
   protected:
   HBUINT16				format;
-  LOffsetTo<VarRegionList>		regions;
-  LOffsetArrayOf<VarData>		dataSets;
+  Offset32To<VarRegionList>		regions;
+  Array16OfOffset32To<VarData>		dataSets;
   public:
-  DEFINE_SIZE_ARRAY (8, dataSets);
+  DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
 };
 
 /*
@@ -2216,6 +2989,14 @@
 {
   friend struct Condition;
 
+  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:
   bool evaluate (const int *coords, unsigned int coord_len) const
   {
@@ -2248,6 +3029,17 @@
     }
   }
 
+  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 ());
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2278,6 +3070,19 @@
     return true;
   }
 
+  bool subset (hb_subset_context_t *c) 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))
+    ;
+
+    return_trace (bool (out->conditions));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2285,7 +3090,7 @@
   }
 
   protected:
-  LOffsetArrayOf<Condition>	conditions;
+  Array16OfOffset32To<Condition>	conditions;
   public:
   DEFINE_SIZE_ARRAY (2, conditions);
 };
@@ -2294,6 +3099,36 @@
 {
   friend struct FeatureTableSubstitution;
 
+  void collect_lookups (const void *base, hb_set_t *lookup_indexes /* OUT */) const
+  {
+    return (base+feature).add_lookup_indexes_to (lookup_indexes);
+  }
+
+  void closure_features (const void *base,
+			 const hb_map_t *lookup_indexes,
+			 hb_set_t       *feature_indexes /* OUT */) const
+  {
+    if ((base+feature).intersects_lookup_indexes (lookup_indexes))
+      feature_indexes->add (featureIndex);
+  }
+
+  bool subset (hb_subset_layout_context_t *c, const void *base) const
+  {
+    TRACE_SUBSET (this);
+    if (!c->feature_index_map->has (featureIndex)) {
+      // Feature that is being substituted is not being retained, so we don't
+      // need this.
+      return_trace (false);
+    }
+
+    auto *out = c->subset_context->serializer->embed (this);
+    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);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -2302,7 +3137,7 @@
 
   protected:
   HBUINT16		featureIndex;
-  LOffsetTo<Feature>	feature;
+  Offset32To<Feature>	feature;
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -2321,6 +3156,49 @@
     return nullptr;
   }
 
+  void collect_lookups (const hb_set_t *feature_indexes,
+			hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    + hb_iter (substitutions)
+    | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+    | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
+		{ r.collect_lookups (this, lookup_indexes); })
+    ;
+  }
+
+  void closure_features (const hb_map_t *lookup_indexes,
+			 hb_set_t       *feature_indexes /* OUT */) const
+  {
+    for (const FeatureTableSubstitutionRecord& record : substitutions)
+      record.closure_features (this, lookup_indexes, feature_indexes);
+  }
+
+  bool intersects_features (const hb_map_t *feature_index_map) const
+  {
+    for (const FeatureTableSubstitutionRecord& record : substitutions)
+    {
+      if (feature_index_map->has (record.featureIndex)) return true;
+    }
+    return false;
+  }
+
+  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);
+
+    out->version.major = version.major;
+    out->version.minor = version.minor;
+
+    + substitutions.iter ()
+    | hb_apply (subset_record_array (l, &(out->substitutions), this))
+    ;
+
+    return_trace (bool (out->substitutions));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2331,7 +3209,7 @@
 
   protected:
   FixedVersion<>	version;	/* Version--0x00010000u */
-  ArrayOf<FeatureTableSubstitutionRecord>
+  Array16Of<FeatureTableSubstitutionRecord>
 			substitutions;
   public:
   DEFINE_SIZE_ARRAY (6, substitutions);
@@ -2341,6 +3219,37 @@
 {
   friend struct FeatureVariations;
 
+  void collect_lookups (const void     *base,
+			const hb_set_t *feature_indexes,
+			hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+  }
+
+  void closure_features (const void     *base,
+			 const hb_map_t *lookup_indexes,
+			 hb_set_t       *feature_indexes /* OUT */) const
+  {
+    (base+substitutions).closure_features (lookup_indexes, feature_indexes);
+  }
+
+  bool intersects_features (const void *base, const hb_map_t *feature_index_map) const
+  {
+    return (base+substitutions).intersects_features (feature_index_map);
+  }
+
+  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->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -2349,9 +3258,9 @@
   }
 
   protected:
-  LOffsetTo<ConditionSet>
+  Offset32To<ConditionSet>
 			conditions;
-  LOffsetTo<FeatureTableSubstitution>
+  Offset32To<FeatureTableSubstitution>
 			substitutions;
   public:
   DEFINE_SIZE_STATIC (8);
@@ -2362,7 +3271,7 @@
   static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
 
   bool find_index (const int *coords, unsigned int coord_len,
-			  unsigned int *index) const
+		   unsigned int *index) const
   {
     unsigned int count = varRecords.len;
     for (unsigned int i = 0; i < count; i++)
@@ -2391,6 +3300,45 @@
     return_trace (c->embed (*this));
   }
 
+  void collect_lookups (const hb_set_t *feature_indexes,
+			hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    for (const FeatureVariationRecord& r : varRecords)
+      r.collect_lookups (this, feature_indexes, lookup_indexes);
+  }
+
+  void closure_features (const hb_map_t *lookup_indexes,
+			 hb_set_t       *feature_indexes /* OUT */) const
+  {
+    for (const FeatureVariationRecord& record : varRecords)
+      record.closure_features (this, lookup_indexes, feature_indexes);
+  }
+
+  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);
+
+    out->version.major = version.major;
+    out->version.minor = version.minor;
+
+    int keep_up_to = -1;
+    for (int i = varRecords.len - 1; i >= 0; i--) {
+      if (varRecords[i].intersects_features (this, l->feature_index_map)) {
+        keep_up_to = i;
+        break;
+      }
+    }
+
+    unsigned count = (unsigned) (keep_up_to + 1);
+    for (unsigned i = 0; i < count; i++) {
+      subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
+    }
+    return_trace (bool (out->varRecords));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2401,7 +3349,7 @@
 
   protected:
   FixedVersion<>	version;	/* Version--0x00010000u */
-  LArrayOf<FeatureVariationRecord>
+  Array32Of<FeatureVariationRecord>
 			varRecords;
   public:
   DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
@@ -2506,10 +3454,28 @@
   hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
   { return font->em_scalef_y (get_delta (font, store)); }
 
-  VariationDevice* copy (hb_serialize_context_t *c) const
+  VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
   {
     TRACE_SERIALIZE (this);
-    return_trace (c->embed<VariationDevice> (this));
+    auto snap = c->snapshot ();
+    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);
+      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);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2522,12 +3488,11 @@
 
   float get_delta (hb_font_t *font, const VariationStore &store) const
   {
-    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
+    return store.get_delta (varIdx, font->coords, font->num_coords);
   }
 
   protected:
-  HBUINT16	outerIndex;
-  HBUINT16	innerIndex;
+  VarIdx	varIdx;
   HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -2597,7 +3562,7 @@
     }
   }
 
-  Device* copy (hb_serialize_context_t *c) const
+  Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const
   {
     TRACE_SERIALIZE (this);
     switch (u.b.format) {
@@ -2609,13 +3574,32 @@
 #endif
 #ifndef HB_NO_VAR
     case 0x8000:
-      return_trace (reinterpret_cast<Device *> (u.variation.copy (c)));
+      return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map)));
 #endif
     default:
       return_trace (nullptr);
     }
   }
 
+  void collect_variation_indices (hb_set_t *layout_variation_indices) const
+  {
+    switch (u.b.format) {
+#ifndef HB_NO_HINTING
+    case 1:
+    case 2:
+    case 3:
+      return;
+#endif
+#ifndef HB_NO_VAR
+    case 0x8000:
+      u.variation.record_variation_index (layout_variation_indices);
+      return;
+#endif
+    default:
+      return;
+    }
+  }
+
   protected:
   union {
   DeviceHeader		b;
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index dc751d8..aea644f 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -41,8 +41,18 @@
  * Attachment List Table
  */
 
-typedef ArrayOf<HBUINT16> AttachPoint;	/* Array of contour point indices--in
-					 * increasing numerical order */
+/* 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
 {
@@ -63,15 +73,35 @@
 
     if (point_count)
     {
-      hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
-      unsigned int count = array.length;
-      for (unsigned int i = 0; i < count; i++)
-	point_array[i] = array[i];
+      + 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);
@@ -79,10 +109,10 @@
   }
 
   protected:
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table -- from
 					 * beginning of AttachList table */
-  OffsetArrayOf<AttachPoint>
+  Array16OfOffset16To<AttachPoint>
 		attachPoint;		/* Array of AttachPoint tables
 					 * in Coverage Index order */
   public:
@@ -96,6 +126,13 @@
 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
@@ -119,6 +156,13 @@
 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
@@ -153,6 +197,19 @@
 	   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);
@@ -162,7 +219,7 @@
   protected:
   HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
   FWORD		coordinate;		/* X or Y value, in design units */
-  OffsetTo<Device>
+  Offset16To<Device>
 		deviceTable;		/* Offset to Device table for X or Y
 					 * value--from beginning of CaretValue
 					 * table */
@@ -173,9 +230,9 @@
 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
+				 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);
@@ -185,6 +242,32 @@
     }
   }
 
+  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);
@@ -210,25 +293,45 @@
 
 struct LigGlyph
 {
-  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 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)
     {
-      hb_array_t <const OffsetTo<CaretValue>> array = carets.sub_array (start_offset, caret_count);
-      unsigned int count = array.length;
-      for (unsigned int i = 0; i < count; i++)
-	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
+      + 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);
@@ -236,7 +339,7 @@
   }
 
   protected:
-  OffsetArrayOf<CaretValue>
+  Array16OfOffset16To<CaretValue>
 		carets;			/* Offset array of CaretValue tables
 					 * --from beginning of LigGlyph table
 					 * --in increasing coordinate order */
@@ -265,6 +368,37 @@
     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);
@@ -272,10 +406,10 @@
   }
 
   protected:
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of LigCaretList table */
-  OffsetArrayOf<LigGlyph>
+  Array16OfOffset16To<LigGlyph>
 		ligGlyph;		/* Array of LigGlyph tables
 					 * in Coverage Index order */
   public:
@@ -288,6 +422,34 @@
   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);
@@ -296,7 +458,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  ArrayOf<LOffsetTo<Coverage>>
+  Array16Of<Offset32To<Coverage>>
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
   public:
@@ -313,6 +475,15 @@
     }
   }
 
+  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);
@@ -356,7 +527,7 @@
   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).add_class (glyphs, klass); }
+  { (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
@@ -386,7 +557,7 @@
 
   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); }
+  { 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).
@@ -409,15 +580,15 @@
     }
   }
 
-  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
 				   hb_face_t *face) const;
 
   struct accelerator_t
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<GDEF> (face);
-      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
+      this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
+      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
       {
 	hb_blob_destroy (this->table.get_blob ());
 	this->table = hb_blob_get_empty ();
@@ -436,24 +607,66 @@
 	   (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);
 
-    out->glyphClassDef.serialize_subset (c, glyphClassDef, this, out);
-    out->attachList = 0;//TODO(subset) serialize_subset (c, attachList, this, out);
-    out->ligCaretList = 0;//TODO(subset) serialize_subset (c, ligCaretList, this, out);
-    out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, out);
+    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)
-      out->markGlyphSetsDef = 0;// TODO(subset) serialize_subset (c, markGlyphSetsDef, this, out);
+    {
+      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)
-      out->varStore = 0;// TODO(subset) serialize_subset (c, varStore, this, out);
+    {
+      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
+      if (!subset_varstore && version.to_int () == 0x00010003u)
+	out->version.minor = 2;
+    }
 
-    return_trace (true);
+    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
@@ -472,28 +685,28 @@
   protected:
   FixedVersion<>version;		/* Version of the GDEF table--currently
 					 * 0x00010003u */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
 					 * for glyph type--from beginning of
 					 * GDEF header (may be Null) */
-  OffsetTo<AttachList>
+  Offset16To<AttachList>
 		attachList;		/* Offset to list of glyphs with
 					 * attachment points--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<LigCaretList>
+  Offset16To<LigCaretList>
 		ligCaretList;		/* Offset to list of positioning points
 					 * for ligature carets--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		markAttachClassDef;	/* Offset to class definition table for
 					 * mark attachment type--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<MarkGlyphSets>
+  Offset16To<MarkGlyphSets>
 		markGlyphSetsDef;	/* Offset to the table of mark set
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 0x00010002. */
-  LOffsetTo<VariationStore>
+  Offset32To<VariationStore>
 		varStore;		/* Offset to the table of Item Variation
 					 * Store--from beginning of GDEF
 					 * header (may be NULL).  Introduced
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 024312d..a8fb5c7 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -34,6 +34,11 @@
 
 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. */
@@ -74,30 +79,32 @@
 
 /* All fields are options.  Only those available advance the value pointer. */
 #if 0
-  HBINT16		xPlacement;		/* Horizontal adjustment for
+  HBINT16		xPlacement;	/* Horizontal adjustment for
 					 * placement--in design units */
-  HBINT16		yPlacement;		/* Vertical adjustment for
+  HBINT16		yPlacement;	/* Vertical adjustment for
 					 * placement--in design units */
-  HBINT16		xAdvance;		/* Horizontal adjustment for
+  HBINT16		xAdvance;	/* Horizontal adjustment for
 					 * advance--in design units (only used
 					 * for horizontal writing) */
-  HBINT16		yAdvance;		/* Vertical adjustment for advance--in
+  HBINT16		yAdvance;	/* Vertical adjustment for advance--in
 					 * design units (only used for vertical
 					 * writing) */
-  OffsetTo<Device>	xPlaDevice;	/* Offset to Device table for
+  Offset16To<Device>	xPlaDevice;	/* Offset to Device table for
 					 * horizontal placement--measured from
 					 * beginning of PosTable (may be NULL) */
-  OffsetTo<Device>	yPlaDevice;	/* Offset to Device table for vertical
+  Offset16To<Device>	yPlaDevice;	/* Offset to Device table for vertical
 					 * placement--measured from beginning
 					 * of PosTable (may be NULL) */
-  OffsetTo<Device>	xAdvDevice;	/* Offset to Device table for
+  Offset16To<Device>	xAdvDevice;	/* Offset to Device table for
 					 * horizontal advance--measured from
 					 * beginning of PosTable (may be NULL) */
-  OffsetTo<Device>	yAdvDevice;	/* Offset to Device table for vertical
+  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; }
 
@@ -155,6 +162,94 @@
     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
   {
@@ -173,18 +268,42 @@
     return true;
   }
 
-  HB_INTERNAL static OffsetTo<Device>& get_device (Value* value)
-  { return *CastP<OffsetTo<Device>> (value); }
-  HB_INTERNAL static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
+  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 *CastP<OffsetTo<Device>> (value);
+    return *static_cast<const Offset16To<Device> *> (value);
   }
 
-  HB_INTERNAL static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+  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 *CastP<HBINT16> (value);
+    return *reinterpret_cast<const HBINT16 *> (value);
   }
 
   public:
@@ -234,12 +353,22 @@
 
     return_trace (true);
   }
+
+ private:
+
+  void should_drop (Value value, Flags flag, unsigned int* format) const
+  {
+    if (value) return;
+    *format = *format & ~flag;
+  }
+
 };
 
-template<typename Iterator>
-static inline void SinglePos_serialize (hb_serialize_context_t *c,
-					Iterator it,
-					ValueFormat valFormat);
+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
@@ -261,7 +390,10 @@
   AnchorFormat1* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
-    return_trace (c->embed<AnchorFormat1> (this));
+    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
+    if (!out) return_trace (out);
+    out->format = 1;
+    return_trace (out);
   }
 
   protected:
@@ -338,26 +470,35 @@
     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
-  AnchorFormat3* copy (hb_serialize_context_t *c) const
+  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, out);
-    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, out);
+    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 */
-  OffsetTo<Device>
+  Offset16To<Device>
 		xDeviceTable;		/* Offset to Device table for X
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
-  OffsetTo<Device>
+  Offset16To<Device>
 		yDeviceTable;		/* Offset to Device table for Y
 					 * coordinate-- from beginning of
 					 * Anchor table (may be NULL) */
@@ -391,14 +532,34 @@
     }
   }
 
-  Anchor* copy (hb_serialize_context_t *c) const
+  bool subset (hb_subset_context_t *c) const
   {
-    TRACE_SERIALIZE (this);
+    TRACE_SUBSET (this);
     switch (u.format) {
-    case 1: return_trace (reinterpret_cast<Anchor *> (u.format1.copy (c)));
-    case 2: return_trace (reinterpret_cast<Anchor *> (u.format2.copy (c)));
-    case 3: return_trace (reinterpret_cast<Anchor *> (u.format3.copy (c)));
-    default:return_trace (nullptr);
+    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;
     }
   }
 
@@ -420,11 +581,44 @@
 			    unsigned int cols, bool *found) const
   {
     *found = false;
-    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
+    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);
@@ -438,8 +632,7 @@
   }
 
   HBUINT16	rows;			/* Number of rows */
-  protected:
-  UnsizedArrayOf<OffsetTo<Anchor>>
+  UnsizedArrayOf<Offset16To<Anchor>>
 		matrixZ;		/* Matrix of offsets to Anchor tables--
 					 * from beginning of AnchorMatrix table */
   public:
@@ -451,22 +644,42 @@
 {
   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 */
-  OffsetTo<Anchor>
+  Offset16To<Anchor>
 		markAnchor;		/* Offset to Anchor table--from
 					 * beginning of MarkArray table */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
+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,
@@ -475,7 +688,7 @@
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
-    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
+    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
     const Anchor& mark_anchor = this + record.markAnchor;
@@ -502,10 +715,42 @@
     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 (ArrayOf<MarkRecord>::sanitize (c, this));
+    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
   }
 };
 
@@ -517,11 +762,27 @@
   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).add_coverage (c->input))) return; }
+  { 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);
@@ -536,29 +797,39 @@
   }
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
+		  const SrcLookup *src,
 		  Iterator it,
-		  ValueFormat valFormat)
+		  ValueFormat newFormat,
+		  const hb_map_t *layout_variation_idx_map)
   {
-    if (unlikely (!c->extend_min (*this))) return;
-    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+    if (unlikely (!c->extend_min (this))) return;
+    if (unlikely (!c->check_assign (valueFormat,
+                                    newFormat,
+                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
 
-    for (const auto &_ : hb_second (*it))
-      c->copy (_);
+    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 (c, this).serialize (c, glyphs);
+    coverage.serialize_serialize (c, glyphs);
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto it =
@@ -569,7 +840,7 @@
     ;
 
     bool ret = bool (it);
-    SinglePos_serialize (c->serializer, it, valueFormat);
+    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
     return_trace (ret);
   }
 
@@ -583,7 +854,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
@@ -600,11 +871,34 @@
   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).add_coverage (c->input))) return; }
+  { 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);
@@ -623,31 +917,37 @@
   }
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
+		  const SrcLookup *src,
 		  Iterator it,
-		  ValueFormat valFormat)
+		  ValueFormat newFormat,
+		  const hb_map_t *layout_variation_idx_map)
   {
-    if (unlikely (!c->extend_min (*this))) return;
-    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
-    if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+    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;
 
-    for (const auto iter : it)
-      for (const auto &_ : iter.second)
-	c->copy (_);
+    + 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 (c, this).serialize (c, glyphs);
+    coverage.serialize_serialize (c, glyphs);
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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 ();
@@ -665,7 +965,7 @@
     ;
 
     bool ret = bool (it);
-    SinglePos_serialize (c->serializer, it, valueFormat);
+    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
     return_trace (ret);
   }
 
@@ -679,7 +979,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
@@ -709,22 +1009,37 @@
 
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
+		  const SrcLookup* src,
 		  Iterator glyph_val_iter_pairs,
-		  ValueFormat valFormat)
+		  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);
+    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, glyph_val_iter_pairs, valFormat);
-	    return;
-    case 2: u.format2.serialize (c, glyph_val_iter_pairs, valFormat);
-	    return;
+    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;
     }
   }
@@ -735,8 +1050,8 @@
     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, hb_forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    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 ());
     }
   }
@@ -749,32 +1064,87 @@
   } u;
 };
 
-template<typename Iterator>
-static inline void
+template<typename Iterator, typename SrcLookup>
+static void
 SinglePos_serialize (hb_serialize_context_t *c,
+		     const SrcLookup *src,
 		     Iterator it,
-		     ValueFormat valFormat)
-{ c->start_embed<SinglePos> ()->serialize (c, it, valFormat); }
+		     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;
 
-  bool serialize (hb_serialize_context_t *c,
-                  unsigned length,
-                  const hb_map_t &glyph_map) const
+  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 *out = c->start_embed (*this);
-    if (unlikely (!c->extend_min (out))) return_trace (false);
-    
-    out->secondGlyph = glyph_map[secondGlyph];
-    return_trace (c->copy (values, length));
+    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:
-  HBGlyphID	secondGlyph;		/* GlyphID of second glyph in the
+  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
@@ -806,7 +1176,7 @@
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
-			      const ValueFormat *valueFormats) const
+		       const ValueFormat *valueFormats) const
   {
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
@@ -816,9 +1186,27 @@
     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
+	      const ValueFormat *valueFormats,
+	      unsigned int pos) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
@@ -826,40 +1214,27 @@
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 
-    unsigned int count = len;
-
-    /* Hand-coded bsearch. */
-    if (unlikely (!count))
-      return_trace (false);
-    hb_codepoint_t x = buffer->info[pos].codepoint;
-    int min = 0, max = (int) count - 1;
-    while (min <= max)
+    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+						&firstPairValueRecord,
+						len,
+						record_size);
+    if (record)
     {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
-      hb_codepoint_t mid_x = record->secondGlyph;
-      if (x < mid_x)
-	max = mid - 1;
-      else if (x > mid_x)
-	min = mid + 1;
-      else
-      {
-	/* Note the intentional use of "|" instead of short-circuit "||". */
-	if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
-	    valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
-	  buffer->unsafe_to_break (buffer->idx, pos + 1);
-	if (len2)
-	  pos++;
-	buffer->idx = pos;
-	return_trace (true);
-      }
+      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);
     }
-
     return_trace (false);
   }
 
   bool subset (hb_subset_context_t *c,
-               const ValueFormat valueFormats[2]) const
+	       const ValueFormat valueFormats[2],
+               const ValueFormat newFormats[2]) const
   {
     TRACE_SUBSET (this);
     auto snap = c->serializer->snapshot ();
@@ -868,19 +1243,29 @@
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->len = 0;
 
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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)) continue;
-      if (record->serialize (c->serializer, len1 + len2, glyph_map)) num++;
+      if (glyphset.has (record->secondGlyph)
+	 && record->subset (c, &context)) num++;
       record = &StructAtOffset<const PairValueRecord> (record, record_size);
     }
 
@@ -891,7 +1276,6 @@
 
   struct sanitize_closure_t
   {
-    const void *base;
     const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
@@ -908,8 +1292,8 @@
 
     unsigned int count = len;
     const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
-		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
+    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:
@@ -929,15 +1313,33 @@
     + hb_zip (this+coverage, pairSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([glyphs, this] (const OffsetTo<PairSet> &_)
+    | 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).add_coverage (c->input))) return;
+    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);
@@ -963,7 +1365,7 @@
   {
     TRACE_SUBSET (this);
 
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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);
@@ -971,17 +1373,23 @@
     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 OffsetTo<PairSet>& _)
+    | 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;
-		   auto snap = c->serializer->snapshot ();
-		   bool ret = o->serialize_subset (c, _, this, out, valueFormat);
+		   bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
 		   if (!ret)
 		   {
 		     out->pairSet.pop ();
@@ -995,12 +1403,41 @@
     | hb_sink (new_coverage)
     ;
 
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    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);
@@ -1011,7 +1448,6 @@
     unsigned int len2 = valueFormat[1].get_len ();
     PairSet::sanitize_closure_t closure =
     {
-      this,
       valueFormat,
       len1,
       1 + len1 + len2
@@ -1022,7 +1458,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
@@ -1031,7 +1467,7 @@
 					/* [1] Defines the types of data in
 					 * ValueRecord2--for the second glyph
 					 * in the pair--may be zero (0) */
-  OffsetArrayOf<PairSet>
+  Array16OfOffset16To<PairSet>
 		pairSet;		/* Array of PairSet tables
 					 * ordered by Coverage Index */
   public:
@@ -1046,10 +1482,60 @@
 	   (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).add_coverage (c->input))) return;
-    if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
+    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; }
@@ -1074,9 +1560,9 @@
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
-    /* Note the intentional use of "|" instead of short-circuit "||". */
-    if (valueFormat1.apply_value (c, this, v, buffer->cur_pos()) |
-	valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]))
+    bool applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+    bool applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+    if (applied_first || applied_second)
       buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
 
     buffer->idx = skippy_iter.idx;
@@ -1092,36 +1578,36 @@
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->format = format;
-    out->valueFormat1 = valueFormat1;
-    out->valueFormat2 = valueFormat2;
 
     hb_map_t klass1_map;
-    out->classDef1.serialize_subset (c, classDef1, this, out, &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, out, &klass2_map);
+    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
     out->class2Count = klass2_map.get_population ();
 
-    unsigned record_len = valueFormat1.get_len () + valueFormat2.get_len ();
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
 
-    + hb_range ((unsigned) class1Count)
-    | hb_filter (klass1_map)
-    | hb_apply ([&] (const unsigned class1_idx)
-                {
-                  + hb_range ((unsigned) class2Count)
-                  | hb_filter (klass2_map)
-                  | hb_apply ([&] (const unsigned class2_idx)
-                              {
-                                unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_len;
-                                for (unsigned i = 0; i < record_len; i++)
-                                  c->serializer->copy (values[idx+i]);
-                              })
-                  ;
-                })
-    ;
+    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);
 
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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 =
@@ -1130,10 +1616,34 @@
     | hb_map_retains_sorting (glyph_map)
     ;
 
-    out->coverage.serialize (c->serializer, out).serialize (c->serializer, it);
+    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);
@@ -1156,7 +1666,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat1;		/* ValueRecord definition--for the
@@ -1165,11 +1675,11 @@
   ValueFormat	valueFormat2;		/* ValueRecord definition--for the
 					 * second glyph of the pair--may be
 					 * zero (0) */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		classDef1;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the first glyph of the pair */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		classDef2;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the second glyph of the pair */
@@ -1192,8 +1702,8 @@
     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, hb_forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    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 ());
     }
   }
@@ -1217,25 +1727,31 @@
     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
-  EntryExitRecord* copy (hb_serialize_context_t *c,
-			 const void *src_base,
-			 const void *dst_base) const
+  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->embed (this);
+    auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (nullptr);
 
-    out->entryAnchor.serialize_copy (c, entryAnchor, src_base, dst_base);
-    out->exitAnchor.serialize_copy (c, exitAnchor, src_base, dst_base);
+    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
     return_trace (out);
   }
 
   protected:
-  OffsetTo<Anchor>
+  Offset16To<Anchor>
 		entryAnchor;		/* Offset to EntryAnchor table--from
 					 * beginning of CursivePos
 					 * subtable--may be NULL */
-  OffsetTo<Anchor>
+  Offset16To<Anchor>
 		exitAnchor;		/* Offset to ExitAnchor table--from
 					 * beginning of CursivePos
 					 * subtable--may be NULL */
@@ -1251,8 +1767,19 @@
   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).add_coverage (c->input))) return; }
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -1353,36 +1880,42 @@
     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_serialize_context_t *c,
+  void serialize (hb_subset_context_t *c,
 		  Iterator it,
 		  const void *src_base)
   {
-    if (unlikely (!c->extend_min ((*this)))) return;
+    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))
-      c->copy (entry_record, src_base, this);
+      entry_record.subset (c, src_base);
 
     auto glyphs =
     + it
     | hb_map_retains_sorting (hb_first)
     ;
 
-    coverage.serialize (c, this).serialize (c, glyphs);
+    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 ();
+    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);
@@ -1396,7 +1929,7 @@
     ;
 
     bool ret = bool (it);
-    out->serialize (c->serializer, it, this);
+    out->serialize (c, it, this);
     return_trace (ret);
   }
 
@@ -1408,10 +1941,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
-  ArrayOf<EntryExitRecord>
+  Array16Of<EntryExitRecord>
 		entryExitRecord;	/* Array of EntryExit records--in
 					 * Coverage Index order */
   public:
@@ -1426,7 +1959,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1444,16 +1977,73 @@
 					 * 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); }
+  {
+    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).add_coverage (c->input))) return;
-    if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
+    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; }
@@ -1501,8 +2091,70 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    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
@@ -1517,17 +2169,17 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		markCoverage;		/* Offset to MarkCoverage table--from
 					 * beginning of MarkBasePos subtable */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		baseCoverage;		/* Offset to BaseCoverage table--from
 					 * beginning of MarkBasePos subtable */
   HBUINT16	classCount;		/* Number of classes defined for marks */
-  OffsetTo<MarkArray>
+  Offset16To<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkBasePos subtable */
-  OffsetTo<BaseArray>
+  Offset16To<BaseArray>
 		baseArray;		/* Offset to BaseArray table--from
 					 * beginning of MarkBasePos subtable */
   public:
@@ -1542,7 +2194,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1560,21 +2212,93 @@
 					 * mark-minor--
 					 * ordered by class--zero-based. */
 
-typedef OffsetListOf<LigatureAttach> LigatureArray;
-					/* Array of LigatureAttach
-					 * tables ordered by
-					 * LigatureCoverage Index */
+/* 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); }
+  {
+    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).add_coverage (c->input))) return;
-    if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
+    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; }
@@ -1625,8 +2349,50 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    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
@@ -1641,24 +2407,25 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		markCoverage;		/* Offset to Mark Coverage table--from
 					 * beginning of MarkLigPos subtable */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		ligatureCoverage;	/* Offset to Ligature Coverage
 					 * table--from beginning of MarkLigPos
 					 * subtable */
   HBUINT16	classCount;		/* Number of defined mark classes */
-  OffsetTo<MarkArray>
+  Offset16To<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkLigPos subtable */
-  OffsetTo<LigatureArray>
+  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>
@@ -1667,7 +2434,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1688,13 +2455,47 @@
 struct MarkMarkPosFormat1
 {
   bool intersects (const hb_set_t *glyphs) const
-  { return (this+mark1Coverage).intersects (glyphs) &&
-	   (this+mark2Coverage).intersects (glyphs); }
+  {
+    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).add_coverage (c->input))) return;
-    if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
+    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; }
@@ -1721,12 +2522,15 @@
     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 (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 {
+    }
+    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))
@@ -1746,8 +2550,68 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    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
@@ -1762,19 +2626,19 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
   HBUINT16	classCount;		/* Number of defined mark classes */
-  OffsetTo<MarkArray>
+  Offset16To<MarkArray>
 		mark1Array;		/* Offset to Mark1Array table--from
 					 * beginning of MarkMarkPos subtable */
-  OffsetTo<Mark2Array>
+  Offset16To<Mark2Array>
 		mark2Array;		/* Offset to Mark2Array table--from
 					 * beginning of MarkMarkPos subtable */
   public:
@@ -1789,7 +2653,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1840,19 +2704,25 @@
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
-    case Pair:			return_trace (u.pair.dispatch (c, hb_forward<Ts> (ds)...));
-    case Cursive:		return_trace (u.cursive.dispatch (c, hb_forward<Ts> (ds)...));
-    case MarkBase:		return_trace (u.markBase.dispatch (c, hb_forward<Ts> (ds)...));
-    case MarkLig:		return_trace (u.markLig.dispatch (c, hb_forward<Ts> (ds)...));
-    case MarkMark:		return_trace (u.markMark.dispatch (c, hb_forward<Ts> (ds)...));
-    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
-    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
+    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;
@@ -1897,21 +2767,40 @@
   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   { return dispatch (c); }
 
-  template <typename set_t>
-  void add_coverage (set_t *glyphs) const
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
   {
-    hb_add_coverage_context_t<set_t> c (glyphs);
+    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);
   }
 
-  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+  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, hb_forward<Ts> (ds)...); }
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1930,21 +2819,39 @@
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
   const PosLookup& get_lookup (unsigned int i) const
-  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
+  { 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
-  { return GSUBGPOS::subset<PosLookup> (c); }
+  {
+    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_blacklisted (hb_blob_t *blob,
+  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;
 };
 
@@ -2060,12 +2967,19 @@
 
 #ifndef HB_NO_OT_LAYOUT
 template <typename context_t>
-/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+/*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
-/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+
+/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (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)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index fc21cb0..710c5fb 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -37,8 +37,8 @@
 typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
 
 template<typename Iterator>
-static inline void SingleSubst_serialize (hb_serialize_context_t *c,
-					  Iterator it);
+static void SingleSubst_serialize (hb_serialize_context_t *c,
+				   Iterator it);
 
 
 struct SingleSubstFormat1
@@ -46,19 +46,26 @@
   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->glyphs)
+    | 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).add_coverage (c->input))) return;
+    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; })
@@ -93,9 +100,9 @@
 		  unsigned delta)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
-    c->check_assign (deltaGlyphID, delta);
+    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);
   }
 
@@ -131,7 +138,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   HBUINT16	deltaGlyphID;		/* Add to original GlyphID to get
@@ -145,18 +152,24 @@
   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->glyphs, hb_first)
+    | 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).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
     + hb_zip (this+coverage, substitute)
     | hb_map (hb_second)
     | hb_sink (c->output)
@@ -196,9 +209,9 @@
       + it
       | hb_map_retains_sorting (hb_first)
       ;
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
     return_trace (true);
   }
 
@@ -212,7 +225,7 @@
     + 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 HBGlyphID &> p) -> hb_codepoint_pair_t
+    | 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]); })
     ;
 
@@ -229,10 +242,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID16>
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -255,9 +268,8 @@
     if (glyphs)
     {
       format = 1;
-      auto get_delta = [=] (hb_codepoint_pair_t _) {
-			 return (unsigned) (_.second - _.first) & 0xFFFF;
-		       };
+      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;
     }
@@ -278,8 +290,8 @@
     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, hb_forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    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 ());
     }
   }
@@ -293,7 +305,7 @@
 };
 
 template<typename Iterator>
-static inline void
+static void
 SingleSubst_serialize (hb_serialize_context_t *c,
 		       Iterator it)
 { c->start_embed<SingleSubst> ()->serialize (c, it); }
@@ -331,9 +343,14 @@
 
     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++) {
-      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+    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 ();
@@ -353,15 +370,15 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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)
-      ;
+    + hb_iter (substitute)
+    | hb_map (glyph_map)
+    ;
 
     auto *out = c->serializer->start_embed (*this);
     return_trace (out->serialize (c->serializer, it));
@@ -374,7 +391,7 @@
   }
 
   protected:
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID16>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
@@ -385,19 +402,24 @@
   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->glyphs, hb_first)
+    | 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).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
     + hb_zip (this+coverage, sequence)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
@@ -421,28 +443,28 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> glyphs,
 		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const HBGlyphID> substitute_glyphs_list)
+		  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    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 (c, this)
-				.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
+      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 (c, this).serialize (c, glyphs));
+    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 ();
+    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);
@@ -452,13 +474,12 @@
     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, out), hb_second)
+    | 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 (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -470,10 +491,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<Sequence>
+  Array16OfOffset16To<Sequence>
 		sequence;		/* Array of Sequence tables
 					 * ordered by Coverage Index */
   public:
@@ -483,9 +504,9 @@
 struct MultipleSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> glyphs,
 		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const HBGlyphID> substitute_glyphs_list)
+		  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
@@ -503,7 +524,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -542,7 +563,12 @@
 
     /* 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_all ();
       alt_index = c->random_number () % count + 1;
+    }
 
     if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
 
@@ -551,6 +577,20 @@
     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,
@@ -563,7 +603,7 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     auto it =
@@ -584,7 +624,7 @@
   }
 
   protected:
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID16>
 		alternates;		/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
   public:
@@ -596,18 +636,25 @@
   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).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
     + hb_zip (this+coverage, alternateSet)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
@@ -620,6 +667,14 @@
   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);
@@ -631,28 +686,28 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> glyphs,
 		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const HBGlyphID> alternate_glyphs_list)
+		  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    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 (c, this)
-				    .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
+      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 (c, this).serialize (c, glyphs));
+    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 ();
+    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);
@@ -662,13 +717,12 @@
     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, out), hb_second)
+    | 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 (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -680,10 +734,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<AlternateSet>
+  Array16OfOffset16To<AlternateSet>
 		alternateSet;		/* Array of AlternateSet tables
 					 * ordered by Coverage Index */
   public:
@@ -693,9 +747,9 @@
 struct AlternateSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> glyphs,
 		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const HBGlyphID> alternate_glyphs_list)
+		  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
@@ -713,7 +767,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -801,19 +855,21 @@
 		  Iterator components /* Starting from second */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    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) const
+  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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)
@@ -822,8 +878,8 @@
 
     auto *out = c->serializer->start_embed (*this);
     return_trace (out->serialize (c->serializer,
-				   glyph_map[ligGlyph],
-				   it));
+				  glyph_map[ligGlyph],
+				  it));
   }
 
   public:
@@ -834,8 +890,8 @@
   }
 
   protected:
-  HBGlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
-  HeadlessArrayOf<HBGlyphID>
+  HBGlyphID16	ligGlyph;		/* GlyphID of ligature to substitute */
+  HeadlessArrayOf<HBGlyphID16>
 		component;		/* Array of component GlyphIDs--start
 					 * with the second  component--ordered
 					 * in writing direction */
@@ -895,36 +951,40 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const HBGlyphID> ligatures,
+		  hb_array_t<const HBGlyphID16> ligatures,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
+		  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 (!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 (c, this)
-				.serialize (c,
-					    ligatures[i],
-					    component_list.sub_array (0, component_count))))
+      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) const
+  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, out))
+    | 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));
   }
 
@@ -935,7 +995,7 @@
   }
 
   protected:
-  OffsetArrayOf<Ligature>
+  Array16OfOffset16To<Ligature>
 		ligature;		/* Array LigatureSet tables
 					 * ordered by preference */
   public:
@@ -950,25 +1010,31 @@
     + hb_zip (this+coverage, ligatureSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
+    | 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->glyphs, hb_first)
+    | 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).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
 
     + hb_zip (this+coverage, ligatureSet)
     | hb_map (hb_second)
@@ -992,7 +1058,7 @@
   {
     TRACE_APPLY (this);
 
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    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];
@@ -1000,49 +1066,71 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> first_glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
 		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const HBGlyphID> ligatures_list,
+		  hb_array_t<const HBGlyphID16> ligatures_list,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
+		  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 (!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 (c, this)
-				   .serialize (c,
-					       ligatures_list.sub_array (0, ligature_count),
-					       component_count_list.sub_array (0, ligature_count),
-					       component_list))) return_trace (false);
+      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 (c, this).serialize (c, first_glyphs));
+    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 ();
+    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, ligatureSet)
+    // 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 (subset_offset_array (c, out->ligatureSet, this, out), hb_second)
+    | hb_filter ([&] (const LigatureSet& _) {
+      return _.intersects (&glyphset);
+    }, hb_second)
     | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
+    | 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))
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+
     return_trace (bool (new_coverage));
   }
 
@@ -1054,10 +1142,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<LigatureSet>
+  Array16OfOffset16To<LigatureSet>
 		ligatureSet;		/* Array LigatureSet tables
 					 * ordered by Coverage Index */
   public:
@@ -1067,11 +1155,11 @@
 struct LigatureSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID> first_glyphs,
+		  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
 		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const HBGlyphID> ligatures_list,
+		  hb_array_t<const HBGlyphID16> ligatures_list,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
+		  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);
@@ -1094,7 +1182,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1114,7 +1202,6 @@
 struct ExtensionSubst : Extension<ExtensionSubst>
 {
   typedef struct SubstLookupSubTable SubTable;
-
   bool is_reverse () const;
 };
 
@@ -1126,7 +1213,7 @@
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
     unsigned int count;
 
@@ -1143,36 +1230,41 @@
     return true;
   }
 
+  bool may_have_non_1to1 () const
+  { return false; }
+
   void closure (hb_closure_context_t *c) const
   {
     if (!intersects (c->glyphs)) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
 
     + hb_zip (this+coverage, substitute)
-    | hb_filter (*c->glyphs, hb_first)
+    | 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).add_coverage (c->input))) return;
+    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]).add_coverage (c->before))) return;
+      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
+      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
 
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -1188,13 +1280,15 @@
     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);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
 
-  unsigned int start_index = 0, end_index = 0;
+    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,
@@ -1215,11 +1309,80 @@
     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);
-    // TODO(subset)
-    return_trace (false);
+    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
@@ -1227,27 +1390,27 @@
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in glyph
 					 * sequence order */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		lookaheadX;		/* Array of coverage tables
 					 * in lookahead sequence, in glyph
 					 * sequence order */
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID16>
 		substituteX;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -1262,7 +1425,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1301,18 +1464,24 @@
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
-    case Multiple:		return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
-    case Alternate:		return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
-    case Ligature:		return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
-    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
-    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
-    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
+    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;
@@ -1336,17 +1505,23 @@
   const SubTable& get_subtable (unsigned int i) const
   { return Lookup::get_subtable<SubTable> (i); }
 
-  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
+  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 CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
+      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);
@@ -1373,6 +1548,24 @@
     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>);
@@ -1380,9 +1573,9 @@
   }
 
   template <typename set_t>
-  void add_coverage (set_t *glyphs) const
+  void collect_coverage (set_t *glyphs) const
   {
-    hb_add_coverage_context_t<set_t> c (glyphs);
+    hb_collect_coverage_context_t<set_t> c (glyphs);
     dispatch (&c);
   }
 
@@ -1394,81 +1587,103 @@
       return dispatch (c);
   }
 
-  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
-  SubTable& serialize_subtable (hb_serialize_context_t *c,
-				unsigned int i)
-  { return get_subtables<SubTable> ()[i].serialize (c, this); }
+  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 HBGlyphID> glyphs,
-			 hb_array_t<const HBGlyphID> substitutes)
+			 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);
-    return_trace (serialize_subtable (c, 0).u.single.
-		  serialize (c, hb_zip (glyphs, substitutes)));
+    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 HBGlyphID> glyphs,
+			   hb_sorted_array_t<const HBGlyphID16> glyphs,
 			   hb_array_t<const unsigned int> substitute_len_list,
-			   hb_array_t<const HBGlyphID> substitute_glyphs_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);
-    return_trace (serialize_subtable (c, 0).u.multiple.
-		  serialize (c,
-			     glyphs,
-			     substitute_len_list,
-			     substitute_glyphs_list));
+    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 HBGlyphID> glyphs,
+			    hb_sorted_array_t<const HBGlyphID16> glyphs,
 			    hb_array_t<const unsigned int> alternate_len_list,
-			    hb_array_t<const HBGlyphID> alternate_glyphs_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);
-    return_trace (serialize_subtable (c, 0).u.alternate.
-		  serialize (c,
-			     glyphs,
-			     alternate_len_list,
-			     alternate_glyphs_list));
+
+    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 HBGlyphID> first_glyphs,
+			   hb_sorted_array_t<const HBGlyphID16> first_glyphs,
 			   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-			   hb_array_t<const HBGlyphID> ligatures_list,
+			   hb_array_t<const HBGlyphID16> ligatures_list,
 			   hb_array_t<const unsigned int> component_count_list,
-			   hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
+			   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);
-    return_trace (serialize_subtable (c, 0).u.ligature.
-		  serialize (c,
-			     first_glyphs,
-			     ligature_per_first_glyph_count_list,
-			     ligatures_list,
-			     component_count_list,
-			     component_list));
+    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>
-  HB_INTERNAL static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_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 = dispatch_recurse_func (c, lookup_index);
+    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
@@ -1478,9 +1693,11 @@
     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, hb_forward<Ts> (ds)...); }
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1499,17 +1716,25 @@
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
 
   const SubstLookup& get_lookup (unsigned int i) const
-  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
+  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
 
   bool subset (hb_subset_context_t *c) const
-  { return GSUBGPOS::subset<SubstLookup> (c); }
+  {
+    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_blacklisted (hb_blob_t *blob,
+  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;
 };
 
@@ -1522,18 +1747,30 @@
 #ifndef HB_NO_OT_LAYOUT
 /*static*/ inline bool ExtensionSubst::is_reverse () const
 {
-  unsigned int type = get_type ();
-  if (unlikely (type == SubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
-  return SubstLookup::lookup_type_is_reverse (type);
+  return SubstLookup::lookup_type_is_reverse (get_type ());
 }
 template <typename context_t>
-/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+/*static*/ typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
-/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+
+/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
+{
+  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
+  if (l.may_have_non_1to1 ())
+      hb_set_add_range (covered_seq_indices, seq_index, end_index);
+  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)
+{
+  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)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 579d178..c0ed2bc 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -42,71 +42,140 @@
 
 
 struct hb_intersects_context_t :
-       hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
+       hb_dispatch_context_t<hb_intersects_context_t, bool>
 {
-  const char *get_name () { return "INTERSECTS"; }
   template <typename T>
   return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
   static return_t default_return_value () { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
 
   const hb_set_t *glyphs;
-  unsigned int debug_depth;
 
   hb_intersects_context_t (const hb_set_t *glyphs_) :
-			     glyphs (glyphs_),
-			     debug_depth (0) {}
+                            glyphs (glyphs_) {}
+};
+
+struct hb_have_non_1to1_context_t :
+       hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
+{
+  template <typename T>
+  return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
+  static return_t default_return_value () { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
 };
 
 struct hb_closure_context_t :
-       hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0>
+       hb_dispatch_context_t<hb_closure_context_t>
 {
-  const char *get_name () { return "CLOSURE"; }
-  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index);
   template <typename T>
   return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
   static return_t default_return_value () { return hb_empty_t (); }
-  void recurse (unsigned int lookup_index)
+  void recurse (unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return;
 
     nesting_level_left--;
-    recurse_func (this, lookup_index);
+    recurse_func (this, lookup_index, covered_seq_indicies, seq_index, end_index);
     nesting_level_left++;
   }
 
+  bool lookup_limit_exceeded ()
+  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
   bool should_visit_lookup (unsigned int lookup_index)
   {
+    if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+      return false;
+
     if (is_lookup_done (lookup_index))
       return false;
-    done_lookups->set (lookup_index, glyphs->get_population ());
+
     return true;
   }
 
   bool is_lookup_done (unsigned int lookup_index)
   {
+    if (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? */
-    return done_lookups->get (lookup_index) == glyphs->get_population ();
+    if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ())
+    {
+      done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
+
+      if (!done_lookups_glyph_set->get (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);
+	  return true;
+	}
+      }
+
+      hb_set_clear (done_lookups_glyph_set->get (lookup_index));
+    }
+
+    hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
+    if (unlikely (covered_glyph_set->in_error ()))
+      return true;
+    if (parent_active_glyphs ()->is_subset (*covered_glyph_set))
+      return true;
+
+    hb_set_union (covered_glyph_set, parent_active_glyphs ());
+    return false;
+  }
+
+  hb_set_t* parent_active_glyphs ()
+  {
+    if (active_glyphs_stack.length < 1)
+      return glyphs;
+
+    return active_glyphs_stack.tail ();
+  }
+
+  void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set)
+  {
+    active_glyphs_stack.push (cur_active_glyph_set);
+  }
+
+  bool pop_cur_done_glyphs ()
+  {
+    if (active_glyphs_stack.length < 1)
+      return false;
+
+    active_glyphs_stack.pop ();
+    return true;
   }
 
   hb_face_t *face;
   hb_set_t *glyphs;
+  hb_set_t *cur_intersected_glyphs;
   hb_set_t output[1];
+  hb_vector_t<hb_set_t *> active_glyphs_stack;
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
-			hb_map_t *done_lookups_,
+			hb_set_t *cur_intersected_glyphs_,
+			hb_map_t *done_lookups_glyph_count_,
+			hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *done_lookups_glyph_set_,
 			unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
+			  cur_intersected_glyphs (cur_intersected_glyphs_),
 			  recurse_func (nullptr),
 			  nesting_level_left (nesting_level_left_),
-			  debug_depth (0),
-			  done_lookups (done_lookups_) {}
+			  done_lookups_glyph_count (done_lookups_glyph_count_),
+			  done_lookups_glyph_set (done_lookups_glyph_set_),
+			  lookup_count (0)
+  {
+    push_cur_active_glyphs (glyphs_);
+  }
 
   ~hb_closure_context_t () { flush (); }
 
@@ -114,19 +183,91 @@
 
   void flush ()
   {
+    hb_set_del_range (output, face->get_num_glyphs (), HB_SET_VALUE_INVALID);	/* Remove invalid glyphs. */
     hb_set_union (glyphs, output);
     hb_set_clear (output);
+    active_glyphs_stack.pop ();
+    active_glyphs_stack.fini ();
   }
 
   private:
-  hb_map_t *done_lookups;
+  hb_map_t *done_lookups_glyph_count;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *done_lookups_glyph_set;
+  unsigned int lookup_count;
 };
 
 
-struct hb_would_apply_context_t :
-       hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
+
+struct hb_closure_lookups_context_t :
+       hb_dispatch_context_t<hb_closure_lookups_context_t>
 {
-  const char *get_name () { return "WOULD_APPLY"; }
+  typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+  void recurse (unsigned lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return;
+
+    /* Return if new lookup was recursed to before. */
+    if (is_lookup_visited (lookup_index))
+      return;
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+  }
+
+  void set_lookup_visited (unsigned lookup_index)
+  { visited_lookups->add (lookup_index); }
+
+  void set_lookup_inactive (unsigned lookup_index)
+  { inactive_lookups->add (lookup_index); }
+
+  bool lookup_limit_exceeded ()
+  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
+  bool is_lookup_visited (unsigned lookup_index)
+  {
+    if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
+      return true;
+
+    if (unlikely (visited_lookups->in_error ()))
+      return true;
+
+    return visited_lookups->has (lookup_index);
+  }
+
+  hb_face_t *face;
+  const hb_set_t *glyphs;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+
+  hb_closure_lookups_context_t (hb_face_t *face_,
+				const hb_set_t *glyphs_,
+				hb_set_t *visited_lookups_,
+				hb_set_t *inactive_lookups_,
+				unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+				face (face_),
+				glyphs (glyphs_),
+				recurse_func (nullptr),
+				nesting_level_left (nesting_level_left_),
+				visited_lookups (visited_lookups_),
+				inactive_lookups (inactive_lookups_),
+				lookup_count (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+
+  private:
+  hb_set_t *visited_lookups;
+  hb_set_t *inactive_lookups;
+  unsigned int lookup_count;
+};
+
+struct hb_would_apply_context_t :
+       hb_dispatch_context_t<hb_would_apply_context_t, bool>
+{
   template <typename T>
   return_t dispatch (const T &obj) { return obj.would_apply (this); }
   static return_t default_return_value () { return false; }
@@ -136,7 +277,6 @@
   const hb_codepoint_t *glyphs;
   unsigned int len;
   bool zero_context;
-  unsigned int debug_depth;
 
   hb_would_apply_context_t (hb_face_t *face_,
 			    const hb_codepoint_t *glyphs_,
@@ -145,15 +285,12 @@
 			      face (face_),
 			      glyphs (glyphs_),
 			      len (len_),
-			      zero_context (zero_context_),
-			      debug_depth (0) {}
+			      zero_context (zero_context_) {}
 };
 
-
 struct hb_collect_glyphs_context_t :
-       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0>
+       hb_dispatch_context_t<hb_collect_glyphs_context_t>
 {
-  const char *get_name () { return "COLLECT_GLYPHS"; }
   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   template <typename T>
   return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
@@ -204,7 +341,6 @@
   recurse_func_t recurse_func;
   hb_set_t *recursed_lookups;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
 			       hb_set_t  *glyphs_before, /* OUT.  May be NULL */
@@ -219,8 +355,7 @@
 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
 			      recurse_func (nullptr),
 			      recursed_lookups (hb_set_create ()),
-			      nesting_level_left (nesting_level_left_),
-			      debug_depth (0) {}
+			      nesting_level_left (nesting_level_left_) {}
   ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
@@ -229,26 +364,23 @@
 
 
 template <typename set_t>
-struct hb_add_coverage_context_t :
-       hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
+struct hb_collect_coverage_context_t :
+       hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
 {
-  const char *get_name () { return "GET_COVERAGE"; }
-  typedef const Coverage &return_t;
+  typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
   template <typename T>
   return_t dispatch (const T &obj) { return obj.get_coverage (); }
-  static return_t default_return_value () { return Null(Coverage); }
+  static return_t default_return_value () { return Null (Coverage); }
   bool stop_sublookup_iteration (return_t r) const
   {
-    r.add_coverage (set);
+    r.collect_coverage (set);
     return false;
   }
 
-  hb_add_coverage_context_t (set_t *set_) :
-			    set (set_),
-			    debug_depth (0) {}
+  hb_collect_coverage_context_t (set_t *set_) :
+				   set (set_) {}
 
   set_t *set;
-  unsigned int debug_depth;
 };
 
 
@@ -276,7 +408,7 @@
     void set_mask (hb_mask_t mask_) { mask = mask_; }
     void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
     void set_match_func (match_func_t match_func_,
-				const void *match_data_)
+			 const void *match_data_)
     { match_func = match_func_; match_data = match_data_; }
 
     enum may_match_t {
@@ -355,7 +487,7 @@
     }
 
     void reset (unsigned int start_index_,
-		       unsigned int num_items_)
+		unsigned int num_items_)
     {
       idx = start_index_;
       num_items = num_items_;
@@ -363,7 +495,11 @@
       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     }
 
-    void reject () { num_items++; match_glyph_data--; }
+    void reject ()
+    {
+      num_items++;
+      if (match_glyph_data) match_glyph_data--;
+    }
 
     matcher_t::may_skip_t
     may_skip (const hb_glyph_info_t &info) const
@@ -467,7 +603,6 @@
   unsigned int lookup_index;
   unsigned int lookup_props;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   bool has_glyph_classes;
   bool auto_zwnj;
@@ -478,8 +613,8 @@
 
 
   hb_ot_apply_context_t (unsigned int table_index_,
-		      hb_font_t *font_,
-		      hb_buffer_t *buffer_) :
+			 hb_font_t *font_,
+			 hb_buffer_t *buffer_) :
 			iter_input (), iter_context (),
 			font (font_), face (font->face), buffer (buffer_),
 			recurse_func (nullptr),
@@ -487,7 +622,7 @@
 #ifndef HB_NO_OT_LAYOUT
 			      *face->table.GDEF->table
 #else
-			      Null(GDEF)
+			      Null (GDEF)
 #endif
 			     ),
 			var_store (gdef.get_var_store ()),
@@ -497,7 +632,6 @@
 			lookup_index ((unsigned int) -1),
 			lookup_props (0),
 			nesting_level_left (HB_MAX_NESTING_LEVEL),
-			debug_depth (0),
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			auto_zwnj (true),
 			auto_zwj (true),
@@ -593,7 +727,7 @@
   void replace_glyph (hb_codepoint_t glyph_index) const
   {
     _set_glyph_props (glyph_index);
-    buffer->replace_glyph (glyph_index);
+    (void) buffer->replace_glyph (glyph_index);
   }
   void replace_glyph_inplace (hb_codepoint_t glyph_index) const
   {
@@ -601,25 +735,25 @@
     buffer->cur().codepoint = glyph_index;
   }
   void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
-					   unsigned int class_guess) const
+				    unsigned int class_guess) const
   {
     _set_glyph_props (glyph_index, class_guess, true);
-    buffer->replace_glyph (glyph_index);
+    (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) const
   {
     _set_glyph_props (glyph_index, class_guess, false, true);
-    buffer->output_glyph (glyph_index);
+    (void) buffer->output_glyph (glyph_index);
   }
 };
 
 
 struct hb_get_subtables_context_t :
-       hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
+       hb_dispatch_context_t<hb_get_subtables_context_t>
 {
   template <typename Type>
-  HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+  static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
   {
     const Type *typed_obj = (const Type *) obj;
     return typed_obj->apply (c);
@@ -635,7 +769,7 @@
       obj = &obj_;
       apply_func = apply_func_;
       digest.init ();
-      obj_.get_coverage ().add_coverage (&digest);
+      obj_.get_coverage ().collect_coverage (&digest);
     }
 
     bool apply (OT::hb_ot_apply_context_t *c) const
@@ -652,7 +786,6 @@
   typedef hb_vector_t<hb_applicable_t> array_t;
 
   /* Dispatch interface. */
-  const char *get_name () { return "GET_SUBTABLES"; }
   template <typename T>
   return_t dispatch (const T &obj)
   {
@@ -663,23 +796,23 @@
   static return_t default_return_value () { return hb_empty_t (); }
 
   hb_get_subtables_context_t (array_t &array_) :
-			      array (array_),
-			      debug_depth (0) {}
+			      array (array_) {}
 
   array_t &array;
-  unsigned int debug_depth;
 };
 
 
 
 
 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);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
+  intersected_glyphs_func_t intersected_glyphs;
 };
 struct ContextCollectGlyphsFuncs
 {
@@ -702,19 +835,38 @@
 }
 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
-  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
 }
 
-static inline bool intersects_array (const hb_set_t *glyphs,
-				     unsigned int count,
-				     const HBUINT16 values[],
-				     intersects_func_t intersects_func,
-				     const void *intersects_data)
+
+static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+{
+  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)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
+}
+static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+{
+  Offset16To<Coverage> coverage;
+  coverage = value;
+  (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
+}
+
+
+static inline bool array_is_subset_of (const hb_set_t *glyphs,
+				       unsigned int count,
+				       const HBUINT16 values[],
+				       intersects_func_t intersects_func,
+				       const void *intersects_data)
 {
   for (const HBUINT16 &_ : + hb_iter (values, count))
-    if (intersects_func (glyphs, _, intersects_data)) return true;
-  return false;
+    if (!intersects_func (glyphs, _, intersects_data)) return false;
+  return true;
 }
 
 
@@ -725,12 +877,12 @@
 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
-  class_def.add_class (glyphs, value);
+  class_def.collect_class (glyphs, value);
 }
 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
-  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
-  (data+coverage).add_coverage (glyphs);
+  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  (data+coverage).collect_coverage (glyphs);
 }
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 				  hb_set_t *glyphs,
@@ -757,7 +909,7 @@
 }
 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
 {
-  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
@@ -980,7 +1132,7 @@
 				    hb_min (this_comp, last_num_components);
 	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
     }
 
     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
@@ -991,18 +1143,19 @@
     buffer->idx++;
   }
 
-  if (!is_mark_ligature && last_lig_id) {
+  if (!is_mark_ligature && last_lig_id)
+  {
     /* Re-adjust components for any marks following. */
-    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
-      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
-	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
-	if (!this_comp)
-	  break;
-	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    hb_min (this_comp, last_num_components);
-	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
-      } else
-	break;
+    for (unsigned i = buffer->idx; i < buffer->len; ++i)
+    {
+      if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
+
+      unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+      if (!this_comp) break;
+
+      unsigned new_lig_comp = components_so_far - last_num_components +
+			      hb_min (this_comp, last_num_components);
+      _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
     }
   }
   return_trace (true);
@@ -1057,6 +1210,16 @@
 
 struct LookupRecord
 {
+  bool serialize (hb_serialize_context_t *c,
+		  const hb_map_t         *lookup_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    return_trace (c->check_assign (out->lookupListIndex, lookup_map->get (lookupListIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1071,10 +1234,97 @@
   DEFINE_SIZE_STATIC (4);
 };
 
+static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
+					      const hb_array_t<const LookupRecord> lookupRecords,
+					      const hb_map_t *lookup_map)
+{
+  unsigned count = 0;
+  for (const LookupRecord& r : lookupRecords)
+  {
+    if (!lookup_map->has (r.lookupListIndex))
+      continue;
+
+    if (!r.serialize (c, lookup_map))
+      return 0;
+
+    count++;
+  }
+  return count;
+}
+
+enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
+
+static void context_closure_recurse_lookups (hb_closure_context_t *c,
+					     unsigned inputCount, const HBUINT16 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)
+{
+  hb_set_t *covered_seq_indicies = hb_set_create ();
+  for (unsigned int i = 0; i < lookupCount; i++)
+  {
+    unsigned seqIndex = lookupRecord[i].sequenceIndex;
+    if (seqIndex >= inputCount) continue;
+
+    hb_set_t *pos_glyphs = nullptr;
+
+    if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex))
+    {
+      pos_glyphs = hb_set_create ();
+      if (seqIndex == 0)
+      {
+        switch (context_format) {
+        case ContextFormat::SimpleContext:
+          pos_glyphs->add (value);
+          break;
+        case ContextFormat::ClassBasedContext:
+          intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs);
+          break;
+        case ContextFormat::CoverageBasedContext:
+          hb_set_set (pos_glyphs, c->cur_intersected_glyphs);
+          break;
+        }
+      }
+      else
+      {
+        const void *input_data = input;
+        unsigned input_value = seqIndex - 1;
+        if (context_format != ContextFormat::SimpleContext)
+        {
+          input_data = data;
+          input_value = input[seqIndex - 1];
+        }
+
+        intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs);
+      }
+    }
+
+    hb_set_add (covered_seq_indicies, seqIndex);
+    if (pos_glyphs)
+      c->push_cur_active_glyphs (pos_glyphs);
+
+    unsigned endIndex = inputCount;
+    if (context_format == ContextFormat::CoverageBasedContext)
+      endIndex += 1;
+
+    c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
+
+    if (pos_glyphs) {
+      c->pop_cur_done_glyphs ();
+      hb_set_destroy (pos_glyphs);
+    }
+  }
+
+  hb_set_destroy (covered_seq_indicies);
+}
+
 template <typename context_t>
 static inline void recurse_lookups (context_t *c,
-				    unsigned int lookupCount,
-				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
+                                    unsigned int lookupCount,
+                                    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
     c->recurse (lookupRecord[i].lookupListIndex);
@@ -1112,7 +1362,7 @@
 
     /* Don't recurse to ourself at same position.
      * Note that this test is too naive, it doesn't catch longer loops. */
-    if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+    if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
       continue;
 
     if (unlikely (!buffer->move_to (match_positions[idx])))
@@ -1150,7 +1400,8 @@
      *     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.
+     *     and current-position + n instead. Though, am not sure which
+     *     one is better. Both cases have valid uses. Sigh.
      *
      * It should be possible to construct tests for both of these cases.
      */
@@ -1196,7 +1447,7 @@
       match_positions[next] += delta;
   }
 
-  buffer->move_to (end);
+  (void) buffer->move_to (end);
 
   return_trace (true);
 }
@@ -1208,6 +1459,7 @@
 struct ContextClosureLookupContext
 {
   ContextClosureFuncs funcs;
+  ContextFormat context_format;
   const void *intersects_data;
 };
 
@@ -1228,9 +1480,9 @@
 				       const HBUINT16 input[], /* Array of input values--start with second glyph */
 				       ContextClosureLookupContext &lookup_context)
 {
-  return intersects_array (glyphs,
-			   inputCount ? inputCount - 1 : 0, input,
-			   lookup_context.funcs.intersects, lookup_context.intersects_data);
+  return array_is_subset_of (glyphs,
+			     inputCount ? inputCount - 1 : 0, input,
+			     lookup_context.funcs.intersects, lookup_context.intersects_data);
 }
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
@@ -1238,13 +1490,19 @@
 					   const HBUINT16 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 */
 					   ContextClosureLookupContext &lookup_context)
 {
   if (context_intersects (c->glyphs,
 			  inputCount, input,
 			  lookup_context))
-    recurse_lookups (c,
-		     lookupCount, lookupRecord);
+    context_closure_recurse_lookups (c,
+				     inputCount, input,
+				     lookupCount, lookupRecord,
+				     value,
+				     lookup_context.context_format,
+				     lookup_context.intersects_data,
+				     lookup_context.funcs.intersected_glyphs);
 }
 
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@@ -1301,14 +1559,27 @@
 			       lookup_context);
   }
 
-  void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
+  void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
   {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
 						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
     context_closure_lookup (c,
 			    inputCount, inputZ.arrayZ,
 			    lookupCount, lookupRecord.arrayZ,
-			    lookup_context);
+			    value, lookup_context);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c,
+                        ContextClosureLookupContext &lookup_context) const
+  {
+    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));
+    recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
@@ -1342,6 +1613,44 @@
     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+		  const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
+		  const hb_map_t *lookup_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!c->extend_min (out))) return_trace (false);
+
+    out->inputCount = inputCount;
+    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    for (const auto org : input)
+    {
+      HBUINT16 d;
+      d = input_mapping->get (org);
+      c->copy (d);
+    }
+
+    const UnsizedArrayOf<LookupRecord> &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));
+  }
+
+  bool subset (hb_subset_context_t *c,
+	       const hb_map_t *lookup_map,
+	       const hb_map_t *klass_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
+    if (!input.length) return_trace (false);
+
+    const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
+    if (!hb_all (input, mapping)) return_trace (false);
+    return_trace (serialize (c->serializer, mapping, lookup_map));
+  }
+
   public:
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1359,7 +1668,7 @@
 					 * glyph */
   HBUINT16	lookupCount;		/* Number of LookupRecords */
   UnsizedArrayOf<HBUINT16>
- 		inputZ;			/* Array of match inputs--start with
+		inputZ;			/* Array of match inputs--start with
 					 * second glyph */
 /*UnsizedArrayOf<LookupRecord>
 		lookupRecordX;*/	/* Array of LookupRecords--in
@@ -1381,13 +1690,25 @@
     ;
   }
 
-  void closure (hb_closure_context_t *c,
+  void closure (hb_closure_context_t *c, unsigned value,
 		ContextClosureLookupContext &lookup_context) const
   {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
     return
     + hb_iter (rule)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
+    | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c,
+                        ContextClosureLookupContext &lookup_context) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
     ;
   }
 
@@ -1425,6 +1746,36 @@
     ;
   }
 
+  bool subset (hb_subset_context_t *c,
+	       const hb_map_t *lookup_map,
+	       const hb_map_t *klass_map = nullptr) 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);
+
+    for (const Offset16To<Rule>& _ : rule)
+    {
+      if (!_) continue;
+      auto o_snap = c->serializer->snapshot ();
+      auto *o = out->rule.serialize_append (c->serializer);
+      if (unlikely (!o)) continue;
+
+      if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
+      {
+	out->rule.pop ();
+	c->serializer->revert (o_snap);
+      }
+    }
+
+    bool ret = bool (out->rule);
+    if (!ret) c->serializer->revert (snap);
+
+    return_trace (ret);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1432,7 +1783,7 @@
   }
 
   protected:
-  OffsetArrayOf<Rule>
+  Array16OfOffset16To<Rule>
 		rule;			/* Array of Rule tables
 					 * ordered by preference */
   public:
@@ -1445,7 +1796,8 @@
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph},
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
       nullptr
     };
 
@@ -1459,10 +1811,32 @@
     ;
   }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph},
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
+      nullptr
+    };
+
+    + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
+    | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
       nullptr
     };
 
@@ -1470,13 +1844,15 @@
     | hb_filter (*c->glyphs, hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+    | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
     ;
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
@@ -1519,8 +1895,25 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    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;
+
+    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)
+    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), 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
@@ -1531,10 +1924,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetArrayOf<RuleSet>
+  Array16OfOffset16To<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by Coverage Index */
   public:
@@ -1552,20 +1945,63 @@
     const ClassDef &class_def = this+classDef;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class},
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
+      &class_def
+    };
+
+    hb_set_t retained_coverage_glyphs;
+    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+
+    hb_set_t coverage_glyph_classes;
+    class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
+
+
+    return
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_enumerate
+    | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
+	      { return class_def.intersects_class (glyphs, p.first) &&
+		       coverage_glyph_classes.has (p.first) &&
+		       p.second.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
+  }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!(this+coverage).intersects (c->glyphs))
+      return;
+
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
+    const ClassDef &class_def = this+classDef;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
       &class_def
     };
 
     return
     + hb_enumerate (ruleSet)
-    | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
-	      { return class_def.intersects_class (glyphs, p.first) &&
-		       (this+p.second).intersects (glyphs, lookup_context); })
-    | hb_any
+    | hb_filter ([&] (unsigned _)
+		 { return class_def.intersects_class (c->cur_intersected_glyphs, _); },
+		 hb_first)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
+                {
+                  const RuleSet& rule_set = this+_.second;
+                  rule_set.closure (c, _.first, lookup_context);
+                })
     ;
   }
 
-  void closure (hb_closure_context_t *c) const
+  void closure_lookups (hb_closure_lookups_context_t *c) const
   {
     if (!(this+coverage).intersects (c->glyphs))
       return;
@@ -1573,24 +2009,26 @@
     const ClassDef &class_def = this+classDef;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class},
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
       &class_def
     };
 
-    return
-    + hb_enumerate (ruleSet)
-    | hb_filter ([&] (unsigned _)
-		 { return class_def.intersects_class (c->glyphs, _); },
-		 hb_first)
-    | hb_map (hb_second)
+    + hb_iter (ruleSet)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
-    ;
+    | hb_enumerate
+    | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
+    { return class_def.intersects_class (c->glyphs, p.first); })
+    | hb_map (hb_second)
+    | hb_apply ([&] (const RuleSet & _)
+    { _.closure_lookups (c, lookup_context); });
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     const ClassDef &class_def = this+classDef;
     struct ContextCollectGlyphsLookupContext lookup_context = {
@@ -1637,8 +2075,53 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
+      return_trace (false);
+
+    hb_map_t klass_map;
+    out->classDef.serialize_subset (c, classDef, this, &klass_map);
+
+    const hb_set_t* glyphset = c->plan->glyphset_gsub ();
+    hb_set_t retained_coverage_glyphs;
+    (this+coverage).intersected_coverage_glyphs (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;
+    bool ret = true;
+    int non_zero_index = -1, index = 0;
+    for (const auto& _ : + hb_enumerate (ruleSet)
+			 | hb_filter (klass_map, hb_first))
+    {
+      auto *o = out->ruleSet.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+	ret = false;
+	break;
+      }
+
+      if (coverage_glyph_classes.has (_.first) &&
+	  o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+	non_zero_index = index;
+
+      index++;
+    }
+
+    if (!ret || non_zero_index == -1) return_trace (false);
+
+    //prune empty trailing ruleSets
+    --index;
+    while (index > non_zero_index)
+    {
+      out->ruleSet.pop ();
+      index--;
+    }
+
+    return_trace (bool (out->ruleSet));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1649,13 +2132,13 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		classDef;		/* Offset to glyph ClassDef table--from
 					 * beginning of table */
-  OffsetArrayOf<RuleSet>
+  Array16OfOffset16To<RuleSet>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by class */
   public:
@@ -1671,7 +2154,8 @@
       return false;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_coverage},
+      {intersects_coverage, intersected_coverage_glyphs},
+      ContextFormat::CoverageBasedContext,
       this
     };
     return context_intersects (glyphs,
@@ -1679,25 +2163,42 @@
 			       lookup_context);
   }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
     if (!(this+coverageZ[0]).intersects (c->glyphs))
       return;
 
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_coverage},
+      {intersects_coverage, intersected_coverage_glyphs},
+      ContextFormat::CoverageBasedContext,
       this
     };
     context_closure_lookup (c,
 			    glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
 			    lookupCount, lookupRecord,
-			    lookup_context);
+			    0, lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    if (!intersects (c->glyphs))
+      return;
+    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
+    recurse_lookups (c, lookupCount, lookupRecord);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverageZ[0]).add_coverage (c->input);
+    (this+coverageZ[0]).collect_coverage (c->input);
 
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextCollectGlyphsLookupContext lookup_context = {
@@ -1743,8 +2244,28 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    out->format = format;
+    out->glyphCount = glyphCount;
+
+    auto coverages = coverageZ.as_array (glyphCount);
+
+    for (const Offset16To<Coverage>& offset : coverages)
+    {
+      /* TODO(subset) This looks like should not be necessary to write this way. */
+      auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
+      if (unlikely (!o)) return_trace (false);
+      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;
+
+
+    unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
+    return_trace (c->serializer->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1765,7 +2286,7 @@
   HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
 					 * sequence */
   HBUINT16	lookupCount;		/* Number of LookupRecords */
-  UnsizedArrayOf<OffsetTo<Coverage>>
+  UnsizedArrayOf<Offset16To<Coverage>>
 		coverageZ;		/* Array of offsets to Coverage
 					 * table in glyph sequence order */
 /*UnsizedArrayOf<LookupRecord>
@@ -1783,9 +2304,9 @@
     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, hb_forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
+    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 ());
     }
   }
@@ -1805,6 +2326,7 @@
 struct ChainContextClosureLookupContext
 {
   ContextClosureFuncs funcs;
+  ContextFormat context_format;
   const void *intersects_data[3];
 };
 
@@ -1829,15 +2351,15 @@
 					     const HBUINT16 lookahead[],
 					     ChainContextClosureLookupContext &lookup_context)
 {
-  return intersects_array (glyphs,
-			   backtrackCount, backtrack,
-			   lookup_context.funcs.intersects, lookup_context.intersects_data[0])
-      && intersects_array (glyphs,
-			   inputCount ? inputCount - 1 : 0, input,
-			   lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-      && intersects_array (glyphs,
-			  lookaheadCount, lookahead,
-			  lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+  return array_is_subset_of (glyphs,
+			     backtrackCount, backtrack,
+			     lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+      && array_is_subset_of (glyphs,
+			     inputCount ? inputCount - 1 : 0, input,
+			     lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+      && array_is_subset_of (glyphs,
+			     lookaheadCount, lookahead,
+			     lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
 }
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
@@ -1849,6 +2371,7 @@
 						 const HBUINT16 lookahead[],
 						 unsigned int lookupCount,
 						 const LookupRecord lookupRecord[],
+						 unsigned value,
 						 ChainContextClosureLookupContext &lookup_context)
 {
   if (chain_context_intersects (c->glyphs,
@@ -1856,8 +2379,13 @@
 				inputCount, input,
 				lookaheadCount, lookahead,
 				lookup_context))
-    recurse_lookups (c,
-		     lookupCount, lookupRecord);
+    context_closure_recurse_lookups (c,
+		     inputCount, input,
+		     lookupCount, lookupRecord,
+		     value,
+		     lookup_context.context_format,
+		     lookup_context.intersects_data[1],
+		     lookup_context.funcs.intersected_glyphs);
 }
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@@ -1938,7 +2466,7 @@
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
     return chain_context_intersects (glyphs,
 				     backtrack.len, backtrack.arrayZ,
 				     input.lenP1, input.arrayZ,
@@ -1946,26 +2474,41 @@
 				     lookup_context);
   }
 
-  void closure (hb_closure_context_t *c,
+  void closure (hb_closure_context_t *c, unsigned value,
 		ChainContextClosureLookupContext &lookup_context) const
   {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.arrayZ,
 				  input.lenP1, input.arrayZ,
 				  lookahead.len, lookahead.arrayZ,
 				  lookup.len, lookup.arrayZ,
+				  value,
 				  lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c,
+                        ChainContextClosureLookupContext &lookup_context) const
+  {
+    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);
+    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 ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.arrayZ,
 					 input.lenP1, input.arrayZ,
@@ -1978,8 +2521,8 @@
 		    ChainContextApplyLookupContext &lookup_context) const
   {
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     return chain_context_would_apply_lookup (c,
 					     backtrack.len, backtrack.arrayZ,
 					     input.lenP1, input.arrayZ,
@@ -1991,8 +2534,8 @@
   {
     TRACE_APPLY (this);
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.arrayZ,
 					      input.lenP1, input.arrayZ,
@@ -2003,26 +2546,23 @@
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   void serialize_array (hb_serialize_context_t *c,
-                        HBUINT16 len,
-                        Iterator it) const
+			HBUINT16 len,
+			Iterator it) const
   {
     c->copy (len);
     for (const auto g : it)
-    {
-      HBUINT16 gid;
-      gid = g;
-      c->copy (gid);
-    }
+      c->copy ((HBUINT16) g);
   }
 
-  ChainRule* copy (hb_serialize_context_t *c,
-		   const hb_map_t *backtrack_map,
-		   const hb_map_t *input_map = nullptr,
-		   const hb_map_t *lookahead_map = nullptr) const
+  bool serialize (hb_serialize_context_t *c,
+		  const hb_map_t *lookup_map,
+		  const hb_map_t *backtrack_map,
+		  const hb_map_t *input_map = nullptr,
+		  const hb_map_t *lookahead_map = nullptr) const
   {
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
+    if (unlikely (!out)) return_trace (false);
 
     const hb_map_t *mapping = backtrack_map;
     serialize_array (c, backtrack.len, + backtrack.iter ()
@@ -2033,45 +2573,49 @@
     serialize_array (c, input.lenP1, + input.iter ()
 				     | hb_map (mapping));
 
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
     if (lookahead_map) mapping = lookahead_map;
     serialize_array (c, lookahead.len, + lookahead.iter ()
 				       | hb_map (mapping));
 
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
-    c->copy (lookup);
+    const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
 
-    return_trace (out);
+    HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+    if (!lookupCount) return_trace (false);
+
+    unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (), lookup_map);
+    return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   bool subset (hb_subset_context_t *c,
-               const hb_map_t *backtrack_map = nullptr,
-               const hb_map_t *input_map = nullptr,
-               const hb_map_t *lookahead_map = nullptr) const
+	       const hb_map_t *lookup_map,
+	       const hb_map_t *backtrack_map = nullptr,
+	       const hb_map_t *input_map = nullptr,
+	       const hb_map_t *lookahead_map = nullptr) const
   {
     TRACE_SUBSET (this);
 
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
 
     if (!backtrack_map)
     {
-      const hb_set_t &glyphset = *c->plan->glyphset ();
+      const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
       if (!hb_all (backtrack, glyphset) ||
-          !hb_all (input, glyphset) ||
-          !hb_all (lookahead, glyphset))
-        return_trace (false);
+	  !hb_all (input, glyphset) ||
+	  !hb_all (lookahead, glyphset))
+	return_trace (false);
 
-      copy (c->serializer, c->plan->glyph_map);
+      serialize (c->serializer, lookup_map, c->plan->glyph_map);
     }
     else
     {
       if (!hb_all (backtrack, backtrack_map) ||
-          !hb_all (input, input_map) ||
-          !hb_all (lookahead, lookahead_map))
-        return_trace (false);
+	  !hb_all (input, input_map) ||
+	  !hb_all (lookahead, lookahead_map))
+	return_trace (false);
 
-      copy (c->serializer, backtrack_map, input_map, lookahead_map);
+      serialize (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
     }
 
     return_trace (true);
@@ -2083,24 +2627,24 @@
     if (!backtrack.sanitize (c)) return_trace (false);
     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
     if (!lookahead.sanitize (c)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  ArrayOf<HBUINT16>
+  Array16Of<HBUINT16>
 		backtrack;		/* Array of backtracking values
 					 * (to be matched before the input
 					 * sequence) */
   HeadlessArrayOf<HBUINT16>
 		inputX;			/* Array of input values (start with
 					 * second glyph) */
-  ArrayOf<HBUINT16>
+  Array16Of<HBUINT16>
 		lookaheadX;		/* Array of lookahead values's (to be
 					 * matched after the input sequence) */
-  ArrayOf<LookupRecord>
+  Array16Of<LookupRecord>
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
@@ -2118,12 +2662,25 @@
     | hb_any
     ;
   }
-  void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
+  void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
   {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
     return
     + hb_iter (rule)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
+    | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c,
+                        ChainContextClosureLookupContext &lookup_context) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
     ;
   }
 
@@ -2159,9 +2716,10 @@
   }
 
   bool subset (hb_subset_context_t *c,
-               const hb_map_t *backtrack_klass_map = nullptr,
-               const hb_map_t *input_klass_map = nullptr,
-               const hb_map_t *lookahead_klass_map = nullptr) const
+	       const hb_map_t *lookup_map,
+	       const hb_map_t *backtrack_klass_map = nullptr,
+	       const hb_map_t *input_klass_map = nullptr,
+	       const hb_map_t *lookahead_klass_map = nullptr) const
   {
     TRACE_SUBSET (this);
 
@@ -2169,20 +2727,21 @@
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
-    for (const OffsetTo<ChainRule>& _ : rule)
+    for (const Offset16To<ChainRule>& _ : rule)
     {
       if (!_) continue;
+      auto o_snap = c->serializer->snapshot ();
       auto *o = out->rule.serialize_append (c->serializer);
       if (unlikely (!o)) continue;
 
-      auto o_snap = c->serializer->snapshot ();
-      if (!o->serialize_subset (c, _, this, out,
-                                backtrack_klass_map,
-                                input_klass_map,
-                                lookahead_klass_map))
+      if (!o->serialize_subset (c, _, this,
+				lookup_map,
+				backtrack_klass_map,
+				input_klass_map,
+				lookahead_klass_map))
       {
-        out->rule.pop ();
-        c->serializer->revert (o_snap);
+	out->rule.pop ();
+	c->serializer->revert (o_snap);
       }
     }
 
@@ -2199,7 +2758,7 @@
   }
 
   protected:
-  OffsetArrayOf<ChainRule>
+  Array16OfOffset16To<ChainRule>
 		rule;			/* Array of ChainRule tables
 					 * ordered by preference */
   public:
@@ -2211,7 +2770,8 @@
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph},
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
       {nullptr, nullptr, nullptr}
     };
 
@@ -2225,10 +2785,32 @@
     ;
   }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph},
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
+      {nullptr, nullptr, nullptr}
+    };
+
+    + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
+    | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_glyph, intersected_glyph},
+      ContextFormat::SimpleContext,
       {nullptr, nullptr, nullptr}
     };
 
@@ -2236,13 +2818,15 @@
     | hb_filter (*c->glyphs, hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
     ;
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
@@ -2284,24 +2868,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset ();
+    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;
 
+    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)
-    | hb_filter (subset_offset_array (c, out->ruleSet, this, out), hb_second)
+    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
     | hb_map (hb_first)
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
 
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -2313,10 +2897,10 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetArrayOf<ChainRuleSet>
+  Array16OfOffset16To<ChainRuleSet>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
@@ -2335,7 +2919,49 @@
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class},
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    hb_set_t retained_coverage_glyphs;
+    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+
+    hb_set_t coverage_glyph_classes;
+    input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
+
+    return
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_enumerate
+    | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
+	      { return input_class_def.intersects_class (glyphs, p.first) &&
+		       coverage_glyph_classes.has (p.first) &&
+		       p.second.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
+  }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!(this+coverage).intersects (c->glyphs))
+      return;
+
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -2343,13 +2969,18 @@
 
     return
     + hb_enumerate (ruleSet)
-    | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
-	      { return input_class_def.intersects_class (glyphs, p.first) &&
-		       (this+p.second).intersects (glyphs, lookup_context); })
-    | hb_any
+    | hb_filter ([&] (unsigned _)
+		 { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); },
+		 hb_first)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
+                {
+                  const ChainRuleSet& chainrule_set = this+_.second;
+                  chainrule_set.closure (c, _.first, lookup_context);
+                })
     ;
   }
-  void closure (hb_closure_context_t *c) const
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const
   {
     if (!(this+coverage).intersects (c->glyphs))
       return;
@@ -2359,26 +2990,29 @@
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class},
+      {intersects_class, intersected_class_glyphs},
+      ContextFormat::ClassBasedContext,
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
     };
 
-    return
-    + hb_enumerate (ruleSet)
-    | hb_filter ([&] (unsigned _)
-		 { return input_class_def.intersects_class (c->glyphs, _); },
-		 hb_first)
-    | hb_map (hb_second)
+    + hb_iter (ruleSet)
     | hb_map (hb_add (this))
-    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    | hb_enumerate
+    | hb_filter([&] (unsigned klass)
+    { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const ChainRuleSet &_)
+    { _.closure_lookups (c, lookup_context); })
     ;
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
@@ -2443,48 +3077,62 @@
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     out->format = format;
-    out->coverage.serialize_subset (c, coverage, this, out);
+    out->coverage.serialize_subset (c, coverage, this);
 
     hb_map_t backtrack_klass_map;
-    out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, out, &backtrack_klass_map);
-
-    // subset inputClassDef based on glyphs survived in Coverage subsetting
     hb_map_t input_klass_map;
-    out->inputClassDef.serialize_subset (c, inputClassDef, this, out, &input_klass_map);
-
     hb_map_t lookahead_klass_map;
-    out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, out, &lookahead_klass_map);
 
-    hb_vector_t<unsigned> rulesets;
+    out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
+    // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
+    out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
+    out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
+
+    if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
+						   input_klass_map,
+						   lookahead_klass_map)))
+      return_trace (false);
+
+    const hb_set_t* glyphset = c->plan->glyphset_gsub ();
+    hb_set_t retained_coverage_glyphs;
+    (this+coverage).intersected_coverage_glyphs (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;
-    for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
-					   | hb_filter (input_klass_map, hb_first)
-					   | hb_map (hb_second))
+    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))
     {
       auto *o = out->ruleSet.serialize_append (c->serializer);
       if (unlikely (!o))
       {
-        ret = false;
-        break;
+	ret = false;
+	break;
       }
-      if (!o->serialize_subset (c, _, this, out,
-                                &backtrack_klass_map,
-                                &input_klass_map,
-                                &lookahead_klass_map))
+      if (coverage_glyph_classes.has (_.first) &&
+          o->serialize_subset (c, _.second, this,
+			       lookup_map,
+			       &backtrack_klass_map,
+			       &input_klass_map,
+			       &lookahead_klass_map))
       {
-        rulesets.push (0);
+        last_non_zero = c->serializer->snapshot ();
+	non_zero_index = index;
       }
-      else rulesets.push (1);
+
+      index++;
     }
 
-    if (!ret) return_trace (ret);
+    if (!ret || non_zero_index == -1) return_trace (false);
 
-    //prune empty trailing ruleSets
-    unsigned count = rulesets.length;
-    while (count > 0 && rulesets[count-1] == 0)
-    {
-      out->ruleSet.pop ();
-      count--;
+    // prune empty trailing ruleSets
+    if (index > non_zero_index) {
+      c->serializer->revert (last_non_zero);
+      out->ruleSet.len = non_zero_index + 1;
     }
 
     return_trace (bool (out->ruleSet));
@@ -2502,22 +3150,22 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		backtrackClassDef;	/* Offset to glyph ClassDef table
 					 * containing backtrack sequence
 					 * data--from beginning of table */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		inputClassDef;		/* Offset to glyph ClassDef
 					 * table containing input sequence
 					 * data--from beginning of table */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		lookaheadClassDef;	/* Offset to glyph ClassDef table
 					 * containing lookahead sequence
 					 * data--from beginning of table */
-  OffsetArrayOf<ChainRuleSet>
+  Array16OfOffset16To<ChainRuleSet>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by class */
   public:
@@ -2528,14 +3176,15 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage},
+      {intersects_coverage, intersected_coverage_glyphs},
+      ContextFormat::CoverageBasedContext,
       {this, this, this}
     };
     return chain_context_intersects (glyphs,
@@ -2545,17 +3194,24 @@
 				     lookup_context);
   }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    c->cur_intersected_glyphs->clear ();
+    get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage},
+      {intersects_coverage, intersected_coverage_glyphs},
+      ContextFormat::CoverageBasedContext,
       {this, this, this}
     };
     chain_context_closure_lookup (c,
@@ -2563,17 +3219,30 @@
 				  input.len, (const HBUINT16 *) input.arrayZ + 1,
 				  lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
 				  lookup.len, lookup.arrayZ,
-				  lookup_context);
+				  0, lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    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);
+    recurse_lookups (c, lookup.len, lookup.arrayZ);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
-    (this+input[0]).add_coverage (c->input);
+    (this+input[0]).collect_coverage (c->input);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
@@ -2588,9 +3257,9 @@
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
@@ -2604,20 +3273,20 @@
 
   const Coverage &get_coverage () const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
     return this+input[0];
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
@@ -2631,21 +3300,21 @@
 
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
-  bool serialize_coverage_offsets (hb_subset_context_t *c,
-                                   Iterator it,
-				   const void* src_base,
-				   const void* dst_base) const
+  bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
   {
     TRACE_SERIALIZE (this);
-    auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
+    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
 
-    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+      return_trace (false);
 
-    + it
-    | hb_apply (subset_offset_array (c, *out, src_base, dst_base))
-    ;
+    for (auto& offset : it) {
+      auto *o = out->serialize_append (c->serializer);
+      if (unlikely (!o) || !o->serialize_subset (c, offset, base))
+        return_trace (false);
+    }
 
-    return_trace (out->len);
+    return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -2656,49 +3325,55 @@
     if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
 
-    if (!serialize_coverage_offsets (c, backtrack.iter (), this, out))
+    if (!serialize_coverage_offsets (c, backtrack.iter (), this))
       return_trace (false);
 
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    if (!serialize_coverage_offsets (c, input.iter (), this, out))
+    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    if (!serialize_coverage_offsets (c, input.iter (), this))
       return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
-    if (!serialize_coverage_offsets (c, lookahead.iter (), this, out))
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    if (!serialize_coverage_offsets (c, lookahead.iter (), this))
       return_trace (false);
 
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
-    return_trace (c->serializer->copy (lookup));
+    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;
+
+    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookupRecord.len);
+    if (!lookupCount) return_trace (false);
+
+    unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.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 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    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 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 3 */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
 					 * sequence order */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		inputX		;	/* Array of coverage
 					 * tables in input sequence, in glyph
 					 * sequence order */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		lookaheadX;		/* Array of coverage tables
 					 * in lookahead sequence, in glyph
 					 * sequence order */
-  ArrayOf<LookupRecord>
+  Array16Of<LookupRecord>
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
@@ -2713,9 +3388,9 @@
     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, hb_forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
+    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 ());
     }
   }
@@ -2737,16 +3412,19 @@
 
   template <typename X>
   const X& get_subtable () const
-  { return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
+  { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
 
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, format);
     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
-    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
+    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { dispatch (c); }
+
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -2755,6 +3433,24 @@
 		  extensionLookupType != T::SubTable::Extension);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    out->format = format;
+    out->extensionLookupType = extensionLookupType;
+
+    const auto& src_offset =
+        reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
+    auto& dest_offset =
+        reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
+
+    return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
+  }
+
   protected:
   HBUINT16	format;			/* Format identifier. Set to 1. */
   HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
@@ -2781,7 +3477,19 @@
   {
     switch (u.format) {
     case 1: return u.format1.template get_subtable<typename T::SubTable> ();
-    default:return Null(typename T::SubTable);
+    default:return Null (typename T::SubTable);
+    }
+  }
+
+  // Specialization of dispatch for subset. dispatch() normally just
+  // dispatches to the sub table this points too, but for subset
+  // we need to run subset on this subtable too.
+  template <typename ...Ts>
+  typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.subset (c);
+    default: return c->default_return_value ();
     }
   }
 
@@ -2791,7 +3499,7 @@
     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, hb_forward<Ts> (ds)...));
+    case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -2814,7 +3522,7 @@
   void init (const TLookup &lookup)
   {
     digest.init ();
-    lookup.add_coverage (&digest);
+    lookup.collect_coverage (&digest);
 
     subtables.init ();
     OT::hb_get_subtables_context_t c_get_subtables (subtables);
@@ -2875,10 +3583,11 @@
   bool find_variations_index (const int *coords, unsigned int num_coords,
 			      unsigned int *index) const
   {
-#ifdef HB_NOVAR
+#ifdef HB_NO_VAR
+    *index = FeatureVariations::NOT_FOUND_INDEX;
     return false;
 #endif
-    return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+    return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
 	    .find_index (coords, num_coords, index);
   }
   const Feature& get_feature_variation (unsigned int feature_index,
@@ -2897,32 +3606,194 @@
     return get_feature (feature_index);
   }
 
+  void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+					  hb_set_t       *lookup_indexes /* OUT */) const
+  {
+#ifndef HB_NO_VAR
+    if (version.to_int () >= 0x00010001u)
+      (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+#endif
+  }
+
   template <typename TLookup>
-  bool subset (hb_subset_context_t *c) const
+  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);
+
+    for (unsigned lookup_index : + hb_iter (lookup_indexes))
+      reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
+
+    hb_set_union (lookup_indexes, &visited_lookups);
+    hb_set_subtract (lookup_indexes, &inactive_lookups);
+  }
+
+  void prune_langsys (const hb_map_t *duplicate_feature_map,
+                      hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *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);
+
+    unsigned count = get_script_count ();
+    for (unsigned script_index = 0; script_index < count; script_index++)
+    {
+      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->serializer->embed (*this);
+    auto *out = c->subset_context->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    out->scriptList.serialize_subset (c, scriptList, this, out);
-    out->featureList.serialize_subset (c, featureList, this, out);
+    typedef LookupOffsetList<TLookup> TLookupList;
+    reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
+	.serialize_subset (c->subset_context,
+			   reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
+			   this,
+			   c);
 
-    typedef OffsetListOf<TLookup> TLookupList;
-    /* TODO Use intersects() to count how many subtables survive? */
-    CastR<OffsetTo<TLookupList>> (out->lookupList)
-      .serialize_subset (c,
-			 CastR<OffsetTo<TLookupList>> (lookupList),
-			 this,
-			 out);
+    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)
-     out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
+    {
+      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 *, (unsigned)-1, nullptr> unique_features;
+    //find out duplicate features after subset
+    for (unsigned i : feature_indices->iter ())
+    {
+      hb_tag_t t = get_feature_tag (i);
+      if (t == unique_features.INVALID_KEY) 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 */
+		       hb_set_t       *feature_indices /* IN/OUT */) const
+  {
+#ifndef HB_NO_VAR
+    // This is the set of feature indices which have alternate versions defined
+    // 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);
+    if (unlikely (alternate_feature_indices.in_error()))
+    {
+      feature_indices->err ();
+      return;
+    }
+#endif
+
+    for (unsigned i : feature_indices->iter())
+    {
+      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.
+        // HarfBuzz chooses shaper for Khmer based on presence of this
+        // feature.	See thread at:
+	// http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
+        continue;
+
+      if (f.featureParams.is_null ()
+	  && !f.intersects_lookup_indexes (lookup_indices)
+#ifndef HB_NO_VAR
+          && !alternate_feature_indices.has (i)
+#endif
+	  )
+	feature_indices->del (i);
+    }
+  }
+
   unsigned int get_size () const
   {
     return min_size +
@@ -2933,12 +3804,12 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    typedef OffsetListOf<TLookup> TLookupList;
+    typedef List16OfOffset16To<TLookup> TLookupList;
     if (unlikely (!(version.sanitize (c) &&
 		    likely (version.major == 1) &&
 		    scriptList.sanitize (c, this) &&
 		    featureList.sanitize (c, this) &&
-		    CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this))))
+		    reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
       return_trace (false);
 
 #ifndef HB_NO_VAR
@@ -2954,8 +3825,8 @@
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<T> (face);
-      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
+      this->table = hb_sanitize_context_t ().reference_table<T> (face);
+      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
       {
 	hb_blob_destroy (this->table.get_blob ());
 	this->table = hb_blob_get_empty ();
@@ -2963,9 +3834,13 @@
 
       this->lookup_count = table->get_lookup_count ();
 
-      this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
+      this->accels = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
       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));
@@ -2975,7 +3850,7 @@
     {
       for (unsigned int i = 0; i < this->lookup_count; i++)
 	this->accels[i].fini ();
-      free (this->accels);
+      hb_free (this->accels);
       this->table.destroy ();
     }
 
@@ -2987,13 +3862,13 @@
   protected:
   FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
 				 * to 0x00010000u */
-  OffsetTo<ScriptList>
-		scriptList;  	/* ScriptList table */
-  OffsetTo<FeatureList>
-		featureList; 	/* FeatureList table */
-  OffsetTo<LookupList>
-		lookupList; 	/* LookupList table */
-  LOffsetTo<FeatureVariations>
+  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
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 53eb623..a1c125b 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -45,7 +45,7 @@
  * JstfMax -- Justification Maximum Table
  */
 
-typedef OffsetListOf<PosLookup> JstfMax;
+typedef List16OfOffset16To<PosLookup> JstfMax;
 
 
 /*
@@ -71,43 +71,43 @@
   }
 
   protected:
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageEnableGSUB;	/* Offset to Shrinkage Enable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageDisableGSUB;	/* Offset to Shrinkage Disable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageEnableGPOS;	/* Offset to Shrinkage Enable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageDisableGPOS;	/* Offset to Shrinkage Disable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfMax>
+  Offset16To<JstfMax>
 		shrinkageJstfMax;	/* Offset to Shrinkage JstfMax table--
 					 * from beginning of JstfPriority table
 					 * --may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionEnableGSUB;	/* Offset to Extension Enable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionDisableGSUB;	/* Offset to Extension Disable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionEnableGPOS;	/* Offset to Extension Enable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionDisableGPOS;	/* Offset to Extension Disable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfMax>
+  Offset16To<JstfMax>
 		extensionJstfMax;	/* Offset to Extension JstfMax table--
 					 * from beginning of JstfPriority table
 					 * --may be NULL */
@@ -121,13 +121,13 @@
  * JstfLangSys -- Justification Language System Table
  */
 
-struct JstfLangSys : OffsetListOf<JstfPriority>
+struct JstfLangSys : List16OfOffset16To<JstfPriority>
 {
   bool sanitize (hb_sanitize_context_t *c,
 		 const Record_sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetListOf<JstfPriority>::sanitize (c));
+    return_trace (List16OfOffset16To<JstfPriority>::sanitize (c));
   }
 };
 
@@ -136,7 +136,7 @@
  * ExtenderGlyphs -- Extender Glyph Table
  */
 
-typedef SortedArrayOf<HBGlyphID> ExtenderGlyphs;
+typedef SortedArray16Of<HBGlyphID16> ExtenderGlyphs;
 
 
 /*
@@ -174,10 +174,10 @@
   }
 
   protected:
-  OffsetTo<ExtenderGlyphs>
+  Offset16To<ExtenderGlyphs>
 		extenderGlyphs;	/* Offset to ExtenderGlyph table--from beginning
 				 * of JstfScript table-may be NULL */
-  OffsetTo<JstfLangSys>
+  Offset16To<JstfLangSys>
 		defaultLangSys;	/* Offset to DefaultJstfLangSys table--from
 				 * beginning of JstfScript table--may be Null */
   RecordArrayOf<JstfLangSys>
@@ -222,7 +222,7 @@
   FixedVersion<>version;	/* Version of the JSTF table--initially set
 				 * to 0x00010000u */
   RecordArrayOf<JstfScript>
-		scriptList;  	/* Array of JstfScripts--listed
+		scriptList;	/* Array of JstfScripts--listed
 				 * alphabetically by ScriptTag */
   public:
   DEFINE_SIZE_ARRAY (6, scriptList);
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index fba3ad1..fbdedd0 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -51,9 +51,7 @@
 #include "hb-ot-name-table.hh"
 #include "hb-ot-os2-table.hh"
 
-#include "hb-aat-layout-lcar-table.hh"
 #include "hb-aat-layout-morx-table.hh"
-
 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
 /**
@@ -78,7 +76,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
@@ -94,7 +92,7 @@
  * 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
@@ -114,7 +112,7 @@
  *
  * Does NOT examine the GPOS table.
  *
- * Return value: true is data found, false otherwise
+ * Return value: %true is data found, %false otherwise
  *
  **/
 bool
@@ -133,7 +131,9 @@
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
+  if (!buffer->message (font, "start table kern")) return;
   kern.apply (&c);
+  (void) buffer->message (font, "end table kern");
 }
 #endif
 
@@ -143,13 +143,13 @@
  */
 
 bool
-OT::GDEF::is_blacklisted (hb_blob_t *blob,
+OT::GDEF::is_blocklisted (hb_blob_t *blob,
 			  hb_face_t *face) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
-  /* The ugly business of blacklisting individual fonts' tables happen here!
+  /* The ugly business of blocklisting individual fonts' tables happen here!
    * See this thread for why we finally had to bend in and do this:
    * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
    *
@@ -270,7 +270,7 @@
  *
  * 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
@@ -318,14 +318,13 @@
   return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
 }
 
-
 #ifndef HB_NO_LAYOUT_UNUSED
 /**
  * hb_ot_layout_get_attach_points:
  * @face: The #hb_face_t to work on
  * @glyph: The #hb_codepoint_t code point to query
  * @start_offset: offset of the first attachment point to retrieve
- * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
+ * @point_count: (inout) (optional): Input = the maximum number of attachment points to return;
  *               Output = the actual number of attachment points returned (may be zero)
  * @point_array: (out) (array length=point_count): The array of attachment points found for the query
  *
@@ -334,6 +333,8 @@
  *
  * Useful if the client program wishes to cache the list.
  *
+ * Return value: Total number of attachment points for @glyph.
+ *
  **/
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
@@ -353,13 +354,15 @@
  * @direction: The #hb_direction_t text direction to use
  * @glyph: The #hb_codepoint_t code point to query
  * @start_offset: offset of the first caret position to retrieve
- * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
+ * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return;
  *               Output = the actual number of caret positions returned (may be zero)
  * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
  *
  * 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.
  *
+ * Return value: Total number of ligature caret positions for @glyph.
+ *
  **/
 unsigned int
 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
@@ -369,21 +372,7 @@
 				  unsigned int   *caret_count /* IN/OUT */,
 				  hb_position_t  *caret_array /* OUT */)
 {
-  unsigned int result_caret_count = 0;
-  unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array);
-  if (result)
-  {
-    if (caret_count) *caret_count = result_caret_count;
-  }
-  else
-  {
-#ifndef HB_NO_AAT
-    result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
-#else
-    if (caret_count) *caret_count = 0;
-#endif
-  }
-  return result;
+  return font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
 }
 #endif
 
@@ -393,41 +382,20 @@
  */
 
 bool
-OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
+OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
-
-#ifndef HB_NO_AAT_SHAPE
-  /* Mac OS X prefers morx over GSUB.  It also ships with various Indic fonts,
-   * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken
-   * GSUB/GPOS tables.  Some have GSUB with zero scripts, those are ignored by
-   * our morx/GSUB preference code.  But if GSUB has non-zero scripts, we tend
-   * to prefer it over morx because we want to be consistent with other OpenType
-   * shapers.
-   *
-   * To work around broken Indic Mac system fonts, we ignore GSUB table if
-   * OS/2 VendorId is 'MUTF' and font has morx table as well.
-   *
-   * https://github.com/harfbuzz/harfbuzz/issues/1410
-   * https://github.com/harfbuzz/harfbuzz/issues/1348
-   * https://github.com/harfbuzz/harfbuzz/issues/1391
-   */
-  if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') &&
-		face->table.morx->has_data ()))
-    return true;
-#endif
-
   return false;
 }
 
 bool
-OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
+OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face HB_UNUSED) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
   return false;
@@ -440,7 +408,7 @@
   switch (table_tag) {
     case HB_OT_TAG_GSUB: return *face->table.GSUB->table;
     case HB_OT_TAG_GPOS: return *face->table.GPOS->table;
-    default:             return Null(OT::GSUBGPOS);
+    default:             return Null (OT::GSUBGPOS);
   }
 }
 
@@ -448,15 +416,17 @@
 /**
  * hb_ot_layout_table_get_script_tags:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @start_offset: offset of the first script tag to retrieve
- * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
+ * @script_count: (inout) (optional): Input = the maximum number of script tags to return;
  *                Output = the actual number of script tags returned (may be zero)
  * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
  *
  * Fetches a list of all scripts enumerated in the specified face's GSUB table
  * or GPOS table. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of script tags.
+ *
  **/
 unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
@@ -475,14 +445,14 @@
 /**
  * hb_ot_layout_table_find_script:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_tag: #hb_tag_t of the script tag requested
  * @script_index: (out): The index of the requested script tag
  *
  * 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
@@ -519,7 +489,7 @@
 /**
  * hb_ot_layout_table_choose_script:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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
@@ -542,11 +512,22 @@
 /**
  * hb_ot_layout_table_select_script:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_count: Number of script tags in the array
  * @script_tags: Array of #hb_tag_t script tags
- * @script_index: (out): The index of the requested script
- * @chosen_script: (out): #hb_tag_t of the requested script
+ * @script_index: (out) (optional): The index of the requested script
+ * @chosen_script: (out) (optional): #hb_tag_t of the requested script
+ *
+ * Selects an OpenType script for @table_tag from the @script_tags array.
+ *
+ * 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.
+ *
+ * Return value:
+ * %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
  **/
@@ -604,14 +585,16 @@
 /**
  * hb_ot_layout_table_get_feature_tags:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
  *                 Output = the actual number of feature tags returned (may be zero)
  * @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.
  *
+ * Return value: Total number of feature tags.
+ *
  **/
 unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
@@ -629,14 +612,14 @@
 /**
  * hb_ot_layout_table_find_feature:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
- * @feature_tag: The #hb_tag_t og the requested feature tag
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
+ * @feature_tag: The #hb_tag_t of the requested feature tag
  * @feature_index: (out): The index of the requested feature
  *
  * 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
  **/
 bool
 hb_ot_layout_table_find_feature (hb_face_t    *face,
@@ -664,16 +647,18 @@
 /**
  * hb_ot_layout_script_get_language_tags:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_index: The index of the requested script tag
  * @start_offset: offset of the first language tag to retrieve
- * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
+ * @language_count: (inout) (optional): Input = the maximum number of language tags to return;
  *                  Output = the actual number of language tags returned (may be zero)
  * @language_tags: (out) (array length=language_count): Array of language tags found in the table
  *
  * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
  * the specified script index. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of language tags.
+ *
  **/
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
@@ -693,7 +678,7 @@
 /**
  * hb_ot_layout_script_find_language:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @script_index: The index of the requested script tag
  * @language_tag: The #hb_tag_t of the requested language
  * @language_index: The index of the requested language
@@ -701,10 +686,10 @@
  * 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: ??
- * Deprecated: ??
+ * Since: 0.6.0
+ * Deprecated: 2.0.0
  **/
 hb_bool_t
 hb_ot_layout_script_find_language (hb_face_t    *face,
@@ -726,16 +711,20 @@
 /**
  * hb_ot_layout_script_select_language:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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 a given language tag in the specified face's GSUB table
- * or GPOS table, underneath the specified script index.
+ * 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.
  *
- * Return value: true if the language tag is found, false otherwise
+ * 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
  **/
@@ -761,7 +750,8 @@
   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
     return false;
 
-  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+  if (language_index)
+    *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
   return false;
 }
 
@@ -769,7 +759,7 @@
 /**
  * hb_ot_layout_language_get_required_feature_index:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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_index: (out): The index of the requested feature
@@ -777,7 +767,7 @@
  * 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
  *
  **/
 hb_bool_t
@@ -785,7 +775,7 @@
 						  hb_tag_t      table_tag,
 						  unsigned int  script_index,
 						  unsigned int  language_index,
-						  unsigned int *feature_index)
+						  unsigned int *feature_index /* OUT */)
 {
   return hb_ot_layout_language_get_required_feature (face,
 						     table_tag,
@@ -799,16 +789,16 @@
 /**
  * hb_ot_layout_language_get_required_feature:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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_index: The index of the requested feature
+ * @feature_index: (out): The index of the requested feature
  * @feature_tag: (out): The #hb_tag_t of the requested feature
  *
  * 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
  **/
@@ -817,8 +807,8 @@
 					    hb_tag_t      table_tag,
 					    unsigned int  script_index,
 					    unsigned int  language_index,
-					    unsigned int *feature_index,
-					    hb_tag_t     *feature_tag)
+					    unsigned int *feature_index /* OUT */,
+					    hb_tag_t     *feature_tag   /* 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);
@@ -834,17 +824,19 @@
 /**
  * hb_ot_layout_language_get_feature_indexes:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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
  * @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
  *                 Output: the actual number of feature tags returned (may be zero)
  * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
  *
  * Fetches a list of all features in the specified face's GSUB table
  * or GPOS table, underneath the specified script and language. The list
  * returned will begin at the offset provided.
+ *
+ * Return value: Total number of features.
  **/
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
@@ -865,11 +857,11 @@
 /**
  * hb_ot_layout_language_get_feature_tags:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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
  * @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
  *                 Output = the actual number of feature tags returned (may be zero)
  * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
  *
@@ -877,6 +869,7 @@
  * or GPOS table, underneath the specified script and language. The list
  * returned will begin at the offset provided.
  *
+ * Return value: Total number of feature tags.
  **/
 unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
@@ -906,7 +899,7 @@
 /**
  * hb_ot_layout_language_find_feature:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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_tag: #hb_tag_t of the feature tag requested
@@ -915,7 +908,7 @@
  * 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
  *
  **/
 hb_bool_t
@@ -948,10 +941,10 @@
 /**
  * hb_ot_layout_feature_get_lookups:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @feature_index: The index of the requested feature
  * @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
  *                Output = the actual number of lookups returned (may be zero)
  * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
  *
@@ -959,6 +952,8 @@
  * the specified face's GSUB table or GPOS table. The list returned will
  * begin at the offset provided.
  *
+ * Return value: Total number of lookups.
+ *
  * Since: 0.9.7
  **/
 unsigned int
@@ -982,11 +977,13 @@
 /**
  * hb_ot_layout_table_get_lookup_count:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  *
  * Fetches the total number of lookups enumerated in the specified
  * face's GSUB table or GPOS table.
  *
+ * Return value: Total number of lookups.
+ *
  * Since: 0.9.22
  **/
 unsigned int
@@ -1001,10 +998,37 @@
 {
   hb_collect_features_context_t (hb_face_t *face,
 				 hb_tag_t   table_tag,
-				 hb_set_t  *feature_indexes_)
+				 hb_set_t  *feature_indices_,
+                                 const hb_tag_t *features)
+
     : g (get_gsubgpos_table (face, table_tag)),
-      feature_indexes (feature_indexes_),
-      script_count(0),langsys_count(0) {}
+      feature_indices (feature_indices_),
+      has_feature_filter (false),
+      script_count (0),langsys_count (0), feature_index_count (0)
+  {
+    compute_feature_filter (features);
+  }
+
+  void compute_feature_filter (const hb_tag_t *features)
+  {
+    if (features == nullptr)
+    {
+      has_feature_filter = false;
+      return;
+    }
+
+    has_feature_filter = true;
+    hb_set_t features_set;
+    for (; *features; features++)
+      features_set.add (*features);
+
+    for (unsigned i = 0; i < g.get_feature_count (); i++)
+    {
+      hb_tag_t tag = g.get_feature_tag (i);
+      if (features_set.has (tag))
+        feature_indices_filter.add(i);
+    }
+  }
 
   bool visited (const OT::Script &s)
   {
@@ -1033,6 +1057,12 @@
     return visited (l, visited_langsys);
   }
 
+  bool visited_feature_indices (unsigned count)
+  {
+    feature_index_count += count;
+    return feature_index_count > HB_MAX_FEATURE_INDICES;
+  }
+
   private:
   template <typename T>
   bool visited (const T &p, hb_set_t &visited_set)
@@ -1047,47 +1077,45 @@
 
   public:
   const OT::GSUBGPOS &g;
-  hb_set_t           *feature_indexes;
+  hb_set_t *feature_indices;
+  hb_set_t  feature_indices_filter;
+  bool has_feature_filter;
 
   private:
   hb_set_t visited_script;
   hb_set_t visited_langsys;
   unsigned int script_count;
   unsigned int langsys_count;
+  unsigned int feature_index_count;
 };
 
 static void
 langsys_collect_features (hb_collect_features_context_t *c,
-			  const OT::LangSys  &l,
-			  const hb_tag_t     *features)
+			  const OT::LangSys  &l)
 {
   if (c->visited (l)) return;
 
-  if (!features)
+  if (!c->has_feature_filter)
   {
     /* All features. */
-    if (l.has_required_feature ())
-      c->feature_indexes->add (l.get_required_feature_index ());
+    if (l.has_required_feature () && !c->visited_feature_indices (1))
+      c->feature_indices->add (l.get_required_feature_index ());
 
-    l.add_feature_indexes_to (c->feature_indexes);
+    // TODO(garretrieger): filter out indices >= feature count?
+    if (!c->visited_feature_indices (l.featureIndex.len))
+      l.add_feature_indexes_to (c->feature_indices);
   }
   else
   {
-    /* Ugh. Any faster way? */
-    for (; *features; features++)
+    if (c->feature_indices_filter.is_empty()) return;
+    unsigned int num_features = l.get_feature_count ();
+    for (unsigned int i = 0; i < num_features; i++)
     {
-      hb_tag_t feature_tag = *features;
-      unsigned int num_features = l.get_feature_count ();
-      for (unsigned int i = 0; i < num_features; i++)
-      {
-	unsigned int feature_index = l.get_feature_index (i);
+      unsigned int feature_index = l.get_feature_index (i);
+      if (!c->feature_indices_filter.has (feature_index)) continue;
 
-	if (feature_tag == c->g.get_feature_tag (feature_index))
-	{
-	  c->feature_indexes->add (feature_index);
-	  break;
-	}
-      }
+      c->feature_indices->add (feature_index);
+      c->feature_indices_filter.del (feature_index);
     }
   }
 }
@@ -1095,8 +1123,7 @@
 static void
 script_collect_features (hb_collect_features_context_t *c,
 			 const OT::Script   &s,
-			 const hb_tag_t *languages,
-			 const hb_tag_t *features)
+			 const hb_tag_t *languages)
 {
   if (c->visited (s)) return;
 
@@ -1105,14 +1132,13 @@
     /* All languages. */
     if (s.has_default_lang_sys ())
       langsys_collect_features (c,
-				s.get_default_lang_sys (),
-				features);
+				s.get_default_lang_sys ());
+
 
     unsigned int count = s.get_lang_sys_count ();
     for (unsigned int language_index = 0; language_index < count; language_index++)
       langsys_collect_features (c,
-				s.get_lang_sys (language_index),
-				features);
+				s.get_lang_sys (language_index));
   }
   else
   {
@@ -1121,8 +1147,8 @@
       unsigned int language_index;
       if (s.find_lang_sys_index (*languages, &language_index))
 	langsys_collect_features (c,
-				  s.get_lang_sys (language_index),
-				  features);
+				  s.get_lang_sys (language_index));
+
     }
   }
 }
@@ -1131,7 +1157,7 @@
 /**
  * hb_ot_layout_collect_features:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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
@@ -1153,7 +1179,7 @@
 			       const hb_tag_t *features,
 			       hb_set_t       *feature_indexes /* OUT */)
 {
-  hb_collect_features_context_t c (face, table_tag, feature_indexes);
+  hb_collect_features_context_t c (face, table_tag, feature_indexes, features);
   if (!scripts)
   {
     /* All scripts. */
@@ -1161,8 +1187,7 @@
     for (unsigned int script_index = 0; script_index < count; script_index++)
       script_collect_features (&c,
 			       c.g.get_script (script_index),
-			       languages,
-			       features);
+			       languages);
   }
   else
   {
@@ -1172,8 +1197,7 @@
       if (c.g.find_script_index (*scripts, &script_index))
 	script_collect_features (&c,
 				 c.g.get_script (script_index),
-				 languages,
-				 features);
+				 languages);
     }
   }
 }
@@ -1182,7 +1206,7 @@
 /**
  * hb_ot_layout_collect_lookups:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @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
@@ -1212,6 +1236,8 @@
   for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
        hb_set_next (&feature_indexes, &feature_index);)
     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
+
+  g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
 }
 
 
@@ -1219,12 +1245,12 @@
 /**
  * hb_ot_layout_lookup_collect_glyphs:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @lookup_index: The index of the feature lookup to query
  * @glyphs_before: (out): Array of glyphs preceding the substitution range
  * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
- * @glyphs_after: (out): Array of glyphs following the substition range
- * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup
+ * @glyphs_after: (out): Array of glyphs following the substitution range
+ * @glyphs_output: (out): Array of glyphs that would be the substituted output of the lookup
  *
  * Fetches a list of all glyphs affected by the specified lookup in the
  * specified face's GSUB table or GPOS table.
@@ -1271,14 +1297,16 @@
 /**
  * hb_ot_layout_table_find_feature_variations:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @coords: The variation coordinates to query
- * @num_coords: The number of variation coorinates
+ * @num_coords: The number of variation coordinates
  * @variations_index: (out): The array of feature variations found for the query
  *
  * 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.
+ *
  **/
 hb_bool_t
 hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
@@ -1296,11 +1324,11 @@
 /**
  * hb_ot_layout_feature_with_variations_get_lookups:
  * @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
  * @feature_index: The index of the feature to query
  * @variations_index: The index of the feature variation to query
  * @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
  *                Output = the actual number of lookups returned (may be zero)
  * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
  *
@@ -1308,6 +1336,8 @@
  * the specified face's GSUB table or GPOS table, enabled at the specified
  * variations index. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of lookups.
+ *
  **/
 unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
@@ -1338,7 +1368,7 @@
  *
  * 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
  *
  **/
 hb_bool_t
@@ -1354,12 +1384,13 @@
  * @lookup_index: The index of the lookup to query
  * @glyphs: The sequence of glyphs to query for substitution
  * @glyphs_length: The length of the glyph sequence
- * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
+ * @zero_context: #hb_bool_t indicating whether pre-/post-context are disallowed
+ * in substitutions
  *
  * 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
  **/
@@ -1374,7 +1405,6 @@
   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]);
 }
 
@@ -1392,7 +1422,7 @@
 hb_ot_layout_substitute_start (hb_font_t    *font,
 			       hb_buffer_t  *buffer)
 {
-_hb_ot_layout_set_glyph_props (font, buffer);
+  _hb_ot_layout_set_glyph_props (font, buffer);
 }
 
 void
@@ -1458,15 +1488,20 @@
  **/
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
-				        unsigned int  lookup_index,
-				        hb_set_t     *glyphs /* OUT */)
+					unsigned int  lookup_index,
+					hb_set_t     *glyphs /* OUT */)
 {
-  hb_map_t done_lookups;
-  OT::hb_closure_context_t c (face, glyphs, &done_lookups);
+  hb_set_t cur_intersected_glyphs;
+  hb_map_t done_lookups_glyph_count;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
+  OT::hb_closure_context_t c (face, glyphs, &cur_intersected_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);
 }
 
 /**
@@ -1485,8 +1520,10 @@
 					 const hb_set_t *lookups,
 					 hb_set_t       *glyphs /* OUT */)
 {
-  hb_map_t done_lookups;
-  OT::hb_closure_context_t c (face, glyphs, &done_lookups);
+  hb_set_t cur_intersected_glyphs;
+  hb_map_t done_lookups_glyph_count;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
+  OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
   const OT::GSUB& gsub = *face->table.GSUB->table;
 
   unsigned int iteration_count = 0;
@@ -1494,7 +1531,7 @@
   do
   {
     glyphs_length = glyphs->get_population ();
-    if (lookups != nullptr)
+    if (lookups)
     {
       for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
 	gsub.get_lookup (lookup_index).closure (&c, lookup_index);
@@ -1506,6 +1543,9 @@
     }
   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
 	   glyphs_length != glyphs->get_population ());
+
+  for (auto _ : done_lookups_glyph_set.iter ())
+    hb_set_destroy (_.second);
 }
 
 /*
@@ -1517,7 +1557,9 @@
  * hb_ot_layout_has_positioning:
  * @face: #hb_face_t to work upon
  *
- * Return value: true if the face has GPOS data, false otherwise
+ * Tests whether the specified face includes any GPOS positioning.
+ *
+ * Return value: %true if the face has GPOS data, %false otherwise
  *
  **/
 hb_bool_t
@@ -1587,10 +1629,10 @@
  * specifically in their respective size ranges; other ways to differentiate fonts within
  * a subfamily are not covered by the `size` feature.
  *
- * For more information on this distinction, see the `size` documentation at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-39size39
+ * 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
  **/
@@ -1639,22 +1681,22 @@
  * @face: #hb_face_t to work upon
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
- * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string
  *            for a user-interface label for this feature. (May be NULL.)
- * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string
  *              that an application can use for tooltip text for this
  *              feature. (May be NULL.)
- * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
+ * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text
  *             that illustrates the effect of this feature. (May be NULL.)
- * @num_named_parameters: (out) (allow-none):  Number of named parameters. (May be zero.)
- * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
+ * @num_named_parameters: (out) (optional):  Number of named parameters. (May be zero.)
+ * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify
  *                  strings for user-interface labels for the feature
  *                  parameters. (Must be zero if numParameters is zero.)
  *
  * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
  * "Character Variant" ('cvXX') features.
  *
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 2.0.0
  **/
@@ -1714,7 +1756,7 @@
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
  * @start_offset: offset of the first character to retrieve
- * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
+ * @char_count: (inout) (optional): Input = the maximum number of characters to return;
  *              Output = the actual number of characters returned (may be zero)
  * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
  *              The Unicode codepoints of the characters for which this feature provides
@@ -1723,12 +1765,6 @@
  * Fetches a list of the characters defined as having a variant under the specified
  * "Character Variant" ("cvXX") feature tag.
  *
- * <note>Note: If the char_count output value is equal to its input value, then there
- *       is a chance there were more characters defined under the feature tag than were
- *       returned. This function can be called with incrementally larger start_offset
- *       until the char_count output value is lower than its input value, or the size
- *       of the characters array can be increased.</note>
- *
  * Return value: Number of total sample characters in the cvXX feature.
  *
  * Since: 2.0.0
@@ -1742,24 +1778,10 @@
 				     hb_codepoint_t *characters  /* OUT.     May be NULL */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-
-  hb_tag_t feature_tag = g.get_feature_tag (feature_index);
-  const OT::Feature &f = g.get_feature (feature_index);
-
-  const OT::FeatureParams &feature_params = f.get_feature_params ();
-
-  const OT::FeatureParamsCharacterVariants& cv_params =
-    feature_params.get_character_variants_params(feature_tag);
-
-  unsigned int len = 0;
-  if (char_count && characters && start_offset < cv_params.characters.len)
-  {
-    len = hb_min (cv_params.characters.len - start_offset, *char_count);
-    for (unsigned int i = 0; i < len; ++i)
-      characters[i] = cv_params.characters[start_offset + i];
-  }
-  if (char_count) *char_count = len;
-  return cv_params.characters.len;
+  return g.get_feature (feature_index)
+	  .get_feature_params ()
+	  .get_character_variants_params(g.get_feature_tag (feature_index))
+	  .get_characters (start_offset, char_count, characters);
 }
 #endif
 
@@ -1818,7 +1840,7 @@
     if (applied)
       ret = true;
     else
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
   }
   return ret;
 }
@@ -1860,27 +1882,20 @@
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (Proxy::table_index == 0u)
+    if (!Proxy::inplace)
       buffer->clear_output ();
-    buffer->idx = 0;
 
-    bool ret;
-    ret = apply_forward (c, accel);
-    if (ret)
-    {
-      if (!Proxy::inplace)
-	buffer->swap_buffers ();
-      else
-	assert (!buffer->has_separate_output ());
-    }
+    buffer->idx = 0;
+    apply_forward (c, accel);
+
+    if (!Proxy::inplace)
+      buffer->swap_buffers ();
   }
   else
   {
     /* in-place backward substitution/positioning */
-    if (Proxy::table_index == 0u)
-      buffer->remove_output ();
+    assert (!buffer->have_output);
     buffer->idx = buffer->len - 1;
-
     apply_backward (c, accel);
   }
 }
@@ -1896,7 +1911,8 @@
   OT::hb_ot_apply_context_t c (table_index, font, buffer);
   c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
 
-  for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
+  {
     const stage_map_t *stage = &stages[table_index][stage_index];
     for (; i < stage->last_lookup; i++)
     {
@@ -1906,11 +1922,8 @@
       c.set_lookup_mask (lookups[table_index][i].mask);
       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
       c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
-      if (lookups[table_index][i].random)
-      {
-	c.set_random (true);
-	buffer->unsafe_to_break_all ();
-      }
+      c.set_random (lookups[table_index][i].random);
+
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
 			   proxy.accels[lookup_index]);
@@ -1918,23 +1931,24 @@
     }
 
     if (stage->pause_func)
-    {
-      buffer->clear_output ();
       stage->pause_func (plan, font, buffer);
-    }
   }
 }
 
 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;
   apply (proxy, plan, font, buffer);
+  (void) buffer->message (font, "end table GSUB");
 }
 
 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;
   apply (proxy, plan, font, buffer);
+  (void) buffer->message (font, "end table GPOS");
 }
 
 void
@@ -1952,12 +1966,12 @@
  * @baseline_tag: a baseline tag
  * @direction: text direction.
  * @script_tag:  script tag.
- * @language_tag: language tag.
+ * @language_tag: language tag, currently unused.
  * @coord: (out): baseline value if found.
  *
  * Fetches a baseline value from the face.
  *
- * Return value: if found baseline value in the the font.
+ * Return value: %true if found baseline value in the font.
  *
  * Since: 2.6.0
  **/
@@ -1977,4 +1991,62 @@
   return result;
 }
 #endif
+
+
+struct hb_get_glyph_alternates_dispatch_t :
+       hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned>
+{
+  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
+  ( obj.get_glyph_alternates (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_glyph_alternates:
+ * @face: a face.
+ * @lookup_index: index of the feature lookup to query.
+ * @glyph: a glyph id.
+ * @start_offset: starting offset.
+ * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return;
+ *                   Output = the actual number of alternate glyphs returned (may be zero).
+ * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
+ *                    Alternate glyphs associated with the glyph id.
+ *
+ * Fetches alternates of a glyph from a given GSUB lookup index.
+ *
+ * Return value: Total number of alternates found in the specific lookup index for the given glyph id.
+ *
+ * Since: 2.6.8
+ **/
+HB_EXTERN unsigned
+hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
+					  unsigned        lookup_index,
+					  hb_codepoint_t  glyph,
+					  unsigned        start_offset,
+					  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);
+  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;
+}
+
 #endif
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index 7e8a897..d47ba0f 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -38,10 +38,35 @@
 HB_BEGIN_DECLS
 
 
+/**
+ * HB_OT_TAG_BASE:
+ *
+ * OpenType [Baseline Table](https://docs.microsoft.com/en-us/typography/opentype/spec/base).
+ */
 #define HB_OT_TAG_BASE HB_TAG('B','A','S','E')
+/**
+ * HB_OT_TAG_GDEF:
+ *
+ * OpenType [Glyph Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef).
+ */
 #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
+/**
+ * HB_OT_TAG_GSUB:
+ *
+ * OpenType [Glyph Substitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub).
+ */
 #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
+/**
+ * HB_OT_TAG_GPOS:
+ *
+ * OpenType [Glyph Positioning Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos).
+ */
 #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+/**
+ * HB_OT_TAG_JSTF:
+ *
+ * OpenType [Justification Table](https://docs.microsoft.com/en-us/typography/opentype/spec/jstf).
+ */
 #define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
 
 
@@ -49,18 +74,34 @@
  * Script & Language tags.
  */
 
+/**
+ * HB_OT_TAG_DEFAULT_SCRIPT:
+ *
+ * OpenType script tag, `DFLT`, for features that are not script-specific.
+ *
+ */
 #define HB_OT_TAG_DEFAULT_SCRIPT	HB_TAG ('D', 'F', 'L', 'T')
+/**
+ * HB_OT_TAG_DEFAULT_LANGUAGE:
+ *
+ * OpenType language tag, `dflt`. Not a valid language tag, but some fonts
+ * mistakenly use it.
+ */
 #define HB_OT_TAG_DEFAULT_LANGUAGE	HB_TAG ('d', 'f', 'l', 't')
 
 /**
  * HB_OT_MAX_TAGS_PER_SCRIPT:
  *
+ * Maximum number of OpenType tags that can correspond to a give #hb_script_t.
+ *
  * Since: 2.0.0
  **/
 #define HB_OT_MAX_TAGS_PER_SCRIPT	3u
 /**
  * HB_OT_MAX_TAGS_PER_LANGUAGE:
  *
+ * Maximum number of OpenType tags that can correspond to a give #hb_language_t.
+ *
  * Since: 2.0.0
  **/
 #define HB_OT_MAX_TAGS_PER_LANGUAGE	3u
@@ -121,7 +162,6 @@
 				  hb_ot_layout_glyph_class_t  klass,
 				  hb_set_t                   *glyphs /* OUT */);
 
-
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 HB_EXTERN unsigned int
@@ -145,9 +185,29 @@
  * GSUB/GPOS feature query and enumeration interface
  */
 
+/**
+ * HB_OT_LAYOUT_NO_SCRIPT_INDEX:
+ *
+ * Special value for script index indicating unsupported script.
+ */
 #define HB_OT_LAYOUT_NO_SCRIPT_INDEX		0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_FEATURE_INDEX:
+ *
+ * Special value for feature index indicating unsupported feature.
+ */
 #define HB_OT_LAYOUT_NO_FEATURE_INDEX		0xFFFFu
+/**
+ * HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX:
+ *
+ * Special value for language index indicating default or unsupported language.
+ */
 #define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX	0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_VARIATIONS_INDEX:
+ *
+ * Special value for variations index indicating unsupported variation.
+ */
 #define HB_OT_LAYOUT_NO_VARIATIONS_INDEX	0xFFFFFFFFu
 
 HB_EXTERN unsigned int
@@ -161,7 +221,7 @@
 hb_ot_layout_table_find_script (hb_face_t    *face,
 				hb_tag_t      table_tag,
 				hb_tag_t      script_tag,
-				unsigned int *script_index);
+				unsigned int *script_index /* OUT */);
 
 HB_EXTERN hb_bool_t
 hb_ot_layout_table_select_script (hb_face_t      *face,
@@ -199,15 +259,15 @@
 						  hb_tag_t      table_tag,
 						  unsigned int  script_index,
 						  unsigned int  language_index,
-						  unsigned int *feature_index);
+						  unsigned int *feature_index /* OUT */);
 
 HB_EXTERN hb_bool_t
 hb_ot_layout_language_get_required_feature (hb_face_t    *face,
 					    hb_tag_t      table_tag,
 					    unsigned int  script_index,
 					    unsigned int  language_index,
-					    unsigned int *feature_index,
-					    hb_tag_t     *feature_tag);
+					    unsigned int *feature_index /* OUT */,
+					    hb_tag_t     *feature_tag /* OUT */);
 
 HB_EXTERN unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
@@ -233,7 +293,7 @@
 				    unsigned int  script_index,
 				    unsigned int  language_index,
 				    hb_tag_t      feature_tag,
-				    unsigned int *feature_index);
+				    unsigned int *feature_index /* OUT */);
 
 HB_EXTERN unsigned int
 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
@@ -324,6 +384,14 @@
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face);
 
+HB_EXTERN unsigned
+hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
+					  unsigned        lookup_index,
+					  hb_codepoint_t  glyph,
+					  unsigned        start_offset,
+					  unsigned       *alternate_count /* IN/OUT */,
+					  hb_codepoint_t *alternate_glyphs /* OUT */);
+
 HB_EXTERN hb_bool_t
 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
 				      unsigned int          lookup_index,
@@ -426,7 +494,7 @@
  * @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.
  *
- * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ * Baseline tags from [Baseline Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags) registry.
  *
  * Since: 2.6.0
  */
@@ -439,6 +507,7 @@
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT	= HB_TAG ('i','d','t','p'),
   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;
 
@@ -450,7 +519,6 @@
 			   hb_tag_t                     language_tag,
 			   hb_position_t               *coord        /* OUT.  May be NULL. */);
 
-
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh
index f3bb155..b15d053 100644
--- a/src/hb-ot-layout.hh
+++ b/src/hb-ot-layout.hh
@@ -187,7 +187,7 @@
  * - General_Category: 5 bits.
  * - A bit each for:
  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
- *   * Whether it's one of the three Mongolian Free Variation Selectors,
+ *   * Whether it's one of the four Mongolian Free Variation Selectors,
  *     CGJ, or other characters that are hidden but should not be ignored
  *     like most other Default_Ignorable()s do during matching.
  *   * Whether it's a grapheme continuation.
@@ -202,7 +202,7 @@
 enum hb_unicode_props_flags_t {
   UPROPS_MASK_GEN_CAT	= 0x001Fu,
   UPROPS_MASK_IGNORABLE	= 0x0020u,
-  UPROPS_MASK_HIDDEN	= 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */
+  UPROPS_MASK_HIDDEN	= 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..4, or TAG characters */
   UPROPS_MASK_CONTINUATION=0x0080u,
 
   /* If GEN_CAT=FORMAT, top byte masks: */
@@ -236,7 +236,7 @@
        * FVSes are GC=Mn, we have use a separate bit to remember them.
        * Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/234 */
-      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x180Bu, 0x180Du, 0x180Fu, 0x180Fu))) props |= UPROPS_MASK_HIDDEN;
       /* TAG characters need similar treatment. Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/463 */
       else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
@@ -314,20 +314,20 @@
 	 hb_unicode_funcs_t::NOT_SPACE;
 }
 
-static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
+static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info);
 
 static inline bool
 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 {
   return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
-	 !_hb_glyph_info_ligated (info);
+	 !_hb_glyph_info_substituted (info);
 }
 static inline bool
 _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
 {
   return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
 	  == UPROPS_MASK_IGNORABLE) &&
-	 !_hb_glyph_info_ligated (info);
+	 !_hb_glyph_info_substituted (info);
 }
 static inline void
 _hb_glyph_info_unhide (hb_glyph_info_t *info)
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index e4bb4b6..12ceea5 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -54,7 +54,6 @@
   face = face_;
   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. */
 
@@ -63,12 +62,28 @@
   hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
   hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
 
-  hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
+  hb_ot_tags_from_script_and_language (props.script,
+				       props.language,
+				       &script_count,
+				       script_tags,
+				       &language_count,
+				       language_tags);
 
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
     hb_tag_t table_tag = table_tags[table_index];
-    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
-    hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
+    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face,
+									 table_tag,
+									 script_count,
+									 script_tags,
+									 &script_index[table_index],
+									 &chosen_script[table_index]);
+    hb_ot_layout_script_select_language (face,
+					 table_tag,
+					 script_index[table_index],
+					 language_count,
+					 language_tags,
+					 &language_index[table_index]);
   }
 }
 
@@ -150,9 +165,8 @@
 hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
 			      const hb_ot_shape_plan_key_t &key)
 {
-  static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
-  unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
-  unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
+  unsigned int global_bit_shift = 8 * sizeof (hb_mask_t) - 1;
+  unsigned int global_bit_mask = 1u << global_bit_shift;
 
   m.global_mask = global_bit_mask;
 
@@ -205,7 +219,8 @@
 
 
   /* Allocate bits now */
-  unsigned int next_bit = global_bit_shift + 1;
+  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++)
   {
@@ -220,7 +235,7 @@
       /* Limit bits per feature. */
       bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
 
-    if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
+    if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
       continue; /* Feature disabled, or not enough bits. */
 
 
@@ -274,7 +289,6 @@
     }
     map->_1_mask = (1u << map->shift) & map->mask;
     map->needs_fallback = !found;
-
   }
   feature_infos.shrink (0); /* Done with these */
 
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 0a4827d..5f2afae 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -134,18 +134,18 @@
   unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const
   {
     const feature_map_t *map = features.bsearch (feature_tag);
-    return map ? map->stage[table_index] : (unsigned int) -1;
+    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
   {
-    if (unlikely (stage == (unsigned int) -1)) {
+    if (unlikely (stage > stages[table_index].length))
+    {
       *plookups = nullptr;
       *lookup_count = 0;
       return;
     }
-    assert (stage <= stages[table_index].length);
     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
     unsigned int end   = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
     *plookups = end == start ? nullptr : &lookups[table_index][start];
@@ -213,8 +213,8 @@
   { add_feature (feat.tag, feat.flags); }
 
   void enable_feature (hb_tag_t tag,
-			      hb_ot_map_feature_flags_t flags=F_NONE,
-			      unsigned int value=1)
+		       hb_ot_map_feature_flags_t flags=F_NONE,
+		       unsigned int value=1)
   { add_feature (tag, F_GLOBAL | flags, value); }
 
   void disable_feature (hb_tag_t tag)
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index 7529e0c..c2e365d 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -41,6 +41,16 @@
   hb_position_t get_y_value (hb_font_t *font, const void *base) const
   { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
 
+  MathValueRecord* 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->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
+
+    return_trace (out);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -48,8 +58,8 @@
   }
 
   protected:
-  HBINT16			value;		/* The X or Y value in design units */
-  OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
+  HBINT16		value;		/* The X or Y value in design units */
+  Offset16To<Device>	deviceTable;	/* Offset to the device table - from the
 					 * beginning of parent table.  May be NULL.
 					 * Suggested format for device table is 1. */
 
@@ -59,6 +69,29 @@
 
 struct MathConstants
 {
+  MathConstants* copy (hb_serialize_context_t *c) const
+  {
+    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);
+
+    HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
+    if (unlikely (!m)) return_trace (nullptr);
+    memcpy (m, minHeight, HBUINT16::static_size * 2);
+
+    unsigned count = ARRAY_LENGTH (mathValueRecords);
+    for (unsigned i = 0; i < count; i++)
+      if (!c->copy (mathValueRecords[i], this))
+        return_trace (nullptr);
+
+    if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
+    return_trace (out);
+  }
+
   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -78,7 +111,7 @@
   }
 
   hb_position_t get_value (hb_ot_math_constant_t constant,
-				  hb_font_t *font) const
+			   hb_font_t *font) const
   {
     switch (constant) {
 
@@ -165,6 +198,28 @@
 
 struct MathItalicsCorrectionInfo
 {
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    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);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, italicsCorrection)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, 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 (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -181,11 +236,11 @@
   }
 
   protected:
-  OffsetTo<Coverage>       coverage;		/* Offset to Coverage table -
+  Offset16To<Coverage>       coverage;		/* Offset to Coverage table -
 						 * from the beginning of
 						 * MathItalicsCorrectionInfo
 						 * table. */
-  ArrayOf<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
+  Array16Of<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
 						 * defining italics correction
 						 * values for each
 						 * covered glyph. */
@@ -196,6 +251,28 @@
 
 struct MathTopAccentAttachment
 {
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    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);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+topAccentCoverage, topAccentAttachment)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -214,11 +291,11 @@
   }
 
   protected:
-  OffsetTo<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
+  Offset16To<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
 						 * from the beginning of
 						 * MathTopAccentAttachment
 						 * table. */
-  ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+  Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
 						 * defining top accent
 						 * attachment points for each
 						 * covered glyph. */
@@ -229,6 +306,22 @@
 
 struct MathKern
 {
+  MathKern* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
+
+    unsigned count = 2 * heightCount + 1;
+    for (unsigned i = 0; i < count; i++)
+      if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
+        return_trace (nullptr);
+
+    return_trace (out);
+  }
+
   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -279,14 +372,15 @@
   protected:
   HBUINT16	heightCount;
   UnsizedArrayOf<MathValueRecord>
-		mathValueRecordsZ;	/* Array of correction heights at
-					 * which the kern value changes.
-					 * Sorted by the height value in
-					 * design units (heightCount entries),
-					 * Followed by:
-					 * Array of kern values corresponding
-					 * to heights. (heightCount+1 entries).
-					 */
+		mathValueRecordsZ;
+				/* Array of correction heights at
+				 * which the kern value changes.
+				 * Sorted by the height value in
+				 * design units (heightCount entries),
+				 * Followed by:
+				 * Array of kern values corresponding
+				 * to heights. (heightCount+1 entries).
+				 */
 
   public:
   DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
@@ -294,6 +388,19 @@
 
 struct MathKernInfoRecord
 {
+  MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    unsigned count = ARRAY_LENGTH (mathKern);
+    for (unsigned i = 0; i < count; i++)
+      out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
+
+    return_trace (out);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -319,7 +426,7 @@
   protected:
   /* Offset to MathKern table for each corner -
    * from the beginning of MathKernInfo table.  May be NULL. */
-  OffsetTo<MathKern> mathKern[4];
+  Offset16To<MathKern> mathKern[4];
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -327,6 +434,28 @@
 
 struct MathKernInfo
 {
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    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);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -345,15 +474,18 @@
   }
 
   protected:
-  OffsetTo<Coverage>		mathKernCoverage;    /* Offset to Coverage table -
-						      * from the beginning of the
-						      * MathKernInfo table. */
-  ArrayOf<MathKernInfoRecord>	mathKernInfoRecords; /* Array of
-						      * MathKernInfoRecords,
-						      * per-glyph information for
-						      * mathematical positioning
-						      * of subscripts and
-						      * superscripts. */
+  Offset16To<Coverage>
+		mathKernCoverage;
+				/* Offset to Coverage table -
+				 * from the beginning of the
+				 * MathKernInfo table. */
+  Array16Of<MathKernInfoRecord>
+		mathKernInfoRecords;
+				/* Array of MathKernInfoRecords,
+				 * per-glyph information for
+				 * mathematical positioning
+				 * of subscripts and
+				 * superscripts. */
 
   public:
   DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
@@ -361,6 +493,30 @@
 
 struct MathGlyphInfo
 {
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    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_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+extendedShapeCoverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
+
+    out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -391,22 +547,22 @@
   protected:
   /* Offset to MathItalicsCorrectionInfo table -
    * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+  Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
 
   /* Offset to MathTopAccentAttachment table -
    * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+  Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
 
   /* Offset to coverage table for Extended Shape glyphs -
    * from the beginning of MathGlyphInfo table. When the left or right glyph of
    * a box is an extended shape variant, the (ink) box (and not the default
    * position defined by values in MathConstants table) should be used for
    * vertical positioning purposes.  May be NULL.. */
-  OffsetTo<Coverage> extendedShapeCoverage;
+  Offset16To<Coverage> extendedShapeCoverage;
 
    /* Offset to MathKernInfo table -
     * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathKernInfo> mathKernInfo;
+  Offset16To<MathKernInfo> mathKernInfo;
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -416,14 +572,27 @@
 {
   friend struct MathGlyphConstruction;
 
+  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_map_t& glyph_map = *c->plan->glyph_map;
+    return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
+  void closure_glyphs (hb_set_t *variant_glyphs) const
+  { variant_glyphs->add (variantGlyph); }
+
   protected:
-  HBGlyphID variantGlyph;       /* Glyph ID for the variant. */
+  HBGlyphID16 variantGlyph;       /* Glyph ID for the variant. */
   HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
 				 * variant, in the direction of requested
 				 * glyph extension. */
@@ -446,6 +615,16 @@
 
 struct MathGlyphPartRecord
 {
+  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_map_t& glyph_map = *c->plan->glyph_map;
+    return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -470,20 +649,25 @@
 		(partFlags & PartFlags::Defined);
   }
 
+  void closure_glyphs (hb_set_t *variant_glyphs) const
+  { variant_glyphs->add (glyph); }
+
   protected:
-  HBGlyphID   glyph;		  /* Glyph ID for the part. */
-  HBUINT16    startConnectorLength; /* Advance width/ height of the straight bar
-				   * connector material, in design units, is at
-				   * the beginning of the glyph, in the
-				   * direction of the extension. */
-  HBUINT16    endConnectorLength;   /* Advance width/ height of the straight bar
-				   * connector material, in design units, is at
-				   * the end of the glyph, in the direction of
-				   * the extension. */
-  HBUINT16    fullAdvance;	  /* Full advance width/height for this part,
-				   * in the direction of the extension.
-				   * In design units. */
-  PartFlags partFlags;		  /* Part qualifiers. */
+  HBGlyphID16	glyph;		/* Glyph ID for the part. */
+  HBUINT16	startConnectorLength;
+				/* Advance width/ height of the straight bar
+				 * connector material, in design units, is at
+				 * the beginning of the glyph, in the
+				 * direction of the extension. */
+  HBUINT16	endConnectorLength;
+				/* Advance width/ height of the straight bar
+				 * connector material, in design units, is at
+				 * the end of the glyph, in the direction of
+				 * the extension. */
+  HBUINT16	fullAdvance;	/* Full advance width/height for this part,
+				 * in the direction of the extension.
+				 * In design units. */
+  PartFlags	partFlags;	/* Part qualifiers. */
 
   public:
   DEFINE_SIZE_STATIC (10);
@@ -491,6 +675,20 @@
 
 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);
+
+    for (const auto& record : partRecords.iter ())
+      if (!record.subset (c)) return_trace (false);
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -509,10 +707,9 @@
     if (parts_count)
     {
       int64_t mult = font->dir_mult (direction);
-      hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count);
-      unsigned int count = arr.length;
-      for (unsigned int i = 0; i < count; i++)
-	arr[i].extract (parts[i], mult, font);
+      for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
+			    hb_array (parts, *parts_count)))
+	_.first.extract (_.second, mult, font);
     }
 
     if (italics_correction)
@@ -521,13 +718,22 @@
     return partRecords.len;
   }
 
+  void closure_glyphs (hb_set_t *variant_glyphs) const
+  {
+    for (const auto& _ : partRecords.iter ())
+      _.closure_glyphs (variant_glyphs);
+  }
+
   protected:
-  MathValueRecord	   italicsCorrection; /* Italics correction of this
-					       * MathGlyphAssembly. Should not
-					       * depend on the assembly size. */
-  ArrayOf<MathGlyphPartRecord> partRecords;   /* Array of part records, from
-					       * left to right and bottom to
-					       * top. */
+  MathValueRecord
+		italicsCorrection;
+				/* Italics correction of this
+				 * MathGlyphAssembly. Should not
+				 * depend on the assembly size. */
+  Array16Of<MathGlyphPartRecord>
+		partRecords;	/* Array of part records, from
+				 * left to right and bottom to
+				 * top. */
 
   public:
   DEFINE_SIZE_ARRAY (6, partRecords);
@@ -535,6 +741,22 @@
 
 struct MathGlyphConstruction
 {
+  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->glyphAssembly.serialize_subset (c, glyphAssembly, this);
+
+    if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+    for (const auto& record : mathGlyphVariantRecord.iter ())
+      if (!record.subset (c)) return_trace (false);
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -554,24 +776,28 @@
     if (variants_count)
     {
       int64_t mult = font->dir_mult (direction);
-      hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count);
-      unsigned int count = arr.length;
-      for (unsigned int i = 0; i < count; i++)
-      {
-	variants[i].glyph = arr[i].variantGlyph;
-	variants[i].advance = font->em_mult (arr[i].advanceMeasurement, mult);
-      }
+      for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
+			    hb_array (variants, *variants_count)))
+	_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
     }
     return mathGlyphVariantRecord.len;
   }
 
+  void closure_glyphs (hb_set_t *variant_glyphs) const
+  {
+    (this+glyphAssembly).closure_glyphs (variant_glyphs);
+
+    for (const auto& _ : mathGlyphVariantRecord.iter ())
+      _.closure_glyphs (variant_glyphs);
+  }
+
   protected:
   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
      MathGlyphConstruction table.  May be NULL. */
-  OffsetTo<MathGlyphAssembly>	  glyphAssembly;
+  Offset16To<MathGlyphAssembly>	  glyphAssembly;
 
   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
-  ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
+  Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
 
   public:
   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
@@ -579,6 +805,91 @@
 
 struct MathVariants
 {
+  void closure_glyphs (const hb_set_t *glyph_set,
+                       hb_set_t *variant_glyphs) const
+  {
+    const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
+
+    if (vertGlyphCoverage)
+    {
+      const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
+      + hb_zip (this+vertGlyphCoverage, vert_offsets)
+      | hb_filter (glyph_set, hb_first)
+      | hb_map (hb_second)
+      | hb_map (hb_add (this))
+      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
+      ;
+    }
+
+    if (horizGlyphCoverage)
+    {
+      const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
+      + hb_zip (this+horizGlyphCoverage, hori_offsets)
+      | hb_filter (glyph_set, hb_first)
+      | hb_map (hb_second)
+      | hb_map (hb_add (this))
+      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
+      ;
+    }
+  }
+
+  void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
+                                     const Offset16To<Coverage>& coverage,
+                                     unsigned i,
+                                     unsigned end_index,
+                                     hb_set_t& indices,
+                                     const hb_set_t& glyphset,
+                                     const hb_map_t& glyph_map) const
+  {
+    if (!coverage) return;
+
+    for (const auto _ : (this+coverage).iter ())
+    {
+      if (i >= end_index) return;
+      if (glyphset.has (_))
+      {
+        unsigned new_gid = glyph_map.get (_);
+        new_coverage.push (new_gid);
+        indices.add (i);
+      }
+      i++;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    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))
+      return_trace (false);
+
+    for (unsigned i : indices.iter ())
+    {
+      auto *o = c->serializer->embed (glyphConstruction[i]);
+      if (!o) return_trace (false);
+      o->serialize_subset (c, glyphConstruction[i], this);
+    }
+
+    out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
+    out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
+    return_trace (true);
+  }
+
   bool sanitize_offsets (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -612,12 +923,12 @@
 	   .get_variants (direction, font, start_offset, variants_count, variants); }
 
   unsigned int get_glyph_parts (hb_codepoint_t glyph,
-				       hb_direction_t direction,
-				       hb_font_t *font,
-				       unsigned int start_offset,
-				       unsigned int *parts_count, /* IN/OUT */
-				       hb_ot_math_glyph_part_t *parts /* OUT */,
-				       hb_position_t *italics_correction /* OUT */) const
+				hb_direction_t direction,
+				hb_font_t *font,
+				unsigned int start_offset,
+				unsigned int *parts_count, /* IN/OUT */
+				hb_ot_math_glyph_part_t *parts /* OUT */,
+				hb_position_t *italics_correction /* OUT */) const
   { return get_glyph_construction (glyph, direction, font)
 	   .get_assembly ()
 	   .get_parts (direction, font,
@@ -632,7 +943,7 @@
   {
     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
-    const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
+    const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
 						  : horizGlyphCoverage;
 
     unsigned int index = (this+coverage).get_coverage (glyph);
@@ -645,27 +956,30 @@
   }
 
   protected:
-  HBUINT16	     minConnectorOverlap; /* Minimum overlap of connecting
-					   * glyphs during glyph construction,
-					   * in design units. */
-  OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
-					   * from the beginning of MathVariants
-					   * table. */
-  OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
-					   * from the beginning of MathVariants
-					   * table. */
-  HBUINT16	     vertGlyphCount;      /* Number of glyphs for which
-					   * information is provided for
-					   * vertically growing variants. */
-  HBUINT16	     horizGlyphCount;     /* Number of glyphs for which
-					   * information is provided for
-					   * horizontally growing variants. */
+  HBUINT16	minConnectorOverlap;
+				/* Minimum overlap of connecting
+				 * glyphs during glyph construction,
+				 * in design units. */
+  Offset16To<Coverage> vertGlyphCoverage;
+				/* Offset to Coverage table -
+				 * from the beginning of MathVariants
+				 * table. */
+  Offset16To<Coverage> horizGlyphCoverage;
+				/* Offset to Coverage table -
+				 * from the beginning of MathVariants
+				 * table. */
+  HBUINT16	vertGlyphCount;	/* Number of glyphs for which
+				 * information is provided for
+				 * vertically growing variants. */
+  HBUINT16	horizGlyphCount;/* Number of glyphs for which
+				 * information is provided for
+				 * horizontally growing variants. */
 
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
-  UnsizedArrayOf<OffsetTo<MathGlyphConstruction>>
- 			glyphConstruction;
+  UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
+			glyphConstruction;
 
   public:
   DEFINE_SIZE_ARRAY (10, glyphConstruction);
@@ -683,6 +997,28 @@
 
   bool has_data () const { return version.to_int (); }
 
+  void closure_glyphs (hb_set_t *glyph_set) const
+  {
+    if (mathVariants)
+    {
+      hb_set_t variant_glyphs;
+      (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
+      hb_set_union (glyph_set, &variant_glyphs);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
+    out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
+    out->mathVariants.serialize_subset (c, mathVariants, this);
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -694,7 +1030,7 @@
   }
 
   hb_position_t get_constant (hb_ot_math_constant_t  constant,
-				     hb_font_t		   *font) const
+			      hb_font_t		   *font) const
   { return (this+mathConstants).get_value (constant, font); }
 
   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
@@ -702,11 +1038,14 @@
   const MathVariants &get_variants () const    { return this+mathVariants; }
 
   protected:
-  FixedVersion<>version;		/* Version of the MATH table
-					 * initially set to 0x00010000u */
-  OffsetTo<MathConstants> mathConstants;/* MathConstants table */
-  OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
-  OffsetTo<MathVariants>  mathVariants;	/* MathVariants table */
+  FixedVersion<>version;	/* Version of the MATH table
+				 * initially set to 0x00010000u */
+  Offset16To<MathConstants>
+		mathConstants;	/* MathConstants table */
+  Offset16To<MathGlyphInfo>
+		mathGlyphInfo;	/* MathGlyphInfo table */
+  Offset16To<MathVariants>
+		mathVariants;	/* MathVariants table */
 
   public:
   DEFINE_SIZE_STATIC (10);
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 9d8c6e7..5781d25 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -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
  **/
@@ -142,7 +142,7 @@
  *
  * 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
  **/
diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h
index ad864a7..d3ffa19 100644
--- a/src/hb-ot-math.h
+++ b/src/hb-ot-math.h
@@ -24,7 +24,7 @@
  * Igalia Author(s): Frédéric Wang
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -40,18 +40,89 @@
  * MATH
  */
 
+/**
+ * HB_OT_TAG_MATH:
+ *
+ * OpenType [Mathematical Typesetting Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math).
+ *
+ * Since: 1.3.3
+ */
 #define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
 
-/* Use with hb_buffer_set_script() for math shaping. */
+/**
+ * HB_OT_MATH_SCRIPT:
+ *
+ * OpenType script tag for math shaping, for use with
+ * Use with hb_buffer_set_script().
+ *
+ * Since: 1.3.3
+ */
 #define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
 
 /* Types */
 
 /**
  * hb_ot_math_constant_t:
+ * @HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: scriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: scriptScriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: delimitedSubFormulaMinHeight
+ * @HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: displayOperatorMinHeight
+ * @HB_OT_MATH_CONSTANT_MATH_LEADING: mathLeading
+ * @HB_OT_MATH_CONSTANT_AXIS_HEIGHT: axisHeight
+ * @HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: accentBaseHeight
+ * @HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: flattenedAccentBaseHeight
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: subscriptShiftDown
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: subscriptTopMax
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: subscriptBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: superscriptShiftUp
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: superscriptShiftUpCramped
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: superscriptBottomMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: superscriptBaselineDropMax
+ * @HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: subSuperscriptGapMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: superscriptBottomMaxWithSubscript
+ * @HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: spaceAfterScript
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: upperLimitGapMin
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: upperLimitBaselineRiseMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: lowerLimitGapMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: lowerLimitBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: stackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: stackTopDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: stackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: stackBottomDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_GAP_MIN: stackGapMin
+ * @HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: stackDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: stretchStackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: stretchStackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: stretchStackGapAboveMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: stretchStackGapBelowMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: fractionNumeratorShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: fractionNumeratorDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: fractionDenominatorShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: fractionDenominatorDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: fractionNumeratorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: fractionNumDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: fractionRuleThickness
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: fractionDenominatorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: fractionDenomDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: skewedFractionHorizontalGap
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: skewedFractionVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: overbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: overbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: overbarExtraAscender
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: underbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: underbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: underbarExtraDescender
+ * @HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: radicalVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: radicalDisplayStyleVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: radicalRuleThickness
+ * @HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: radicalExtraAscender
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: radicalKernBeforeDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: radicalKernAfterDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: radicalDegreeBottomRaisePercent
  *
- * The 'MATH' table constants specified at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/math
+ * The 'MATH' table constants, refer to
+ * [OpenType documentation](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table)
+ * For more explanations.
  *
  * Since: 1.3.3
  */
@@ -116,6 +187,10 @@
 
 /**
  * hb_ot_math_kern_t:
+ * @HB_OT_MATH_KERN_TOP_RIGHT: The top right corner of the glyph.
+ * @HB_OT_MATH_KERN_TOP_LEFT: The top left corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_RIGHT: The bottom right corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_LEFT: The bottom left corner of the glyph.
  *
  * The math kerning-table types defined for the four corners
  * of a glyph.
@@ -145,6 +220,8 @@
 
 /**
  * hb_ot_math_glyph_part_flags_t:
+ * @HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER: This is an extender glyph part that
+ * can be repeated to reach the desired length.
  *
  * Flags for math glyph parts.
  *
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 1c25eda..3a019ef 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -107,7 +107,7 @@
       maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
       if (unlikely (!dest_v1)) return_trace (false);
 
-      if (c->plan->drop_hints)
+      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
 	drop_hint_fields (dest_v1);
     }
 
@@ -126,9 +126,10 @@
   }
 
   protected:
-  FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
-					 * 0x00005000u or 0x00010000u. */
-  HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
+  FixedVersion<>version;/* Version of the maxp table (0.5 or 1.0),
+			 * 0x00005000u or 0x00010000u. */
+  HBUINT16	numGlyphs;
+			/* The number of glyphs in the font. */
 /*maxpV1Tail	v1Tail[HB_VAR_ARRAY]; */
   public:
   DEFINE_SIZE_STATIC (6);
diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh
index 43a02d6..e31447f 100644
--- a/src/hb-ot-meta-table.hh
+++ b/src/hb-ot-meta-table.hh
@@ -56,7 +56,7 @@
 
   protected:
   Tag		tag;		/* A tag indicating the type of metadata. */
-  LOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		dataZ;		/* Offset in bytes from the beginning of the
 				 * metadata table to the data for this tag. */
   HBUINT32	dataLength;	/* Length of the data. The data is not required to
@@ -108,12 +108,13 @@
   protected:
   HBUINT32	version;	/* Version number of the metadata table — set to 1. */
   HBUINT32	flags;		/* Flags — currently unused; set to 0. */
-  HBUINT32	dataOffset;	/* Per Apple specification:
+  HBUINT32	dataOffset;
+				/* Per Apple specification:
 				 * Offset from the beginning of the table to the data.
 				 * Per OT specification:
 				 * Reserved. Not used; should be set to 0. */
-  LArrayOf<DataMap>
-		dataMaps;	/* Array of data map records. */
+  Array32Of<DataMap>
+		dataMaps;/* Array of data map records. */
   public:
   DEFINE_SIZE_ARRAY (16, dataMaps);
 };
diff --git a/src/hb-ot-meta.cc b/src/hb-ot-meta.cc
index a1e081b..35c8eb5 100644
--- a/src/hb-ot-meta.cc
+++ b/src/hb-ot-meta.cc
@@ -38,12 +38,14 @@
  **/
 
 /**
- * hb_ot_meta_reference_entry:
+ * hb_ot_meta_get_entry_tags:
  * @face: a face object
  * @start_offset: iteration's start offset
- * @entries_count:(inout) (allow-none): buffer size as input, filled size as output
+ * @entries_count:(inout) (optional): buffer size as input, filled size as output
  * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer
  *
+ * Fetches all available feature types.
+ *
  * Return value: Number of all available feature types.
  *
  * Since: 2.6.0
diff --git a/src/hb-ot-meta.h b/src/hb-ot-meta.h
index 0278d84..7748eb4 100644
--- a/src/hb-ot-meta.h
+++ b/src/hb-ot-meta.h
@@ -22,7 +22,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -54,6 +54,7 @@
   HB_OT_META_TAG_DESIGN_LANGUAGES	= HB_TAG ('d','l','n','g'),
   HB_OT_META_TAG_SUPPORTED_LANGUAGES	= HB_TAG ('s','l','n','g'),
 
+  /*< private >*/
   _HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_meta_tag_t;
 
diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc
index 181ac4d..72aeff8 100644
--- a/src/hb-ot-metrics.cc
+++ b/src/hb-ot-metrics.cc
@@ -33,6 +33,15 @@
 #include "hb-ot-face.hh"
 
 
+/**
+ * SECTION:hb-ot-metrics
+ * @title: hb-ot-metrics
+ * @short_description: OpenType Metrics
+ * @include: hb-ot.h
+ *
+ * Functions for fetching metrics from fonts.
+ **/
+
 static float
 _fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag)
 {
@@ -110,11 +119,11 @@
 
 /**
  * hb_ot_metrics_get_position:
- * @font: a #hb_font_t object.
+ * @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.
  *
- * It fetches metrics value corresponding to a given tag from a font.
+ * Fetches metrics value corresponding to @metrics_tag from @font.
  *
  * Returns: Whether found the requested metrics in the font.
  * Since: 2.6.0
@@ -184,10 +193,13 @@
 #ifndef HB_NO_VAR
 /**
  * hb_ot_metrics_get_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
  *
- * Returns:
+ * Fetches metrics value corresponding to @metrics_tag from @font with the
+ * current font variation settings applied.
+ *
+ * Returns: The requested metric value.
  *
  * Since: 2.6.0
  **/
@@ -199,10 +211,13 @@
 
 /**
  * hb_ot_metrics_get_x_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
  *
- * Returns:
+ * Fetches horizontal metrics value corresponding to @metrics_tag from @font
+ * with the current font variation settings applied.
+ *
+ * Returns: The requested metric value.
  *
  * Since: 2.6.0
  **/
@@ -214,10 +229,13 @@
 
 /**
  * hb_ot_metrics_get_y_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
  *
- * Returns:
+ * Fetches vertical metrics value corresponding to @metrics_tag from @font with
+ * the current font variation settings applied.
+ *
+ * Returns: The requested metric value.
  *
  * Since: 2.6.0
  **/
diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h
index 42c7363..5841fc8 100644
--- a/src/hb-ot-metrics.h
+++ b/src/hb-ot-metrics.h
@@ -22,7 +22,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -66,7 +66,8 @@
  * @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size.
  * @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset.
  *
- * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags
+ * Metric tags corresponding to [MVAR Value
+ * Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags)
  *
  * Since: 2.6.0
  **/
@@ -100,6 +101,7 @@
   HB_OT_METRICS_TAG_UNDERLINE_SIZE		= HB_TAG ('u','n','d','s'),
   HB_OT_METRICS_TAG_UNDERLINE_OFFSET		= HB_TAG ('u','n','d','o'),
 
+  /*< private >*/
   _HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_metrics_tag_t;
 
diff --git a/src/hb-ot-name-language-static.hh b/src/hb-ot-name-language-static.hh
index 580e763..c496dc2 100644
--- a/src/hb-ot-name-language-static.hh
+++ b/src/hb-ot-name-language-static.hh
@@ -37,12 +37,8 @@
 
 struct hb_ot_language_map_t
 {
-  static int cmp (const void *key, const void *item)
-  {
-    unsigned int a = * (unsigned int *) key;
-    unsigned int b = ((const hb_ot_language_map_t *) item)->code;
-    return a < b ? -1 : a > b ? +1 : 0;
-  }
+  int cmp (unsigned int key) const
+  { return key < code ? -1 : key > code ? +1 : 0; }
 
   uint16_t	code;
   char		lang[6];
@@ -433,12 +429,7 @@
 #ifdef HB_NO_OT_NAME_LANGUAGE
   return HB_LANGUAGE_INVALID;
 #endif
-  const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *)
-				      hb_bsearch (&code,
-						  array,
-						  len,
-						  sizeof (array[0]),
-						  hb_ot_language_map_t::cmp);
+  auto *entry = hb_bsearch (code, array, len);
 
   if (entry)
     return hb_language_from_string (entry->lang, -1);
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 84be04c..c17bb4a 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -97,17 +97,47 @@
     return UNSUPPORTED;
   }
 
-  NameRecord* copy (hb_serialize_context_t *c,
-		    const void *src_base,
-		    const void *dst_base) const
+  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, src_base, dst_base, length);
+    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);
@@ -119,7 +149,7 @@
   HBUINT16	languageID;	/* Language ID. */
   HBUINT16	nameID;		/* Name ID. */
   HBUINT16	length;		/* String length (in bytes). */
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
 		offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -134,7 +164,7 @@
   /* Compare by name_id, then language. */
 
   if (a->name_id != b->name_id)
-    return a->name_id < b->name_id ? -1 : +1;
+    return a->name_id - b->name_id;
 
   if (a->language == b->language) return 0;
   if (!a->language) return -1;
@@ -156,10 +186,10 @@
   const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
 
   if (a->entry_score != b->entry_score)
-    return a->entry_score < b->entry_score ? -1 : +1;
+    return a->entry_score - b->entry_score;
 
   if (a->entry_index != b->entry_index)
-    return a->entry_index < b->entry_index ? -1 : +1;
+    return a->entry_index - b->entry_index;
 
   return 0;
 }
@@ -184,18 +214,26 @@
     this->format = 0;
     this->count = it.len ();
 
-    auto snap = c->snapshot ();
-    this->nameRecordZ.serialize (c, this->count);
-    if (unlikely (!c->check_assign (this->stringOffset, c->length ()))) return_trace (false);
-    c->revert (snap);
+    NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
+    if (unlikely (!name_records)) return_trace (false);
 
-    const void *dst_string_pool = &(this + this->stringOffset);
+    hb_array_t<NameRecord> records (name_records, it.len ());
 
-    for (const auto &_ : it) c->copy (_, src_string_pool, dst_string_pool);
+    for (const NameRecord& record : it)
+    {
+      memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
 
-    if (unlikely (c->ran_out_of_room)) return_trace (false);
+    records.qsort ();
 
-    assert (this->stringOffset == c->length ());
+    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);
   }
@@ -210,6 +248,12 @@
     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, hb_addressof (this + stringOffset));
@@ -237,7 +281,7 @@
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<name> (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;
@@ -281,16 +325,14 @@
       this->table.destroy ();
     }
 
-    int get_index (hb_ot_name_id_t   name_id,
-			  hb_language_t     language,
-			  unsigned int     *width=nullptr) const
+    int get_index (hb_ot_name_id_t  name_id,
+		   hb_language_t    language,
+		   unsigned int    *width=nullptr) const
     {
       const hb_ot_name_entry_t key = {name_id, {0}, language};
-      const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
-					hb_bsearch (&key,
-						    (const hb_ot_name_entry_t *) this->names,
+      const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
 						    this->names.length,
-						    sizeof (key),
+						    sizeof (hb_ot_name_entry_t),
 						    _hb_ot_name_entry_cmp_key);
       if (!entry)
 	return -1;
@@ -318,12 +360,12 @@
   };
 
   /* We only implement format 0 for now. */
-  HBUINT16	format;			/* Format selector (=0/1). */
-  HBUINT16	count;			/* Number of name records. */
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
-		stringOffset;		/* Offset to start of string storage (from start of table). */
+  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. */
+		nameRecordZ;	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecordZ);
 };
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index 10122b8..eff46ef 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -46,7 +46,7 @@
 /**
  * hb_ot_name_list_names:
  * @face: font face.
- * @num_entries: (out) (allow-none): number of returned entries.
+ * @num_entries: (out) (optional): number of returned entries.
  *
  * Enumerates all available name IDs and language combinations. Returned
  * array is owned by the @face and should not be modified.  It can be
@@ -150,13 +150,14 @@
  * @face: font face.
  * @name_id: OpenType name identifier to fetch.
  * @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
  *                                   text written to buffer.
  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-8 encoding.
+ * Returns string in UTF-8 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -177,13 +178,14 @@
  * @face: font face.
  * @name_id: OpenType name identifier to fetch.
  * @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
  *                                   text written to buffer.
  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-16 encoding.
+ * Returns string in UTF-16 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -203,13 +205,14 @@
  * @face: font face.
  * @name_id: OpenType name identifier to fetch.
  * @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
  *                                   text written to buffer.
  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-32 encoding.
+ * Returns string in UTF-32 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
diff --git a/src/hb-ot-name.h b/src/hb-ot-name.h
index 3b4ad58..1ea4b55 100644
--- a/src/hb-ot-name.h
+++ b/src/hb-ot-name.h
@@ -22,7 +22,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -36,12 +36,42 @@
 
 /**
  * hb_ot_name_id_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
+ * @HB_OT_NAME_ID_UNIQUE_ID: Unique font identifier
+ * @HB_OT_NAME_ID_FULL_NAME: Full font name that reflects
+ * all family and relevant subfamily descriptors
+ * @HB_OT_NAME_ID_VERSION_STRING: Version string
+ * @HB_OT_NAME_ID_POSTSCRIPT_NAME: PostScript name for the font
+ * @HB_OT_NAME_ID_TRADEMARK: Trademark
+ * @HB_OT_NAME_ID_MANUFACTURER: Manufacturer Name
+ * @HB_OT_NAME_ID_DESIGNER: Designer
+ * @HB_OT_NAME_ID_DESCRIPTION: Description
+ * @HB_OT_NAME_ID_VENDOR_URL: URL of font vendor
+ * @HB_OT_NAME_ID_DESIGNER_URL: URL of typeface designer
+ * @HB_OT_NAME_ID_LICENSE: License Description
+ * @HB_OT_NAME_ID_LICENSE_URL: URL where additional licensing
+ * information can be found
+ * @HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY: Typographic Family name
+ * @HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: Typographic Subfamily name
+ * @HB_OT_NAME_ID_MAC_FULL_NAME: Compatible Full Name for MacOS
+ * @HB_OT_NAME_ID_SAMPLE_TEXT: Sample text
+ * @HB_OT_NAME_ID_CID_FINDFONT_NAME: PostScript CID findfont name
+ * @HB_OT_NAME_ID_WWS_FAMILY: WWS Family Name
+ * @HB_OT_NAME_ID_WWS_SUBFAMILY: WWS Subfamily Name
+ * @HB_OT_NAME_ID_LIGHT_BACKGROUND: Light Background Palette
+ * @HB_OT_NAME_ID_DARK_BACKGROUND: Dark Background Palette
+ * @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.
  *
+ * 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
  **/
 enum
@@ -88,8 +118,7 @@
  *
  * Since: 2.1.0
  **/
-typedef struct hb_ot_name_entry_t
-{
+typedef struct hb_ot_name_entry_t {
   hb_ot_name_id_t name_id;
   /*< private >*/
   hb_var_int_t    var;
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index f6b1503..f0035e2 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -171,7 +171,11 @@
     TRACE_SUBSET (this);
     OS2 *os2_prime = c->serializer->embed (this);
     if (unlikely (!os2_prime)) return_trace (false);
+    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;
@@ -216,19 +220,20 @@
 					  uint16_t *min_cp, /* OUT */
 					  uint16_t *max_cp  /* OUT */)
   {
-    *min_cp = codepoints->get_min ();
-    *max_cp = codepoints->get_max ();
+    *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 */
-  enum font_page_t {
-    HEBREW_FONT_PAGE		= 0xB100, // Hebrew Windows 3.1 font page
-    SIMP_ARABIC_FONT_PAGE	= 0xB200, // Simplified Arabic Windows 3.1 font page
-    TRAD_ARABIC_FONT_PAGE	= 0xB300, // Traditional Arabic Windows 3.1 font page
-    OEM_ARABIC_FONT_PAGE	= 0xB400, // OEM Arabic Windows 3.1 font page
-    SIMP_FARSI_FONT_PAGE	= 0xBA00, // Simplified Farsi Windows 3.1 font page
-    TRAD_FARSI_FONT_PAGE	= 0xBB00, // Traditional Farsi Windows 3.1 font page
-    THAI_FONT_PAGE		= 0xDE00  // Thai Windows 3.1 font page
+  enum font_page_t
+  {
+    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 */
+    FONT_PAGE_OEM_ARABIC	= 0xB400, /* OEM Arabic Windows 3.1 font page */
+    FONT_PAGE_SIMP_FARSI	= 0xBA00, /* Simplified Farsi Windows 3.1 font page */
+    FONT_PAGE_TRAD_FARSI	= 0xBB00, /* Traditional Farsi Windows 3.1 font page */
+    FONT_PAGE_THAI		= 0xDE00  /* Thai Windows 3.1 font page */
   };
   font_page_t get_font_page () const
   { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh
index b0ccd00..9613d2d 100644
--- a/src/hb-ot-os2-unicode-ranges.hh
+++ b/src/hb-ot-os2-unicode-ranges.hh
@@ -33,19 +33,8 @@
 
 struct OS2Range
 {
-  static int
-  cmp (const void *_key, const void *_item)
-  {
-    hb_codepoint_t cp = *((hb_codepoint_t *) _key);
-    const OS2Range *range = (OS2Range *) _item;
-
-    if (cp < range->start)
-      return -1;
-    else if (cp <= range->end)
-      return 0;
-    else
-      return +1;
-  }
+  int cmp (hb_codepoint_t key) const
+  { return (key < start) ? -1 : key <= end ? 0 : +1; }
 
   hb_codepoint_t start;
   hb_codepoint_t end;
@@ -233,13 +222,8 @@
 static unsigned int
 _hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
 {
-  OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges,
-					    ARRAY_LENGTH (_hb_os2_unicode_ranges),
-					    sizeof (OS2Range),
-					    OS2Range::cmp);
-  if (range != nullptr)
-    return range->bit;
-  return -1;
+  auto *range = hb_sorted_array (_hb_os2_unicode_ranges).bsearch (cp);
+  return range ? range->bit : -1;
 }
 
 } /* namespace OT */
diff --git a/src/hb-ot-post-table-v2subset.hh b/src/hb-ot-post-table-v2subset.hh
new file mode 100644
index 0000000..94450eb
--- /dev/null
+++ b/src/hb-ot-post-table-v2subset.hh
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2021  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_POST_TABLE_V2SUBSET_HH
+#define HB_OT_POST_TABLE_V2SUBSET_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-post-table.hh"
+
+/*
+ * post -- PostScript
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/post
+ */
+
+namespace OT {
+template<typename Iterator>
+HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
+                                        Iterator it,
+                                        const void* _post) const
+{
+  TRACE_SERIALIZE (this);
+  auto *out = c->start_embed (this);
+  if (unlikely (!c->check_success (out))) return_trace (false);
+  if (!out->glyphNameIndex.serialize (c, + it
+                                         | hb_map (hb_second)))
+      return_trace (false);
+
+  hb_set_t copied_indices;
+  for (const auto& _ : + it )
+  {
+    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);
+  }
+
+  return_trace (true);
+}
+
+HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
+{
+  TRACE_SUBSET (this);
+
+  const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+  unsigned num_glyphs = c->plan->num_output_glyphs ();
+  hb_map_t old_new_index_map, old_gid_new_index_map;
+  unsigned i = 0;
+
+  post::accelerator_t _post;
+  _post.init (c->plan->source);
+
+  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);
+    else
+    {
+      hb_bytes_t s = _post.find_glyph_name (old_gid);
+      int standard_glyph_index = -1;
+      for (unsigned i = 0; i < format1_names_length; i++)
+      {
+        if (s == format1_names (i))
+        {
+          standard_glyph_index = i;
+          break;
+        }
+      }
+      if (standard_glyph_index == -1)
+      {
+        new_index = 258 + i;
+        i++;
+      }
+      else
+      { new_index = standard_glyph_index; }
+      old_new_index_map.set (old_index, new_index);
+    }
+    old_gid_new_index_map.set (old_gid, new_index);
+  }
+
+  auto index_iter =
+  + hb_range (num_glyphs)
+  | hb_map (reverse_glyph_map)
+  | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
+                            {
+                              unsigned new_index = old_gid_new_index_map.get (old_gid);
+                              return hb_pair_t<unsigned, unsigned> (old_gid, new_index);
+                            })
+  ;
+
+  bool ret = serialize (c->serializer, index_iter, &_post);
+  _post.fini ();
+  return_trace (ret);
+}
+
+} /* namespace OT */
+#endif /* HB_OT_POST_TABLE_V2SUBSET_HH */
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 38302f5..39de671 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -35,8 +35,6 @@
 #undef HB_STRING_ARRAY_LIST
 #undef HB_STRING_ARRAY_NAME
 
-#define NUM_FORMAT1_NAMES 258
-
 /*
  * post -- PostScript
  * https://docs.microsoft.com/en-us/typography/opentype/spec/post
@@ -57,8 +55,15 @@
     return_trace (glyphNameIndex.sanitize (c));
   }
 
+  template<typename Iterator>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  const void* _post) const;
+
+  bool subset (hb_subset_context_t *c) const;
+
   protected:
-  ArrayOf<HBUINT16>	glyphNameIndex;	/* This is not an offset, but is the
+  Array16Of<HBUINT16>	glyphNameIndex;	/* This is not an offset, but is the
 					 * ordinal number of the glyph in 'post'
 					 * string tables. */
 /*UnsizedArrayOf<HBUINT8>
@@ -73,13 +78,18 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
-  void serialize (hb_serialize_context_t *c) const
+  bool serialize (hb_serialize_context_t *c, bool glyph_names) const
   {
+    TRACE_SERIALIZE (this);
     post *post_prime = c->allocate_min<post> ();
-    if (unlikely (!post_prime))  return;
+    if (unlikely (!post_prime))  return_trace (false);
 
     memcpy (post_prime, this, post::min_size);
-    post_prime->version.major = 3; // Version 3 does not have any glyph names.
+    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.
+
+    return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -88,14 +98,19 @@
     post *post_prime = c->serializer->start_embed<post> ();
     if (unlikely (!post_prime)) return_trace (false);
 
-    serialize (c->serializer);
-    if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
+    bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
+    if (!serialize (c->serializer, glyph_names))
+      return_trace (false);
+
+    if (glyph_names && version.major == 2)
+      return_trace (v2X.subset (c));
 
     return_trace (true);
   }
 
   struct accelerator_t
   {
+    friend struct postV2Tail;
     void init (hb_face_t *face)
     {
       index_to_offset.init ();
@@ -120,7 +135,7 @@
     void fini ()
     {
       index_to_offset.fini ();
-      free (gids_sorted_by_name.get ());
+      hb_free (gids_sorted_by_name.get ());
       table.destroy ();
     }
 
@@ -151,7 +166,7 @@
 
       if (unlikely (!gids))
       {
-	gids = (uint16_t *) malloc (count * sizeof (gids[0]));
+	gids = (uint16_t *) hb_malloc (count * sizeof (gids[0]));
 	if (unlikely (!gids))
 	  return false; /* Anything better?! */
 
@@ -161,14 +176,13 @@
 
 	if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
 	{
-	  free (gids);
+	  hb_free (gids);
 	  goto retry;
 	}
       }
 
       hb_bytes_t st (name, len);
-      const uint16_t *gid = (const uint16_t *) hb_bsearch (hb_addressof (st), gids, count,
-							   sizeof (gids[0]), cmp_key, (void *) this);
+      auto* gid = hb_bsearch (st, gids, count, sizeof (gids[0]), cmp_key, (void *) this);
       if (gid)
       {
 	*glyph = *gid;
@@ -185,7 +199,7 @@
     unsigned int get_glyph_count () const
     {
       if (version == 0x00010000)
-	return NUM_FORMAT1_NAMES;
+	return format1_names_length;
 
       if (version == 0x00020000)
 	return glyphNameIndex->len;
@@ -213,7 +227,7 @@
     {
       if (version == 0x00010000)
       {
-	if (glyph >= NUM_FORMAT1_NAMES)
+	if (glyph >= format1_names_length)
 	  return hb_bytes_t ();
 
 	return format1_names (glyph);
@@ -223,9 +237,9 @@
 	return hb_bytes_t ();
 
       unsigned int index = glyphNameIndex->arrayZ[glyph];
-      if (index < NUM_FORMAT1_NAMES)
+      if (index < format1_names_length)
 	return format1_names (index);
-      index -= NUM_FORMAT1_NAMES;
+      index -= format1_names_length;
 
       if (index >= index_to_offset.length)
 	return hb_bytes_t ();
@@ -240,7 +254,7 @@
 
     private:
     uint32_t version;
-    const ArrayOf<HBUINT16> *glyphNameIndex;
+    const Array16Of<HBUINT16> *glyphNameIndex;
     hb_vector_t<uint32_t> index_to_offset;
     const uint8_t *pool;
     hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
@@ -262,7 +276,7 @@
 					 * 0x00020000 for version 2.0
 					 * 0x00025000 for version 2.5 (deprecated)
 					 * 0x00030000 for version 3.0 */
-  HBFixed		italicAngle;		/* Italic angle in counter-clockwise degrees
+  HBFixed	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-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 2a7a8eb..78f46c1 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -49,8 +49,8 @@
 					  hb_font_t *font,
 					  unsigned int feature_index)
 {
-  OT::HBGlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
-  OT::HBGlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID16 glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID16 substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
   unsigned int num_glyphs = 0;
 
   /* Populate arrays */
@@ -78,7 +78,7 @@
   /* Bubble-sort or something equally good!
    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
   hb_stable_sort (&glyphs[0], num_glyphs,
-		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp,
 		  &substitutes[0]);
 
 
@@ -92,22 +92,22 @@
 				       hb_array (substitutes, num_glyphs));
   c.end_serialize ();
 
-  return ret ? c.copy<OT::SubstLookup> () : nullptr;
+  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
 					    hb_font_t *font)
 {
-  OT::HBGlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
+  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 */
-  OT::HBGlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
+  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::HBGlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
   unsigned int num_ligatures = 0;
 
   /* Populate arrays */
@@ -125,7 +125,7 @@
     num_first_glyphs++;
   }
   hb_stable_sort (&first_glyphs[0], num_first_glyphs,
-		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp,
 		  &first_glyphs_indirection[0]);
 
   /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
@@ -170,7 +170,7 @@
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : nullptr;
+  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
@@ -208,11 +208,11 @@
 {
   public:
   OT::Tag tag;
-  OT::OffsetTo<OT::SubstLookup> lookupOffset;
+  OT::Offset16To<OT::SubstLookup> lookupOffset;
   public:
   DEFINE_SIZE_STATIC (6);
 };
-typedef OT::ArrayOf<ManifestLookup> Manifest;
+typedef OT::Array16Of<ManifestLookup> Manifest;
 
 static bool
 arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
@@ -290,9 +290,9 @@
 arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
 			     hb_font_t *font)
 {
-  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_calloc (1, sizeof (arabic_fallback_plan_t));
   if (unlikely (!fallback_plan))
-    return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
+    return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 
   fallback_plan->num_lookups = 0;
   fallback_plan->free_lookups = false;
@@ -308,8 +308,8 @@
     return fallback_plan;
 
   assert (fallback_plan->num_lookups == 0);
-  free (fallback_plan);
-  return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
+  hb_free (fallback_plan);
+  return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 }
 
 static void
@@ -323,10 +323,10 @@
     {
       fallback_plan->accel_array[i].fini ();
       if (fallback_plan->free_lookups)
-	free (fallback_plan->lookup_array[i]);
+	hb_free (fallback_plan->lookup_array[i]);
     }
 
-  free (fallback_plan);
+  hb_free (fallback_plan);
 }
 
 static void
diff --git a/src/hb-ot-shape-complex-arabic-joining-list.hh b/src/hb-ot-shape-complex-arabic-joining-list.hh
new file mode 100644
index 0000000..e6339ee
--- /dev/null
+++ b/src/hb-ot-shape-complex-arabic-joining-list.hh
@@ -0,0 +1,47 @@
+/* == Start of generated function == */
+/*
+ * The following function is generated by running:
+ *
+ *   ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt
+ *
+ * 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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+
+static bool
+has_arabic_joining (hb_script_t script)
+{
+  /* List of scripts that have data in arabic-table. */
+  switch ((int) script)
+  {
+    case HB_SCRIPT_ADLAM:
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_HANIFI_ROHINGYA:
+    case HB_SCRIPT_MANDAIC:
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_OLD_UYGHUR:
+    case HB_SCRIPT_PHAGS_PA:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+    case HB_SCRIPT_SOGDIAN:
+    case HB_SCRIPT_SYRIAC:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */
+
+/* == End of generated function == */
diff --git a/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shape-complex-arabic-table.hh
index 719fabd..c158964 100644
--- a/src/hb-ot-shape-complex-arabic-table.hh
+++ b/src/hb-ot-shape-complex-arabic-table.hh
@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-12.0.0.txt
- * # Date: 2018-09-22, 23:54:00 GMT [KW, RP]
- * # Blocks-12.0.0.txt
- * # Date: 2018-07-30, 19:40:00 GMT [KW]
+ * # 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]
  * UnicodeData.txt does not have a header.
  */
 
@@ -17,15 +17,15 @@
 #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 
 
-#define X	JOINING_TYPE_X
+#define A	JOINING_GROUP_ALAPH
+#define DR	JOINING_GROUP_DALATH_RISH
+#define C	JOINING_TYPE_C
+#define D	JOINING_TYPE_D
+#define L	JOINING_TYPE_L
 #define R	JOINING_TYPE_R
 #define T	JOINING_TYPE_T
 #define U	JOINING_TYPE_U
-#define A	JOINING_GROUP_ALAPH
-#define DR	JOINING_GROUP_DALATH_RISH
-#define L	JOINING_TYPE_L
-#define C	JOINING_TYPE_C
-#define D	JOINING_TYPE_D
+#define X	JOINING_TYPE_X
 
 static const uint8_t joining_table[] =
 {
@@ -71,17 +71,21 @@
 
   /* Mandaic */
 
-  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
+  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,R,R,R,X,X,X,X,X,X,X,
 
   /* Syriac Supplement */
 
-  /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
-  /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,
+
+  /* Arabic Extended-B */
+
+  /* 0860 */                                 R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,
+  /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
   /* Arabic Extended-A */
 
-  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,X,X,
-  /* 08C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,D,D,D,D,R,D,D,D,D,D,D,
+  /* 08C0 */ D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
   /* 08E0 */ X,X,U,
 
 #define joining_offset_0x1806u 739
@@ -137,16 +141,28 @@
   /* Sogdian */
 
   /* 10F20 */                                 D,D,D,R,D,D,D,D,D,D,D,D,D,D,D,D,
-  /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,
+  /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10F60 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
-#define joining_offset_0x110bdu 1219
+  /* Old Uyghur */
+
+  /* 10F60 */                                 D,D,D,D,R,R,D,D,D,D,D,D,D,D,D,D,
+  /* 10F80 */ D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10FA0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Chorasmian */
+
+  /* 10FA0 */                                 D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
+  /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
+
+#define joining_offset_0x110bdu 1338
 
   /* Kaithi */
 
   /* 110A0 */                                                           U,X,X,
   /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
 
-#define joining_offset_0x1e900u 1236
+#define joining_offset_0x1e900u 1355
 
   /* Adlam */
 
@@ -154,7 +170,7 @@
   /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1312; occupancy: 56% */
+}; /* Table items: 1431; occupancy: 57% */
 
 
 static unsigned int
@@ -182,7 +198,7 @@
       if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10F54u)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
       break;
 
     case 0x11u:
@@ -199,15 +215,15 @@
   return X;
 }
 
-#undef X
+#undef A
+#undef DR
+#undef C
+#undef D
+#undef L
 #undef R
 #undef T
 #undef U
-#undef A
-#undef DR
-#undef L
-#undef C
-#undef D
+#undef X
 
 
 static const uint16_t shaping_table[][4] =
@@ -406,16 +422,16 @@
 } ligature_table[] =
 {
   { 0xFEDFu, {
-    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
     { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
-    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF 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, {
-    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
     { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
-    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF 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 */
   }},
 };
 
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
index b15e145..41e3dd3 100644
--- a/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -142,7 +142,7 @@
 		OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
 	) \
 	OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
-	/* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+	/* static_assert_expr (len(FromGlyphs) == len(ToGlyphs)) */
 
 #define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
 	OT_SUBLOOKUP(Name, 1, \
@@ -151,7 +151,7 @@
 		OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
 	) \
 	OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
-	/* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+	/* static_assert_expr (len(FirstGlyphs) == len(LigatureSetOffsets)) */
 
 #define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
 	OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index f92e637..222c5d6 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -33,7 +33,7 @@
 
 
 /* buffer var allocations */
-#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */
 
 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
 
@@ -228,8 +228,6 @@
   map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
   map->add_gsub_pause (nullptr);
 
-  /* And undo here. */
-
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
    * that Windows 8 and later do not enable it by default,
@@ -261,7 +259,7 @@
 void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
-  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) hb_calloc (1, sizeof (arabic_shape_plan_t));
   if (unlikely (!arabic_plan))
     return nullptr;
 
@@ -271,7 +269,7 @@
     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
     arabic_plan->do_fallback = arabic_plan->do_fallback &&
 			       (FEATURE_IS_SYRIAC (arabic_features[i]) ||
-			        plan->map.needs_fallback (arabic_features[i]));
+				plan->map.needs_fallback (arabic_features[i]));
   }
 
   return arabic_plan;
@@ -284,7 +282,7 @@
 
   arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
 
-  free (data);
+  hb_free (data);
 }
 
 static void
@@ -292,7 +290,7 @@
 {
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
-  unsigned int prev = (unsigned int) -1, state = 0;
+  unsigned int prev = UINT_MAX, state = 0;
 
   /* Check pre-context */
   for (unsigned int i = 0; i < buffer->context_len[0]; i++)
@@ -318,7 +316,7 @@
 
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
 
-    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+    if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
       buffer->unsafe_to_break (prev, i + 1);
@@ -338,7 +336,7 @@
       continue;
 
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
-    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+    if (entry->prev_action != NONE && prev != UINT_MAX)
       info[prev].arabic_shaping_action() = entry->prev_action;
     break;
   }
@@ -351,7 +349,7 @@
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du)))
+    if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du, 0x180Fu, 0x180Fu)))
       info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
 }
 
@@ -604,7 +602,7 @@
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
-/* http://www.unicode.org/reports/tr53/ */
+/* https://www.unicode.org/reports/tr53/ */
 
 static hb_codepoint_t
 modifier_combining_marks[] =
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index a921f16..a755aea 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -49,5 +49,25 @@
   true, /* fallback_position */
 };
 
+/* 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 =
+{
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  HB_TAG_NONE, /* gpos_tag */
+  nullptr, /* reorder_marks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
+
 
 #endif
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index f5915f4..0d84a76 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -80,7 +80,7 @@
 static void *
 data_create_hangul (const hb_ot_shape_plan_t *plan)
 {
-  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
+  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) hb_calloc (1, sizeof (hangul_shape_plan_t));
   if (unlikely (!hangul_plan))
     return nullptr;
 
@@ -93,7 +93,7 @@
 static void
 data_destroy_hangul (void *data)
 {
-  free (data);
+  hb_free (data);
 }
 
 /* Constants for algorithmic hangul syllable [de]composition. */
@@ -119,7 +119,7 @@
 #define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
 
 /* buffer var allocations */
-#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */
 
 static bool
 is_zero_width_char (hb_font_t *font,
@@ -205,7 +205,7 @@
       {
 	/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
 	buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
-	buffer->next_glyph ();
+	if (unlikely (!buffer->next_glyph ())) break;
 	if (!is_zero_width_char (font, u))
 	{
 	  buffer->merge_out_clusters (start, end + 1);
@@ -218,23 +218,25 @@
       else
       {
 	/* No valid syllable as base for tone mark; try to insert dotted circle. */
-      if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
-	  font->has_glyph (0x25CCu))
+	if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
+	    font->has_glyph (0x25CCu))
 	{
 	  hb_codepoint_t chars[2];
-	  if (!is_zero_width_char (font, u)) {
+	  if (!is_zero_width_char (font, u))
+	  {
 	    chars[0] = u;
 	    chars[1] = 0x25CCu;
-	  } else {
+	  } else
+	  {
 	    chars[0] = 0x25CCu;
 	    chars[1] = u;
 	  }
-	  buffer->replace_glyphs (1, 2, chars);
+	  (void) buffer->replace_glyphs (1, 2, chars);
 	}
 	else
 	{
 	  /* No dotted circle available in the font; just leave tone mark untouched. */
-	  buffer->next_glyph ();
+	  (void) buffer->next_glyph ();
 	}
       }
       start = end = buffer->out_len;
@@ -271,9 +273,7 @@
 	  hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
 	  if (font->has_glyph (s))
 	  {
-	    buffer->replace_glyphs (t ? 3 : 2, 1, &s);
-	    if (unlikely (!buffer->successful))
-	      return;
+	    (void) buffer->replace_glyphs (t ? 3 : 2, 1, &s);
 	    end = start + 1;
 	    continue;
 	  }
@@ -285,17 +285,19 @@
 	 * Set jamo features on the individual glyphs, and advance past them.
 	 */
 	buffer->cur().hangul_shaping_feature() = LJMO;
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	buffer->cur().hangul_shaping_feature() = VJMO;
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (t)
 	{
 	  buffer->cur().hangul_shaping_feature() = TJMO;
-	  buffer->next_glyph ();
+	  (void) buffer->next_glyph ();
 	  end = start + 3;
 	}
 	else
 	  end = start + 2;
+	if (unlikely (!buffer->successful))
+	  break;
 	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
 	  buffer->merge_out_clusters (start, end);
 	continue;
@@ -321,9 +323,7 @@
 	hb_codepoint_t new_s = s + new_tindex;
 	if (font->has_glyph (new_s))
 	{
-	  buffer->replace_glyphs (2, 1, &new_s);
-	  if (unlikely (!buffer->successful))
-	    return;
+	  (void) buffer->replace_glyphs (2, 1, &new_s);
 	  end = start + 1;
 	  continue;
 	}
@@ -347,19 +347,18 @@
 	    (!tindex || font->has_glyph (decomposed[2])))
 	{
 	  unsigned int s_len = tindex ? 3 : 2;
-	  buffer->replace_glyphs (1, s_len, decomposed);
+	  (void) buffer->replace_glyphs (1, s_len, decomposed);
 
 	  /* If we decomposed an LV because of a non-combining T following,
 	   * we want to include this T in the syllable.
 	   */
 	  if (has_glyph && !tindex)
 	  {
-	    buffer->next_glyph ();
+	    (void) buffer->next_glyph ();
 	    s_len++;
 	  }
-
 	  if (unlikely (!buffer->successful))
-	    return;
+	    break;
 
 	  /* We decomposed S: apply jamo features to the individual glyphs
 	   * that are now in buffer->out_info.
@@ -383,17 +382,15 @@
 
       if (has_glyph)
       {
-	/* We didn't decompose the S, so just advance past it. */
+	/* We didn't decompose the S, so just advance past it and fall through. */
 	end = start + 1;
-	buffer->next_glyph ();
-	continue;
       }
     }
 
     /* Didn't find a recognizable syllable, so we leave end <= start;
      * this will prevent tone-mark reordering happening.
      */
-    buffer->next_glyph ();
+    (void) buffer->next_glyph ();
   }
   buffer->swap_buffers ();
 }
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
index 670b6bf..74bf3ca 100644
--- a/src/hb-ot-shape-complex-indic-machine.hh
+++ b/src/hb-ot-shape-complex-indic-machine.hh
@@ -31,8 +31,37 @@
 
 #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 36 "hb-ot-shape-complex-indic-machine.hh"
+
+#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, 
@@ -384,18 +413,18 @@
 static const int indic_syllable_machine_en_main = 39;
 
 
-#line 36 "hb-ot-shape-complex-indic-machine.rl"
+#line 46 "hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 93 "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) | indic_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
@@ -407,7 +436,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 411 "hb-ot-shape-complex-indic-machine.hh"
+#line 440 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
@@ -415,7 +444,7 @@
 	act = 0;
 	}
 
-#line 113 "hb-ot-shape-complex-indic-machine.rl"
+#line 122 "hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
@@ -423,7 +452,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 427 "hb-ot-shape-complex-indic-machine.hh"
+#line 456 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -437,7 +466,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 441 "hb-ot-shape-complex-indic-machine.hh"
+#line 470 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -460,64 +489,64 @@
 	{te = p+1;}
 	break;
 	case 11:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p+1;{ found_syllable (indic_non_indic_cluster); }}
 	break;
 	case 13:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_consonant_syllable); }}
 	break;
 	case 14:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_vowel_syllable); }}
 	break;
 	case 17:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_standalone_cluster); }}
 	break;
 	case 19:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_symbol_cluster); }}
 	break;
 	case 15:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_broken_cluster); }}
 	break;
 	case 16:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p;p--;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
 	break;
 	case 1:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
 	break;
 	case 3:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
 	break;
 	case 7:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
 	break;
 	case 8:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
 	break;
 	case 4:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+#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 (consonant_syllable); }
+	{{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
 	break;
 	case 5:
-	{{p = ((te))-1;} found_syllable (broken_cluster); }
+	{{p = ((te))-1;} found_syllable (indic_broken_cluster); }
 	break;
 	case 6:
-	{{p = ((te))-1;} found_syllable (non_indic_cluster); }
+	{{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
 	break;
 	}
 	}
@@ -525,22 +554,22 @@
 	case 18:
 #line 1 "NONE"
 	{te = p+1;}
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 1;}
 	break;
 	case 5:
 #line 1 "NONE"
 	{te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 5;}
 	break;
 	case 12:
 #line 1 "NONE"
 	{te = p+1;}
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 6;}
 	break;
-#line 544 "hb-ot-shape-complex-indic-machine.hh"
+#line 573 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 _again:
@@ -549,7 +578,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 553 "hb-ot-shape-complex-indic-machine.hh"
+#line 582 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -565,7 +594,7 @@
 
 	}
 
-#line 121 "hb-ot-shape-complex-indic-machine.rl"
+#line 130 "hb-ot-shape-complex-indic-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 5f819bd..df9583f 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -29,32 +29,41 @@
 
 #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,
+};
+
 %%{
   machine indic_syllable_machine;
   alphtype unsigned char;
+  write exports;
   write data;
 }%%
 
 %%{
 
-# Same order as enum indic_category_t.  Not sure how to avoid duplication.
-C    = 1;
-V    = 2;
-N    = 3;
-H    = 4;
-ZWNJ = 5;
-ZWJ  = 6;
-M    = 7;
-SM   = 8;
-A    = 10;
-PLACEHOLDER = 11;
-DOTTEDCIRCLE = 12;
-RS    = 13;
-Repha = 15;
-Ra    = 16;
-CM    = 17;
-Symbol= 18;
-CS    = 19;
+export C    = 1;
+export V    = 2;
+export N    = 3;
+export H    = 4;
+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;
 
 c = (C | Ra);			# is_consonant
 n = ((ZWNJ?.RS)? (N.N?)?);	# is_consonant_modifier
@@ -76,17 +85,17 @@
 consonant_syllable =	(Repha|CS)? cn complex_syllable_tail;
 vowel_syllable =	reph? V.n? (ZWJ | complex_syllable_tail);
 standalone_cluster =	((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? complex_syllable_tail;
-symbol_cluster = 	symbol syllable_tail;
+symbol_cluster =	symbol syllable_tail;
 broken_cluster =	reph? n? complex_syllable_tail;
 other =			any;
 
 main := |*
-	consonant_syllable	=> { found_syllable (consonant_syllable); };
-	vowel_syllable		=> { found_syllable (vowel_syllable); };
-	standalone_cluster	=> { found_syllable (standalone_cluster); };
-	symbol_cluster		=> { found_syllable (symbol_cluster); };
-	broken_cluster		=> { found_syllable (broken_cluster); };
-	other			=> { found_syllable (non_indic_cluster); };
+	consonant_syllable	=> { found_syllable (indic_consonant_syllable); };
+	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); };
+	other			=> { found_syllable (indic_non_indic_cluster); };
 *|;
 
 
@@ -96,7 +105,7 @@
   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) | indic_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
index cc91f17..326aa9f 100644
--- a/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -6,12 +6,12 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-12.0.0.txt
- * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
- * # IndicPositionalCategory-12.0.0.txt
- * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
- * # Blocks-12.0.0.txt
- * # Date: 2018-07-30, 19:40:00 GMT [KW]
+ * # 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"
@@ -24,32 +24,32 @@
 #pragma GCC diagnostic ignored "-Wunused-macros"
 
 #define ISC_A    INDIC_SYLLABIC_CATEGORY_AVAGRAHA                    /*   17 chars; Avagraha */
-#define ISC_Bi   INDIC_SYLLABIC_CATEGORY_BINDU                       /*   86 chars; Bindu */
+#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                   /* 2160 chars; Consonant */
-#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   12 chars; Consonant_Dead */
-#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   67 chars; Consonant_Final */
+#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            /*   29 chars; Consonant_Medial */
+#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   /*    2 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED          /*    9 chars; Consonant_Prefixed */
+#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  /*    4 chars; Consonant_Succeeding_Repha */
-#define ISC_CWS  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER      /*    6 chars; Consonant_With_Stacker */
+#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           /*   11 chars; Invisible_Stacker */
+#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                       /*   30 chars; Nukta */
-#define ISC_Nd   INDIC_SYLLABIC_CATEGORY_NUMBER                      /*  481 chars; Number */
+#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                 /*   21 chars; Pure_Killer */
+#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 */
@@ -57,19 +57,20 @@
 #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             /*  673 chars; Vowel_Dependent */
-#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  476 chars; Vowel_Independent */
+#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                         /*  349 chars; Bottom */
+#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               /*    2 chars; Bottom_And_Right */
-#define IMC_L    INDIC_MATRA_CATEGORY_LEFT                           /*   61 chars; Left */
-#define IMC_LR   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                 /*   21 chars; Left_And_Right */
+#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                          /*  281 chars; Right */
-#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  398 chars; Top */
+#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 */
@@ -81,7 +82,7 @@
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
 
 
-static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
+static const uint16_t indic_table[] = {
 
 
 #define indic_offset_0x0028u 0
@@ -195,7 +196,7 @@
   /* 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),  _(x,x),  _(M,T), _(M,TR),
+  /* 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),
@@ -230,11 +231,11 @@
   /* 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),  _(x,x),  _(A,x),  _(M,T),  _(M,T),
+  /* 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),  _(x,x),  _(x,x),  _(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),
@@ -253,7 +254,7 @@
   /* 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),  _(x,x),  _(C,x),  _(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),
@@ -261,7 +262,7 @@
 
   /* Malayalam */
 
-  /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 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),
@@ -270,7 +271,7 @@
   /* 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,x),  _(x,x),
+  /* 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),
@@ -280,7 +281,7 @@
 
   /* Sinhala */
 
-  /* 0D80 */  _(x,x),  _(x,x), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 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),
@@ -308,7 +309,7 @@
   /* 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,x), _(CM,B), _(CM,B),  _(C,x),
+  /* 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),
@@ -401,9 +402,9 @@
   /* 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: 70% */
+}; /* Table items: 1792; occupancy: 71% */
 
-INDIC_TABLE_ELEMENT_TYPE
+uint16_t
 hb_indic_get_categories (hb_codepoint_t u)
 {
   switch (u >> 12)
@@ -488,6 +489,7 @@
 #undef IMC_R
 #undef IMC_T
 #undef IMC_TB
+#undef IMC_TBL
 #undef IMC_TBR
 #undef IMC_TL
 #undef IMC_TLR
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 26dc60d..4a8781c 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -29,6 +29,7 @@
 #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-layout.hh"
 
@@ -105,7 +106,8 @@
 {
   /*
    * Basic features.
-   * These features are applied in order, one at a time, after initial_reordering.
+   * These features are applied in order, one at a time, after 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},
@@ -120,8 +122,8 @@
   {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
   /*
    * Other features.
-   * These features are applied all at once, after final_reordering
-   * but before clearing syllables.
+   * These features are applied all at once, after final_reordering, constrained
+   * to the syllable.
    * Default Bengali font in Windows for example has intermixed
    * lookups for init,pres,abvs,blws features.
    */
@@ -200,9 +202,6 @@
   for (; i < INDIC_NUM_FEATURES; i++)
     map->add_feature (indic_features[i]);
 
-  map->enable_feature (HB_TAG('c','a','l','t'));
-  map->enable_feature (HB_TAG('c','l','i','g'));
-
   map->add_gsub_pause (_hb_clear_syllables);
 }
 
@@ -248,6 +247,7 @@
   hb_indic_would_substitute_feature_t pref;
   hb_indic_would_substitute_feature_t blwf;
   hb_indic_would_substitute_feature_t pstf;
+  hb_indic_would_substitute_feature_t vatu;
 
   hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
@@ -255,7 +255,7 @@
 static void *
 data_create_indic (const hb_ot_shape_plan_t *plan)
 {
-  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) hb_calloc (1, sizeof (indic_shape_plan_t));
   if (unlikely (!indic_plan))
     return nullptr;
 
@@ -286,6 +286,7 @@
   indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
   indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
   indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+  indic_plan->vatu.init (&plan->map, HB_TAG('v','a','t','u'), zero_context);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
     indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
@@ -297,7 +298,7 @@
 static void
 data_destroy_indic (void *data)
 {
-  free (data);
+  hb_free (data);
 }
 
 static indic_position_t
@@ -315,10 +316,16 @@
    * base at 0.  The font however, only has lookups matching
    * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
    * table).  As such, we simply match both sequences.  Seems
-   * to work. */
+   * to work.
+   *
+   * Vatu is done as well, for:
+   * https://github.com/harfbuzz/harfbuzz/issues/1587
+   */
   hb_codepoint_t glyphs[3] = {virama, consonant, virama};
   if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
-      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face) ||
+      indic_plan->vatu.would_substitute (glyphs  , 2, face) ||
+      indic_plan->vatu.would_substitute (glyphs+1, 2, face))
     return POS_BELOW_C;
   if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
       indic_plan->pstf.would_substitute (glyphs+1, 2, face))
@@ -329,19 +336,6 @@
   return POS_BASE_C;
 }
 
-
-enum indic_syllable_type_t {
-  indic_consonant_syllable,
-  indic_vowel_syllable,
-  indic_standalone_cluster,
-  indic_symbol_cluster,
-  indic_broken_cluster,
-  indic_non_indic_cluster,
-};
-
-#include "hb-ot-shape-complex-indic-machine.hh"
-
-
 static void
 setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		   hb_buffer_t              *buffer,
@@ -642,7 +636,7 @@
    * is *not* a Halant after last consonant already.  We know that is the
    * case for Kannada, while it reorders unconditionally in other scripts,
    * eg. Malayalam, Bengali, and Devanagari.  We don't currently know about
-   * other scripts, so we blacklist Kannada.
+   * other scripts, so we block Kannada.
    *
    * Kannada test case:
    * U+0C9A,U+0CCD,U+0C9A,U+0CCD
@@ -756,7 +750,28 @@
      * We could use buffer->sort() for this, if there was no special
      * reordering of pre-base stuff happening later...
      * We don't want to merge_clusters all of that, which buffer->sort()
-     * would.
+     * would.  Here's a concrete example:
+     *
+     * Assume there's a pre-base consonant and explicit Halant before base,
+     * followed by a prebase-reordering (left) Matra:
+     *
+     *   C,H,ZWNJ,B,M
+     *
+     * At this point in reordering we would have:
+     *
+     *   M,C,H,ZWNJ,B
+     *
+     * whereas in final reordering we will bring the Matra closer to Base:
+     *
+     *   C,H,ZWNJ,M,B
+     *
+     * That's why we don't want to merge-clusters anything before the Base
+     * at this point.  But if something moved from after Base to before it,
+     * we should merge clusters from base to them.  In final-reordering, we
+     * only move things around before base, and merge-clusters up to base.
+     * These two merge-clusters from the two sides of base will interlock
+     * to merge things correctly.  See:
+     * https://github.com/harfbuzz/harfbuzz/issues/2272
      */
     if (indic_plan->is_old_spec || end - start > 127)
       buffer->merge_clusters (base, end);
@@ -766,17 +781,18 @@
       for (unsigned int i = base; i < end; i++)
 	if (info[i].syllable() != 255)
 	{
+	  unsigned int min = i;
 	  unsigned int max = i;
 	  unsigned int j = start + info[i].syllable();
 	  while (j != i)
 	  {
+	    min = hb_min (min, j);
 	    max = hb_max (max, j);
 	    unsigned int next = start + info[j].syllable();
 	    info[j].syllable() = 255; /* So we don't process j later again. */
 	    j = next;
 	  }
-	  if (i != max)
-	    buffer->merge_clusters (i, max + 1);
+	  buffer->merge_clusters (hb_max (base, min), max + 1);
 	}
     }
 
@@ -930,79 +946,25 @@
   }
 }
 
-static inline void
-insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			     hb_font_t *font,
-			     hb_buffer_t *buffer)
-{
-  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) == indic_broken_cluster)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
-
-
-  hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
-    return;
-
-  hb_glyph_info_t dottedcircle = {0};
-  dottedcircle.codepoint = 0x25CCu;
-  set_indic_properties (dottedcircle);
-  dottedcircle.codepoint = dottedcircle_glyph;
-
-  buffer->clear_output ();
-
-  buffer->idx = 0;
-  unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && buffer->successful)
-  {
-    unsigned int syllable = buffer->cur().syllable();
-    indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster))
-    {
-      last_syllable = syllable;
-
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
-
-      /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len && buffer->successful &&
-	     last_syllable == buffer->cur().syllable() &&
-	     buffer->cur().indic_category() == OT_Repha)
-	buffer->next_glyph ();
-
-      buffer->output_info (ginfo);
-    }
-    else
-      buffer->next_glyph ();
-  }
-  buffer->swap_buffers ();
-}
-
 static void
 initial_reordering_indic (const hb_ot_shape_plan_t *plan,
 			  hb_font_t *font,
 			  hb_buffer_t *buffer)
 {
+  if (!buffer->message (font, "start reordering indic initial"))
+    return;
+
   update_consonant_positions_indic (plan, font, buffer);
-  insert_dotted_circles_indic (plan, font, buffer);
+  hb_syllabic_insert_dotted_circles (font, buffer,
+				     indic_broken_cluster,
+				     OT_DOTTEDCIRCLE,
+				     OT_Repha,
+				     POS_END);
 
   foreach_syllable (buffer, start, end)
     initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
+
+  (void) buffer->message (font, "end reordering indic initial");
 }
 
 static void
@@ -1325,6 +1287,7 @@
 	goto reph_move;
       }
     }
+    /* See https://github.com/harfbuzz/harfbuzz/issues/2298#issuecomment-615318654 */
 
     /*       6. Otherwise, reorder reph to the end of the syllable.
      */
@@ -1476,8 +1439,11 @@
   unsigned int count = buffer->len;
   if (unlikely (!count)) return;
 
-  foreach_syllable (buffer, start, end)
-    final_reordering_syllable_indic (plan, buffer, start, end);
+  if (buffer->message (font, "start reordering indic final")) {
+    foreach_syllable (buffer, start, end)
+      final_reordering_syllable_indic (plan, buffer, start, end);
+    (void) buffer->message (font, "end reordering indic final");
+  }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh
index 1eeed68..dcb28a4 100644
--- a/src/hb-ot-shape-complex-indic.hh
+++ b/src/hb-ot-shape-complex-indic.hh
@@ -29,16 +29,14 @@
 
 #include "hb.hh"
 
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape-complex-syllabic.hh"
 
 
 /* buffer var allocations */
-#define indic_category() complex_var_u8_0() /* indic_category_t */
-#define indic_position() complex_var_u8_1() /* indic_position_t */
+#define indic_category() complex_var_u8_category() /* indic_category_t */
+#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */
 
 
-#define INDIC_TABLE_ELEMENT_TYPE uint16_t
-
 /* Cateories used in the OpenType spec:
  * https://docs.microsoft.com/en-us/typography/script-development/devanagari
  */
@@ -165,6 +163,7 @@
   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,
@@ -176,7 +175,7 @@
 
 #define INDIC_COMBINE_CATEGORIES(S,M) \
   ( \
-    ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+    static_assert_expr (S < 255 && M < 255) + \
     ( S | \
      ( \
       ( \
@@ -193,7 +192,7 @@
     ) \
    )
 
-HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+HB_INTERNAL uint16_t
 hb_indic_get_categories (hb_codepoint_t u);
 
 
@@ -306,17 +305,12 @@
   0x0D30u, /* Malayalam */	/* No Reph, Logical Repha */
 
   0x0DBBu, /* Sinhala */	/* Reph formed only with ZWJ */
-
-  0x179Au, /* Khmer */
 };
 
 static inline bool
 is_ra (hb_codepoint_t u)
 {
-  for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
-    if (u == ra_chars[i])
-      return true;
-  return false;
+  return hb_array (ra_chars).lfind (u);
 }
 
 static inline void
@@ -324,7 +318,7 @@
 {
   hb_codepoint_t u = info.codepoint;
   unsigned int type = hb_indic_get_categories (u);
-  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+  indic_category_t cat = (indic_category_t) (type & 0xFFu);
   indic_position_t pos = (indic_position_t) (type >> 8);
 
 
@@ -369,6 +363,7 @@
   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 */
diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh
index a040318..c52f72f 100644
--- a/src/hb-ot-shape-complex-khmer-machine.hh
+++ b/src/hb-ot-shape-complex-khmer-machine.hh
@@ -31,8 +31,32 @@
 
 #include "hb.hh"
 
+enum khmer_syllable_type_t {
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
+};
 
-#line 36 "hb-ot-shape-complex-khmer-machine.hh"
+
+#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, 
@@ -215,18 +239,18 @@
 static const int khmer_syllable_machine_en_main = 20;
 
 
-#line 36 "hb-ot-shape-complex-khmer-machine.rl"
+#line 43 "hb-ot-shape-complex-khmer-machine.rl"
 
 
 
-#line 80 "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) | khmer_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
@@ -238,7 +262,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 242 "hb-ot-shape-complex-khmer-machine.hh"
+#line 266 "hb-ot-shape-complex-khmer-machine.hh"
 	{
 	cs = khmer_syllable_machine_start;
 	ts = 0;
@@ -246,7 +270,7 @@
 	act = 0;
 	}
 
-#line 100 "hb-ot-shape-complex-khmer-machine.rl"
+#line 106 "hb-ot-shape-complex-khmer-machine.rl"
 
 
   p = 0;
@@ -254,7 +278,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 258 "hb-ot-shape-complex-khmer-machine.hh"
+#line 282 "hb-ot-shape-complex-khmer-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -268,7 +292,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 272 "hb-ot-shape-complex-khmer-machine.hh"
+#line 296 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 	_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -291,37 +315,37 @@
 	{te = p+1;}
 	break;
 	case 8:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
-	{te = p+1;{ found_syllable (non_khmer_cluster); }}
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+	{te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
 	break;
 	case 10:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
-	{te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+	{te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
 	break;
 	case 12:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
-	{te = p;p--;{ found_syllable (broken_cluster); }}
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+	{te = p;p--;{ found_syllable (khmer_broken_cluster); }}
 	break;
 	case 11:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
-	{te = p;p--;{ found_syllable (non_khmer_cluster); }}
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+	{te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
 	break;
 	case 1:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
 	break;
 	case 5:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+#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 (broken_cluster); }
+	{{p = ((te))-1;} found_syllable (khmer_broken_cluster); }
 	break;
 	case 3:
-	{{p = ((te))-1;} found_syllable (non_khmer_cluster); }
+	{{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
 	break;
 	}
 	}
@@ -329,16 +353,16 @@
 	case 4:
 #line 1 "NONE"
 	{te = p+1;}
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
 	{act = 2;}
 	break;
 	case 9:
 #line 1 "NONE"
 	{te = p+1;}
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
 	{act = 3;}
 	break;
-#line 342 "hb-ot-shape-complex-khmer-machine.hh"
+#line 366 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 _again:
@@ -347,7 +371,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 351 "hb-ot-shape-complex-khmer-machine.hh"
+#line 375 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -363,7 +387,7 @@
 
 	}
 
-#line 108 "hb-ot-shape-complex-khmer-machine.rl"
+#line 114 "hb-ot-shape-complex-khmer-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl
index e7f1453..c9cf33f 100644
--- a/src/hb-ot-shape-complex-khmer-machine.rl
+++ b/src/hb-ot-shape-complex-khmer-machine.rl
@@ -29,30 +29,36 @@
 
 #include "hb.hh"
 
+enum khmer_syllable_type_t {
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
+};
+
 %%{
   machine khmer_syllable_machine;
   alphtype unsigned char;
+  write exports;
   write data;
 }%%
 
 %%{
 
-# Same order as enum khmer_category_t.  Not sure how to avoid duplication.
-C    = 1;
-V    = 2;
-ZWNJ = 5;
-ZWJ  = 6;
-PLACEHOLDER = 11;
-DOTTEDCIRCLE = 12;
-Coeng= 14;
-Ra   = 16;
-Robatic = 20;
-Xgroup  = 21;
-Ygroup  = 22;
-VAbv = 26;
-VBlw = 27;
-VPre = 28;
-VPst = 29;
+export C    = 1;
+export V    = 2;
+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;
 
 c = (C | Ra | V);
 cn = c.((ZWJ|ZWNJ)?.Robatic)?;
@@ -71,9 +77,9 @@
 other =			any;
 
 main := |*
-	consonant_syllable	=> { found_syllable (consonant_syllable); };
-	broken_cluster		=> { found_syllable (broken_cluster); };
-	other			=> { found_syllable (non_khmer_cluster); };
+	consonant_syllable	=> { found_syllable (khmer_consonant_syllable); };
+	broken_cluster		=> { found_syllable (khmer_broken_cluster); };
+	other			=> { found_syllable (khmer_non_khmer_cluster); };
 *|;
 
 
@@ -83,7 +89,7 @@
   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) | khmer_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc
index fd8a9be..7787886 100644
--- a/src/hb-ot-shape-complex-khmer.cc
+++ b/src/hb-ot-shape-complex-khmer.cc
@@ -29,6 +29,7 @@
 #ifndef HB_NO_OT_SHAPE
 
 #include "hb-ot-shape-complex-khmer.hh"
+#include "hb-ot-shape-complex-khmer-machine.hh"
 #include "hb-ot-layout.hh"
 
 
@@ -41,7 +42,8 @@
 {
   /*
    * Basic features.
-   * These features are applied in order, one at a time, after reordering.
+   * 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},
@@ -140,43 +142,16 @@
 
 struct khmer_shape_plan_t
 {
-  bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
-  {
-    hb_codepoint_t glyph = virama_glyph;
-    if (unlikely (virama_glyph == (hb_codepoint_t) -1))
-    {
-      if (!font->get_nominal_glyph (0x17D2u, &glyph))
-	glyph = 0;
-      /* Technically speaking, the spec says we should apply 'locl' to virama too.
-       * Maybe one day... */
-
-      /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
-       * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
-      virama_glyph = glyph;
-    }
-
-    *pglyph = glyph;
-    return glyph != 0;
-  }
-
-  mutable hb_codepoint_t virama_glyph;
-
-  hb_indic_would_substitute_feature_t pref;
-
   hb_mask_t mask_array[KHMER_NUM_FEATURES];
 };
 
 static void *
 data_create_khmer (const hb_ot_shape_plan_t *plan)
 {
-  khmer_shape_plan_t *khmer_plan = (khmer_shape_plan_t *) calloc (1, sizeof (khmer_shape_plan_t));
+  khmer_shape_plan_t *khmer_plan = (khmer_shape_plan_t *) hb_calloc (1, sizeof (khmer_shape_plan_t));
   if (unlikely (!khmer_plan))
     return nullptr;
 
-  khmer_plan->virama_glyph = (hb_codepoint_t) -1;
-
-  khmer_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), true);
-
   for (unsigned int i = 0; i < ARRAY_LENGTH (khmer_plan->mask_array); i++)
     khmer_plan->mask_array[i] = (khmer_features[i].flags & F_GLOBAL) ?
 				 0 : plan->map.get_1_mask (khmer_features[i].tag);
@@ -187,18 +162,9 @@
 static void
 data_destroy_khmer (void *data)
 {
-  free (data);
+  hb_free (data);
 }
 
-
-enum khmer_syllable_type_t {
-  khmer_consonant_syllable,
-  khmer_broken_cluster,
-  khmer_non_khmer_cluster,
-};
-
-#include "hb-ot-shape-complex-khmer-machine.hh"
-
 static void
 setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		   hb_buffer_t              *buffer,
@@ -325,79 +291,22 @@
   }
 }
 
-static inline void
-insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			     hb_font_t *font,
-			     hb_buffer_t *buffer)
-{
-  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) == khmer_broken_cluster)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
-
-
-  hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
-    return;
-
-  hb_glyph_info_t dottedcircle = {0};
-  dottedcircle.codepoint = 0x25CCu;
-  set_khmer_properties (dottedcircle);
-  dottedcircle.codepoint = dottedcircle_glyph;
-
-  buffer->clear_output ();
-
-  buffer->idx = 0;
-  unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && buffer->successful)
-  {
-    unsigned int syllable = buffer->cur().syllable();
-    khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster))
-    {
-      last_syllable = syllable;
-
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
-
-      /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len && buffer->successful &&
-	     last_syllable == buffer->cur().syllable() &&
-	     buffer->cur().khmer_category() == OT_Repha)
-	buffer->next_glyph ();
-
-      buffer->output_info (ginfo);
-    }
-    else
-      buffer->next_glyph ();
-  }
-  buffer->swap_buffers ();
-}
-
 static void
 reorder_khmer (const hb_ot_shape_plan_t *plan,
 	       hb_font_t *font,
 	       hb_buffer_t *buffer)
 {
-  insert_dotted_circles_khmer (plan, font, buffer);
+  if (buffer->message (font, "start reordering khmer"))
+  {
+    hb_syllabic_insert_dotted_circles (font, buffer,
+				       khmer_broken_cluster,
+				       OT_DOTTEDCIRCLE,
+				       OT_Repha);
 
-  foreach_syllable (buffer, start, end)
-    reorder_syllable_khmer (plan, font->face, buffer, start, end);
-
+    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);
 }
 
diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh
index 11a77bf..35bfbb6 100644
--- a/src/hb-ot-shape-complex-khmer.hh
+++ b/src/hb-ot-shape-complex-khmer.hh
@@ -49,13 +49,15 @@
   //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 & 0x7Fu);
-  indic_position_t pos = (indic_position_t) (type >> 8);
+  khmer_category_t cat = (khmer_category_t) (type & 0xFFu);
+  khmer_position_t pos = (khmer_position_t) (type >> 8);
 
 
   /*
diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh
index c2f4c00..f4ef330 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -31,36 +31,73 @@
 
 #include "hb.hh"
 
+enum myanmar_syllable_type_t {
+  myanmar_consonant_syllable,
+  myanmar_punctuation_cluster,
+  myanmar_broken_cluster,
+  myanmar_non_myanmar_cluster,
+};
 
-#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
+
+#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, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
-	3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 29u, 1u, 16u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 
-	3u, 29u, 1u, 32u, 1u, 32u, 8u, 8u, 0
+	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[] = {
-	32, 28, 25, 4, 25, 23, 21, 21, 
-	27, 27, 27, 27, 16, 27, 27, 27, 
-	27, 27, 28, 27, 27, 27, 27, 27, 
-	25, 4, 25, 23, 21, 21, 27, 27, 
-	27, 27, 16, 28, 27, 27, 27, 27, 
-	27, 28, 27, 27, 27, 27, 27, 28, 
-	27, 32, 32, 1
+	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, 33, 62, 88, 93, 119, 143, 165, 
-	187, 215, 243, 271, 299, 316, 344, 372, 
-	400, 428, 456, 485, 513, 541, 569, 597, 
-	625, 651, 656, 682, 706, 728, 750, 778, 
-	806, 834, 862, 879, 908, 936, 964, 992, 
-	1020, 1048, 1077, 1105, 1133, 1161, 1189, 1217, 
-	1246, 1274, 1307, 1340
+	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[] = {
@@ -68,192 +105,217 @@
 	0, 6, 1, 0, 0, 0, 0, 7, 
 	0, 8, 9, 0, 10, 11, 12, 13, 
 	14, 15, 16, 17, 18, 19, 20, 1, 
-	0, 22, 23, 24, 24, 21, 25, 21, 
-	26, 21, 21, 21, 21, 21, 21, 21, 
-	27, 21, 21, 28, 29, 30, 31, 32, 
-	33, 34, 35, 36, 37, 21, 24, 24, 
-	21, 25, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 38, 21, 21, 21, 21, 
-	21, 21, 32, 21, 21, 21, 36, 21, 
-	24, 24, 21, 25, 21, 24, 24, 21, 
-	25, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 32, 21, 21, 21, 36, 21, 39, 
-	21, 24, 24, 21, 25, 21, 32, 21, 
-	21, 21, 21, 21, 21, 21, 40, 21, 
-	21, 21, 21, 21, 21, 32, 21, 24, 
-	24, 21, 25, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 40, 21, 21, 21, 
-	21, 21, 21, 32, 21, 24, 24, 21, 
-	25, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 32, 21, 22, 21, 24, 24, 21, 
-	25, 21, 26, 21, 21, 21, 21, 21, 
-	21, 21, 41, 21, 21, 41, 21, 21, 
-	21, 32, 42, 21, 21, 36, 21, 22, 
-	21, 24, 24, 21, 25, 21, 26, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 32, 21, 21, 
-	21, 36, 21, 22, 21, 24, 24, 21, 
-	25, 21, 26, 21, 21, 21, 21, 21, 
-	21, 21, 41, 21, 21, 21, 21, 21, 
-	21, 32, 42, 21, 21, 36, 21, 22, 
-	21, 24, 24, 21, 25, 21, 26, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 32, 42, 21, 
-	21, 36, 21, 1, 1, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 1, 21, 22, 21, 24, 24, 
-	21, 25, 21, 26, 21, 21, 21, 21, 
-	21, 21, 21, 27, 21, 21, 28, 29, 
-	30, 31, 32, 33, 34, 35, 36, 21, 
-	22, 21, 24, 24, 21, 25, 21, 26, 
-	21, 21, 21, 21, 21, 21, 21, 43, 
-	21, 21, 21, 21, 21, 21, 32, 33, 
-	34, 35, 36, 21, 22, 21, 24, 24, 
-	21, 25, 21, 26, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 32, 33, 34, 35, 36, 21, 
-	22, 21, 24, 24, 21, 25, 21, 26, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 32, 33, 
-	34, 21, 36, 21, 22, 21, 24, 24, 
-	21, 25, 21, 26, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 32, 21, 34, 21, 36, 21, 
-	22, 21, 24, 24, 21, 25, 21, 26, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 32, 33, 
-	34, 35, 36, 43, 21, 22, 21, 24, 
-	24, 21, 25, 21, 26, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 28, 
-	21, 30, 21, 32, 33, 34, 35, 36, 
-	21, 22, 21, 24, 24, 21, 25, 21, 
-	26, 21, 21, 21, 21, 21, 21, 21, 
-	43, 21, 21, 28, 21, 21, 21, 32, 
-	33, 34, 35, 36, 21, 22, 21, 24, 
-	24, 21, 25, 21, 26, 21, 21, 21, 
-	21, 21, 21, 21, 44, 21, 21, 28, 
-	29, 30, 21, 32, 33, 34, 35, 36, 
-	21, 22, 21, 24, 24, 21, 25, 21, 
-	26, 21, 21, 21, 21, 21, 21, 21, 
-	21, 21, 21, 28, 29, 30, 21, 32, 
-	33, 34, 35, 36, 21, 22, 23, 24, 
-	24, 21, 25, 21, 26, 21, 21, 21, 
-	21, 21, 21, 21, 27, 21, 21, 28, 
-	29, 30, 31, 32, 33, 34, 35, 36, 
-	21, 46, 46, 45, 5, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 47, 45, 
-	45, 45, 45, 45, 45, 14, 45, 45, 
-	45, 18, 45, 46, 46, 45, 5, 45, 
-	46, 46, 45, 5, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 14, 45, 45, 45, 
-	18, 45, 48, 45, 46, 46, 45, 5, 
-	45, 14, 45, 45, 45, 45, 45, 45, 
-	45, 49, 45, 45, 45, 45, 45, 45, 
-	14, 45, 46, 46, 45, 5, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 49, 
-	45, 45, 45, 45, 45, 45, 14, 45, 
-	46, 46, 45, 5, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 14, 45, 2, 45, 
-	46, 46, 45, 5, 45, 6, 45, 45, 
-	45, 45, 45, 45, 45, 50, 45, 45, 
-	50, 45, 45, 45, 14, 51, 45, 45, 
-	18, 45, 2, 45, 46, 46, 45, 5, 
-	45, 6, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	14, 45, 45, 45, 18, 45, 2, 45, 
-	46, 46, 45, 5, 45, 6, 45, 45, 
-	45, 45, 45, 45, 45, 50, 45, 45, 
-	45, 45, 45, 45, 14, 51, 45, 45, 
-	18, 45, 2, 45, 46, 46, 45, 5, 
-	45, 6, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	14, 51, 45, 45, 18, 45, 52, 52, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 52, 45, 2, 
-	3, 46, 46, 45, 5, 45, 6, 45, 
-	45, 45, 45, 45, 45, 45, 8, 45, 
-	45, 10, 11, 12, 13, 14, 15, 16, 
-	17, 18, 19, 45, 2, 45, 46, 46, 
-	45, 5, 45, 6, 45, 45, 45, 45, 
-	45, 45, 45, 8, 45, 45, 10, 11, 
-	12, 13, 14, 15, 16, 17, 18, 45, 
-	2, 45, 46, 46, 45, 5, 45, 6, 
-	45, 45, 45, 45, 45, 45, 45, 53, 
-	45, 45, 45, 45, 45, 45, 14, 15, 
-	16, 17, 18, 45, 2, 45, 46, 46, 
-	45, 5, 45, 6, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 14, 15, 16, 17, 18, 45, 
-	2, 45, 46, 46, 45, 5, 45, 6, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 14, 15, 
-	16, 45, 18, 45, 2, 45, 46, 46, 
-	45, 5, 45, 6, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 14, 45, 16, 45, 18, 45, 
-	2, 45, 46, 46, 45, 5, 45, 6, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 14, 15, 
-	16, 17, 18, 53, 45, 2, 45, 46, 
-	46, 45, 5, 45, 6, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 45, 10, 
-	45, 12, 45, 14, 15, 16, 17, 18, 
-	45, 2, 45, 46, 46, 45, 5, 45, 
-	6, 45, 45, 45, 45, 45, 45, 45, 
-	53, 45, 45, 10, 45, 45, 45, 14, 
-	15, 16, 17, 18, 45, 2, 45, 46, 
-	46, 45, 5, 45, 6, 45, 45, 45, 
-	45, 45, 45, 45, 54, 45, 45, 10, 
-	11, 12, 45, 14, 15, 16, 17, 18, 
-	45, 2, 45, 46, 46, 45, 5, 45, 
-	6, 45, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 10, 11, 12, 45, 14, 
-	15, 16, 17, 18, 45, 2, 3, 46, 
-	46, 45, 5, 45, 6, 45, 45, 45, 
-	45, 45, 45, 45, 8, 45, 45, 10, 
-	11, 12, 13, 14, 15, 16, 17, 18, 
-	45, 22, 23, 24, 24, 21, 25, 21, 
-	26, 21, 21, 21, 21, 21, 21, 21, 
-	55, 21, 21, 28, 29, 30, 31, 32, 
-	33, 34, 35, 36, 37, 21, 22, 56, 
-	24, 24, 21, 25, 21, 26, 21, 21, 
-	21, 21, 21, 21, 21, 27, 21, 21, 
-	28, 29, 30, 31, 32, 33, 34, 35, 
-	36, 21, 1, 1, 2, 3, 46, 46, 
-	45, 5, 45, 6, 1, 45, 45, 45, 
-	45, 1, 45, 8, 45, 45, 10, 11, 
-	12, 13, 14, 15, 16, 17, 18, 19, 
-	45, 1, 45, 1, 1, 57, 57, 57, 
-	57, 57, 57, 57, 57, 1, 57, 57, 
-	57, 57, 1, 57, 57, 57, 57, 57, 
-	57, 57, 57, 57, 57, 57, 57, 57, 
-	57, 57, 1, 57, 58, 57, 0
+	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, 24, 34, 0, 25, 31, 47, 
-	36, 50, 37, 42, 43, 44, 27, 39, 
-	40, 41, 30, 46, 51, 0, 2, 12, 
-	0, 3, 9, 13, 14, 19, 20, 21, 
-	5, 16, 17, 18, 8, 23, 4, 6, 
-	7, 10, 11, 15, 22, 0, 0, 26, 
-	28, 29, 32, 33, 35, 38, 45, 48, 
-	49, 0, 0
+	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, 5, 0, 0, 
-	6, 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, 7, 8, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 9, 10
+	7, 8, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 9, 10
 };
 
 static const char _myanmar_syllable_machine_to_state_actions[] = {
@@ -263,7 +325,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 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[] = {
@@ -273,17 +335,17 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 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, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 22, 
-	22, 46, 58, 58
+	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;
@@ -293,18 +355,18 @@
 static const int myanmar_syllable_machine_en_main = 0;
 
 
-#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 44 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
 
-#line 94 "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) | myanmar_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
@@ -316,7 +378,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 382 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	cs = myanmar_syllable_machine_start;
 	ts = 0;
@@ -324,7 +386,7 @@
 	act = 0;
 	}
 
-#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
   p = 0;
@@ -332,7 +394,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 398 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -346,7 +408,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 412 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -365,38 +427,38 @@
 
 	switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
 	case 6:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p+1;{ found_syllable (consonant_syllable); }}
+#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
 	break;
 	case 4:
-#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 95 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
 	break;
 	case 10:
-#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p+1;{ found_syllable (punctuation_cluster); }}
+#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p+1;{ found_syllable (myanmar_punctuation_cluster); }}
 	break;
 	case 8:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p+1;{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p+1;{ found_syllable (myanmar_broken_cluster); }}
 	break;
 	case 3:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
 	break;
 	case 5:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
 	break;
 	case 7:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p;p--;{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p;p--;{ found_syllable (myanmar_broken_cluster); }}
 	break;
 	case 9:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
-	{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
+#line 98 "hb-ot-shape-complex-myanmar-machine.rl"
+	{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
 	break;
-#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 462 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 _again:
@@ -405,7 +467,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 471 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -421,7 +483,7 @@
 
 	}
 
-#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 130 "hb-ot-shape-complex-myanmar-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
index 67133cd..2e6ac78 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -29,65 +29,73 @@
 
 #include "hb.hh"
 
+enum myanmar_syllable_type_t {
+  myanmar_consonant_syllable,
+  myanmar_punctuation_cluster,
+  myanmar_broken_cluster,
+  myanmar_non_myanmar_cluster,
+};
+
 %%{
   machine myanmar_syllable_machine;
   alphtype unsigned char;
+  write exports;
   write data;
 }%%
 
 %%{
 
-# Same order as enum myanmar_category_t.  Not sure how to avoid duplication.
-A    = 10;
-As   = 18;
-C    = 1;
-D    = 32;
-D0   = 20;
-DB   = 3;
-GB   = 11;
-H    = 4;
-IV   = 2;
-MH   = 21;
-MR   = 22;
-MW   = 23;
-MY   = 24;
-PT   = 25;
-V    = 8;
-VAbv = 26;
-VBlw = 27;
-VPre = 28;
-VPst = 29;
-VS   = 30;
-ZWJ  = 6;
-ZWNJ = 5;
-Ra   = 16;
-P    = 31;
-CS   = 19;
+export A    = 10;
+export As   = 18;
+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 ZWNJ = 5;
+export Ra   = 16;
+export P    = 31;
+export CS   = 19;
 
 j = ZWJ|ZWNJ;			# Joiners
 k = (Ra As H);			# Kinzi
 
 c = C|Ra;			# is_consonant
 
-medial_group = MY? As? MR? ((MW MH? | MH) As?)?;
+medial_group = MY? As? MR? ((MW MH? ML? | MH ML? | ML) As?)?;
 main_vowel_group = (VPre.VS?)* VAbv* VBlw* A* (DB As?)?;
-post_vowel_group = VPst MH? As* VAbv* 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?;
 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;
+punctuation_cluster =	P V;
 broken_cluster =	k? VS? syllable_tail;
 other =			any;
 
 main := |*
-	consonant_syllable	=> { found_syllable (consonant_syllable); };
-	j			=> { found_syllable (non_myanmar_cluster); };
-	punctuation_cluster	=> { found_syllable (punctuation_cluster); };
-	broken_cluster		=> { found_syllable (broken_cluster); };
-	other			=> { found_syllable (non_myanmar_cluster); };
+	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); };
+	other			=> { found_syllable (myanmar_non_myanmar_cluster); };
 *|;
 
 
@@ -97,7 +105,7 @@
   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) | myanmar_##syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index fc3490d..e6ae75e 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -29,6 +29,7 @@
 #ifndef HB_NO_OT_SHAPE
 
 #include "hb-ot-shape-complex-myanmar.hh"
+#include "hb-ot-shape-complex-myanmar-machine.hh"
 
 
 /*
@@ -40,7 +41,8 @@
 {
   /*
    * Basic features.
-   * These features are applied in order, one at a time, after reordering.
+   * These features are applied in order, one at a time, after reordering,
+   * constrained to the syllable.
    */
   HB_TAG('r','p','h','f'),
   HB_TAG('p','r','e','f'),
@@ -98,23 +100,6 @@
 }
 
 static void
-override_features_myanmar (hb_ot_shape_planner_t *plan)
-{
-  plan->map.disable_feature (HB_TAG('l','i','g','a'));
-}
-
-
-enum myanmar_syllable_type_t {
-  myanmar_consonant_syllable,
-  myanmar_punctuation_cluster,
-  myanmar_broken_cluster,
-  myanmar_non_myanmar_cluster,
-};
-
-#include "hb-ot-shape-complex-myanmar-machine.hh"
-
-
-static void
 setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		     hb_buffer_t              *buffer,
 		     hb_font_t                *font HB_UNUSED)
@@ -200,7 +185,7 @@
       info[i].myanmar_position() = POS_BASE_C;
       i++;
     }
-    indic_position_t pos = POS_AFTER_MAIN;
+    myanmar_position_t pos = POS_AFTER_MAIN;
     /* The following loop may be ugly, but it implements all of
      * Myanmar reordering! */
     for (; i < end; i++)
@@ -271,72 +256,21 @@
   }
 }
 
-static inline void
-insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			       hb_font_t *font,
-			       hb_buffer_t *buffer)
-{
-  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) == myanmar_broken_cluster)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
-
-
-  hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
-    return;
-
-  hb_glyph_info_t dottedcircle = {0};
-  dottedcircle.codepoint = 0x25CCu;
-  set_myanmar_properties (dottedcircle);
-  dottedcircle.codepoint = dottedcircle_glyph;
-
-  buffer->clear_output ();
-
-  buffer->idx = 0;
-  unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && buffer->successful)
-  {
-    unsigned int syllable = buffer->cur().syllable();
-    myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster))
-    {
-      last_syllable = syllable;
-
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
-
-      buffer->output_info (ginfo);
-    }
-    else
-      buffer->next_glyph ();
-  }
-  buffer->swap_buffers ();
-}
-
 static void
 reorder_myanmar (const hb_ot_shape_plan_t *plan,
 		 hb_font_t *font,
 		 hb_buffer_t *buffer)
 {
-  insert_dotted_circles_myanmar (plan, font, buffer);
+  if (buffer->message (font, "start reordering myanmar"))
+  {
+    hb_syllabic_insert_dotted_circles (font, buffer,
+				       myanmar_broken_cluster,
+				       OT_GB);
 
-  foreach_syllable (buffer, start, end)
-    reorder_syllable_myanmar (plan, font->face, buffer, start, end);
+    foreach_syllable (buffer, start, end)
+      reorder_syllable_myanmar (plan, font->face, buffer, start, end);
+    (void) buffer->message (font, "end reordering myanmar");
+  }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
@@ -346,7 +280,7 @@
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
   collect_features_myanmar,
-  override_features_myanmar,
+  nullptr, /* override_features */
   nullptr, /* data_create */
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
diff --git a/src/hb-ot-shape-complex-myanmar.hh b/src/hb-ot-shape-complex-myanmar.hh
index 7b9821e..7fbca38 100644
--- a/src/hb-ot-shape-complex-myanmar.hh
+++ b/src/hb-ot-shape-complex-myanmar.hh
@@ -56,16 +56,18 @@
   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 & 0x7Fu;
-  indic_position_t pos = (indic_position_t) (type >> 8);
+  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
@@ -114,10 +116,14 @@
       cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
       break;
 
-    case 0x103Eu: case 0x1060u:
+    case 0x103Eu:
       cat = OT_MH;
       break;
 
+    case 0x1060u:
+      cat = OT_ML;
+      break;
+
     case 0x103Cu:
       cat = OT_MR;
       break;
diff --git a/src/hb-ot-shape-complex-syllabic.cc b/src/hb-ot-shape-complex-syllabic.cc
new file mode 100644
index 0000000..5a08f87
--- /dev/null
+++ b/src/hb-ot-shape-complex-syllabic.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2021  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_OT_SHAPE
+
+#include "hb-ot-shape-complex-syllabic.hh"
+
+
+void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+				   hb_buffer_t *buffer,
+				   unsigned int broken_syllable_type,
+				   unsigned int dottedcircle_category,
+				   int repha_category,
+				   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;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  dottedcircle.complex_var_u8_category() = dottedcircle_category;
+  if (dottedcircle_position != -1)
+    dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position;
+  dottedcircle.codepoint = dottedcircle_glyph;
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len && buffer->successful)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    if (unlikely (last_syllable != syllable && (syllable & 0x0F) == broken_syllable_type))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
+
+      /* Insert dottedcircle after possible Repha. */
+      if (repha_category != -1)
+      {
+	while (buffer->idx < buffer->len && buffer->successful &&
+	       last_syllable == buffer->cur().syllable() &&
+	       buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
+	  (void) buffer->next_glyph ();
+      }
+
+      (void) buffer->output_info (ginfo);
+    }
+    else
+      (void) buffer->next_glyph ();
+  }
+  buffer->swap_buffers ();
+}
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-syllabic.hh b/src/hb-ot-shape-complex-syllabic.hh
new file mode 100644
index 0000000..b901a66
--- /dev/null
+++ b/src/hb-ot-shape-complex-syllabic.hh
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2021  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_OT_SHAPE_COMPLEX_SYLLABIC_HH
+#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shape-complex.hh"
+
+
+HB_INTERNAL void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+				   hb_buffer_t *buffer,
+				   unsigned int broken_syllable_type,
+				   unsigned int dottedcircle_category,
+				   int repha_category = -1,
+				   int dottedcircle_position = -1);
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index 347ea2e..4c30681 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -323,20 +323,19 @@
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+  for (buffer->idx = 0; buffer->idx < count /* No need for: && buffer->successful */;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
-    if (likely (!IS_SARA_AM (u))) {
-      buffer->next_glyph ();
+    if (likely (!IS_SARA_AM (u)))
+    {
+      if (unlikely (!buffer->next_glyph ())) break;
       continue;
     }
 
     /* Is SARA AM. Decompose and reorder. */
-    hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
-    _hb_glyph_info_set_continuation (&nikhahit);
-    buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u));
-    if (unlikely (!buffer->successful))
-      return;
+    (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
+    _hb_glyph_info_set_continuation (&buffer->prev());
+    if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
 
     /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
     unsigned int end = buffer->out_len;
diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
index 462342c..c3920b2 100644
--- a/src/hb-ot-shape-complex-use-machine.hh
+++ b/src/hb-ot-shape-complex-use-machine.hh
@@ -33,366 +33,423 @@
 
 #include "hb.hh"
 
+#include "hb-ot-shape-complex-syllabic.hh"
 
-#line 38 "hb-ot-shape-complex-use-machine.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[] = {
-	12u, 48u, 1u, 15u, 1u, 1u, 12u, 48u, 1u, 1u, 0u, 48u, 21u, 21u, 11u, 48u, 
-	11u, 48u, 1u, 15u, 1u, 1u, 11u, 48u, 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, 22u, 48u, 11u, 48u, 
-	1u, 48u, 11u, 48u, 13u, 21u, 4u, 4u, 13u, 13u, 11u, 48u, 11u, 48u, 41u, 42u, 
-	42u, 42u, 11u, 48u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 
-	45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u, 
-	23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, 1u, 48u, 1u, 15u, 
-	4u, 4u, 13u, 21u, 13u, 13u, 12u, 48u, 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u, 
-	21u, 42u, 1u, 5u, 0
+	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[] = {
-	37, 15, 1, 37, 1, 49, 1, 38, 
-	38, 15, 1, 38, 27, 26, 24, 23, 
-	22, 2, 1, 25, 25, 25, 1, 25, 
-	26, 26, 26, 27, 27, 27, 27, 38, 
-	48, 38, 9, 1, 1, 38, 38, 2, 
-	1, 38, 38, 27, 26, 24, 23, 22, 
-	2, 1, 25, 25, 25, 25, 26, 26, 
-	26, 27, 27, 27, 27, 38, 48, 15, 
-	1, 9, 1, 37, 48, 38, 2, 1, 
-	22, 5
+	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, 38, 54, 56, 94, 96, 146, 148, 
-	187, 226, 242, 244, 283, 311, 338, 363, 
-	387, 410, 413, 415, 441, 467, 493, 495, 
-	521, 548, 575, 602, 630, 658, 686, 714, 
-	753, 802, 841, 851, 853, 855, 894, 933, 
-	936, 938, 977, 1016, 1044, 1071, 1096, 1120, 
-	1143, 1146, 1148, 1174, 1200, 1226, 1252, 1279, 
-	1306, 1333, 1361, 1389, 1417, 1445, 1484, 1533, 
-	1549, 1551, 1561, 1563, 1601, 1650, 1689, 1692, 
-	1694, 1717
+	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, 
-	1, 0, 0, 0, 1, 0, 3, 2, 
-	2, 2, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 4, 2, 3, 2, 
-	6, 5, 5, 5, 5, 5, 5, 5, 
-	5, 5, 5, 5, 5, 5, 5, 5, 
-	5, 5, 5, 5, 5, 5, 5, 5, 
-	5, 5, 5, 5, 5, 5, 5, 5, 
-	6, 5, 5, 5, 6, 5, 7, 5, 
-	8, 9, 10, 8, 11, 12, 10, 10, 
-	10, 10, 10, 3, 13, 14, 10, 15, 
-	8, 8, 16, 17, 10, 10, 18, 19, 
-	20, 21, 22, 23, 24, 18, 25, 26, 
-	27, 28, 29, 30, 10, 31, 32, 33, 
-	10, 34, 35, 36, 37, 38, 39, 40, 
-	13, 10, 42, 41, 44, 1, 43, 43, 
-	45, 43, 43, 43, 43, 43, 46, 47, 
-	48, 49, 50, 51, 52, 53, 47, 54, 
-	46, 55, 56, 57, 58, 43, 59, 60, 
-	61, 43, 43, 43, 43, 62, 63, 64, 
-	65, 1, 43, 44, 1, 43, 43, 45, 
-	43, 43, 43, 43, 43, 66, 47, 48, 
-	49, 50, 51, 52, 53, 47, 54, 55, 
-	55, 56, 57, 58, 43, 59, 60, 61, 
-	43, 43, 43, 43, 62, 63, 64, 65, 
-	1, 43, 44, 67, 67, 67, 67, 67, 
-	67, 67, 67, 67, 67, 67, 67, 67, 
-	68, 67, 44, 67, 44, 1, 43, 43, 
-	45, 43, 43, 43, 43, 43, 43, 47, 
-	48, 49, 50, 51, 52, 53, 47, 54, 
-	55, 55, 56, 57, 58, 43, 59, 60, 
-	61, 43, 43, 43, 43, 62, 63, 64, 
-	65, 1, 43, 47, 48, 49, 50, 51, 
-	43, 43, 43, 43, 43, 43, 56, 57, 
-	58, 43, 59, 60, 61, 43, 43, 43, 
-	43, 48, 63, 64, 65, 69, 43, 48, 
-	49, 50, 51, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 59, 60, 61, 
-	43, 43, 43, 43, 43, 63, 64, 65, 
-	69, 43, 49, 50, 51, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 63, 
-	64, 65, 43, 50, 51, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 63, 
-	64, 65, 43, 51, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 63, 64, 
-	65, 43, 63, 64, 43, 64, 43, 49, 
-	50, 51, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 59, 60, 61, 43, 
-	43, 43, 43, 43, 63, 64, 65, 69, 
-	43, 49, 50, 51, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 60, 
-	61, 43, 43, 43, 43, 43, 63, 64, 
-	65, 69, 43, 49, 50, 51, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 61, 43, 43, 43, 43, 43, 
-	63, 64, 65, 69, 43, 71, 70, 49, 
-	50, 51, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 43, 63, 64, 65, 69, 
-	43, 48, 49, 50, 51, 43, 43, 43, 
-	43, 43, 43, 56, 57, 58, 43, 59, 
-	60, 61, 43, 43, 43, 43, 48, 63, 
-	64, 65, 69, 43, 48, 49, 50, 51, 
-	43, 43, 43, 43, 43, 43, 43, 57, 
-	58, 43, 59, 60, 61, 43, 43, 43, 
-	43, 48, 63, 64, 65, 69, 43, 48, 
-	49, 50, 51, 43, 43, 43, 43, 43, 
-	43, 43, 43, 58, 43, 59, 60, 61, 
-	43, 43, 43, 43, 48, 63, 64, 65, 
-	69, 43, 47, 48, 49, 50, 51, 43, 
-	53, 47, 43, 43, 43, 56, 57, 58, 
-	43, 59, 60, 61, 43, 43, 43, 43, 
-	48, 63, 64, 65, 69, 43, 47, 48, 
-	49, 50, 51, 43, 72, 47, 43, 43, 
-	43, 56, 57, 58, 43, 59, 60, 61, 
-	43, 43, 43, 43, 48, 63, 64, 65, 
-	69, 43, 47, 48, 49, 50, 51, 43, 
-	43, 47, 43, 43, 43, 56, 57, 58, 
-	43, 59, 60, 61, 43, 43, 43, 43, 
-	48, 63, 64, 65, 69, 43, 47, 48, 
-	49, 50, 51, 52, 53, 47, 43, 43, 
-	43, 56, 57, 58, 43, 59, 60, 61, 
-	43, 43, 43, 43, 48, 63, 64, 65, 
-	69, 43, 44, 1, 43, 43, 45, 43, 
-	43, 43, 43, 43, 43, 47, 48, 49, 
-	50, 51, 52, 53, 47, 54, 43, 55, 
-	56, 57, 58, 43, 59, 60, 61, 43, 
-	43, 43, 43, 62, 63, 64, 65, 1, 
-	43, 44, 67, 67, 67, 67, 67, 67, 
-	67, 67, 67, 67, 67, 67, 67, 68, 
-	67, 67, 67, 67, 67, 67, 67, 48, 
-	49, 50, 51, 67, 67, 67, 67, 67, 
-	67, 67, 67, 67, 67, 59, 60, 61, 
-	67, 67, 67, 67, 67, 63, 64, 65, 
-	69, 67, 44, 1, 43, 43, 45, 43, 
-	43, 43, 43, 43, 43, 47, 48, 49, 
-	50, 51, 52, 53, 47, 54, 46, 55, 
-	56, 57, 58, 43, 59, 60, 61, 43, 
-	43, 43, 43, 62, 63, 64, 65, 1, 
-	43, 74, 73, 73, 73, 73, 73, 73, 
-	73, 75, 73, 11, 76, 74, 73, 44, 
-	1, 43, 43, 45, 43, 43, 43, 43, 
-	43, 77, 47, 48, 49, 50, 51, 52, 
-	53, 47, 54, 46, 55, 56, 57, 58, 
-	43, 59, 60, 61, 43, 78, 79, 43, 
-	62, 63, 64, 65, 1, 43, 44, 1, 
-	43, 43, 45, 43, 43, 43, 43, 43, 
-	43, 47, 48, 49, 50, 51, 52, 53, 
-	47, 54, 46, 55, 56, 57, 58, 43, 
-	59, 60, 61, 43, 78, 79, 43, 62, 
-	63, 64, 65, 1, 43, 78, 79, 80, 
-	79, 80, 3, 6, 81, 81, 82, 81, 
-	81, 81, 81, 81, 83, 18, 19, 20, 
-	21, 22, 23, 24, 18, 25, 27, 27, 
-	28, 29, 30, 81, 31, 32, 33, 81, 
-	81, 81, 81, 37, 38, 39, 40, 6, 
-	81, 3, 6, 81, 81, 82, 81, 81, 
-	81, 81, 81, 81, 18, 19, 20, 21, 
-	22, 23, 24, 18, 25, 27, 27, 28, 
-	29, 30, 81, 31, 32, 33, 81, 81, 
-	81, 81, 37, 38, 39, 40, 6, 81, 
-	18, 19, 20, 21, 22, 81, 81, 81, 
-	81, 81, 81, 28, 29, 30, 81, 31, 
-	32, 33, 81, 81, 81, 81, 19, 38, 
-	39, 40, 84, 81, 19, 20, 21, 22, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 31, 32, 33, 81, 81, 81, 
-	81, 81, 38, 39, 40, 84, 81, 20, 
-	21, 22, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 38, 39, 40, 81, 
-	21, 22, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 38, 39, 40, 81, 
-	22, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 38, 39, 40, 81, 38, 
-	39, 81, 39, 81, 20, 21, 22, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 31, 32, 33, 81, 81, 81, 81, 
-	81, 38, 39, 40, 84, 81, 20, 21, 
-	22, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 32, 33, 81, 81, 
-	81, 81, 81, 38, 39, 40, 84, 81, 
-	20, 21, 22, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 33, 
-	81, 81, 81, 81, 81, 38, 39, 40, 
-	84, 81, 20, 21, 22, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 38, 
-	39, 40, 84, 81, 19, 20, 21, 22, 
-	81, 81, 81, 81, 81, 81, 28, 29, 
-	30, 81, 31, 32, 33, 81, 81, 81, 
-	81, 19, 38, 39, 40, 84, 81, 19, 
-	20, 21, 22, 81, 81, 81, 81, 81, 
-	81, 81, 29, 30, 81, 31, 32, 33, 
-	81, 81, 81, 81, 19, 38, 39, 40, 
-	84, 81, 19, 20, 21, 22, 81, 81, 
-	81, 81, 81, 81, 81, 81, 30, 81, 
-	31, 32, 33, 81, 81, 81, 81, 19, 
-	38, 39, 40, 84, 81, 18, 19, 20, 
-	21, 22, 81, 24, 18, 81, 81, 81, 
-	28, 29, 30, 81, 31, 32, 33, 81, 
-	81, 81, 81, 19, 38, 39, 40, 84, 
-	81, 18, 19, 20, 21, 22, 81, 85, 
-	18, 81, 81, 81, 28, 29, 30, 81, 
-	31, 32, 33, 81, 81, 81, 81, 19, 
-	38, 39, 40, 84, 81, 18, 19, 20, 
-	21, 22, 81, 81, 18, 81, 81, 81, 
-	28, 29, 30, 81, 31, 32, 33, 81, 
-	81, 81, 81, 19, 38, 39, 40, 84, 
-	81, 18, 19, 20, 21, 22, 23, 24, 
-	18, 81, 81, 81, 28, 29, 30, 81, 
-	31, 32, 33, 81, 81, 81, 81, 19, 
-	38, 39, 40, 84, 81, 3, 6, 81, 
-	81, 82, 81, 81, 81, 81, 81, 81, 
-	18, 19, 20, 21, 22, 23, 24, 18, 
-	25, 81, 27, 28, 29, 30, 81, 31, 
-	32, 33, 81, 81, 81, 81, 37, 38, 
-	39, 40, 6, 81, 3, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 4, 81, 81, 81, 81, 81, 
-	81, 81, 19, 20, 21, 22, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	31, 32, 33, 81, 81, 81, 81, 81, 
-	38, 39, 40, 84, 81, 3, 86, 86, 
-	86, 86, 86, 86, 86, 86, 86, 86, 
-	86, 86, 86, 4, 86, 87, 81, 14, 
-	81, 81, 81, 81, 81, 81, 81, 88, 
-	81, 14, 81, 6, 86, 86, 86, 86, 
-	86, 86, 86, 86, 86, 86, 86, 86, 
-	86, 86, 86, 86, 86, 86, 86, 86, 
-	86, 86, 86, 86, 86, 86, 86, 86, 
-	86, 86, 86, 6, 86, 86, 86, 6, 
-	86, 9, 81, 81, 81, 9, 81, 81, 
-	81, 81, 81, 3, 6, 14, 81, 82, 
-	81, 81, 81, 81, 81, 81, 18, 19, 
-	20, 21, 22, 23, 24, 18, 25, 26, 
-	27, 28, 29, 30, 81, 31, 32, 33, 
-	81, 34, 35, 81, 37, 38, 39, 40, 
-	6, 81, 3, 6, 81, 81, 82, 81, 
-	81, 81, 81, 81, 81, 18, 19, 20, 
-	21, 22, 23, 24, 18, 25, 26, 27, 
-	28, 29, 30, 81, 31, 32, 33, 81, 
-	81, 81, 81, 37, 38, 39, 40, 6, 
-	81, 34, 35, 81, 35, 81, 78, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 78, 79, 80, 9, 86, 86, 
-	86, 9, 86, 0
-};
-
-static const char _use_syllable_machine_trans_targs[] = {
-	5, 9, 5, 41, 2, 5, 1, 53, 
-	6, 7, 5, 34, 37, 63, 64, 67, 
-	68, 72, 43, 44, 45, 46, 47, 57, 
-	58, 60, 69, 61, 54, 55, 56, 50, 
-	51, 52, 70, 71, 73, 62, 48, 49, 
-	5, 5, 5, 5, 8, 0, 33, 12, 
-	13, 14, 15, 16, 27, 28, 30, 31, 
-	24, 25, 26, 19, 20, 21, 32, 17, 
-	18, 5, 11, 5, 10, 22, 5, 23, 
-	29, 5, 35, 36, 5, 38, 39, 40, 
-	5, 5, 3, 42, 4, 59, 5, 65, 
-	66
-};
-
-static const char _use_syllable_machine_trans_actions[] = {
-	1, 0, 2, 3, 0, 4, 0, 5, 
-	0, 5, 8, 0, 5, 9, 0, 9, 
-	3, 0, 5, 5, 0, 0, 0, 5, 
-	5, 5, 3, 3, 5, 5, 5, 5, 
-	5, 5, 0, 0, 0, 3, 0, 0, 
-	10, 11, 12, 13, 5, 0, 5, 0, 
-	0, 0, 0, 0, 0, 0, 0, 5, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 14, 5, 15, 0, 0, 16, 0, 
-	0, 17, 0, 0, 18, 5, 0, 0, 
-	19, 20, 0, 3, 0, 5, 21, 0, 
-	0
-};
-
-static const char _use_syllable_machine_to_state_actions[] = {
-	0, 0, 0, 0, 0, 6, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 7, 0, 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
 };
 
 static const short _use_syllable_machine_eof_trans[] = {
-	1, 3, 3, 6, 6, 0, 42, 44, 
-	44, 68, 68, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 71, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	68, 44, 74, 77, 74, 44, 44, 81, 
-	81, 82, 82, 82, 82, 82, 82, 82, 
-	82, 82, 82, 82, 82, 82, 82, 82, 
-	82, 82, 82, 82, 82, 82, 82, 87, 
-	82, 82, 82, 87, 82, 82, 82, 82, 
-	81, 87
+	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 = 5;
-static const int use_syllable_machine_first_final = 5;
+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 = 5;
+static const int use_syllable_machine_en_main = 0;
 
 
-#line 38 "hb-ot-shape-complex-use-machine.rl"
+#line 58 "hb-ot-shape-complex-use-machine.rl"
 
 
 
-#line 162 "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, te, #syllable_type); \
-    for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
+    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
 
-static void
+
+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)
 {
-  unsigned int p, pe, eof, ts, te, act;
-  int cs;
   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 396 "hb-ot-shape-complex-use-machine.hh"
+#line 453 "hb-ot-shape-complex-use-machine.hh"
 	{
 	cs = use_syllable_machine_start;
 	ts = 0;
@@ -400,15 +457,12 @@
 	act = 0;
 	}
 
-#line 182 "hb-ot-shape-complex-use-machine.rl"
+#line 263 "hb-ot-shape-complex-use-machine.rl"
 
 
-  p = 0;
-  pe = eof = buffer->len;
-
   unsigned int syllable_serial = 1;
   
-#line 412 "hb-ot-shape-complex-use-machine.hh"
+#line 466 "hb-ot-shape-complex-use-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -418,20 +472,20 @@
 		goto _test_eof;
 _resume:
 	switch ( _use_syllable_machine_from_state_actions[cs] ) {
-	case 7:
+	case 2:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 426 "hb-ot-shape-complex-use-machine.hh"
+#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] <=( info[p].use_category()) &&
-		( info[p].use_category()) <= _keys[1] ?
-		( info[p].use_category()) - _keys[0] : _slen ];
+	_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];
@@ -440,104 +494,64 @@
 		goto _again;
 
 	switch ( _use_syllable_machine_trans_actions[_trans] ) {
-	case 5:
-#line 1 "NONE"
-	{te = p+1;}
-	break;
-	case 12:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
-	{te = p+1;{ found_syllable (independent_cluster); }}
-	break;
-	case 14:
-#line 153 "hb-ot-shape-complex-use-machine.rl"
-	{te = p+1;{ found_syllable (standard_cluster); }}
-	break;
-	case 10:
-#line 157 "hb-ot-shape-complex-use-machine.rl"
-	{te = p+1;{ found_syllable (broken_cluster); }}
-	break;
-	case 8:
-#line 158 "hb-ot-shape-complex-use-machine.rl"
-	{te = p+1;{ found_syllable (non_cluster); }}
-	break;
-	case 11:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (independent_cluster); }}
-	break;
-	case 15:
-#line 151 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
-	break;
-	case 16:
-#line 152 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (sakot_terminated_cluster); }}
-	break;
-	case 13:
-#line 153 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (standard_cluster); }}
-	break;
-	case 18:
-#line 154 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
-	break;
-	case 17:
-#line 155 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (numeral_cluster); }}
-	break;
-	case 19:
-#line 156 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (symbol_cluster); }}
-	break;
-	case 20:
-#line 157 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (broken_cluster); }}
-	break;
-	case 21:
-#line 158 "hb-ot-shape-complex-use-machine.rl"
-	{te = p;p--;{ found_syllable (non_cluster); }}
-	break;
-	case 1:
-#line 153 "hb-ot-shape-complex-use-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (standard_cluster); }}
+	case 7:
+#line 169 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (use_standard_cluster); }}
 	break;
 	case 4:
-#line 157 "hb-ot-shape-complex-use-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
-	break;
-	case 2:
-#line 1 "NONE"
-	{	switch( act ) {
-	case 8:
-	{{p = ((te))-1;} found_syllable (broken_cluster); }
-	break;
-	case 9:
-	{{p = ((te))-1;} found_syllable (non_cluster); }
-	break;
-	}
-	}
+#line 174 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (use_broken_cluster); }}
 	break;
 	case 3:
-#line 1 "NONE"
-	{te = p+1;}
-#line 157 "hb-ot-shape-complex-use-machine.rl"
-	{act = 8;}
+#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 1 "NONE"
-	{te = p+1;}
-#line 158 "hb-ot-shape-complex-use-machine.rl"
-	{act = 9;}
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
 	break;
-#line 532 "hb-ot-shape-complex-use-machine.hh"
+	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 6:
+	case 1:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 541 "hb-ot-shape-complex-use-machine.hh"
+#line 555 "hb-ot-shape-complex-use-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -553,7 +567,7 @@
 
 	}
 
-#line 190 "hb-ot-shape-complex-use-machine.rl"
+#line 268 "hb-ot-shape-complex-use-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl
index 9b75b5c..9e0d98d 100644
--- a/src/hb-ot-shape-complex-use-machine.rl
+++ b/src/hb-ot-shape-complex-use-machine.rl
@@ -31,80 +31,91 @@
 
 #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,
+};
+
 %%{
   machine use_syllable_machine;
   alphtype unsigned char;
+  write exports;
   write data;
 }%%
 
 %%{
 
-# Same order as enum use_category_t.  Not sure how to avoid duplication.
+# Categories used in the Universal Shaping Engine spec:
+# https://docs.microsoft.com/en-us/typography/script-development/use
 
-O	= 0; # OTHER
+export O	= 0; # OTHER
 
-B	= 1; # BASE
-IND	= 3; # BASE_IND
-N	= 4; # BASE_NUM
-GB	= 5; # BASE_OTHER
-CGJ	= 6; # CGJ
-#F	= 7; # CONS_FINAL
-#FM	= 8; # CONS_FINAL_MOD
-#M	= 9; # CONS_MED
-#CM	= 10; # CONS_MOD
-SUB	= 11; # CONS_SUB
-H	= 12; # HALANT
+export B	= 1; # BASE
+export N	= 4; # BASE_NUM
+export GB	= 5; # BASE_OTHER
+export CGJ	= 6; # CGJ
+export SUB	= 11; # CONS_SUB
+export H	= 12; # HALANT
 
-HN	= 13; # HALANT_NUM
-ZWNJ	= 14; # Zero width non-joiner
-ZWJ	= 15; # Zero width joiner
-WJ	= 16; # Word joiner
-Rsv	= 17; # Reserved characters
-R	= 18; # REPHA
-S	= 19; # SYM
-#SM	= 20; # SYM_MOD
-VS	= 21; # VARIATION_SELECTOR
-#V	= 36; # VOWEL
-#VM	= 40; # VOWEL_MOD
-CS	= 43; # CONS_WITH_STACKER
-HVM	= 44; # HALANT_OR_VOWEL_MODIFIER
-Sk	= 48; # SAKOT
+export HN	= 13; # HALANT_NUM
+export ZWNJ	= 14; # Zero width non-joiner
+export R	= 18; # REPHA
+export CS	= 43; # CONS_WITH_STACKER
+export HVM	= 44; # HALANT_OR_VOWEL_MODIFIER
+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
 
-FAbv	= 24; # CONS_FINAL_ABOVE
-FBlw	= 25; # CONS_FINAL_BELOW
-FPst	= 26; # CONS_FINAL_POST
-MAbv	= 27; # CONS_MED_ABOVE
-MBlw	= 28; # CONS_MED_BELOW
-MPst	= 29; # CONS_MED_POST
-MPre	= 30; # CONS_MED_PRE
-CMAbv	= 31; # CONS_MOD_ABOVE
-CMBlw	= 32; # CONS_MOD_BELOW
-VAbv	= 33; # VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST
-VBlw	= 34; # VOWEL_BELOW / VOWEL_BELOW_POST
-VPst	= 35; # VOWEL_POST	UIPC = Right
-VPre	= 22; # VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST
-VMAbv	= 37; # VOWEL_MOD_ABOVE
-VMBlw	= 38; # VOWEL_MOD_BELOW
-VMPst	= 39; # VOWEL_MOD_POST
-VMPre	= 23; # VOWEL_MOD_PRE
-SMAbv	= 41; # SYM_MOD_ABOVE
-SMBlw	= 42; # SYM_MOD_BELOW
-FMAbv	= 45; # CONS_FINAL_MOD	UIPC = Top
-FMBlw	= 46; # CONS_FINAL_MOD	UIPC = Bottom
-FMPst	= 47; # CONS_FINAL_MOD	UIPC = Not_Applicable
+export FAbv	= 24; # CONS_FINAL_ABOVE
+export FBlw	= 25; # CONS_FINAL_BELOW
+export FPst	= 26; # CONS_FINAL_POST
+export MAbv	= 27; # CONS_MED_ABOVE
+export MBlw	= 28; # CONS_MED_BELOW
+export MPst	= 29; # CONS_MED_POST
+export MPre	= 30; # CONS_MED_PRE
+export CMAbv	= 31; # CONS_MOD_ABOVE
+export CMBlw	= 32; # CONS_MOD_BELOW
+export VAbv	= 33; # VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST
+export VBlw	= 34; # VOWEL_BELOW / VOWEL_BELOW_POST
+export VPst	= 35; # VOWEL_POST	UIPC = Right
+export VPre	= 22; # VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST
+export VMAbv	= 37; # VOWEL_MOD_ABOVE
+export VMBlw	= 38; # VOWEL_MOD_BELOW
+export VMPst	= 39; # VOWEL_MOD_POST
+export VMPre	= 23; # VOWEL_MOD_PRE
+export SMAbv	= 41; # SYM_MOD_ABOVE
+export SMBlw	= 42; # SYM_MOD_BELOW
+export FMAbv	= 45; # CONS_FINAL_MOD	UIPC = Top
+export FMBlw	= 46; # CONS_FINAL_MOD	UIPC = Bottom
+export FMPst	= 47; # CONS_FINAL_MOD	UIPC = Not_Applicable
+
 
 h = H | HVM | Sk;
 
-# Override: Adhoc ZWJ placement. https://github.com/harfbuzz/harfbuzz/issues/542#issuecomment-353169729
-consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.h.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*;
-# Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376
-medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
+consonant_modifiers = CMAbv* CMBlw* ((h B | SUB) CMAbv? CMBlw*)*;
+medial_consonants = MPre? MAbv? MBlw? MPst?;
 dependent_vowels = VPre* VAbv* VBlw* VPst*;
 vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
 final_consonants = FAbv* FBlw* FPst*;
 final_modifiers = FMAbv* FMBlw* | FMPst?;
 
-complex_syllable_start = (R | CS)? (B | GB) VS?;
+complex_syllable_start = (R | CS)? (B | GB);
 complex_syllable_middle =
 	consonant_modifiers
 	medial_consonants
@@ -117,19 +128,25 @@
 	final_consonants
 	final_modifiers
 ;
-number_joiner_terminated_cluster_tail = (HN N VS?)* HN;
-numeral_cluster_tail = (HN N VS?)+;
+number_joiner_terminated_cluster_tail = (HN N)* HN;
+numeral_cluster_tail = (HN N)+;
 symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
 
+virama_terminated_cluster_tail =
+	consonant_modifiers
+	h
+;
 virama_terminated_cluster =
 	complex_syllable_start
-	consonant_modifiers
-	ZWJ?.h.ZWJ?
+	virama_terminated_cluster_tail
+;
+sakot_terminated_cluster_tail =
+	complex_syllable_middle
+	Sk
 ;
 sakot_terminated_cluster =
 	complex_syllable_start
-	complex_syllable_middle
-	Sk
+	sakot_terminated_cluster_tail
 ;
 standard_cluster =
 	complex_syllable_start
@@ -137,25 +154,25 @@
 ;
 broken_cluster =
 	R?
-	(complex_syllable_tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail | symbol_cluster_tail)
+	(complex_syllable_tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail | sakot_terminated_cluster_tail)
 ;
 
-number_joiner_terminated_cluster = N VS? number_joiner_terminated_cluster_tail;
-numeral_cluster = N VS? numeral_cluster_tail?;
-symbol_cluster = (S | GB) VS? symbol_cluster_tail?;
-independent_cluster = (IND | O | Rsv | WJ) VS?;
+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*)?)*;
 other = any;
 
 main := |*
-	independent_cluster			=> { found_syllable (independent_cluster); };
-	virama_terminated_cluster		=> { found_syllable (virama_terminated_cluster); };
-	sakot_terminated_cluster		=> { found_syllable (sakot_terminated_cluster); };
-	standard_cluster			=> { found_syllable (standard_cluster); };
-	number_joiner_terminated_cluster	=> { found_syllable (number_joiner_terminated_cluster); };
-	numeral_cluster				=> { found_syllable (numeral_cluster); };
-	symbol_cluster				=> { found_syllable (symbol_cluster); };
-	broken_cluster				=> { found_syllable (broken_cluster); };
-	other					=> { found_syllable (non_cluster); };
+	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); };
+	other					=> { found_syllable (use_non_cluster); };
 *|;
 
 
@@ -163,27 +180,88 @@
 
 #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) | use_##syllable_type; \
+    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
 
-static void
+
+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)
 {
-  unsigned int p, pe, eof, ts, te, act;
-  int cs;
   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;
   %%{
     write init;
-    getkey info[p].use_category();
+    getkey (*p).second.second.use_category();
   }%%
 
-  p = 0;
-  pe = eof = buffer->len;
-
   unsigned int syllable_serial = 1;
   %%{
     write exec;
diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc
deleted file mode 100644
index e3889b3..0000000
--- a/src/hb-ot-shape-complex-use-table.cc
+++ /dev/null
@@ -1,860 +0,0 @@
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
- *
- * on files with these headers:
- *
- * # IndicSyllabicCategory-12.0.0.txt
- * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
- * # IndicPositionalCategory-12.0.0.txt
- * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
- * # Blocks-12.0.0.txt
- * # Date: 2018-07-30, 19:40:00 GMT [KW]
- * UnicodeData.txt does not have a header.
- */
-
-#include "hb.hh"
-
-#ifndef HB_NO_OT_SHAPE
-
-#include "hb-ot-shape-complex-use.hh"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-#define B	USE_B	/* BASE */
-#define CGJ	USE_CGJ	/* CGJ */
-#define CS	USE_CS	/* CONS_WITH_STACKER */
-#define GB	USE_GB	/* BASE_OTHER */
-#define H	USE_H	/* HALANT */
-#define HN	USE_HN	/* HALANT_NUM */
-#define HVM	USE_HVM	/* HALANT_OR_VOWEL_MODIFIER */
-#define IND	USE_IND	/* BASE_IND */
-#define N	USE_N	/* BASE_NUM */
-#define O	USE_O	/* OTHER */
-#define R	USE_R	/* REPHA */
-#define Rsv	USE_Rsv	/* Reserved */
-#define S	USE_S	/* SYM */
-#define SUB	USE_SUB	/* CONS_SUB */
-#define Sk	USE_Sk	/* SAKOT */
-#define VS	USE_VS	/* VARIATION_SELECTOR */
-#define WJ	USE_WJ	/* Word_Joiner */
-#define ZWJ	USE_ZWJ	/* ZWJ */
-#define ZWNJ	USE_ZWNJ	/* ZWNJ */
-#define CMBlw	USE_CMBlw
-#define CMAbv	USE_CMAbv
-#define FBlw	USE_FBlw
-#define FPst	USE_FPst
-#define FAbv	USE_FAbv
-#define FMBlw	USE_FMBlw
-#define FMPst	USE_FMPst
-#define FMAbv	USE_FMAbv
-#define MPre	USE_MPre
-#define MBlw	USE_MBlw
-#define MPst	USE_MPst
-#define MAbv	USE_MAbv
-#define SMBlw	USE_SMBlw
-#define SMAbv	USE_SMAbv
-#define VPre	USE_VPre
-#define VBlw	USE_VBlw
-#define VPst	USE_VPst
-#define VAbv	USE_VAbv
-#define VMPre	USE_VMPre
-#define VMBlw	USE_VMBlw
-#define VMPst	USE_VMPst
-#define VMAbv	USE_VMAbv
-#pragma GCC diagnostic pop
-
-static const USE_TABLE_ELEMENT_TYPE 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_0x0900u 88
-
-
-  /* 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,  VPst,  VPst,     H,   IND,     O,
-  /* 09D0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     B,     B,     O,     B,
-  /* 09E0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O, 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,  VPst,     O,     O,  VPst,  VPst,     H,     O,     O,
-  /* 0B50 */     O,     O,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,     O,     O,     B,     B,     O,     B,
-  /* 0B60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0B70 */     O,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Tamil */
-
-  /* 0B80 */     O,     O, VMAbv,   IND,     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,  VPst,  VPst,  VPst,     H,     O,     O,
-  /* 0BD0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 0BE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0BF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* 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,     O,     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,     O,     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,  VPst,  VPst,  VPst,     H,     R,     O,
-  /* 0D50 */     O,     O,     O,     O,   IND,   IND,   IND,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,
-  /* 0D60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0D70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,   IND,   IND,   IND,   IND,   IND,   IND,
-
-  /* Sinhala */
-
-  /* 0D80 */     O,     O, 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,  VPst,  VPre,  VPst,  VPst,  VPst,  VPst,
-  /* 0DE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0DF0 */     O,     O,  VPst,  VPst,     O,     O,     O,     O,
-
-#define use_offset_0x0f18u 1360
-
-
-  /* Tibetan */
-                                                                      VBlw,  VBlw,     O,     O,     O,     O,     O,     O,
-  /* 0F20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0F30 */     B,     B,     B,     B,     O, FMBlw,     O, FMBlw,     O, CMAbv,     O,     O,     O,     O,  VPst,  VPre,
-  /* 0F40 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
-  /* 0F50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0F60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
-  /* 0F70 */     O,  VBlw,  VBlw,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw, VMAbv, VMPst,
-  /* 0F80 */  VBlw,  VAbv, VMAbv, VMAbv,  VBlw,   IND, VMAbv, VMAbv,     B,     B,     B,     B,     B,   SUB,   SUB,   SUB,
-  /* 0F90 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
-  /* 0FA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
-  /* 0FB0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,     O,     O,
-  /* 0FC0 */     O,     O,     O,     O,     O,     O, FMBlw,     O,
-
-#define use_offset_0x1000u 1536
-
-
-  /* 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 1696
-
-
-  /* Tagalog */
-
-  /* 1700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
-  /* 1710 */     B,     B,  VAbv,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Hanunoo */
-
-  /* 1720 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1730 */     B,     B,  VAbv,  VBlw,  VBlw,     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,     O,     O,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPst,  VPst,
-  /* 17C0 */  VPst,  VPre,  VPre,  VPre,  VPst,  VPst, VMAbv, VMPst,  VPst, VMAbv, VMAbv, FMAbv,  FAbv, CMAbv, FMAbv, FMAbv,
-  /* 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,
-
-#define use_offset_0x1900u 1936
-
-
-  /* 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,  VAbv, 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,  VBlw,  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, FMAbv, FMAbv,     O,     O, FMBlw,
-  /* 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 2352
-
-
-  /* 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 */  VPst,  VPst,  VAbv,  VAbv,     H,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
-  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,    GB,     O,     O,    GB,
-  /* 1B60 */     O,     S,    GB,     S,     S,     S,     S,     S,    GB,     S,     S, 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 2688
-
-
-  /* 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,   IND,   IND, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,    GB,     O,     O,     O,     O,     O,
-
-#define use_offset_0x1df8u 2736
-
-
-  /* Combining Diacritical Marks Supplement */
-                                                                         O,     O,     O, FMAbv,     O,     O,     O,     O,
-
-#define use_offset_0x2008u 2744
-
-
-  /* General Punctuation */
-                                                                         O,     O,     O,     O,  ZWNJ,   ZWJ,     O,     O,
-  /* 2010 */    GB,    GB,    GB,    GB,    GB,     O,     O,     O,
-
-#define use_offset_0x2060u 2760
-
-  /* 2060 */    WJ,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* 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 2800
-
-
-  /* Combining Diacritical Marks for Symbols */
-
-  /* 20F0 */ VMAbv,     O,     O,     O,     O,     O,     O,     O,
-
-#define use_offset_0x25c8u 2808
-
-
-  /* Geometric Shapes */
-                                                                         O,     O,     O,     O,    GB,     O,     O,     O,
-
-#define use_offset_0xa800u 2816
-
-
-  /* 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,     O,     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,  MBlw,  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 3576
-
-
-  /* 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 3640
-
-
-  /* Variation Selectors */
-
-  /* FE00 */    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,
-
-#define use_offset_0x10a00u 3656
-
-
-  /* Kharoshthi */
-
-  /* 10A00 */     B,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,  VBlw,  VBlw, 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_0x11000u 3736
-
-
-  /* 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,   HVM,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11050 */     O,     O,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,
-  /* 11060 */     N,     N,     N,     N,     N,     N,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11070 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    HN,
-
-  /* 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,
-
-#define use_offset_0x11100u 3928
-
-
-  /* Chakma */
-
-  /* 11100 */ VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11120 */     B,     B,     B,     B,     B,     B,     B,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VBlw,  VAbv,  VAbv,
-  /* 11130 */  VBlw,  VAbv,  VAbv,     H, CMBlw,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Mahajani */
-
-  /* 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,     O,     O,
-  /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     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 4248
-
-
-  /* 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,  VPst,  VPst,   HVM,     O,     O,
-  /* 11350 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     B,     B,
-  /* 11360 */     B,     B,  VPst,  VPst,     O,     O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
-  /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
-
-#define use_offset_0x11400u 4496
-
-
-  /* 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 */     O,     O,     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,  VPst,  VPst,  VPst,  VPst, 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 4720
-
-
-  /* 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,  VPst,  VPst,  VPst, VMAbv, VMAbv, VMPst,     H,
-  /* 115C0 */ CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 115D0 */     O,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,  VBlw,  VBlw,     O,     O,
-  /* 115E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 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,
-
-#define use_offset_0x11800u 5168
-
-
-  /* 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_0x119a0u 5232
-
-
-  /* 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 5488
-
-
-  /* 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 5672
-
-
-  /* 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 5848
-
-
-  /* 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,
-
-}; /* Table items: 5872; occupancy: 74% */
-
-USE_TABLE_ELEMENT_TYPE
-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, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x0F18u, 0x0FC7u)) return use_table[u - 0x0F18u + use_offset_0x0f18u];
-      break;
-
-    case 0x1u:
-      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, 0x17EFu)) 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, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
-      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];
-      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, 0x10A00u, 0x10A4Fu)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
-      break;
-
-    case 0x11u:
-      if (hb_in_range<hb_codepoint_t> (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
-      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, 0x1173Fu)) 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, 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;
-
-    default:
-      break;
-  }
-  return USE_O;
-}
-
-#undef B
-#undef CGJ
-#undef CS
-#undef GB
-#undef H
-#undef HN
-#undef HVM
-#undef IND
-#undef N
-#undef O
-#undef R
-#undef Rsv
-#undef S
-#undef SUB
-#undef Sk
-#undef VS
-#undef WJ
-#undef ZWJ
-#undef ZWNJ
-#undef CMBlw
-#undef CMAbv
-#undef FBlw
-#undef FPst
-#undef FAbv
-#undef FMBlw
-#undef FMPst
-#undef FMAbv
-#undef MPre
-#undef MBlw
-#undef MPst
-#undef MAbv
-#undef SMBlw
-#undef SMAbv
-#undef VPre
-#undef VBlw
-#undef VPst
-#undef VAbv
-#undef VMPre
-#undef VMBlw
-#undef VMPst
-#undef VMAbv
-
-
-#endif
-/* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-use-table.hh b/src/hb-ot-shape-complex-use-table.hh
new file mode 100644
index 0000000..7a3a995
--- /dev/null
+++ b/src/hb-ot-shape-complex-use-table.hh
@@ -0,0 +1,1283 @@
+/* == 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 == */
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index 10f5822..70b6379 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -30,13 +30,12 @@
 
 #ifndef HB_NO_OT_SHAPE
 
-#include "hb-ot-shape-complex-use.hh"
+#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"
 
-/* buffer var allocations */
-#define use_category() complex_var_u8_0()
-
 
 /*
  * Universal Shaping Engine.
@@ -48,7 +47,8 @@
 {
   /*
    * Basic features.
-   * These features are applied all at once, before reordering.
+   * These features are applied all at once, before reordering, constrained
+   * to the syllable.
    */
   HB_TAG('r','k','r','f'),
   HB_TAG('a','b','v','f'),
@@ -68,11 +68,11 @@
 };
 /* Same order as use_topographical_features. */
 enum joining_form_t {
-  USE_ISOL,
-  USE_INIT,
-  USE_MEDI,
-  USE_FINA,
-  _USE_NONE
+  JOINING_FORM_ISOL,
+  JOINING_FORM_INIT,
+  JOINING_FORM_MEDI,
+  JOINING_FORM_FINA,
+  _JOINING_FORM_NONE
 };
 static const hb_tag_t
 use_other_features[] =
@@ -152,44 +152,10 @@
   arabic_shape_plan_t *arabic_plan;
 };
 
-static bool
-has_arabic_joining (hb_script_t script)
-{
-  /* List of scripts that have data in arabic-table. */
-  switch ((int) script)
-  {
-    /* Unicode-1.1 additions */
-    case HB_SCRIPT_ARABIC:
-
-    /* Unicode-3.0 additions */
-    case HB_SCRIPT_MONGOLIAN:
-    case HB_SCRIPT_SYRIAC:
-
-    /* Unicode-5.0 additions */
-    case HB_SCRIPT_NKO:
-    case HB_SCRIPT_PHAGS_PA:
-
-    /* Unicode-6.0 additions */
-    case HB_SCRIPT_MANDAIC:
-
-    /* Unicode-7.0 additions */
-    case HB_SCRIPT_MANICHAEAN:
-    case HB_SCRIPT_PSALTER_PAHLAVI:
-
-    /* Unicode-9.0 additions */
-    case HB_SCRIPT_ADLAM:
-
-      return true;
-
-    default:
-      return false;
-  }
-}
-
 static void *
 data_create_use (const hb_ot_shape_plan_t *plan)
 {
-  use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
+  use_shape_plan_t *use_plan = (use_shape_plan_t *) hb_calloc (1, sizeof (use_shape_plan_t));
   if (unlikely (!use_plan))
     return nullptr;
 
@@ -200,7 +166,7 @@
     use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
     if (unlikely (!use_plan->arabic_plan))
     {
-      free (use_plan);
+      hb_free (use_plan);
       return nullptr;
     }
   }
@@ -216,24 +182,9 @@
   if (use_plan->arabic_plan)
     data_destroy_arabic (use_plan->arabic_plan);
 
-  free (data);
+  hb_free (data);
 }
 
-enum use_syllable_type_t {
-  use_independent_cluster,
-  use_virama_terminated_cluster,
-  use_sakot_terminated_cluster,
-  use_standard_cluster,
-  use_number_joiner_terminated_cluster,
-  use_numeral_cluster,
-  use_symbol_cluster,
-  use_broken_cluster,
-  use_non_cluster,
-};
-
-#include "hb-ot-shape-complex-use-machine.hh"
-
-
 static void
 setup_masks_use (const hb_ot_shape_plan_t *plan,
 		 hb_buffer_t              *buffer,
@@ -271,7 +222,7 @@
 
   foreach_syllable (buffer, start, end)
   {
-    unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
+    unsigned int limit = info[start].use_category() == USE(R) ? 1 : hb_min (3u, end - start);
     for (unsigned int i = start; i < start + limit; i++)
       info[i].mask |= mask;
   }
@@ -285,7 +236,7 @@
   if (use_plan->arabic_plan)
     return;
 
-  static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
+  static_assert ((JOINING_FORM_INIT < 4 && JOINING_FORM_ISOL < 4 && JOINING_FORM_MEDI < 4 && JOINING_FORM_FINA < 4), "");
   hb_mask_t masks[4], all_masks = 0;
   for (unsigned int i = 0; i < 4; i++)
   {
@@ -299,18 +250,18 @@
   hb_mask_t other_masks = ~all_masks;
 
   unsigned int last_start = 0;
-  joining_form_t last_form = _USE_NONE;
+  joining_form_t last_form = _JOINING_FORM_NONE;
   hb_glyph_info_t *info = buffer->info;
   foreach_syllable (buffer, start, end)
   {
     use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
     switch (syllable_type)
     {
-      case use_independent_cluster:
       case use_symbol_cluster:
+      case use_hieroglyph_cluster:
       case use_non_cluster:
 	/* These don't join.  Nothing to do. */
-	last_form = _USE_NONE;
+	last_form = _JOINING_FORM_NONE;
 	break;
 
       case use_virama_terminated_cluster:
@@ -320,18 +271,18 @@
       case use_numeral_cluster:
       case use_broken_cluster:
 
-	bool join = last_form == USE_FINA || last_form == USE_ISOL;
+	bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
 
 	if (join)
 	{
 	  /* Fixup previous syllable's form. */
-	  last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
+	  last_form = last_form == JOINING_FORM_FINA ? JOINING_FORM_MEDI : JOINING_FORM_INIT;
 	  for (unsigned int i = last_start; i < start; i++)
 	    info[i].mask = (info[i].mask & other_masks) | masks[last_form];
 	}
 
 	/* Form for this syllable. */
-	last_form = join ? USE_FINA : USE_ISOL;
+	last_form = join ? JOINING_FORM_FINA : JOINING_FORM_ISOL;
 	for (unsigned int i = start; i < end; i++)
 	  info[i].mask = (info[i].mask & other_masks) | masks[last_form];
 
@@ -367,11 +318,11 @@
 
   foreach_syllable (buffer, start, end)
   {
-    /* Mark a substituted repha as USE_R. */
+    /* Mark a substituted repha as USE(R). */
     for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
       if (_hb_glyph_info_substituted (&info[i]))
       {
-	info[i].use_category() = USE_R;
+	info[i].use_category() = USE(R);
 	break;
       }
   }
@@ -390,7 +341,7 @@
     for (unsigned int i = start; i < end; i++)
       if (_hb_glyph_info_substituted (&info[i]))
       {
-	info[i].use_category() = USE_VPre;
+	info[i].use_category() = USE(VPre);
 	break;
       }
   }
@@ -399,7 +350,7 @@
 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)) &&
 	 !_hb_glyph_info_ligated (&info);
 }
 
@@ -418,25 +369,24 @@
 
   hb_glyph_info_t *info = buffer->info;
 
-#define POST_BASE_FLAGS64 (FLAG64 (USE_FM) | \
-			   FLAG64 (USE_FAbv) | \
-			   FLAG64 (USE_FBlw) | \
-			   FLAG64 (USE_FPst) | \
-			   FLAG64 (USE_MAbv) | \
-			   FLAG64 (USE_MBlw) | \
-			   FLAG64 (USE_MPst) | \
-			   FLAG64 (USE_MPre) | \
-			   FLAG64 (USE_VAbv) | \
-			   FLAG64 (USE_VBlw) | \
-			   FLAG64 (USE_VPst) | \
-			   FLAG64 (USE_VPre) | \
-			   FLAG64 (USE_VMAbv) | \
-			   FLAG64 (USE_VMBlw) | \
-			   FLAG64 (USE_VMPst) | \
-			   FLAG64 (USE_VMPre))
+#define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
+			   FLAG64 (USE(FBlw)) | \
+			   FLAG64 (USE(FPst)) | \
+			   FLAG64 (USE(MAbv)) | \
+			   FLAG64 (USE(MBlw)) | \
+			   FLAG64 (USE(MPst)) | \
+			   FLAG64 (USE(MPre)) | \
+			   FLAG64 (USE(VAbv)) | \
+			   FLAG64 (USE(VBlw)) | \
+			   FLAG64 (USE(VPst)) | \
+			   FLAG64 (USE(VPre)) | \
+			   FLAG64 (USE(VMAbv)) | \
+			   FLAG64 (USE(VMBlw)) | \
+			   FLAG64 (USE(VMPst)) | \
+			   FLAG64 (USE(VMPre)))
 
   /* Move things forward. */
-  if (info[start].use_category() == USE_R && end - start > 1)
+  if (info[start].use_category() == USE(R) && end - start > 1)
   {
     /* Got a repha.  Reorder it towards the end, but before the first post-base
      * glyph. */
@@ -473,7 +423,7 @@
        * shift things in between forward. */
       j = i + 1;
     }
-    else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+    else if (((flag) & (FLAG (USE(VPre)) | FLAG (USE(VMPre)))) &&
 	     /* Only move the first component of a MultipleSubst. */
 	     0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
 	     j < i)
@@ -486,73 +436,23 @@
   }
 }
 
-static inline void
-insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			   hb_font_t *font,
-			   hb_buffer_t *buffer)
-{
-  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) == use_broken_cluster)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
-
-  hb_glyph_info_t dottedcircle = {0};
-  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
-    return;
-  dottedcircle.use_category() = hb_use_get_category (0x25CC);
-
-  buffer->clear_output ();
-
-  buffer->idx = 0;
-  unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && buffer->successful)
-  {
-    unsigned int syllable = buffer->cur().syllable();
-    use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
-    {
-      last_syllable = syllable;
-
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
-
-      /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len && buffer->successful &&
-	     last_syllable == buffer->cur().syllable() &&
-	     buffer->cur().use_category() == USE_R)
-	buffer->next_glyph ();
-
-      buffer->output_info (ginfo);
-    }
-    else
-      buffer->next_glyph ();
-  }
-  buffer->swap_buffers ();
-}
-
 static void
 reorder_use (const hb_ot_shape_plan_t *plan,
 	     hb_font_t *font,
 	     hb_buffer_t *buffer)
 {
-  insert_dotted_circles_use (plan, font, buffer);
+  if (buffer->message (font, "start reordering USE"))
+  {
+    hb_syllabic_insert_dotted_circles (font, buffer,
+				       use_broken_cluster,
+				       USE(B),
+				       USE(R));
 
-  foreach_syllable (buffer, start, end)
-    reorder_syllable_use (buffer, start, end);
+    foreach_syllable (buffer, start, end)
+      reorder_syllable_use (buffer, start, end);
+
+    (void) buffer->message (font, "end reordering USE");
+  }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
 }
diff --git a/src/hb-ot-shape-complex-use.hh b/src/hb-ot-shape-complex-use.hh
deleted file mode 100644
index ce6645e..0000000
--- a/src/hb-ot-shape-complex-use.hh
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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_HH
-#define HB_OT_SHAPE_COMPLEX_USE_HH
-
-#include "hb.hh"
-
-
-#include "hb-ot-shape-complex.hh"
-
-
-#define USE_TABLE_ELEMENT_TYPE uint8_t
-
-/* Cateories used in the Universal Shaping Engine spec:
- * https://docs.microsoft.com/en-us/typography/script-development/use
- */
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum use_category_t {
-  USE_O		= 0,	/* OTHER */
-
-  USE_B		= 1,	/* BASE */
-  USE_IND	= 3,	/* BASE_IND */
-  USE_N		= 4,	/* BASE_NUM */
-  USE_GB	= 5,	/* BASE_OTHER */
-  USE_CGJ	= 6,	/* CGJ */
-//  USE_F		= 7,	/* CONS_FINAL */
-  USE_FM	= 8,	/* CONS_FINAL_MOD */
-//  USE_M		= 9,	/* CONS_MED */
-//  USE_CM	= 10,	/* CONS_MOD */
-  USE_SUB	= 11,	/* CONS_SUB */
-  USE_H		= 12,	/* HALANT */
-
-  USE_HN	= 13,	/* HALANT_NUM */
-  USE_ZWNJ	= 14,	/* Zero width non-joiner */
-  USE_ZWJ	= 15,	/* Zero width joiner */
-  USE_WJ	= 16,	/* Word joiner */
-  USE_Rsv	= 17,	/* Reserved characters */
-  USE_R		= 18,	/* REPHA */
-  USE_S		= 19,	/* SYM */
-//  USE_SM	= 20,	/* SYM_MOD */
-  USE_VS	= 21,	/* VARIATION_SELECTOR */
-//  USE_V	= 36,	/* VOWEL */
-//  USE_VM	= 40,	/* VOWEL_MOD */
-  USE_CS	= 43,	/* CONS_WITH_STACKER */
-
-  /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
-  USE_HVM	= 44,	/* HALANT_OR_VOWEL_MODIFIER */
-
-  USE_Sk	= 48,	/* SAKOT */
-
-  USE_FAbv	= 24,	/* CONS_FINAL_ABOVE */
-  USE_FBlw	= 25,	/* CONS_FINAL_BELOW */
-  USE_FPst	= 26,	/* CONS_FINAL_POST */
-  USE_MAbv	= 27,	/* CONS_MED_ABOVE */
-  USE_MBlw	= 28,	/* CONS_MED_BELOW */
-  USE_MPst	= 29,	/* CONS_MED_POST */
-  USE_MPre	= 30,	/* CONS_MED_PRE */
-  USE_CMAbv	= 31,	/* CONS_MOD_ABOVE */
-  USE_CMBlw	= 32,	/* CONS_MOD_BELOW */
-  USE_VAbv	= 33,	/* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
-  USE_VBlw	= 34,	/* VOWEL_BELOW / VOWEL_BELOW_POST */
-  USE_VPst	= 35,	/* VOWEL_POST	UIPC = Right */
-  USE_VPre	= 22,	/* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
-  USE_VMAbv	= 37,	/* VOWEL_MOD_ABOVE */
-  USE_VMBlw	= 38,	/* VOWEL_MOD_BELOW */
-  USE_VMPst	= 39,	/* VOWEL_MOD_POST */
-  USE_VMPre	= 23,	/* VOWEL_MOD_PRE */
-  USE_SMAbv	= 41,	/* SYM_MOD_ABOVE */
-  USE_SMBlw	= 42,	/* SYM_MOD_BELOW */
-  USE_FMAbv	= 45,	/* CONS_FINAL_MOD	UIPC = Top */
-  USE_FMBlw	= 46,	/* CONS_FINAL_MOD	UIPC = Bottom */
-  USE_FMPst	= 47,	/* CONS_FINAL_MOD	UIPC = Not_Applicable */
-};
-
-HB_INTERNAL USE_TABLE_ELEMENT_TYPE
-hb_use_get_category (hb_codepoint_t u);
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */
diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc
index 2f80413..045731d 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -2,15 +2,16 @@
 /*
  * The following functions are generated by running:
  *
- *   ./gen-vowel-constraints.py use Scripts.txt
+ *   ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
  *
  * on files with these headers:
  *
- * # Copied from https://docs.microsoft.com/en-us/typography/script-development/use
- * # On October 23, 2018; with documentd dated 02/07/2018.
+ * # IndicShapingInvalidCluster.txt
+ * # Date: 2015-03-12, 21:17:00 GMT [AG]
+ * # Date: 2019-11-08, 23:22:00 GMT [AG]
  *
- * # Scripts-12.0.0.txt
- * # Date: 2019-01-28, 22:16:47 GMT
+ * # Scripts-14.0.0.txt
+ * # Date: 2021-07-10, 00:35:31 GMT
  */
 
 #include "hb.hh"
@@ -22,15 +23,15 @@
 static void
 _output_dotted_circle (hb_buffer_t *buffer)
 {
-  hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
-  _hb_glyph_info_reset_continuation (&dottedcircle);
+  (void) buffer->output_glyph (0x25CCu);
+  _hb_glyph_info_reset_continuation (&buffer->prev());
 }
 
 static void
 _output_with_dotted_circle (hb_buffer_t *buffer)
 {
   _output_dotted_circle (buffer);
-  buffer->next_glyph ();
+  (void) buffer->next_glyph ();
 }
 
 void
@@ -50,7 +51,6 @@
    *
    * https://github.com/harfbuzz/harfbuzz/issues/1019
    */
-  bool processed = false;
   buffer->clear_output ();
   unsigned int count = buffer->len;
   switch ((unsigned) buffer->props.script)
@@ -96,16 +96,14 @@
 		buffer->idx + 2 < count &&
 		0x0907u == buffer->cur (2).codepoint)
 	    {
-	      buffer->next_glyph ();
-	      buffer->next_glyph ();
-	      _output_dotted_circle (buffer);
+	      (void) buffer->next_glyph ();
+	      matched = true;
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_BENGALI:
@@ -124,10 +122,9 @@
 	    matched = 0x09E2u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_GURMUKHI:
@@ -161,10 +158,9 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_GUJARATI:
@@ -186,10 +182,9 @@
 	    matched = 0x0ABEu == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_ORIYA:
@@ -205,10 +200,23 @@
 	    matched = 0x0B57u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
+      break;
+
+    case HB_SCRIPT_TAMIL:
+      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+      {
+	bool matched = false;
+	if (0x0B85u == buffer->cur ().codepoint &&
+	    0x0BC2u == buffer->cur (1).codepoint)
+	{
+	  matched = true;
+	}
+	(void) buffer->next_glyph ();
+	if (matched) _output_with_dotted_circle (buffer);
+      }
       break;
 
     case HB_SCRIPT_TELUGU:
@@ -229,10 +237,9 @@
 	    matched = 0x0C55u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_KANNADA:
@@ -248,10 +255,9 @@
 	    matched = 0x0CCCu == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_MALAYALAM:
@@ -275,10 +281,9 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_SINHALA:
@@ -305,16 +310,15 @@
 	    switch (buffer->cur (1).codepoint)
 	    {
 	      case 0x0DCAu: case 0x0DD9u: case 0x0DDAu: case 0x0DDCu:
-	      case 0x0DDDu:
+	      case 0x0DDDu: case 0x0DDEu:
 		matched = true;
 		break;
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_BRAHMI:
@@ -333,10 +337,9 @@
 	    matched = 0x11042u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_KHUDAWADI:
@@ -355,10 +358,9 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_TIRHUTA:
@@ -382,10 +384,9 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_MODI:
@@ -403,10 +404,9 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     case HB_SCRIPT_TAKRI:
@@ -427,21 +427,15 @@
 	    matched = 0x116B2u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
-      processed = true;
       break;
 
     default:
       break;
   }
-  if (processed)
-  {
-    if (buffer->idx < count)
-      buffer->next_glyph ();
-    buffer->swap_buffers ();
-  }
+  buffer->swap_buffers ();
 }
 
 
diff --git a/src/hb-ot-shape-complex.hh b/src/hb-ot-shape-complex.hh
index 2691622..8012a9a 100644
--- a/src/hb-ot-shape-complex.hh
+++ b/src/hb-ot-shape-complex.hh
@@ -35,8 +35,8 @@
 
 
 /* buffer var allocations, used by complex shapers */
-#define complex_var_u8_0()	var2.u8[2]
-#define complex_var_u8_1()	var2.u8[3]
+#define complex_var_u8_category()	var2.u8[2]
+#define complex_var_u8_auxiliary()	var2.u8[3]
 
 
 #define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
@@ -50,8 +50,9 @@
 
 /* Master OT shaper list */
 #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
-  HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
   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) \
@@ -60,7 +61,7 @@
   HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \
   HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
   HB_COMPLEX_SHAPER_IMPLEMENT (use) \
-  /* ^--- Add new shapers here */
+  /* ^--- Add new shapers here; keep sorted. */
 
 
 struct hb_ot_complex_shaper_t
@@ -185,27 +186,8 @@
     case HB_SCRIPT_ARABIC:
 
     /* Unicode-3.0 additions */
-    case HB_SCRIPT_MONGOLIAN:
     case HB_SCRIPT_SYRIAC:
 
-    /* Unicode-5.0 additions */
-    case HB_SCRIPT_NKO:
-    case HB_SCRIPT_PHAGS_PA:
-
-    /* Unicode-6.0 additions */
-    case HB_SCRIPT_MANDAIC:
-
-    /* Unicode-7.0 additions */
-    case HB_SCRIPT_MANICHAEAN:
-    case HB_SCRIPT_PSALTER_PAHLAVI:
-
-    /* Unicode-9.0 additions */
-    case HB_SCRIPT_ADLAM:
-
-    /* Unicode-11.0 additions */
-    case HB_SCRIPT_HANIFI_ROHINGYA:
-    case HB_SCRIPT_SOGDIAN:
-
       /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
        * This is because we do fallback shaping for Arabic script (and not others).
        * But note that Arabic shaping is applicable only to horizontal layout; for
@@ -283,8 +265,9 @@
 	return &_hb_ot_complex_shaper_myanmar;
 
 
-    /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
+#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;
 
@@ -293,7 +276,7 @@
     case HB_SCRIPT_TIBETAN:
 
     /* Unicode-3.0 additions */
-    //case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_MONGOLIAN:
     //case HB_SCRIPT_SINHALA:
 
     /* Unicode-3.2 additions */
@@ -314,8 +297,8 @@
 
     /* Unicode-5.0 additions */
     case HB_SCRIPT_BALINESE:
-    //case HB_SCRIPT_NKO:
-    //case HB_SCRIPT_PHAGS_PA:
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_CHAM:
@@ -336,10 +319,11 @@
     /* Unicode-6.0 additions */
     case HB_SCRIPT_BATAK:
     case HB_SCRIPT_BRAHMI:
-    //case HB_SCRIPT_MANDAIC:
+    case HB_SCRIPT_MANDAIC:
 
     /* Unicode-6.1 additions */
     case HB_SCRIPT_CHAKMA:
+    case HB_SCRIPT_MIAO:
     case HB_SCRIPT_SHARADA:
     case HB_SCRIPT_TAKRI:
 
@@ -349,18 +333,19 @@
     case HB_SCRIPT_KHOJKI:
     case HB_SCRIPT_KHUDAWADI:
     case HB_SCRIPT_MAHAJANI:
-    //case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MANICHAEAN:
     case HB_SCRIPT_MODI:
     case HB_SCRIPT_PAHAWH_HMONG:
-    //case HB_SCRIPT_PSALTER_PAHLAVI:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
     case HB_SCRIPT_SIDDHAM:
     case HB_SCRIPT_TIRHUTA:
 
     /* Unicode-8.0 additions */
     case HB_SCRIPT_AHOM:
+    case HB_SCRIPT_MULTANI:
 
     /* Unicode-9.0 additions */
-    //case HB_SCRIPT_ADLAM:
+    case HB_SCRIPT_ADLAM:
     case HB_SCRIPT_BHAIKSUKI:
     case HB_SCRIPT_MARCHEN:
     case HB_SCRIPT_NEWA:
@@ -373,12 +358,30 @@
     /* Unicode-11.0 additions */
     case HB_SCRIPT_DOGRA:
     case HB_SCRIPT_GUNJALA_GONDI:
-    //case HB_SCRIPT_HANIFI_ROHINGYA:
+    case HB_SCRIPT_HANIFI_ROHINGYA:
     case HB_SCRIPT_MAKASAR:
-    //case HB_SCRIPT_SOGDIAN:
+    case HB_SCRIPT_MEDEFAIDRIN:
+    case HB_SCRIPT_OLD_SOGDIAN:
+    case HB_SCRIPT_SOGDIAN:
 
     /* Unicode-12.0 additions */
+    case HB_SCRIPT_ELYMAIC:
     case HB_SCRIPT_NANDINAGARI:
+    case HB_SCRIPT_NYIAKENG_PUACHUE_HMONG:
+    case HB_SCRIPT_WANCHO:
+
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_DIVES_AKURU:
+    case HB_SCRIPT_KHITAN_SMALL_SCRIPT:
+    case HB_SCRIPT_YEZIDI:
+
+    /* Unicode-14.0 additions */
+    case HB_SCRIPT_CYPRO_MINOAN:
+    case HB_SCRIPT_OLD_UYGHUR:
+    case HB_SCRIPT_TANGSA:
+    case HB_SCRIPT_TOTO:
+    case HB_SCRIPT_VITHKUQI:
 
       /* If the designer designed the font for the 'DFLT' script,
        * (or we ended up arbitrarily pick 'latn'), use the default shaper.
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index 024bcfe..eb1bc79 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -92,7 +92,7 @@
     case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
     case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
     case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
-    case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
+    case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats & qamats qatan */
     case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
     case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
       return HB_UNICODE_COMBINING_CLASS_BELOW;
@@ -104,7 +104,7 @@
       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
 
     case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
-    case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
+    case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam & holam haser for vav */
       return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
 
     case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
@@ -301,7 +301,7 @@
       /* Don't shift down "above" marks too much. */
       if ((y_gap > 0) != (pos.y_offset > 0))
       {
-	unsigned int correction = -pos.y_offset / 2;
+	int correction = -pos.y_offset / 2;
 	base_extents.y_bearing += correction;
 	base_extents.height -= correction;
 	pos.y_offset += correction;
@@ -422,12 +422,12 @@
   /* Find the base glyph */
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
-    if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+    if (!_hb_glyph_info_is_unicode_mark (&info[i]))
     {
       /* Find mark glyphs */
       unsigned int j;
       for (j = i + 1; j < end; j++)
-	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
+	if (!_hb_glyph_info_is_unicode_mark (&info[j]))
 	  break;
 
       position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
@@ -452,7 +452,7 @@
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
+    if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]))) {
       position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 553d532..839cc91 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -101,8 +101,9 @@
 static inline void
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
+  /* This is very confusing indeed. */
   buffer->cur().glyph_index() = glyph;
-  buffer->output_glyph (unichar); /* This is very confusing indeed. */
+  (void) buffer->output_glyph (unichar);
   _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
 }
 
@@ -110,7 +111,7 @@
 next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
-  buffer->next_glyph ();
+  (void) buffer->next_glyph ();
 }
 
 static inline void
@@ -170,7 +171,7 @@
   hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph = 0;
 
-  if (shortest && c->font->get_nominal_glyph (u, &glyph))
+  if (shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
   {
     next_char (buffer, glyph);
     return;
@@ -182,7 +183,7 @@
     return;
   }
 
-  if (!shortest && c->font->get_nominal_glyph (u, &glyph))
+  if (!shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
   {
     next_char (buffer, glyph);
     return;
@@ -229,30 +230,35 @@
       if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
       {
 	hb_codepoint_t unicode = buffer->cur().codepoint;
-	buffer->replace_glyphs (2, 1, &unicode);
+	(void) buffer->replace_glyphs (2, 1, &unicode);
       }
       else
       {
 	/* Just pass on the two characters separately, let GSUB do its magic. */
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
       }
       /* Skip any further variation selectors. */
-      while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+      while (buffer->idx < end &&
+	     buffer->successful &&
+	     unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
       {
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
       }
-    } else {
+    }
+    else
+    {
       set_glyph (buffer->cur(), font);
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
     }
   }
-  if (likely (buffer->idx < end)) {
+  if (likely (buffer->idx < end))
+  {
     set_glyph (buffer->cur(), font);
-    buffer->next_glyph ();
+    (void) buffer->next_glyph ();
   }
 }
 
@@ -306,6 +312,7 @@
     buffer,
     font,
     buffer->unicode,
+    buffer->not_found,
     plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
     plan->shaper->compose   ? plan->shaper->compose   : compose_unicode
   };
@@ -334,7 +341,7 @@
     {
       unsigned int end;
       for (end = buffer->idx + 1; end < count; end++)
-	if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+	if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end])))
 	  break;
 
       if (end < count)
@@ -348,7 +355,7 @@
 						      sizeof (buffer->info[0]),
 						      &buffer->cur().glyph_index(),
 						      sizeof (buffer->info[0]));
-	buffer->next_glyphs (done);
+	if (unlikely (!buffer->next_glyphs (done))) break;
       }
       while (buffer->idx < end && buffer->successful)
 	decompose_current_character (&c, might_short_circuit);
@@ -360,7 +367,7 @@
 
       /* Find all the marks now. */
       for (end = buffer->idx + 1; end < count; end++)
-	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))
+	if (!_hb_glyph_info_is_unicode_mark(&buffer->info[end]))
 	  break;
 
       /* idx to end is one non-simple cluster. */
@@ -373,7 +380,7 @@
 
   /* Second round, reorder (inplace) */
 
-  if (!all_simple)
+  if (!all_simple && buffer->message(font, "start reorder"))
   {
     count = buffer->len;
     for (unsigned int i = 0; i < count; i++)
@@ -399,6 +406,7 @@
 
       i = end;
     }
+    (void) buffer->message(font, "end reorder");
   }
   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ)
   {
@@ -408,7 +416,7 @@
      */
     for (unsigned int i = 1; i + 1 < buffer->len; i++)
       if (buffer->info[i].codepoint == 0x034Fu/*CGJ*/ &&
-	  info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1]))
+	  (info_cc(buffer->info[i+1]) == 0 || info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1])))
       {
 	_hb_glyph_info_unhide (&buffer->info[i]);
       }
@@ -418,6 +426,7 @@
   /* Third round, recompose */
 
   if (!all_simple &&
+      buffer->successful &&
       (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
        mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT))
   {
@@ -427,15 +436,15 @@
     buffer->clear_output ();
     count = buffer->len;
     unsigned int starter = 0;
-    buffer->next_glyph ();
-    while (buffer->idx < count && buffer->successful)
+    (void) buffer->next_glyph ();
+    while (buffer->idx < count /* No need for: && buffer->successful */)
     {
       hb_codepoint_t composed, glyph;
       if (/* We don't try to compose a non-mark character with it's preceding starter.
 	   * This is both an optimization to avoid trying to compose every two neighboring
 	   * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
 	   * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
-	  HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())))
+	  _hb_glyph_info_is_unicode_mark(&buffer->cur()))
       {
 	if (/* If there's anything between the starter and this char, they should have CCC
 	     * smaller than this character's. */
@@ -450,9 +459,7 @@
 	    font->get_nominal_glyph (composed, &glyph))
 	{
 	  /* Composes. */
-	  buffer->next_glyph (); /* Copy to out-buffer. */
-	  if (unlikely (!buffer->successful))
-	    return;
+	  if (unlikely (!buffer->next_glyph ())) break; /* Copy to out-buffer. */
 	  buffer->merge_out_clusters (starter, buffer->out_len);
 	  buffer->out_len--; /* Remove the second composable. */
 	  /* Modify starter and carry on. */
@@ -465,7 +472,7 @@
       }
 
       /* Blocked, or doesn't compose. */
-      buffer->next_glyph ();
+      if (unlikely (!buffer->next_glyph ())) break;
 
       if (info_cc (buffer->prev()) == 0)
 	starter = buffer->out_len - 1;
diff --git a/src/hb-ot-shape-normalize.hh b/src/hb-ot-shape-normalize.hh
index 04f1a80..12c78a2 100644
--- a/src/hb-ot-shape-normalize.hh
+++ b/src/hb-ot-shape-normalize.hh
@@ -56,6 +56,7 @@
   hb_buffer_t *buffer;
   hb_font_t *font;
   hb_unicode_funcs_t *unicode;
+  const hb_codepoint_t not_found;
   bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
 		     hb_codepoint_t  ab,
 		     hb_codepoint_t *a,
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 5d9a70c..4e8a4bc 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -48,6 +48,16 @@
 #include "hb-aat-layout.hh"
 
 
+#ifndef HB_NO_AAT_SHAPE
+static inline bool
+_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));
+}
+#endif
+
 /**
  * SECTION:hb-ot-shape
  * @title: hb-ot-shape
@@ -63,23 +73,6 @@
 			      const hb_feature_t             *user_features,
 			      unsigned int                    num_user_features);
 
-#ifndef HB_NO_AAT_SHAPE
-static inline bool
-_hb_apply_morx (hb_face_t *face)
-{
-  if (hb_options ().aat &&
-      hb_aat_layout_has_substitution (face))
-    return true;
-
-  /* Ignore empty GSUB tables. */
-  return (!hb_ot_layout_has_substitution (face) ||
-	  !hb_ot_layout_table_get_script_tags (face,
-					       HB_OT_TAG_GSUB,
-					       0, nullptr, nullptr)) &&
-	 hb_aat_layout_has_substitution (face);
-}
-#endif
-
 hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *face,
 					      const hb_segment_properties_t *props) :
 						face (face),
@@ -87,7 +80,7 @@
 						map (face, props),
 						aat_map (face, props)
 #ifndef HB_NO_AAT_SHAPE
-						, apply_morx (_hb_apply_morx (face))
+						, apply_morx (_hb_apply_morx (face, props))
 #endif
 {
   shaper = hb_ot_shape_complex_categorize (this);
@@ -95,8 +88,9 @@
   script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
   script_fallback_mark_positioning = shaper->fallback_position;
 
-  if (apply_morx)
-    shaper = &_hb_ot_complex_shaper_default;
+  /* https://github.com/harfbuzz/harfbuzz/issues/1528 */
+  if (apply_morx && shaper != &_hb_ot_complex_shaper_default)
+    shaper = &_hb_ot_complex_shaper_dumber;
 }
 
 void
@@ -119,6 +113,8 @@
 #endif
 
   plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+  plan.has_vert = !!plan.map.get_1_mask (HB_TAG ('v','e','r','t'));
+
   hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ?
 		      HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
 #ifndef HB_NO_OT_KERN
@@ -153,24 +149,26 @@
    * Decide who does positioning. GPOS, kerx, kern, or fallback.
    */
 
-  if (0)
+#ifndef HB_NO_AAT_SHAPE
+  bool has_kerx = hb_aat_layout_has_positioning (face);
+  bool has_gsub = !apply_morx && hb_ot_layout_has_substitution (face);
+#endif
+  bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
+  if (false)
     ;
 #ifndef HB_NO_AAT_SHAPE
-  else if (hb_options ().aat && hb_aat_layout_has_positioning (face))
+  /* Prefer GPOS over kerx if GSUB is present;
+   * https://github.com/harfbuzz/harfbuzz/issues/3008 */
+  else if (has_kerx && !(has_gsub && has_gpos))
     plan.apply_kerx = true;
 #endif
-  else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
+  else if (has_gpos)
     plan.apply_gpos = true;
-#ifndef HB_NO_AAT_SHAPE
-  else if (hb_aat_layout_has_positioning (face))
-    plan.apply_kerx = true;
-#endif
 
-  if (!plan.apply_kerx && !has_gpos_kern)
+  if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
   {
-    /* Apparently Apple applies kerx if GPOS kern was not applied. */
 #ifndef HB_NO_AAT_SHAPE
-    if (hb_aat_layout_has_positioning (face))
+    if (has_kerx)
       plan.apply_kerx = true;
     else
 #endif
@@ -180,6 +178,8 @@
 #endif
   }
 
+  plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
+
   plan.zero_marks = script_zero_marks &&
 		    !plan.apply_kerx &&
 		    (!plan.apply_kern
@@ -201,6 +201,12 @@
 				   script_fallback_mark_positioning;
 
 #ifndef HB_NO_AAT_SHAPE
+  /* If we're using morx shaping, we cancel mark position adjustment because
+     Apple Color Emoji assumes this will NOT be done when forming emoji sequences;
+     https://github.com/harfbuzz/harfbuzz/issues/2967. */
+  if (plan.apply_morx)
+    plan.adjust_mark_positioning_when_zeroing = false;
+
   /* Currently we always apply trak. */
   plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
 #endif
@@ -228,7 +234,13 @@
   {
     data = shaper->data_create (this);
     if (unlikely (!data))
+    {
+      map.fini ();
+#ifndef HB_NO_AAT_SHAPE
+      aat_map.fini ();
+#endif
       return false;
+    }
   }
 
   return true;
@@ -268,11 +280,12 @@
   else if (this->apply_kerx)
     hb_aat_layout_position (this, font, buffer);
 #endif
+
 #ifndef HB_NO_OT_KERN
-  else if (this->apply_kern)
+  if (this->apply_kern)
     hb_ot_layout_kern (this, font, buffer);
 #endif
-  else
+  else if (this->apply_fallback_kern)
     _hb_ot_shape_fallback_kern (this, font, buffer);
 
 #ifndef HB_NO_AAT_SHAPE
@@ -308,16 +321,17 @@
 };
 
 static void
-hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
-			      const hb_feature_t             *user_features,
-			      unsigned int                    num_user_features)
+hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
+			      const hb_feature_t    *user_features,
+			      unsigned int           num_user_features)
 {
   hb_ot_map_builder_t *map = &planner->map;
 
   map->enable_feature (HB_TAG('r','v','r','n'));
   map->add_gsub_pause (nullptr);
 
-  switch (planner->props.direction) {
+  switch (planner->props.direction)
+  {
     case HB_DIRECTION_LTR:
       map->enable_feature (HB_TAG ('l','t','r','a'));
       map->enable_feature (HB_TAG ('l','t','r','m'));
@@ -350,12 +364,14 @@
   map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
 #endif
 
-  map->enable_feature (HB_TAG ('H','A','R','F'));
+  map->enable_feature (HB_TAG ('H','a','r','f')); /* Considered required. */
+  map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
 
   if (planner->shaper->collect_features)
     planner->shaper->collect_features (planner);
 
-  map->enable_feature (HB_TAG ('B','U','Z','Z'));
+  map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */
+  map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
     map->add_feature (common_features[i]);
@@ -365,6 +381,10 @@
       map->add_feature (horizontal_features[i]);
   else
   {
+    /* We only apply `vert` feature. See:
+     * https://github.com/harfbuzz/harfbuzz/commit/d71c0df2d17f4590d5611239577a6cb532c26528
+     * https://lists.freedesktop.org/archives/harfbuzz/2013-August/003490.html */
+
     /* We really want to find a 'vert' feature if there's any in the font, no
      * matter which script/langsys it is listed (or not) under.
      * See various bugs referenced from:
@@ -480,6 +500,14 @@
     if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
 		  hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
     {
+      _hb_glyph_info_set_continuation (&info[i]);
+    }
+    /* 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)))
+    {
+      if (hb_in_range<hb_codepoint_t> (info[i - 1].codepoint, 0x1F1E6u, 0x1F1FFu) &&
+	  !_hb_glyph_info_is_continuation (&info[i - 1]))
 	_hb_glyph_info_set_continuation (&info[i]);
     }
 #ifndef HB_NO_EMOJI_SEQUENCES
@@ -536,9 +564,8 @@
   hb_glyph_info_t info = dottedcircle;
   info.cluster = buffer->cur().cluster;
   info.mask = buffer->cur().mask;
-  buffer->output_info (info);
-  while (buffer->idx < buffer->len && buffer->successful)
-    buffer->next_glyph ();
+  (void) buffer->output_info (info);
+
   buffer->swap_buffers ();
 }
 
@@ -562,6 +589,36 @@
   hb_direction_t direction = buffer->props.direction;
   hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
 
+  /* Numeric runs in natively-RTL scripts are actually native-LTR, so we reset
+   * the horiz_dir if the run contains at least one decimal-number char, and no
+   * letter chars (ideally we should be checking for chars with strong
+   * directionality but hb-unicode currently lacks bidi categories).
+   *
+   * This allows digit sequences in Arabic etc to be shaped in "native"
+   * direction, so that features like ligatures will work as intended.
+   *
+   * https://github.com/harfbuzz/harfbuzz/issues/501
+   */
+  if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR))
+  {
+    bool found_number = false, found_letter = 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;
+      else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
+      {
+        found_letter = true;
+        break;
+      }
+    }
+    if (found_number && !found_letter)
+      horiz_dir = HB_DIRECTION_LTR;
+  }
+
   /* 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
@@ -594,24 +651,85 @@
  * Substitute
  */
 
-static inline void
-hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
+static hb_codepoint_t
+hb_vert_char_for (hb_codepoint_t u)
 {
-  if (HB_DIRECTION_IS_FORWARD (c->target_direction))
-    return;
+  switch (u >> 8)
+  {
+    case 0x20: switch (u) {
+      case 0x2013u: return 0xfe32u; // EN DASH
+      case 0x2014u: return 0xfe31u; // EM DASH
+      case 0x2025u: return 0xfe30u; // TWO DOT LEADER
+      case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS
+    } break;
+    case 0x30: switch (u) {
+      case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA
+      case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP
+      case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET
+      case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET
+      case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET
+      case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET
+      case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET
+      case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET
+      case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET
+      case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET
+      case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET
+      case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET
+      case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET
+      case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET
+      case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET
+      case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET
+    } break;
+    case 0xfe: switch (u) {
+      case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE
+    } break;
+    case 0xff: switch (u) {
+      case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK
+      case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS
+      case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS
+      case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA
+      case 0xff1au: return 0xfe13u; // FULLWIDTH COLON
+      case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON
+      case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK
+      case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET
+      case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET
+      case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE
+      case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET
+      case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET
+    } break;
+  }
 
+  return u;
+}
+
+static inline void
+hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
+{
   hb_buffer_t *buffer = c->buffer;
-  hb_unicode_funcs_t *unicode = buffer->unicode;
-  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
-
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
-  for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
-    if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
-      info[i].mask |= rtlm_mask;
-    else
-      info[i].codepoint = codepoint;
+
+  if (HB_DIRECTION_IS_BACKWARD (c->target_direction))
+  {
+    hb_unicode_funcs_t *unicode = buffer->unicode;
+    hb_mask_t rtlm_mask = c->plan->rtlm_mask;
+
+    for (unsigned int i = 0; i < count; i++) {
+      hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+      if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
+	info[i].codepoint = codepoint;
+      else
+	info[i].mask |= rtlm_mask;
+    }
+  }
+
+  if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
+  {
+    for (unsigned int i = 0; i < count; i++) {
+      hb_codepoint_t codepoint = hb_vert_char_for (info[i].codepoint);
+      if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
+	info[i].codepoint = codepoint;
+    }
   }
 }
 
@@ -693,7 +811,7 @@
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
     const hb_feature_t *feature = &c->user_features[i];
-    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+    if (!(feature->start == HB_FEATURE_GLOBAL_START && feature->end == HB_FEATURE_GLOBAL_END)) {
       unsigned int shift;
       hb_mask_t mask = map->get_mask (feature->tag, &shift);
       buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
@@ -788,7 +906,7 @@
 {
   hb_buffer_t *buffer = c->buffer;
 
-  hb_ot_mirror_chars (c);
+  hb_ot_rotate_chars (c);
 
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
 
@@ -837,8 +955,11 @@
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
 #endif
 
-  if (c->plan->shaper->postprocess_glyphs)
+  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);
+    (void) c->buffer->message(c->font, "end postprocess-glyphs");
+  }
 }
 
 
@@ -1038,12 +1159,12 @@
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
   {
     c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
-			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
+				 (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
   {
     c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
-			      (unsigned) HB_BUFFER_MAX_OPS_MIN);
+				 (unsigned) HB_BUFFER_MAX_OPS_MIN);
   }
 
   /* Save the original direction, we use it later. */
@@ -1051,8 +1172,6 @@
 
   _hb_buffer_allocate_unicode_vars (c->buffer);
 
-  c->buffer->clear_output ();
-
   hb_ot_shape_initialize_masks (c);
   hb_set_unicode_props (c->buffer);
   hb_insert_dotted_circle (c->buffer, c->font);
@@ -1061,8 +1180,12 @@
 
   hb_ensure_native_direction (c->buffer);
 
-  if (c->plan->shaper->preprocess_text)
+  if (c->plan->shaper->preprocess_text &&
+      c->buffer->message(c->font, "start preprocess-text"))
+  {
     c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+    (void) c->buffer->message(c->font, "end preprocess-text");
+  }
 
   hb_ot_substitute_pre (c);
   hb_ot_position (c);
@@ -1096,6 +1219,12 @@
 
 /**
  * hb_ot_shape_plan_collect_lookups:
+ * @shape_plan: #hb_shape_plan_t to query
+ * @table_tag: GSUB or GPOS
+ * @lookup_indexes: (out): The #hb_set_t set of lookups returned
+ *
+ * Computes the complete set of GSUB or GPOS lookups that are applicable
+ * under a given @shape_plan.
  *
  * Since: 0.9.7
  **/
@@ -1130,6 +1259,15 @@
 
 /**
  * hb_ot_shape_glyphs_closure:
+ * @font: #hb_font_t to work upon
+ * @buffer: The input buffer to compute from
+ * @features: (array length=num_features): The features enabled on the buffer
+ * @num_features: The number of features enabled on the buffer
+ * @glyphs: (out): The #hb_set_t set of glyphs comprising the transitive closure of the query
+ *
+ * Computes the transitive closure of glyphs needed for a specified
+ * input buffer under the given font and feature list. The closure is
+ * computed as a set, not as a list.
  *
  * Since: 0.9.2
  **/
diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h
index 7b1bcc0..afdff72 100644
--- a/src/hb-ot-shape.h
+++ b/src/hb-ot-shape.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh
index 2cde73d..e8c8101 100644
--- a/src/hb-ot-shape.hh
+++ b/src/hb-ot-shape.hh
@@ -37,9 +37,9 @@
 {
   unsigned int variations_index[2];
 
-  void init (hb_face_t   *face,
-		    const int   *coords,
-		    unsigned int num_coords)
+  void init (hb_face_t *face,
+	     const int *coords,
+	     unsigned   num_coords)
   {
     for (unsigned int table_index = 0; table_index < 2; table_index++)
       hb_ot_layout_table_find_feature_variations (face,
@@ -99,6 +99,7 @@
 #else
   static constexpr bool has_frac = false;
 #endif
+  bool has_vert : 1;
   bool has_gpos_mark : 1;
   bool zero_marks : 1;
   bool fallback_glyph_classes : 1;
@@ -111,6 +112,7 @@
 #else
   static constexpr bool apply_kern = false;
 #endif
+  bool apply_fallback_kern : 1;
 #ifndef HB_NO_AAT_SHAPE
   bool apply_kerx : 1;
   bool apply_morx : 1;
diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index 2cdd3a4..41d1734 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -59,6 +59,9 @@
 
 struct AxisValueFormat1
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -77,13 +80,16 @@
   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	value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct AxisValueFormat2
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return nominalValue.to_float (); }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -102,10 +108,10 @@
   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
+  HBFixed	nominalValue;	/* A numeric value for this attribute value. */
+  HBFixed	rangeMinValue;	/* The minimum value for a range associated
 				 * with the specified name ID. */
-  HBFixed		rangeMaxValue;	/* The maximum value for a range associated
+  HBFixed	rangeMaxValue;	/* The maximum value for a range associated
 				 * with the specified name ID. */
   public:
   DEFINE_SIZE_STATIC (20);
@@ -113,6 +119,9 @@
 
 struct AxisValueFormat3
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -131,8 +140,8 @@
   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
+  HBFixed	value;		/* A numeric value for this attribute value. */
+  HBFixed	linkedValue;	/* The numeric value for a style-linked mapping
 				 * from this value. */
   public:
   DEFINE_SIZE_STATIC (16);
@@ -140,6 +149,9 @@
 
 struct AxisValueRecord
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -150,13 +162,16 @@
   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. */
+  HBFixed	value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AxisValueFormat4
 {
+  const AxisValueRecord &get_axis_record (unsigned int axis_index) const
+  { return axisValues.as_array (axisCount)[axis_index]; }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -183,6 +198,30 @@
 
 struct AxisValue
 {
+  bool get_value (unsigned int axis_index) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value ();
+    case 2: return u.format2.get_value ();
+    case 3: return u.format3.get_value ();
+    case 4: return u.format4.get_axis_record (axis_index).get_value ();
+    default:return 0;
+    }
+  }
+
+  unsigned int get_axis_index () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_axis_index ();
+    case 2: return u.format2.get_axis_index ();
+    case 3: return u.format3.get_axis_index ();
+    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
+    default:return -1;
+    }
+  }
+
   hb_ot_name_id_t get_value_name_id () const
   {
     switch (u.format)
@@ -226,6 +265,8 @@
 
 struct StatAxisRecord
 {
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
   hb_ot_name_id_t get_name_id () const { return nameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -251,6 +292,25 @@
 
   bool has_data () const { return version.to_int (); }
 
+  bool get_value (hb_tag_t tag, float *value) const
+  {
+    unsigned int axis_index;
+    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
+
+    hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
+    for (unsigned int i = 0; i < axis_values.length; i++)
+    {
+      const AxisValue& axis_value = this+axis_values[i];
+      if (axis_value.get_axis_index () == axis_index)
+      {
+	if (value)
+	  *value = axis_value.get_value (axis_index);
+	return true;
+      }
+    }
+    return false;
+  }
+
   unsigned get_design_axis_count () const { return designAxisCount; }
 
   hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
@@ -299,7 +359,7 @@
   hb_array_t<const StatAxisRecord> const get_design_axes () const
   { return (this+designAxesOffset).as_array (designAxisCount); }
 
-  hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
+  hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
   { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
 
 
@@ -313,7 +373,7 @@
 				 * in the 'fvar' table. In all fonts, must
 				 * be greater than zero if axisValueCount
 				 * is greater than zero. */
-  LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
+  NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
 		designAxesOffset;
 				/* Offset in bytes from the beginning of
 				 * the STAT table to the start of the design
@@ -321,7 +381,7 @@
 				 * set to zero; if designAxisCount is greater
 				 * than zero, must be greater than zero. */
   HBUINT16	axisValueCount;	/* The number of axis value tables. */
-  LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
+  NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
 		offsetToAxisValueOffsets;
 				/* Offset in bytes from the beginning of
 				 * the STAT table to the start of the design
diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh
index d8fcd2f..fc9bffc 100644
--- a/src/hb-ot-tag-table.hh
+++ b/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2018-11-18 05:25 AM" />
- * File-Date: 2019-04-03
+ * <meta name="updated_at" content="2021-09-02 09:40 PM" />
+ * File-Date: 2021-08-06
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
@@ -19,14 +19,18 @@
   {"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('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 */
@@ -38,15 +42,21 @@
   {"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] */
-  {"ak",	HB_TAG('T','W','I',' ')},	/* Akan [macrolanguage] -> Twi */
+  {"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 */
@@ -55,6 +65,8 @@
   {"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 [family] -> 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 */
@@ -64,19 +76,24 @@
   {"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 [family] -> 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 */
@@ -86,17 +103,29 @@
   {"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','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 [family] */
+  {"bag",	HB_TAG_NONE	       },	/* Tuki != Baghelkhandi */
+  {"bah",	HB_TAG('C','P','P',' ')},	/* Bahamas Creole English -> Creoles */
   {"bai",	HB_TAG('B','M','L',' ')},	/* Bamileke [family] */
   {"bal",	HB_TAG('B','L','I',' ')},	/* Baluchi [macrolanguage] */
 /*{"ban",	HB_TAG('B','A','N',' ')},*/	/* Balinese */
 /*{"bar",	HB_TAG('B','A','R',' ')},*/	/* Bavarian */
-/*{"bbc",	HB_TAG('B','B','C',' ')},*/	/* Batak Toba */
-  {"bbz",	HB_TAG('A','R','A',' ')},	/* Babalia Creole Arabic -> Arabic */
+  {"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 */
@@ -107,6 +136,8 @@
   {"beb",	HB_TAG('B','T','I',' ')},	/* Bebele -> Beti */
 /*{"bem",	HB_TAG('B','E','M',' ')},*/	/* Bemba (Zambia) */
   {"ber",	HB_TAG('B','B','R',' ')},	/* Berber [family] */
+  {"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 */
@@ -115,7 +146,8 @@
 /*{"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('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 */
@@ -123,58 +155,108 @@
 /*{"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 */
-/*{"blk",	HB_TAG('B','L','K',' ')},*/	/* Pa’o Karen */
+  {"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 [family] */
+  {"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','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','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 */
-/*{"cbk",	HB_TAG('C','B','K',' ')},*/	/* Chavacano -> Zamboanga Chavacano */
+  {"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 */
+  {"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 */
+  {"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 */
@@ -186,57 +268,86 @@
   {"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 */
+  {"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 */
-  {"cmn",	HB_TAG('Z','H','S',' ')},	/* Mandarin Chinese -> Chinese Simplified */
+  {"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 [family] -> Creoles */
   {"cpf",	HB_TAG('C','P','P',' ')},	/* French-based creoles and pidgins [family] -> Creoles */
+  {"cpi",	HB_TAG('C','P','P',' ')},	/* Chinese Pidgin English -> Creoles */
 /*{"cpp",	HB_TAG('C','P','P',' ')},*/	/* Portuguese-based creoles and pidgins [family] -> Creoles */
-  {"cpx",	HB_TAG('Z','H','S',' ')},	/* Pu-Xian Chinese -> Chinese Simplified */
+  {"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] */
-  {"cr",	HB_TAG('Y','C','R',' ')},	/* Cree [macrolanguage] -> Y-Cree */
   {"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 [family] -> 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 */
@@ -244,56 +355,73 @@
   {"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 */
+  {"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 */
-/*{"dgo",	HB_TAG('D','G','O',' ')},*/	/* Dogri */
+  {"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('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 */
-  {"doi",	HB_TAG('D','G','R',' ')},	/* Dogri [macrolanguage] */
+  {"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 -> Forest Nenets */
-  {"enh",	HB_TAG('T','N','E',' ')},	/* Tundra Enets -> Tundra Nenets */
+  {"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 */
@@ -303,13 +431,18 @@
   {"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 [family] != 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) */
-/*{"fat",	HB_TAG('F','A','T',' ')},*/	/* Fanti */
+  {"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 */
@@ -318,9 +451,13 @@
   {"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('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 */
@@ -328,68 +465,101 @@
   {"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','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 */
-  {"gan",	HB_TAG('Z','H','S',' ')},	/* Gan Chinese -> Chinese Simplified */
+  {"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('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 */
-  {"guk",	HB_TAG('G','U','K',' ')},	/* Gumuz (SIL fonts) */
+  {"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 */
-  {"hak",	HB_TAG('Z','H','S',' ')},	/* Hakka Chinese -> Chinese Simplified */
+  {"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 */
@@ -401,26 +571,34 @@
 /*{"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 */
+  {"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 */
@@ -428,121 +606,208 @@
   {"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 [family] */
+  {"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 */
   {"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] */
   {"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('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',' ')},	/* Kara-Kalpak -> Karakalpak */
+  {"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 [family] */
+/*{"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) */
-/*{"kek",	HB_TAG('K','E','K',' ')},*/	/* Kekchi */
+  {"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) */
-  {"kht",	HB_TAG('K','H','T',' ')},	/* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
+  {"khv",	HB_TAG_NONE	       },	/* Khvarshi != Khanty-Vakhi */
 /*{"khw",	HB_TAG('K','H','W',' ')},*/	/* Khowar */
   {"ki",	HB_TAG('K','I','K',' ')},	/* Kikuyu (Gikuyu) */
-/*{"kiu",	HB_TAG('K','I','U',' ')},*/	/* Kirmanjki */
+  {"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','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('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','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 */
-  {"kxu",	HB_TAG('K','U','I',' ')},	/* Kui (India) */
+  {"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) */
-/*{"kyu",	HB_TAG('K','Y','U',' ')},*/	/* Western Kayah */
+  {"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 */
@@ -550,85 +815,131 @@
   {"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 */
+  {"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','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 [family] != 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','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('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','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 */
+  {"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 */
+  {"mnx",	HB_TAG_NONE	       },	/* Manikion != Manx */
   {"mo",	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) */
+  {"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 */
@@ -639,9 +950,14 @@
   {"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 [family] != 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 */
@@ -650,49 +966,101 @@
   {"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('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 [family] */
   {"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('N','A','G',' ')},	/* Naga Pidgin -> Naga-Assamese */
+  {"nag",	HB_TAG('C','P','P',' ')},	/* Naga Pidgin -> Creoles */
 /*{"nah",	HB_TAG('N','A','H',' ')},*/	/* Nahuatl [family] */
-  {"nan",	HB_TAG('Z','H','S',' ')},	/* Min Nan Chinese -> Chinese Simplified */
+  {"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 */
-  {"ngo",	HB_TAG('S','X','T',' ')},	/* Ngoni -> Sutu */
+  {"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) */
+  {"nn",	HB_TAG('N','O','R',' ')},	/* Norwegian 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 */
-/*{"nso",	HB_TAG('N','S','O',' ')},*/	/* Pedi -> Sotho, Northern */
+  {"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 */
@@ -704,21 +1072,33 @@
   {"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 [family] != 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 */
@@ -726,84 +1106,148 @@
 /*{"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('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 */
-  {"plp",	HB_TAG('P','A','P',' ')},	/* Palpa */
+  {"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 */
-/*{"poh",	HB_TAG('P','O','H',' ')},*/	/* Poqomchi' -> Pocomchi */
+  {"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 */
-/*{"pwo",	HB_TAG('P','W','O',' ')},*/	/* Pwo Western Karen -> Western Pwo Karen */
+  {"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) */
-/*{"quc",	HB_TAG('Q','U','C',' ')},*/	/* K’iche’ */
+  {"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) */
-/*{"quh",	HB_TAG('Q','U','H',' ')},*/	/* South Bolivian Quechua -> Quechua (Bolivia) */
+  {"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) */
-/*{"qvi",	HB_TAG('Q','V','I',' ')},*/	/* Imbabura Highland Quichua -> Quechua (Ecuador) */
+  {"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','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 */
-/*{"rit",	HB_TAG('R','I','T',' ')},*/	/* Ritarungo */
+  {"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 */
@@ -812,13 +1256,16 @@
   {"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','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 */
-  {"rnl",	HB_TAG('H','A','L',' ')},	/* Ranglong -> Halam (Falam Chin) */
   {"ro",	HB_TAG('R','O','M',' ')},	/* Romanian */
   {"rom",	HB_TAG('R','O','Y',' ')},	/* Romany [macrolanguage] */
+  {"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 */
@@ -826,11 +1273,16 @@
   {"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 */
@@ -841,60 +1293,89 @@
   {"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 */
-  {"sgw",	HB_TAG('S','G','W',' ')},	/* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
-/*{"shi",	HB_TAG('S','H','I',' ')},*/	/* Tachelhit */
+  {"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 [family] != 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 */
-  {"st",	HB_TAG('S','O','T',' ')},	/* Southern Sotho -> Sotho, Southern */
+  {"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 */
@@ -904,11 +1385,16 @@
   {"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 */
@@ -917,41 +1403,71 @@
   {"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 */
+  {"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 */
-/*{"tmh",	HB_TAG('T','M','H',' ')},*/	/* Tamashek [macrolanguage] */
+/*{"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 */
-/*{"tpi",	HB_TAG('T','P','I',' ')},*/	/* Tok Pisin */
+  {"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 [family] != 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 */
@@ -959,32 +1475,49 @@
   {"ty",	HB_TAG('T','H','T',' ')},	/* Tahitian */
   {"tyv",	HB_TAG('T','U','V',' ')},	/* Tuvinian -> Tuvin */
 /*{"tyz",	HB_TAG('T','Y','Z',' ')},*/	/* Tày */
-/*{"tzm",	HB_TAG('T','Z','M',' ')},*/	/* Central Atlas Tamazight -> Tamazight */
-/*{"tzo",	HB_TAG('T','Z','O',' ')},*/	/* Tzotzil */
+  {"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 */
@@ -993,45 +1526,63 @@
   {"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 */
+  {"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 */
-  {"xnr",	HB_TAG('D','G','R',' ')},	/* Kangri -> Dogri */
+  {"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('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 */
-  {"yrk",	HB_TAG('T','N','E',' ')},	/* Nenets -> Tundra Nenets */
-  {"yrk",	HB_TAG('F','N','E',' ')},	/* Nenets -> Forest Nenets */
-  {"yue",	HB_TAG('Z','H','H',' ')},	/* Yue Chinese -> Chinese, Hong Kong SAR */
+  {"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('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 [macrolanguage] -> Chinese Simplified */
+  {"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 */
@@ -1039,6 +1590,8 @@
   {"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 [family] != 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 */
@@ -1049,6 +1602,7 @@
   {"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 */
 };
@@ -1087,6 +1641,13 @@
     *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 */
@@ -1134,7 +1695,7 @@
   case 'a':
     if (0 == strcmp (&lang_str[1], "rt-lojban"))
     {
-      /* Lojban */
+      /* Lojban (retired code) */
       tags[0] = HB_TAG('J','B','O',' ');  /* Lojban */
       *count = 1;
       return true;
@@ -1143,169 +1704,273 @@
   case 'c':
     if (lang_matches (&lang_str[1], "do-hant-hk"))
     {
-      /* Min Dong Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Min Dong Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Min Dong Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "jy-hant-hk"))
     {
-      /* Jinyu Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Jinyu Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Jinyu Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "mn-hant-hk"))
     {
-      /* Mandarin Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Mandarin Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* Mandarin Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "np-hant-hk"))
+    {
+      /* 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"))
+    {
+      /* Northern Ping Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "px-hant-hk"))
     {
-      /* Pu-Xian Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Pu-Xian Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* Pu-Xian Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "sp-hant-hk"))
+    {
+      /* 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"))
+    {
+      /* Southern Ping Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "zh-hant-hk"))
     {
-      /* Huizhou Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Huizhou Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Huizhou Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "zo-hant-hk"))
     {
-      /* Min Zhong Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Min Zhong Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Min Zhong Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "do-hans"))
     {
-      /* Min Dong Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Min Dong Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
     {
-      /* Jinyu Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Jinyu Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
     {
-      /* Mandarin Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Mandarin Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
+    {
+      /* 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"))
+    {
+      /* 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"))
     {
-      /* Pu-Xian Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Pu-Xian Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
+    {
+      /* 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"))
+    {
+      /* 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"))
     {
-      /* Huizhou Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Huizhou Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
     {
-      /* Min Zhong Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Min Zhong Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Min Zhong Chinese; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1313,7 +1978,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Min Dong Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1321,15 +1986,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Min Dong Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "do-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Min Dong Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1337,7 +2008,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Jinyu Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1345,15 +2016,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Jinyu Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "jy-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Jinyu Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1361,7 +2038,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Mandarin Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1369,15 +2046,51 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Mandarin Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "mn-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Mandarin Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+	&& subtag_matches (lang_str, limit, "-hk"))
+    {
+      /* Northern Ping Chinese; Hong Kong */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+	&& subtag_matches (lang_str, limit, "-mo"))
+    {
+      /* Northern Ping Chinese; Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+	&& subtag_matches (lang_str, limit, "-tw"))
+    {
+      /* Northern Ping Chinese; Taiwan, Province of China */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1385,7 +2098,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Pu-Xian Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1393,15 +2106,51 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Pu-Xian Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "px-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Pu-Xian Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+	&& subtag_matches (lang_str, limit, "-hk"))
+    {
+      /* Southern Ping Chinese; Hong Kong */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+	&& subtag_matches (lang_str, limit, "-mo"))
+    {
+      /* Southern Ping Chinese; Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+	&& subtag_matches (lang_str, limit, "-tw"))
+    {
+      /* Southern Ping Chinese; Taiwan, Province of China */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1409,7 +2158,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Huizhou Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1417,15 +2166,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Huizhou Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zh-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Huizhou Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1433,7 +2188,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Min Zhong Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1441,15 +2196,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Min Zhong Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "zo-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Min Zhong Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1457,35 +2218,41 @@
   case 'g':
     if (lang_matches (&lang_str[1], "an-hant-hk"))
     {
-      /* Gan Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Gan Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Gan Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "an-hans"))
     {
-      /* Gan Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Gan Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
     {
-      /* Irish */
+      /* Irish; Latin (Gaelic variant) */
       tags[0] = HB_TAG('I','R','T',' ');  /* Irish Traditional */
       *count = 1;
       return true;
@@ -1494,7 +2261,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Gan Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1502,15 +2269,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Gan Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Gan Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1518,57 +2291,69 @@
   case 'h':
     if (lang_matches (&lang_str[1], "ak-hant-hk"))
     {
-      /* Hakka Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Hakka Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Hakka Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "sn-hant-hk"))
     {
-      /* Xiang Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Xiang Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Xiang Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "ak-hans"))
     {
-      /* Hakka Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Hakka Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* 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"))
     {
-      /* Xiang Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Xiang Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Xiang Chinese; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1576,7 +2361,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Hakka Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1584,15 +2369,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Hakka Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "ak-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Hakka Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1600,7 +2391,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Xiang Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1608,15 +2399,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Xiang Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "sn-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Xiang Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1624,7 +2421,7 @@
   case 'i':
     if (0 == strcmp (&lang_str[1], "-navajo"))
     {
-      /* Navajo */
+      /* Navajo (retired code) */
       unsigned int i;
       hb_tag_t possible_tags[] = {
 	HB_TAG('N','A','V',' '),  /* Navajo */
@@ -1637,14 +2434,14 @@
     }
     if (0 == strcmp (&lang_str[1], "-hak"))
     {
-      /* Hakka */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* Hakka (retired code) */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
     if (0 == strcmp (&lang_str[1], "-lux"))
     {
-      /* Luxembourgish */
+      /* Luxembourgish (retired code) */
       tags[0] = HB_TAG('L','T','Z',' ');  /* Luxembourgish */
       *count = 1;
       return true;
@@ -1653,8 +2450,8 @@
   case 'l':
     if (lang_matches (&lang_str[1], "zh-hans"))
     {
-      /* Literary Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* Literary Chinese; Han (Simplified variant) */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
@@ -1662,29 +2459,35 @@
   case 'm':
     if (lang_matches (&lang_str[1], "np-hant-hk"))
     {
-      /* Min Bei Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Min Bei Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Min Bei Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "np-hans"))
     {
-      /* Min Bei Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Min Bei Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Min Bei Chinese; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1692,7 +2495,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Min Bei Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1700,15 +2503,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Min Bei Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "np-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Min Bei Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1716,29 +2525,35 @@
   case 'n':
     if (lang_matches (&lang_str[1], "an-hant-hk"))
     {
-      /* Min Nan Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Min Nan Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Min Nan Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "an-hans"))
     {
-      /* Min Nan Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Min Nan Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Min Nan Chinese; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1746,7 +2561,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Min Nan Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1754,30 +2569,42 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Min Nan Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "an-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Min Nan Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
     if (0 == strcmp (&lang_str[1], "o-bok"))
     {
-      /* Norwegian Bokmal */
+      /* Norwegian Bokmal (retired code) */
       tags[0] = HB_TAG('N','O','R',' ');  /* Norwegian */
       *count = 1;
       return true;
     }
     if (0 == strcmp (&lang_str[1], "o-nyn"))
     {
-      /* Norwegian Nynorsk */
-      tags[0] = HB_TAG('N','Y','N',' ');  /* Norwegian Nynorsk (Nynorsk, Norwegian) */
-      *count = 1;
+      /* Norwegian Nynorsk (retired code) */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('N','Y','N',' '),  /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+	HB_TAG('N','O','R',' '),  /* Norwegian */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     break;
@@ -1794,29 +2621,35 @@
   case 'w':
     if (lang_matches (&lang_str[1], "uu-hant-hk"))
     {
-      /* Wu Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Wu Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Wu Chinese; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (lang_matches (&lang_str[1], "uu-hans"))
     {
-      /* Wu Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Wu Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Wu Chinese; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1824,7 +2657,7 @@
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
       /* Wu Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
@@ -1832,15 +2665,21 @@
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
       /* Wu Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "uu-", 3)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
       /* Wu Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1848,8 +2687,8 @@
   case 'y':
     if (lang_matches (&lang_str[1], "ue-hans"))
     {
-      /* Yue Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* Yue Chinese; Han (Simplified variant) */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
@@ -1857,67 +2696,79 @@
   case 'z':
     if (lang_matches (&lang_str[1], "h-hant-hk"))
     {
-      /* Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* 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"))
     {
-      /* Chinese */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Chinese [macrolanguage]; Han (Traditional variant); Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strcmp (&lang_str[1], "h-min-nan"))
     {
-      /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo (retired code) */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
     if (lang_matches (&lang_str[1], "h-hans"))
     {
-      /* Chinese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* 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"))
     {
-      /* Chinese */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Chinese [macrolanguage]; Han (Traditional variant) */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
     if (0 == strcmp (&lang_str[1], "h-min"))
     {
-      /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese */
-      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese (retired code) */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese, Simplified */
       *count = 1;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
 	&& subtag_matches (lang_str, limit, "-hk"))
     {
-      /* Chinese; Hong Kong */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      /* Chinese [macrolanguage]; Hong Kong */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Traditional, Hong Kong SAR */
       *count = 1;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
 	&& subtag_matches (lang_str, limit, "-mo"))
     {
-      /* Chinese; Macao */
-      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
-      *count = 1;
+      /* Chinese [macrolanguage]; Macao */
+      unsigned int i;
+      hb_tag_t possible_tags[] = {
+	HB_TAG('Z','H','T','M'),  /* Chinese, Traditional, Macao SAR */
+	HB_TAG('Z','H','H',' '),  /* Chinese, Traditional, Hong Kong SAR */
+      };
+      for (i = 0; i < 2 && i < *count; i++)
+	tags[i] = possible_tags[i];
+      *count = i;
       return true;
     }
     if (0 == strncmp (&lang_str[1], "h-", 2)
 	&& subtag_matches (lang_str, limit, "-tw"))
     {
-      /* Chinese; Taiwan, Province of China */
-      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      /* Chinese [macrolanguage]; Taiwan, Province of China */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese, Traditional */
       *count = 1;
       return true;
     }
@@ -1948,97 +2799,131 @@
   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
     return hb_language_from_string ("und-fonnapa", -1);  /* Undetermined; North American Phonetic Alphabet */
   case HB_TAG('A','R','A',' '):  /* Arabic */
-    return hb_language_from_string ("ar", -1);  /* Arabic */
+    return hb_language_from_string ("ar", -1);  /* Arabic [macrolanguage] */
   case HB_TAG('A','R','K',' '):  /* Rakhine */
     return hb_language_from_string ("rki", -1);  /* Rakhine */
   case HB_TAG('A','T','H',' '):  /* Athapaskan */
-    return hb_language_from_string ("ath", -1);  /* Athapascan */
+    return hb_language_from_string ("ath", -1);  /* Athapascan [family] */
+  case HB_TAG('B','B','R',' '):  /* Berber */
+    return hb_language_from_string ("ber", -1);  /* Berber [family] */
   case HB_TAG('B','I','K',' '):  /* Bikol */
-    return hb_language_from_string ("bik", -1);  /* Bikol */
+    return hb_language_from_string ("bik", -1);  /* Bikol [macrolanguage] */
+  case HB_TAG('B','T','K',' '):  /* Batak */
+    return hb_language_from_string ("btk", -1);  /* Batak [family] */
   case HB_TAG('C','P','P',' '):  /* Creoles */
-    return hb_language_from_string ("crp", -1);  /* Creoles and pidgins */
+    return hb_language_from_string ("crp", -1);  /* Creoles and pidgins [family] */
   case HB_TAG('C','R','R',' '):  /* Carrier */
     return hb_language_from_string ("crx", -1);  /* Carrier */
+  case HB_TAG('D','G','R',' '):  /* Dogri (macrolanguage) */
+    return hb_language_from_string ("doi", -1);  /* Dogri [macrolanguage] */
   case HB_TAG('D','N','K',' '):  /* Dinka */
-    return hb_language_from_string ("din", -1);  /* Dinka */
+    return hb_language_from_string ("din", -1);  /* Dinka [macrolanguage] */
   case HB_TAG('D','R','I',' '):  /* Dari */
     return hb_language_from_string ("prs", -1);  /* Dari */
   case HB_TAG('D','Z','N',' '):  /* Dzongkha */
     return hb_language_from_string ("dz", -1);  /* Dzongkha */
   case HB_TAG('E','T','I',' '):  /* Estonian */
-    return hb_language_from_string ("et", -1);  /* Estonian */
+    return hb_language_from_string ("et", -1);  /* Estonian [macrolanguage] */
+  case HB_TAG('F','A','R',' '):  /* Persian */
+    return hb_language_from_string ("fa", -1);  /* Persian [macrolanguage] */
   case HB_TAG('G','O','N',' '):  /* Gondi */
-    return hb_language_from_string ("gon", -1);  /* Gondi */
+    return hb_language_from_string ("gon", -1);  /* Gondi [macrolanguage] */
   case HB_TAG('H','M','N',' '):  /* Hmong */
-    return hb_language_from_string ("hmn", -1);  /* Hmong */
+    return hb_language_from_string ("hmn", -1);  /* Hmong [macrolanguage] */
   case HB_TAG('H','N','D',' '):  /* Hindko */
     return hb_language_from_string ("hnd", -1);  /* Southern Hindko */
+  case HB_TAG('H','Y','E',' '):  /* Armenian */
+    return hb_language_from_string ("hyw", -1);  /* Western Armenian */
+  case HB_TAG('I','B','A',' '):  /* Iban */
+    return hb_language_from_string ("iba", -1);  /* Iban */
   case HB_TAG('I','J','O',' '):  /* Ijo */
-    return hb_language_from_string ("ijo", -1);  /* Ijo */
+    return hb_language_from_string ("ijo", -1);  /* Ijo [family] */
   case HB_TAG('I','N','U',' '):  /* Inuktitut */
-    return hb_language_from_string ("iu", -1);  /* Inuktitut */
+    return hb_language_from_string ("iu", -1);  /* Inuktitut [macrolanguage] */
   case HB_TAG('I','P','K',' '):  /* Inupiat */
-    return hb_language_from_string ("ik", -1);  /* Inupiaq */
+    return hb_language_from_string ("ik", -1);  /* Inupiaq [macrolanguage] */
   case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
     return hb_language_from_string ("und-fonipa", -1);  /* Undetermined; International Phonetic Alphabet */
   case HB_TAG('I','R','T',' '):  /* Irish Traditional */
     return hb_language_from_string ("ga-Latg", -1);  /* Irish; Latin (Gaelic variant) */
   case HB_TAG('J','I','I',' '):  /* Yiddish */
-    return hb_language_from_string ("yi", -1);  /* Yiddish */
+    return hb_language_from_string ("yi", -1);  /* Yiddish [macrolanguage] */
   case HB_TAG('K','A','L',' '):  /* Kalenjin */
-    return hb_language_from_string ("kln", -1);  /* Kalenjin */
+    return hb_language_from_string ("kln", -1);  /* Kalenjin [macrolanguage] */
   case HB_TAG('K','G','E',' '):  /* Khutsuri Georgian */
     return hb_language_from_string ("und-Geok", -1);  /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
   case HB_TAG('K','N','R',' '):  /* Kanuri */
-    return hb_language_from_string ("kr", -1);  /* Kanuri */
+    return hb_language_from_string ("kr", -1);  /* Kanuri [macrolanguage] */
+  case HB_TAG('K','O','H',' '):  /* Korean Old Hangul */
+    return hb_language_from_string ("okm", -1);  /* Middle Korean (10th-16th cent.) */
   case HB_TAG('K','O','K',' '):  /* Konkani */
-    return hb_language_from_string ("kok", -1);  /* Konkani */
+    return hb_language_from_string ("kok", -1);  /* Konkani [macrolanguage] */
+  case HB_TAG('K','O','M',' '):  /* Komi */
+    return hb_language_from_string ("kv", -1);  /* Komi [macrolanguage] */
+  case HB_TAG('K','P','L',' '):  /* Kpelle */
+    return hb_language_from_string ("kpe", -1);  /* Kpelle [macrolanguage] */
+  case HB_TAG('K','R','N',' '):  /* Karen */
+    return hb_language_from_string ("kar", -1);  /* Karen [family] */
+  case HB_TAG('K','U','I',' '):  /* Kui */
+    return hb_language_from_string ("uki", -1);  /* Kui (India) */
   case HB_TAG('K','U','R',' '):  /* Kurdish */
-    return hb_language_from_string ("ku", -1);  /* Kurdish */
+    return hb_language_from_string ("ku", -1);  /* Kurdish [macrolanguage] */
   case HB_TAG('L','U','H',' '):  /* Luyia */
-    return hb_language_from_string ("luy", -1);  /* Luyia */
+    return hb_language_from_string ("luy", -1);  /* Luyia [macrolanguage] */
   case HB_TAG('L','V','I',' '):  /* Latvian */
-    return hb_language_from_string ("lv", -1);  /* Latvian */
+    return hb_language_from_string ("lv", -1);  /* Latvian [macrolanguage] */
   case HB_TAG('M','A','W',' '):  /* Marwari */
-    return hb_language_from_string ("mwr", -1);  /* Marwari */
+    return hb_language_from_string ("mwr", -1);  /* Marwari [macrolanguage] */
   case HB_TAG('M','L','G',' '):  /* Malagasy */
-    return hb_language_from_string ("mg", -1);  /* Malagasy */
+    return hb_language_from_string ("mg", -1);  /* Malagasy [macrolanguage] */
   case HB_TAG('M','L','Y',' '):  /* Malay */
-    return hb_language_from_string ("ms", -1);  /* Malay */
+    return hb_language_from_string ("ms", -1);  /* Malay [macrolanguage] */
   case HB_TAG('M','N','G',' '):  /* Mongolian */
-    return hb_language_from_string ("mn", -1);  /* Mongolian */
+    return hb_language_from_string ("mn", -1);  /* Mongolian [macrolanguage] */
+  case HB_TAG('M','N','K',' '):  /* Maninka */
+    return hb_language_from_string ("man", -1);  /* Mandingo [macrolanguage] */
   case HB_TAG('M','O','L',' '):  /* Moldavian */
     return hb_language_from_string ("ro-MD", -1);  /* Romanian; Moldova */
+  case HB_TAG('M','Y','N',' '):  /* Mayan */
+    return hb_language_from_string ("myn", -1);  /* Mayan [family] */
+  case HB_TAG('N','A','H',' '):  /* Nahuatl */
+    return hb_language_from_string ("nah", -1);  /* Nahuatl [family] */
   case HB_TAG('N','E','P',' '):  /* Nepali */
-    return hb_language_from_string ("ne", -1);  /* Nepali */
+    return hb_language_from_string ("ne", -1);  /* Nepali [macrolanguage] */
   case HB_TAG('N','I','S',' '):  /* Nisi */
     return hb_language_from_string ("njz", -1);  /* Nyishi */
   case HB_TAG('N','O','R',' '):  /* Norwegian */
-    return hb_language_from_string ("no", -1);  /* Norwegian */
+    return hb_language_from_string ("no", -1);  /* Norwegian [macrolanguage] */
   case HB_TAG('O','J','B',' '):  /* Ojibway */
-    return hb_language_from_string ("oj", -1);  /* Ojibwa */
+    return hb_language_from_string ("oj", -1);  /* Ojibwa [macrolanguage] */
   case HB_TAG('O','R','O',' '):  /* Oromo */
-    return hb_language_from_string ("om", -1);  /* Oromo */
+    return hb_language_from_string ("om", -1);  /* Oromo [macrolanguage] */
   case HB_TAG('P','A','S',' '):  /* Pashto */
-    return hb_language_from_string ("ps", -1);  /* Pashto */
+    return hb_language_from_string ("ps", -1);  /* Pashto [macrolanguage] */
   case HB_TAG('P','G','R',' '):  /* Polytonic Greek */
     return hb_language_from_string ("el-polyton", -1);  /* Modern Greek (1453-); Polytonic Greek */
   case HB_TAG('P','R','O',' '):  /* Provençal / Old Provençal */
     return hb_language_from_string ("pro", -1);  /* Old Provençal (to 1500) */
   case HB_TAG('Q','U','H',' '):  /* Quechua (Bolivia) */
     return hb_language_from_string ("quh", -1);  /* South Bolivian Quechua */
+  case HB_TAG('Q','U','Z',' '):  /* Quechua */
+    return hb_language_from_string ("qu", -1);  /* Quechua [macrolanguage] */
   case HB_TAG('Q','V','I',' '):  /* Quechua (Ecuador) */
     return hb_language_from_string ("qvi", -1);  /* Imbabura Highland Quichua */
   case HB_TAG('Q','W','H',' '):  /* Quechua (Peru) */
     return hb_language_from_string ("qwh", -1);  /* Huaylas Ancash Quechua */
   case HB_TAG('R','A','J',' '):  /* Rajasthani */
-    return hb_language_from_string ("raj", -1);  /* Rajasthani */
+    return hb_language_from_string ("raj", -1);  /* Rajasthani [macrolanguage] */
   case HB_TAG('R','O','Y',' '):  /* Romany */
-    return hb_language_from_string ("rom", -1);  /* Romany */
+    return hb_language_from_string ("rom", -1);  /* Romany [macrolanguage] */
   case HB_TAG('S','Q','I',' '):  /* Albanian */
-    return hb_language_from_string ("sq", -1);  /* Albanian */
+    return hb_language_from_string ("sq", -1);  /* Albanian [macrolanguage] */
+  case HB_TAG('S','R','B',' '):  /* Serbian */
+    return hb_language_from_string ("sr", -1);  /* Serbian */
+  case HB_TAG('S','X','T',' '):  /* Sutu */
+    return hb_language_from_string ("xnj", -1);  /* Ngoni (Tanzania) */
   case HB_TAG('S','Y','R',' '):  /* Syriac */
-    return hb_language_from_string ("syr", -1);  /* Syriac */
+    return hb_language_from_string ("syr", -1);  /* Syriac [macrolanguage] */
   case HB_TAG('S','Y','R','E'):  /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
     return hb_language_from_string ("und-Syre", -1);  /* Undetermined; Syriac (Estrangelo variant) */
   case HB_TAG('S','Y','R','J'):  /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */
@@ -2046,15 +2931,19 @@
   case HB_TAG('S','Y','R','N'):  /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */
     return hb_language_from_string ("und-Syrn", -1);  /* Undetermined; Syriac (Eastern variant) */
   case HB_TAG('T','M','H',' '):  /* Tamashek */
-    return hb_language_from_string ("tmh", -1);  /* Tamashek */
-  case HB_TAG('T','N','E',' '):  /* Tundra Nenets */
-    return hb_language_from_string ("yrk", -1);  /* Nenets */
-  case HB_TAG('Z','H','H',' '):  /* Chinese, Hong Kong SAR */
-    return hb_language_from_string ("zh-HK", -1);  /* Chinese; Hong Kong */
-  case HB_TAG('Z','H','S',' '):  /* Chinese Simplified */
-    return hb_language_from_string ("zh-Hans", -1);  /* Chinese; Han (Simplified variant) */
-  case HB_TAG('Z','H','T',' '):  /* Chinese Traditional */
-    return hb_language_from_string ("zh-Hant", -1);  /* Chinese; Han (Traditional variant) */
+    return hb_language_from_string ("tmh", -1);  /* Tamashek [macrolanguage] */
+  case HB_TAG('T','O','D',' '):  /* Todo */
+    return hb_language_from_string ("xwo", -1);  /* Written Oirat */
+  case HB_TAG('Z','H','H',' '):  /* Chinese, Traditional, Hong Kong SAR */
+    return hb_language_from_string ("zh-HK", -1);  /* Chinese [macrolanguage]; Hong Kong */
+  case HB_TAG('Z','H','S',' '):  /* Chinese, Simplified */
+    return hb_language_from_string ("zh-Hans", -1);  /* Chinese [macrolanguage]; Han (Simplified variant) */
+  case HB_TAG('Z','H','T',' '):  /* Chinese, Traditional */
+    return hb_language_from_string ("zh-Hant", -1);  /* Chinese [macrolanguage]; Han (Traditional variant) */
+  case HB_TAG('Z','H','T','M'):  /* Chinese, Traditional, Macao SAR */
+    return hb_language_from_string ("zh-MO", -1);  /* Chinese [macrolanguage]; Macao */
+  case HB_TAG('Z','Z','A',' '):  /* Zazaki */
+    return hb_language_from_string ("zza", -1);  /* Zazaki [macrolanguage] */
   default:
     return HB_LANGUAGE_INVALID;
   }
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 8ad917a..1837063 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -164,6 +164,15 @@
   *count = i;
 }
 
+/**
+ * hb_ot_tag_to_script:
+ * @tag: a script tag
+ *
+ * Converts a script tag to an #hb_script_t.
+ *
+ * Return value: The #hb_script_t corresponding to @tag.
+ *
+ **/
 hb_script_t
 hb_ot_tag_to_script (hb_tag_t tag)
 {
@@ -280,6 +289,7 @@
       for (i = 0;
 	   i < *count &&
 	   tag_idx + i < ARRAY_LENGTH (ot_languages) &&
+	   ot_languages[tag_idx + i].tag != HB_TAG_NONE &&
 	   0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language);
 	   i++)
 	tags[i] = ot_languages[tag_idx + i].tag;
@@ -319,12 +329,26 @@
   char tag[4];
   int i;
   s += strlen (prefix);
-  for (i = 0; i < 4 && ISALNUM (s[i]); i++)
-    tag[i] = normalize (s[i]);
-  if (!i) return false;
+  if (s[0] == '-') {
+    s += 1;
+    char c;
+    for (i = 0; i < 8 && ISHEX (s[i]); i++)
+    {
+      c = FROMHEX (s[i]);
+      if (i % 2 == 0)
+	tag[i / 2] = c << 4;
+      else
+	tag[i / 2] += c;
+    }
+    if (i != 8) return false;
+  } else {
+    for (i = 0; i < 4 && ISALNUM (s[i]); i++)
+      tag[i] = normalize (s[i]);
+    if (!i) return false;
 
-  for (; i < 4; i++)
-    tag[i] = ' ';
+    for (; i < 4; i++)
+      tag[i] = ' ';
+  }
   tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
   if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
     tags[0] ^= ~0xDFDFDFDF;
@@ -336,13 +360,13 @@
  * hb_ot_tags_from_script_and_language:
  * @script: an #hb_script_t to convert.
  * @language: an #hb_language_t to convert.
- * @script_count: (allow-none): maximum number of script tags to retrieve (IN)
+ * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
  * and actual number of script tags retrieved (OUT)
- * @script_tags: (out) (allow-none): array of size at least @script_count to store the
+ * @script_tags: (out) (optional): array of size at least @script_count to store the
  * script tag results
- * @language_count: (allow-none): maximum number of language tags to retrieve
+ * @language_count: (inout) (optional): maximum number of language tags to retrieve
  * (IN) and actual number of language tags retrieved (OUT)
- * @language_tags: (out) (allow-none): array of size at least @language_count to store
+ * @language_tags: (out) (optional): array of size at least @language_count to store
  * the language tag results
  *
  * Converts an #hb_script_t and an #hb_language_t to script and language tags.
@@ -409,10 +433,12 @@
 
 /**
  * hb_ot_tag_to_language:
+ * @tag: an language tag
  *
+ * Converts a language tag to an #hb_language_t.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none) (nullable):
+ * The #hb_language_t corresponding to @tag.
  *
  * Since: 0.9.2
  **/
@@ -434,30 +460,28 @@
     if (ot_languages[i].tag == tag)
       return hb_language_from_string (ot_languages[i].language, -1);
 
-  /* If it's three letters long, assume it's ISO 639-3 and lower-case and use it
-   * (if it's not a registered tag, calling hb_ot_tag_from_language on the
-   * result might not return the same tag as the original tag).
-   * Else return a custom language in the form of "x-hbotABCD". */
+  /* 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
+   * prepend it (if it's not a registered tag, the private use subtags will
+   * ensure that calling hb_ot_tag_from_language on the result will still return
+   * the same tag as the original tag).
+   */
   {
-    char buf[11] = "x-hbot";
+    char buf[20];
     char *str = buf;
-    buf[6] = tag >> 24;
-    buf[7] = (tag >> 16) & 0xFF;
-    buf[8] = (tag >> 8) & 0xFF;
-    buf[9] = tag & 0xFF;
-    if (buf[9] == 0x20)
+    if (ISALPHA (tag >> 24)
+	&& ISALPHA ((tag >> 16) & 0xFF)
+	&& ISALPHA ((tag >> 8) & 0xFF)
+	&& (tag & 0xFF) == ' ')
     {
-      buf[9] = '\0';
-      if (ISALPHA (buf[6]) && ISALPHA (buf[7]) && ISALPHA (buf[8]))
-      {
-	buf[6] = TOLOWER (buf[6]);
-	buf[7] = TOLOWER (buf[7]);
-	buf[8] = TOLOWER (buf[8]);
-	str += 6;
-      }
+      buf[0] = TOLOWER (tag >> 24);
+      buf[1] = TOLOWER ((tag >> 16) & 0xFF);
+      buf[2] = TOLOWER ((tag >> 8) & 0xFF);
+      buf[3] = '-';
+      str += 4;
     }
-    buf[10] = '\0';
-    return hb_language_from_string (str, -1);
+    snprintf (str, 16, "x-hbot-%08x", tag);
+    return hb_language_from_string (&*buf, -1);
   }
 }
 
@@ -465,9 +489,9 @@
  * hb_ot_tags_to_script_and_language:
  * @script_tag: a script tag
  * @language_tag: a language tag
- * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT).
- * @language: (allow-none): the #hb_language_t corresponding to @script_tag and
- * @language_tag (OUT).
+ * @script: (out) (optional): the #hb_script_t corresponding to @script_tag.
+ * @language: (out) (optional): the #hb_language_t corresponding to @script_tag and
+ * @language_tag.
  *
  * Converts a script tag and a language tag to an #hb_script_t and an
  * #hb_language_t.
@@ -498,13 +522,14 @@
       unsigned char *buf;
       const char *lang_str = hb_language_to_string (*language);
       size_t len = strlen (lang_str);
-      buf = (unsigned char *) malloc (len + 11);
+      buf = (unsigned char *) hb_malloc (len + 16);
       if (unlikely (!buf))
       {
 	*language = nullptr;
       }
       else
       {
+	int shift;
 	memcpy (buf, lang_str, len);
 	if (lang_str[0] != 'x' || lang_str[1] != '-') {
 	  buf[len++] = '-';
@@ -515,12 +540,11 @@
 	buf[len++] = 'b';
 	buf[len++] = 's';
 	buf[len++] = 'c';
-	buf[len++] = script_tag >> 24;
-	buf[len++] = (script_tag >> 16) & 0xFF;
-	buf[len++] = (script_tag >> 8) & 0xFF;
-	buf[len++] = script_tag & 0xFF;
+	buf[len++] = '-';
+	for (shift = 28; shift >= 0; shift -= 4)
+	  buf[len++] = TOHEX (script_tag >> shift);
 	*language = hb_language_from_string ((char *) buf, len);
-	free (buf);
+	hb_free (buf);
       }
     }
   }
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index ef8ba3f..65f26c1 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -51,14 +51,14 @@
   public:
   F2DOT14	coords[2];
 //   F2DOT14	fromCoord;	/* A normalized coordinate value obtained using
-// 				 * default normalization. */
+//				 * default normalization. */
 //   F2DOT14	toCoord;	/* The modified, normalized coordinate value. */
 
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-struct SegmentMaps : ArrayOf<AxisValueMap>
+struct SegmentMaps : Array16Of<AxisValueMap>
 {
   int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
   {
@@ -79,7 +79,7 @@
       return value - arrayZ[0].fromCoord + arrayZ[0].toCoord;
 
     unsigned int i;
-    unsigned int count = len;
+    unsigned int count = len - 1;
     for (i = 1; i < count && value > arrayZ[i].fromCoord; i++)
       ;
 
@@ -90,9 +90,8 @@
       return arrayZ[i-1].toCoord;
 
     int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord;
-    return arrayZ[i-1].toCoord +
-	   ((arrayZ[i].toCoord - arrayZ[i-1].toCoord) *
-	    (value - arrayZ[i-1].fromCoord) + denom/2) / denom;
+    return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) *
+					  (value - arrayZ[i-1].fromCoord)) / denom);
 #undef toCoord
 #undef fromCoord
   }
diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh
new file mode 100644
index 0000000..0eafb94
--- /dev/null
+++ b/src/hb-ot-var-common.hh
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2021  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_COMMON_HH
+#define HB_OT_VAR_COMMON_HH
+
+#include "hb-ot-layout-common.hh"
+
+
+namespace OT {
+
+struct DeltaSetIndexMapFormat0
+{
+  friend struct DeltaSetIndexMap;
+
+  private:
+  DeltaSetIndexMapFormat0* 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);
+  }
+
+  template <typename T>
+  bool serialize (hb_serialize_context_t *c, const T &plan)
+  {
+    unsigned int width = plan.get_width ();
+    unsigned int inner_bit_count = plan.get_inner_bit_count ();
+    const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
+
+    TRACE_SERIALIZE (this);
+    if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
+      return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    entryFormat = ((width-1)<<4)|(inner_bit_count-1);
+    mapCount = output_map.length;
+    HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
+    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;)
+      {
+        p[--w] = u;
+        u >>= 8;
+      }
+      p += width;
+    }
+    return_trace (true);
+  }
+
+  uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
+  {
+    /* If count is zero, pass value unchanged.  This takes
+     * care of direct mapping for advance map. */
+    if (!mapCount)
+      return v;
+
+    if (v >= mapCount)
+      v = mapCount - 1;
+
+    unsigned int u = 0;
+    { /* Fetch it. */
+      unsigned int w = get_width ();
+      const HBUINT8 *p = mapDataZ.arrayZ + w * v;
+      for (; w; w--)
+        u = (u << 8) + *p++;
+    }
+
+    { /* Repack it. */
+      unsigned int n = get_inner_bit_count ();
+      unsigned int outer = u >> n;
+      unsigned int inner = u & ((1 << n) - 1);
+      u = (outer<<16) | inner;
+    }
+
+    return u;
+  }
+
+  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 = 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. */
+  UnsizedArrayOf<HBUINT8>
+                mapDataZ;       /* The delta-set index mapping data. */
+
+  public:
+  DEFINE_SIZE_ARRAY (6, mapDataZ);
+};
+
+struct DeltaSetIndexMap
+{
+  template <typename T>
+  bool serialize (hb_serialize_context_t *c, const T &plan)
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.format) {
+    case 0: return_trace (u.format0.serialize (c, plan));
+    default:return_trace (false);
+    }
+  }
+
+  uint32_t map (unsigned v) const
+  {
+    switch (u.format) {
+    case 0: return (u.format0.map (v));
+    default:return v;
+    }
+  }
+
+  unsigned get_map_count () const
+  {
+    switch (u.format) {
+    case 0: return u.format0.get_map_count ();
+    case 1: return u.format1.get_map_count ();
+    default:return 0;
+    }
+  }
+
+  unsigned get_width () const
+  {
+    switch (u.format) {
+    case 0: return u.format0.get_width ();
+    case 1: return u.format1.get_width ();
+    default:return 0;
+    }
+  }
+
+  unsigned get_inner_bit_count () const
+  {
+    switch (u.format) {
+    case 0: return u.format0.get_inner_bit_count ();
+    case 1: return u.format1.get_inner_bit_count ();
+    default:return 0;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 0: return_trace (u.format0.sanitize (c));
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.format) {
+    case 0: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format0.copy (c)));
+    case 1: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format1.copy (c)));
+    default:return_trace (nullptr);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT8                       format;         /* Format identifier */
+  DeltaSetIndexMapFormat0       format0;
+  DeltaSetIndexMapFormat1       format1;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (1, format);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_VAR_COMMON_HH */
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 7ce3123..05f289d 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -70,22 +70,85 @@
 
 struct AxisRecord
 {
+  int cmp (hb_tag_t key) const { return axisTag.cmp (key); }
+
   enum
   {
     AXIS_FLAG_HIDDEN	= 0x0001,
   };
 
+#ifndef HB_DISABLE_DEPRECATED
+  void get_axis_deprecated (hb_ot_var_axis_t *info) const
+  {
+    info->tag = axisTag;
+    info->name_id = axisNameID;
+    get_coordinates (info->min_value, info->default_value, info->max_value);
+  }
+#endif
+
+  void get_axis_info (unsigned axis_index, hb_ot_var_axis_info_t *info) const
+  {
+    info->axis_index = axis_index;
+    info->tag = axisTag;
+    info->name_id = axisNameID;
+    info->flags = (hb_ot_var_axis_flags_t) (unsigned int) flags;
+    get_coordinates (info->min_value, info->default_value, info->max_value);
+    info->reserved = 0;
+  }
+
+  int normalize_axis_value (float v) const
+  {
+    float min_value, default_value, max_value;
+    get_coordinates (min_value, default_value, max_value);
+
+    v = hb_clamp (v, min_value, max_value);
+
+    if (v == default_value)
+      return 0;
+    else if (v < default_value)
+      v = (v - default_value) / (default_value - min_value);
+    else
+      v = (v - default_value) / (max_value - default_value);
+    return roundf (v * 16384.f);
+  }
+
+  float unnormalize_axis_value (int v) const
+  {
+    float min_value, default_value, max_value;
+    get_coordinates (min_value, default_value, max_value);
+
+    if (v == 0)
+      return default_value;
+    else if (v < 0)
+      return v * (default_value - min_value) / 16384.f + default_value;
+    else
+      return v * (max_value - default_value) / 16384.f + default_value;
+  }
+
+  hb_ot_name_id_t get_name_id () const { return axisNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
+  protected:
+  void get_coordinates (float &min, float &default_, float &max) const
+  {
+    default_ = defaultValue / 65536.f;
+    /* Ensure order, to simplify client math. */
+    min = hb_min (default_, minValue / 65536.f);
+    max = hb_max (default_, maxValue / 65536.f);
+  }
+
   public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
-  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. */
+  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. */
+  public:
   HBUINT16	flags;		/* Axis flags. */
   NameID	axisNameID;	/* The name ID for entries in the 'name' table that
 				 * provide a display name for this axis. */
@@ -115,53 +178,15 @@
   unsigned int get_axis_count () const { return axisCount; }
 
 #ifndef HB_DISABLE_DEPRECATED
-  void get_axis_deprecated (unsigned int axis_index,
-				   hb_ot_var_axis_t *info) const
-  {
-    const AxisRecord &axis = get_axes ()[axis_index];
-    info->tag = axis.axisTag;
-    info->name_id =  axis.axisNameID;
-    info->default_value = axis.defaultValue / 65536.f;
-    /* Ensure order, to simplify client math. */
-    info->min_value = hb_min (info->default_value, axis.minValue / 65536.f);
-    info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f);
-  }
-#endif
-
-  void get_axis_info (unsigned int axis_index,
-		      hb_ot_var_axis_info_t *info) const
-  {
-    const AxisRecord &axis = get_axes ()[axis_index];
-    info->axis_index = axis_index;
-    info->tag = axis.axisTag;
-    info->name_id =  axis.axisNameID;
-    info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags;
-    info->default_value = axis.defaultValue / 65536.f;
-    /* Ensure order, to simplify client math. */
-    info->min_value = hb_min (info->default_value, axis.minValue / 65536.f);
-    info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f);
-    info->reserved = 0;
-  }
-
-#ifndef HB_DISABLE_DEPRECATED
   unsigned int get_axes_deprecated (unsigned int      start_offset,
 				    unsigned int     *axes_count /* IN/OUT */,
 				    hb_ot_var_axis_t *axes_array /* OUT */) const
   {
     if (axes_count)
     {
-      /* TODO Rewrite as hb_array_t<>::sub-array() */
-      unsigned int count = axisCount;
-      start_offset = hb_min (start_offset, count);
-
-      count -= start_offset;
-      axes_array += start_offset;
-
-      count = hb_min (count, *axes_count);
-      *axes_count = count;
-
-      for (unsigned int i = 0; i < count; i++)
-	get_axis_deprecated (start_offset + i, axes_array + i);
+      hb_array_t<const AxisRecord> arr = get_axes ().sub_array (start_offset, axes_count);
+      for (unsigned i = 0; i < arr.length; ++i)
+	arr[i].get_axis_deprecated (&axes_array[i]);
     }
     return axisCount;
   }
@@ -173,86 +198,37 @@
   {
     if (axes_count)
     {
-      /* TODO Rewrite as hb_array_t<>::sub-array() */
-      unsigned int count = axisCount;
-      start_offset = hb_min (start_offset, count);
-
-      count -= start_offset;
-      axes_array += start_offset;
-
-      count = hb_min (count, *axes_count);
-      *axes_count = count;
-
-      for (unsigned int i = 0; i < count; i++)
-	get_axis_info (start_offset + i, axes_array + i);
+      hb_array_t<const AxisRecord> arr = get_axes ().sub_array (start_offset, axes_count);
+      for (unsigned i = 0; i < arr.length; ++i)
+	arr[i].get_axis_info (start_offset + i, &axes_array[i]);
     }
     return axisCount;
   }
 
 #ifndef HB_DISABLE_DEPRECATED
-  bool find_axis_deprecated (hb_tag_t tag,
-			     unsigned int *axis_index,
-			     hb_ot_var_axis_t *info) const
+  bool
+  find_axis_deprecated (hb_tag_t tag, unsigned *axis_index, hb_ot_var_axis_t *info) const
   {
-    const AxisRecord *axes = get_axes ();
-    unsigned int count = get_axis_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (axes[i].axisTag == tag)
-      {
-	if (axis_index)
-	  *axis_index = i;
-	get_axis_deprecated (i, info);
-	return true;
-      }
-    if (axis_index)
-      *axis_index = HB_OT_VAR_NO_AXIS_INDEX;
-    return false;
+    unsigned i;
+    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);
   }
 #endif
-
-  bool find_axis_info (hb_tag_t tag,
-		       hb_ot_var_axis_info_t *info) const
+  bool
+  find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const
   {
-    const AxisRecord *axes = get_axes ();
-    unsigned int count = get_axis_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (axes[i].axisTag == tag)
-      {
-	get_axis_info (i, info);
-	return true;
-      }
-    return false;
+    unsigned i;
+    auto axes = get_axes ();
+    return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true);
   }
 
   int normalize_axis_value (unsigned int axis_index, float v) const
-  {
-    hb_ot_var_axis_info_t axis;
-    get_axis_info (axis_index, &axis);
+  { return get_axes ()[axis_index].normalize_axis_value (v); }
 
-    v = hb_max (hb_min (v, axis.max_value), axis.min_value); /* Clamp. */
-
-    if (v == axis.default_value)
-      return 0;
-    else if (v < axis.default_value)
-      v = (v - axis.default_value) / (axis.default_value - axis.min_value);
-    else
-      v = (v - axis.default_value) / (axis.max_value - axis.default_value);
-    return roundf (v * 16384.f);
-  }
-
-  float unnormalize_axis_value (unsigned int axis_index, float v) const
-  {
-    hb_ot_var_axis_info_t axis;
-    get_axis_info (axis_index, &axis);
-
-    if (v == 0)
-      return axis.default_value;
-    else if (v < 0)
-      v = v * (axis.default_value - axis.min_value) / 16384.f + axis.default_value;
-    else
-      v = v * (axis.max_value - axis.default_value) / 16384.f + axis.default_value;
-    return v;
-  }
+  float unnormalize_axis_value (unsigned int axis_index, int v) const
+  { return get_axes ()[axis_index].unnormalize_axis_value (v); }
 
   unsigned int get_instance_count () const { return instanceCount; }
 
@@ -299,7 +275,7 @@
     if (!has_data ()) return;
 
     + get_axes ()
-    | hb_map (&AxisRecord::axisNameID)
+    | hb_map (&AxisRecord::get_name_id)
     | hb_sink (nameids)
     ;
 
@@ -314,8 +290,7 @@
     ;
   }
 
-
-  protected:
+  public:
   hb_array_t<const AxisRecord> get_axes () const
   { return hb_array (&(this+firstAxis), axisCount); }
 
@@ -329,7 +304,7 @@
   protected:
   FixedVersion<>version;	/* Version of the fvar table
 				 * initially set to 0x00010000u */
-  OffsetTo<AxisRecord>
+  Offset16To<AxisRecord>
 		firstAxis;	/* Offset in bytes from the beginning of the table
 				 * to the start of the AxisRecord array. */
   HBUINT16	reserved;	/* This field is permanently reserved. Set to 2. */
diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh
index a76121d..49b5532 100644
--- a/src/hb-ot-var-gvar-table.hh
+++ b/src/hb-ot-var-gvar-table.hh
@@ -29,8 +29,6 @@
 #define HB_OT_VAR_GVAR_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-var-fvar-table.hh"
 
 /*
  * gvar -- Glyph Variation Table
@@ -42,12 +40,14 @@
 
 struct contour_point_t
 {
-  void init (float x_=0.f, float y_=0.f) { flag = 0; x = x_; y = y_; }
+  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 translate (const contour_point_t &p) { x += p.x; y += p.y; }
 
   uint8_t flag;
   float x, y;
+  bool is_end_point;
 };
 
 struct contour_point_vector_t : hb_vector_t<contour_point_t>
@@ -78,50 +78,34 @@
   }
 };
 
-struct Tuple : UnsizedArrayOf<F2DOT14> {};
-
-struct TuppleIndex : HBUINT16
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
+struct TupleVariationHeader
 {
-  enum Flags {
-    EmbeddedPeakTuple   = 0x8000u,
-    IntermediateRegion  = 0x4000u,
-    PrivatePointNumbers = 0x2000u,
-    TupleIndexMask      = 0x0FFFu
-  };
+  unsigned get_size (unsigned axis_count) const
+  { return min_size + get_all_tuples (axis_count).get_size (); }
 
-  DEFINE_SIZE_STATIC (2);
-};
+  unsigned get_data_size () const { return varDataSize; }
 
-struct TupleVarHeader
-{
-  unsigned int get_size (unsigned int axis_count) const
-  {
-    return min_size +
-	   (has_peak () ? get_peak_tuple ().get_size (axis_count) : 0) +
-	   (has_intermediate () ? (get_start_tuple (axis_count).get_size (axis_count) +
-				   get_end_tuple (axis_count).get_size (axis_count)) : 0);
-  }
-
-  const TupleVarHeader &get_next (unsigned int axis_count) const
-  { return StructAtOffset<TupleVarHeader> (this, get_size (axis_count)); }
+  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
+			  const hb_array_t<const F2DOT14> shared_tuples) const
   {
-    const F2DOT14 *peak_tuple;
+    hb_array_t<const F2DOT14> peak_tuple;
 
     if (has_peak ())
-      peak_tuple = &(get_peak_tuple ()[0]);
+      peak_tuple = get_peak_tuple (coord_count);
     else
     {
       unsigned int index = get_index ();
       if (unlikely (index * coord_count >= shared_tuples.length))
 	return 0.f;
-      peak_tuple = &shared_tuples[coord_count * index];
+      peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
     }
 
-    const F2DOT14 *start_tuple = nullptr;
-    const F2DOT14 *end_tuple = nullptr;
+    hb_array_t<const F2DOT14> start_tuple;
+    hb_array_t<const F2DOT14> end_tuple;
     if (has_intermediate ())
     {
       start_tuple = get_start_tuple (coord_count);
@@ -154,58 +138,64 @@
     return scalar;
   }
 
-  unsigned int get_data_size () const { return varDataSize; }
-
-  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 int  get_index () const { return (tupleIndex & TuppleIndex::TupleIndexMask); }
+  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:
-  const Tuple &get_peak_tuple () const
-  { return StructAfter<Tuple> (tupleIndex); }
-  const Tuple &get_start_tuple (unsigned int axis_count) const
-  { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? axis_count : 0]; }
-  const Tuple &get_end_tuple (unsigned int axis_count) const
-  { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? (axis_count * 2) : axis_count]; }
+  struct TuppleIndex : HBUINT16
+  {
+    enum Flags {
+      EmbeddedPeakTuple   = 0x8000u,
+      IntermediateRegion  = 0x4000u,
+      PrivatePointNumbers = 0x2000u,
+      TupleIndexMask      = 0x0FFFu
+    };
 
-  HBUINT16		varDataSize;
-  TuppleIndex		tupleIndex;
+    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);
 };
 
-struct TupleVarCount : HBUINT16
+struct GlyphVariationData
 {
-  bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
-  unsigned int get_count () const { return (*this) & CountMask; }
-
-  protected:
-  enum Flags
-  {
-    SharedPointNumbers	= 0x8000u,
-    CountMask		= 0x0FFFu
-  };
-
-  public:
-  DEFINE_SIZE_STATIC (2);
-};
-
-struct GlyphVarData
-{
-  const TupleVarHeader &get_tuple_var_header (void) const
-  { return StructAfter<TupleVarHeader> (data); }
+  const TupleVariationHeader &get_tuple_var_header (void) const
+  { return StructAfter<TupleVariationHeader> (data); }
 
   struct tuple_iterator_t
   {
-    void init (const GlyphVarData *var_data_, unsigned int length_, unsigned int axis_count_)
+    void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
     {
-      var_data = var_data_;
-      length = length_;
+      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 ();
@@ -216,10 +206,9 @@
     {
       if (var_data->has_shared_point_numbers ())
       {
-	hb_bytes_t bytes ((const char *) var_data, length);
 	const HBUINT8 *base = &(var_data+var_data->data);
 	const HBUINT8 *p = base;
-	if (!unpack_points (p, shared_indices, bytes)) return false;
+	if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
 	data_offset = p - base;
       }
       return true;
@@ -228,7 +217,8 @@
     bool is_valid () const
     {
       return (index < var_data->tupleVarCount.get_count ()) &&
-	     in_range (current_tuple) &&
+	     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);
     }
 
@@ -240,32 +230,25 @@
       return is_valid ();
     }
 
-    bool in_range (const void *p, unsigned int l) const
-    { return (const char*) p >= (const char*) var_data && (const char*) p+l <= (const char*) var_data + length; }
-
-    template <typename T> bool in_range (const T *p) const { return in_range (p, sizeof (*p)); }
-
     const HBUINT8 *get_serialized_data () const
     { return &(var_data+var_data->data) + data_offset; }
 
     private:
-    const GlyphVarData *var_data;
-    unsigned int length;
+    const GlyphVariationData *var_data;
     unsigned int index;
     unsigned int axis_count;
     unsigned int data_offset;
 
     public:
-    const TupleVarHeader *current_tuple;
+    hb_bytes_t var_data_bytes;
+    const TupleVariationHeader *current_tuple;
   };
 
-  static bool get_tuple_iterator (const GlyphVarData *var_data,
-  				  unsigned int length,
-  				  unsigned int axis_count,
-  				  hb_vector_t<unsigned int> &shared_indices /* OUT */,
-  				  tuple_iterator_t *iterator /* OUT */)
+  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, length, axis_count);
+    iterator->init (var_data_bytes, axis_count);
     if (!iterator->get_shared_indices (shared_indices))
       return false;
     return iterator->is_valid ();
@@ -283,12 +266,12 @@
       POINT_RUN_COUNT_MASK = 0x7F
     };
 
-    if (unlikely (!bytes.in_range (p))) return false;
+    if (unlikely (!bytes.check_range (p))) return false;
 
     uint16_t count = *p++;
     if (count & POINTS_ARE_WORDS)
     {
-      if (unlikely (!bytes.in_range (p))) return false;
+      if (unlikely (!bytes.check_range (p))) return false;
       count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
     }
     points.resize (count);
@@ -297,7 +280,7 @@
     uint16_t i = 0;
     while (i < count)
     {
-      if (unlikely (!bytes.in_range (p))) return false;
+      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;
@@ -305,7 +288,7 @@
       {
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+	  if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
 	    return false;
 	  n += *(const HBUINT16 *)p;
 	  points[i] = n;
@@ -316,7 +299,7 @@
       {
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.in_range (p))) return false;
+	  if (unlikely (!bytes.check_range (p))) return false;
 	  n += *p++;
 	  points[i] = n;
 	}
@@ -341,7 +324,7 @@
     unsigned int count = deltas.length;
     while (i < count)
     {
-      if (unlikely (!bytes.in_range (p))) return false;
+      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;
@@ -351,7 +334,7 @@
       else if (control & DELTAS_ARE_WORDS)
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+	  if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
 	    return false;
 	  deltas[i] = *(const HBINT16 *) p;
 	  p += HBUINT16::static_size;
@@ -359,7 +342,7 @@
       else
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.in_range (p)))
+	  if (unlikely (!bytes.check_range (p)))
 	    return false;
 	  deltas[i] = *(const HBINT8 *) p++;
 	}
@@ -369,10 +352,32 @@
     return true;
   }
 
+  bool has_data () const { return tupleVarCount; }
+
   protected:
-  TupleVarCount		tupleVarCount;
-  OffsetTo<HBUINT8>	data;
-  /* TupleVarHeader tupleVarHeaders[] */
+  struct TupleVarCount : HBUINT16
+  {
+    bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+    unsigned int get_count () const { return (*this) & CountMask; }
+
+    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 GlyphVariationData table
+				 * to the serialized data. */
+  /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
   public:
   DEFINE_SIZE_MIN (4);
 };
@@ -386,7 +391,7 @@
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && (version.major == 1) &&
 		  (glyphCount == c->get_num_glyphs ()) &&
-		  c->check_array (&(this+sharedTuples), axisCount * sharedTupleCount) &&
+		  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)) &&
@@ -394,7 +399,7 @@
 				  get_offset (glyphCount) - get_offset (0)));
   }
 
-  /* GlyphVarData not sanitized here; must be checked while accessing each glyph varation data */
+  /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */
   bool sanitize (hb_sanitize_context_t *c) const
   { return sanitize_shallow (c); }
 
@@ -414,11 +419,13 @@
     out->glyphCount = num_glyphs;
 
     unsigned int subset_data_size = 0;
-    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
+         gid < num_glyphs;
+         gid++)
     {
       hb_codepoint_t old_gid;
       if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
-      subset_data_size += get_glyph_var_data_length (old_gid);
+      subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
     }
 
     bool long_offset = subset_data_size & ~0xFFFFu;
@@ -436,27 +443,32 @@
       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);
+      memcpy (tuples, this+sharedTuples, shared_tuple_size);
     }
 
     char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
     if (!subset_data) return_trace (false);
-    out->dataZ = subset_data - (char *)out;
+    out->dataZ = subset_data - (char *) out;
 
     unsigned int glyph_offset = 0;
-    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
+         gid < num_glyphs;
+         gid++)
     {
       hb_codepoint_t old_gid;
-      unsigned int length = c->plan->old_gid_for_new_gid (gid, &old_gid) ? get_glyph_var_data_length (old_gid) : 0;
+      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 ();
 
       if (long_offset)
 	((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
       else
 	((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
 
-      if (length > 0) memcpy (subset_data, get_glyph_var_data (old_gid), length);
-      subset_data += length;
-      glyph_offset += length;
+      if (var_data_bytes.length > 0)
+	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)[num_glyphs] = glyph_offset;
@@ -467,36 +479,18 @@
   }
 
   protected:
-  const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
+  const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
   {
-    unsigned int start_offset = get_offset (glyph);
-    unsigned int end_offset = get_offset (glyph+1);
-
-    if ((start_offset == end_offset) ||
-	unlikely ((start_offset > get_offset (glyphCount)) ||
-		  (start_offset + GlyphVarData::min_size > end_offset)))
-      return &Null (GlyphVarData);
-    return &(((unsigned char *) this + start_offset) + dataZ);
+    unsigned start_offset = get_offset (glyph);
+    unsigned length = get_offset (glyph+1) - 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) != 0; }
+  bool is_long_offset () const { return flags & 1; }
 
-  unsigned int get_offset (unsigned int i) const
-  {
-    if (is_long_offset ())
-      return get_long_offset_array ()[i];
-    else
-      return get_short_offset_array ()[i] * 2;
-  }
-
-  unsigned int get_glyph_var_data_length (unsigned int glyph) const
-  {
-    unsigned int end_offset = get_offset (glyph + 1);
-    unsigned int start_offset = get_offset (glyph);
-    if (unlikely (start_offset > end_offset || end_offset > get_offset (glyphCount)))
-      return 0;
-    return end_offset - start_offset;
-  }
+  unsigned get_offset (unsigned i) const
+  { 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; }
@@ -505,27 +499,8 @@
   struct accelerator_t
   {
     void init (hb_face_t *face)
-    {
-      gvar_table = hb_sanitize_context_t ().reference_table<gvar> (face);
-      hb_blob_ptr_t<fvar> fvar_table = hb_sanitize_context_t ().reference_table<fvar> (face);
-      unsigned int axis_count = fvar_table->get_axis_count ();
-      fvar_table.destroy ();
-
-      if (unlikely ((gvar_table->glyphCount != face->get_num_glyphs ()) ||
-		    (gvar_table->axisCount != axis_count)))
-      	fini ();
-
-      unsigned int num_shared_coord = gvar_table->sharedTupleCount * gvar_table->axisCount;
-      shared_tuples.resize (num_shared_coord);
-      for (unsigned int i = 0; i < num_shared_coord; i++)
-	shared_tuples[i] = (&(gvar_table + gvar_table->sharedTuples))[i];
-    }
-
-    void fini ()
-    {
-      gvar_table.destroy ();
-      shared_tuples.fini ();
-    }
+    { table = hb_sanitize_context_t ().reference_table<gvar> (face); }
+    void fini () { table.destroy (); }
 
     private:
     struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
@@ -543,11 +518,11 @@
       float next_delta = T::get (deltas[next]);
 
       if (prev_val == next_val)
-      	return (prev_delta == next_delta) ? prev_delta : 0.f;
+	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;
+	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;
+	return (prev_val > next_val) ? prev_delta : next_delta;
 
       /* linear interpolation */
       float r = (target_val - prev_val) / (next_val - prev_val);
@@ -558,23 +533,21 @@
     { return (i >= end) ? start : (i + 1); }
 
     public:
-    bool apply_deltas_to_points (hb_codepoint_t glyph,
-				 const int *coords, unsigned int coord_count,
-				 const hb_array_t<contour_point_t> points,
-				 const hb_array_t<unsigned int> end_points) const
+    bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
+				 const hb_array_t<contour_point_t> points) const
     {
-      if (unlikely (coord_count != gvar_table->axisCount)) return false;
+      /* 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;
 
-      const GlyphVarData *var_data = gvar_table->get_glyph_var_data (glyph);
-      if (var_data == &Null (GlyphVarData)) return true;
+      if (unlikely (glyph >= table->glyphCount)) return true;
+
+      hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
+      if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
       hb_vector_t<unsigned int> shared_indices;
-      GlyphVarData::tuple_iterator_t iterator;
-      if (!GlyphVarData::get_tuple_iterator (var_data,
-					     gvar_table->get_glyph_var_data_length (glyph),
-					     gvar_table->axisCount,
-					     shared_indices,
-					     &iterator))
-	return false;
+      GlyphVariationData::tuple_iterator_t iterator;
+      if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
+						   shared_indices, &iterator))
+	return true; /* so isn't applied at all */
 
       /* Save original points for inferred delta calculation */
       contour_point_vector_t orig_points;
@@ -585,19 +558,27 @@
       contour_point_vector_t deltas; /* flag is used to indicate referenced point */
       deltas.resize (points.length);
 
+      hb_vector_t<unsigned> end_points;
+      for (unsigned i = 0; i < points.length; ++i)
+	if (points[i].is_end_point)
+	  end_points.push (i);
+
+      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);
       do
       {
-	float scalar = iterator.current_tuple->calculate_scalar (coords, coord_count, shared_tuples.as_array ());
+	float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, 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.in_range (p, length)))
+	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 () &&
-	    !GlyphVarData::unpack_points (p, private_indices, bytes))
+	    !GlyphVariationData::unpack_points (p, private_indices, bytes))
 	  return false;
 	const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
 
@@ -605,11 +586,11 @@
 	unsigned int num_deltas = apply_to_all ? points.length : indices.length;
 	hb_vector_t<int> x_deltas;
 	x_deltas.resize (num_deltas);
-	if (!GlyphVarData::unpack_deltas (p, x_deltas, bytes))
+	if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
 	  return false;
 	hb_vector_t<int> y_deltas;
 	y_deltas.resize (num_deltas);
-	if (!GlyphVarData::unpack_deltas (p, y_deltas, bytes))
+	if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
 	  return false;
 
 	for (unsigned int i = 0; i < deltas.length; i++)
@@ -623,26 +604,26 @@
 	}
 
 	/* infer deltas for unreferenced points */
-	unsigned int start_point = 0;
-	for (unsigned int c = 0; c < end_points.length; c++)
+	unsigned start_point = 0;
+	for (unsigned c = 0; c < end_points.length; c++)
 	{
-	  unsigned int end_point = end_points[c];
-	  unsigned int i, j;
+	  unsigned end_point = end_points[c];
 
 	  /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
-	  unsigned int unref_count = 0;
-	  for (i = start_point; i <= end_point; i++)
+	  unsigned unref_count = 0;
+	  for (unsigned i = start_point; i <= end_point; i++)
 	    if (!deltas[i].flag) unref_count++;
+
+	  unsigned j = start_point;
 	  if (unref_count == 0 || unref_count > end_point - start_point)
 	    goto no_more_gaps;
 
-	  j = start_point;
 	  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;
+	    unsigned int prev, next, i;
 	    for (;;)
 	    {
 	      i = j;
@@ -675,37 +656,44 @@
 	/* apply specified / inferred deltas to points */
 	for (unsigned int i = 0; i < points.length; i++)
 	{
-	  points[i].x += (float) roundf (deltas[i].x);
-	  points[i].y += (float) roundf (deltas[i].y);
+	  points[i].x += deltas[i].x;
+	  points[i].y += deltas[i].y;
 	}
       } while (iterator.move_to_next ());
 
       return true;
     }
 
-    unsigned int get_axis_count () const { return gvar_table->axisCount; }
-
-    protected:
-    const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
-    { return gvar_table->get_glyph_var_data (glyph); }
+    unsigned int get_axis_count () const { return table->axisCount; }
 
     private:
-    hb_blob_ptr_t<gvar> gvar_table;
-    hb_vector_t<F2DOT14> shared_tuples;
+    hb_blob_ptr_t<gvar> table;
   };
 
   protected:
-  FixedVersion<>version;	/* Version of gvar table. Set to 0x00010000u. */
-  HBUINT16	axisCount;
+  FixedVersion<>version;	/* Version number of the glyph variations table
+				 * Set to 0x00010000u. */
+  HBUINT16	axisCount;	/* The number of variation axes for this font. This must be
+				 * the same number as axisCount in the 'fvar' table. */
   HBUINT16	sharedTupleCount;
-  LOffsetTo<F2DOT14>
-		sharedTuples;	/* LOffsetTo<UnsizedArrayOf<Tupple>> */
-  HBUINT16	glyphCount;
-  HBUINT16	flags;
-  LOffsetTo<GlyphVarData>
-		dataZ;		/* Array of GlyphVarData */
+				/* The number of shared tuple records. Shared tuple records
+				 * can be referenced within glyph variation data tables for
+				 * multiple glyphs, as opposed to other tuple records stored
+				 * directly within a glyph variation data table. */
+  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
+				 * 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
+				 * offsets are uint32. */
+  Offset32To<GlyphVariationData>
+		dataZ;		/* Offset from the start of this table to the array of
+				 * GlyphVariationData tables. */
   UnsizedArrayOf<HBUINT8>
-		offsetZ;	/* Array of 16-bit or 32-bit (glyphCount+1) offsets */
+		offsetZ;	/* Offsets from the start of the GlyphVariationData array
+				 * to each GlyphVariationData table. */
   public:
   DEFINE_SIZE_MIN (20);
 };
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 223430f..074b6a3 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -28,66 +28,220 @@
 #define HB_OT_VAR_HVAR_TABLE_HH
 
 #include "hb-ot-layout-common.hh"
-
+#include "hb-ot-var-common.hh"
 
 namespace OT {
 
 
-struct DeltaSetIndexMap
+struct index_map_subset_plan_t
 {
-  bool sanitize (hb_sanitize_context_t *c) const
+  enum index_map_index_t {
+    ADV_INDEX,
+    LSB_INDEX,	/* dual as TSB */
+    RSB_INDEX,	/* dual as BSB */
+    VORG_INDEX
+  };
+
+  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)
   {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  c->check_range (mapDataZ.arrayZ,
-				  mapCount,
-				  get_width ()));
-  }
+    map_count = 0;
+    outer_bit_count = 0;
+    inner_bit_count = 1;
+    max_inners.init ();
+    output_map.init ();
 
-  unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */
-  {
-    /* If count is zero, pass value unchanged.  This takes
-     * care of direct mapping for advance map. */
-    if (!mapCount)
-      return v;
+    if (&index_map == &Null (DeltaSetIndexMap)) return;
 
-    if (v >= mapCount)
-      v = mapCount - 1;
+    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 ());
 
-    unsigned int u = 0;
-    { /* Fetch it. */
-      unsigned int w = get_width ();
-      const HBUINT8 *p = mapDataZ.arrayZ + w * v;
-      for (; w; w--)
-	u = (u << 8) + *p++;
+    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--)
+    {
+      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;
+      }
+
+      unsigned int v = index_map.map (old_gid);
+      if (last_gid == (hb_codepoint_t) -1)
+      {
+	last_val = v;
+	last_gid = gid;
+	continue;
+      }
+      if (v != last_val) break;
+
+      last_gid = gid;
     }
 
-    { /* Repack it. */
-      unsigned int n = get_inner_bitcount ();
-      unsigned int outer = u >> n;
-      unsigned int inner = u & ((1 << n) - 1);
-      u = (outer<<16) | inner;
+    if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
+    map_count = last_gid;
+    for (gid = 0; gid < map_count; gid++)
+    {
+      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);
+      }
     }
-
-    return u;
   }
 
-  protected:
-  unsigned int get_width () const          { return ((format >> 4) & 3) + 1; }
+  void fini ()
+  {
+    max_inners.fini ();
+    output_map.fini ();
+  }
 
-  unsigned int get_inner_bitcount () const { return (format & 0xF) + 1; }
+  void remap (const DeltaSetIndexMap *input_map,
+	      const hb_inc_bimap_t &outer_map,
+	      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;
+      unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]);
+      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++)
+    {
+      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 */
+    }
+  }
+
+  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; }
+
+  unsigned int get_size () const
+  { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); }
+
+  bool is_identity () const { return get_output_map ().length == 0; }
+  hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
 
   protected:
-  HBUINT16	format;		/* 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);
+  unsigned int map_count;
+  hb_vector_t<unsigned int> max_inners;
+  unsigned int outer_bit_count;
+  unsigned int inner_bit_count;
+  hb_vector_t<uint32_t> output_map;
 };
 
+struct hvarvvar_subset_plan_t
+{
+  hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {}
+  ~hvarvvar_subset_plan_t() { fini (); }
+
+  void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
+	     const VariationStore &_var_store,
+	     const hb_subset_plan_t *plan)
+  {
+    index_map_plans.resize (index_maps.length);
+
+    var_store = &_var_store;
+    inner_sets.resize (var_store->get_sub_table_count ());
+    for (unsigned int i = 0; i < inner_sets.length; i++)
+      inner_sets[i] = hb_set_create ();
+    adv_set = hb_set_create ();
+
+    inner_maps.resize (var_store->get_sub_table_count ());
+
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      inner_maps[i].init ();
+
+    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);
+    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);
+      }
+      hb_set_union (adv_set, inner_sets[0]);
+    }
+
+    for (unsigned int i = 1; i < index_maps.length; i++)
+      index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan);
+
+    outer_map.sort ();
+
+    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 ();
+    }
+    else
+    {
+      inner_maps[0].add_set (adv_set);
+      hb_set_subtract (inner_sets[0], adv_set);
+      inner_maps[0].add_set (inner_sets[0]);
+    }
+
+    for (unsigned int i = 1; i < inner_maps.length; i++)
+      inner_maps[i].add_set (inner_sets[i]);
+
+    for (unsigned int i = 0; i < index_maps.length; i++)
+      index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
+  }
+
+  void fini ()
+  {
+    for (unsigned int i = 0; i < inner_sets.length; i++)
+      hb_set_destroy (inner_sets[i]);
+    hb_set_destroy (adv_set);
+    inner_maps.fini_deep ();
+    index_map_plans.fini_deep ();
+  }
+
+  hb_inc_bimap_t outer_map;
+  hb_vector_t<hb_inc_bimap_t> inner_maps;
+  hb_vector_t<index_map_subset_plan_t> index_map_plans;
+  const VariationStore *var_store;
+
+  protected:
+  hb_vector_t<hb_set_t *> inner_sets;
+  hb_set_t *adv_set;
+};
 
 /*
  * HVAR -- Horizontal Metrics Variations
@@ -114,9 +268,63 @@
 		  rsbMap.sanitize (c, this));
   }
 
-  float get_advance_var (hb_font_t *font, hb_codepoint_t glyph) const
+  void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
   {
-    unsigned int varidx = (this+advMap).map (glyph);
+    index_maps.push (&(this+advMap));
+    index_maps.push (&(this+lsbMap));
+    index_maps.push (&(this+rsbMap));
+  }
+
+  bool serialize_index_maps (hb_serialize_context_t *c,
+			     const hb_array_t<index_map_subset_plan_t> &im_plans)
+  {
+    TRACE_SERIALIZE (this);
+    if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
+      advMap = 0;
+    else if (unlikely (!advMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX])))
+      return_trace (false);
+    if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
+      lsbMap = 0;
+    else if (unlikely (!lsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX])))
+      return_trace (false);
+    if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
+      rsbMap = 0;
+    else if (unlikely (!rsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX])))
+      return_trace (false);
+
+    return_trace (true);
+  }
+
+  template <typename T>
+  bool _subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    hvarvvar_subset_plan_t	hvar_plan;
+    hb_vector_t<const DeltaSetIndexMap *>
+				index_maps;
+
+    ((T*)this)->listup_index_maps (index_maps);
+    hvar_plan.init (index_maps.as_array (), this+varStore, c->plan);
+
+    T *out = c->serializer->allocate_min<T> ();
+    if (unlikely (!out)) return_trace (false);
+
+    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 ())))
+      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
+  {
+    uint32_t varidx = (this+advMap).map (glyph);
     return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
   }
 
@@ -124,7 +332,7 @@
 			      const int *coords, unsigned int coord_count) const
   {
     if (!has_side_bearing_deltas ()) return 0.f;
-    unsigned int varidx = (this+lsbMap).map (glyph);
+    uint32_t varidx = (this+lsbMap).map (glyph);
     return (this+varStore).get_delta (varidx, coords, coord_count);
   }
 
@@ -133,13 +341,13 @@
   protected:
   FixedVersion<>version;	/* Version of the metrics variation table
 				 * initially set to 0x00010000u */
-  LOffsetTo<VariationStore>
+  Offset32To<VariationStore>
 		varStore;	/* Offset to item variation store table. */
-  LOffsetTo<DeltaSetIndexMap>
+  Offset32To<DeltaSetIndexMap>
 		advMap;		/* Offset to advance var-idx mapping. */
-  LOffsetTo<DeltaSetIndexMap>
+  Offset32To<DeltaSetIndexMap>
 		lsbMap;		/* Offset to lsb/tsb var-idx mapping. */
-  LOffsetTo<DeltaSetIndexMap>
+  Offset32To<DeltaSetIndexMap>
 		rsbMap;		/* Offset to rsb/bsb var-idx mapping. */
 
   public:
@@ -148,6 +356,7 @@
 
 struct HVAR : HVARVVAR {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
+  bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<HVAR> (c); }
 };
 struct VVAR : HVARVVAR {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
@@ -159,8 +368,30 @@
 		  vorgMap.sanitize (c, this));
   }
 
+  void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
+  {
+    HVARVVAR::listup_index_maps (index_maps);
+    index_maps.push (&(this+vorgMap));
+  }
+
+  bool serialize_index_maps (hb_serialize_context_t *c,
+			     const hb_array_t<index_map_subset_plan_t> &im_plans)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans)))
+      return_trace (false);
+    if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
+      vorgMap = 0;
+    else if (unlikely (!vorgMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX])))
+      return_trace (false);
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
+
   protected:
-  LOffsetTo<DeltaSetIndexMap>
+  Offset32To<DeltaSetIndexMap>
 		vorgMap;	/* Offset to vertical-origin var-idx mapping. */
 
   public:
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index 5a9d2af..208db46 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -77,7 +77,9 @@
 		 const int *coords, unsigned int coord_count) const
   {
     const VariationValueRecord *record;
-    record = (VariationValueRecord *) hb_bsearch (&tag, valuesZ.arrayZ,
+    record = (VariationValueRecord *) hb_bsearch (tag,
+						  (const VariationValueRecord *)
+						    (const HBUINT8 *) valuesZ,
 						  valueRecordCount, valueRecordSize,
 						  tag_compare);
     if (!record)
@@ -101,7 +103,7 @@
   HBUINT16	valueRecordSize;/* The size in bytes of each value record —
 				 * must be greater than zero. */
   HBUINT16	valueRecordCount;/* The number of value records — may be zero. */
-  OffsetTo<VariationStore>
+  Offset16To<VariationStore>
 		varStore;	/* Offset to item variation store table. */
   UnsizedArrayOf<HBUINT8>
 		valuesZ;	/* Array of value records. The records must be
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index 6b8b09b..6b42b45 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -52,11 +52,11 @@
 
 /**
  * hb_ot_var_has_data:
- * @face: #hb_face_t to test
+ * @face: The #hb_face_t to work on
  *
- * This function allows to verify the presence of OpenType variation data on the face.
+ * Tests whether a face includes any OpenType variation data in the `fvar` table.
  *
- * Return value: true if face has a `fvar' table and false otherwise
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 1.4.2
  **/
@@ -68,6 +68,11 @@
 
 /**
  * hb_ot_var_get_axis_count:
+ * @face: The #hb_face_t to work on
+ *
+ * Fetches the number of OpenType variation axes included in the face. 
+ *
+ * Return value: the number of variation axes defined
  *
  * Since: 1.4.2
  **/
@@ -80,9 +85,17 @@
 #ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_ot_var_get_axes:
+ * @face: #hb_face_t to work upon
+ * @start_offset: offset of the first lookup to retrieve
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
+ *                Output = the actual number of variation axes returned (may be zero)
+ * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
+ *
+ * Fetches a list of all variation axes in the specified face. The list returned will begin
+ * at the offset provided.
  *
  * Since: 1.4.2
- * Deprecated: 2.2.0
+ * Deprecated: 2.2.0: use hb_ot_var_get_axis_infos() instead
  **/
 unsigned int
 hb_ot_var_get_axes (hb_face_t        *face,
@@ -95,9 +108,16 @@
 
 /**
  * hb_ot_var_find_axis:
+ * @face: #hb_face_t to work upon
+ * @axis_tag: The #hb_tag_t of the variation axis to query
+ * @axis_index: The index of the variation axis
+ * @axis_info: (out): The #hb_ot_var_axis_info_t of the axis tag queried
+ *
+ * Fetches the variation-axis information corresponding to the specified axis tag
+ * in the specified face.
  *
  * Since: 1.4.2
- * Deprecated: 2.2.0
+ * Deprecated: 2.2.0 - use hb_ot_var_find_axis_info() instead
  **/
 hb_bool_t
 hb_ot_var_find_axis (hb_face_t        *face,
@@ -111,6 +131,16 @@
 
 /**
  * hb_ot_var_get_axis_infos:
+ * @face: #hb_face_t to work upon
+ * @start_offset: offset of the first lookup to retrieve
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
+ *                Output = the actual number of variation axes returned (may be zero)
+ * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
+ *
+ * Fetches a list of all variation axes in the specified face. The list returned will begin
+ * at the offset provided.
+ *
+ * Return value: the number of variation axes in the face
  *
  * Since: 2.2.0
  **/
@@ -125,6 +155,14 @@
 
 /**
  * hb_ot_var_find_axis_info:
+ * @face: #hb_face_t to work upon
+ * @axis_tag: The #hb_tag_t of the variation axis to query
+ * @axis_info: (out): The #hb_ot_var_axis_info_t of the axis tag queried
+ *
+ * Fetches the variation-axis information corresponding to the specified axis tag
+ * in the specified face.
+ *
+ * Return value: %true if data found, %false otherwise
  *
  * Since: 2.2.0
  **/
@@ -141,12 +179,34 @@
  * Named instances.
  */
 
+/**
+ * hb_ot_var_get_named_instance_count:
+ * @face: The #hb_face_t to work on
+ *
+ * Fetches the number of named instances included in the face. 
+ *
+ * Return value: the number of named instances defined
+ *
+ * Since: 2.2.0
+ **/
 unsigned int
 hb_ot_var_get_named_instance_count (hb_face_t *face)
 {
   return face->table.fvar->get_instance_count ();
 }
 
+/**
+ * hb_ot_var_named_instance_get_subfamily_name_id:
+ * @face: The #hb_face_t to work on
+ * @instance_index: The index of the named instance to query
+ *
+ * Fetches the `name` table Name ID that provides display names for
+ * the "Subfamily name" defined for the given named instance in the face.
+ *
+ * Return value: the Name ID found for the Subfamily name
+ *
+ * Since: 2.2.0
+ **/
 hb_ot_name_id_t
 hb_ot_var_named_instance_get_subfamily_name_id (hb_face_t   *face,
 						unsigned int instance_index)
@@ -154,6 +214,18 @@
   return face->table.fvar->get_instance_subfamily_name_id (instance_index);
 }
 
+/**
+ * hb_ot_var_named_instance_get_postscript_name_id:
+ * @face: The #hb_face_t to work on
+ * @instance_index: The index of the named instance to query
+ *
+ * Fetches the `name` table Name ID that provides display names for
+ * the "PostScript name" defined for the given named instance in the face.
+ *
+ * Return value: the Name ID found for the PostScript name
+ *
+ * Since: 2.2.0
+ **/
 hb_ot_name_id_t
 hb_ot_var_named_instance_get_postscript_name_id (hb_face_t  *face,
 						unsigned int instance_index)
@@ -161,6 +233,21 @@
   return face->table.fvar->get_instance_postscript_name_id (instance_index);
 }
 
+/**
+ * hb_ot_var_named_instance_get_design_coords:
+ * @face: The #hb_face_t to work on
+ * @instance_index: The index of the named instance to query
+ * @coords_length: (inout) (optional): Input = the maximum number of coordinates to return;
+ *                 Output = the actual number of coordinates returned (may be zero)
+ * @coords: (out) (array length=coords_length): The array of coordinates found for the query
+ *
+ * Fetches the design-space coordinates corresponding to the given
+ * named instance in the face.
+ *
+ * Return value: the number of variation axes in the face
+ *
+ * Since: 2.2.0
+ **/
 unsigned int
 hb_ot_var_named_instance_get_design_coords (hb_face_t    *face,
 					    unsigned int  instance_index,
@@ -173,6 +260,13 @@
 
 /**
  * hb_ot_var_normalize_variations:
+ * @face: The #hb_face_t to work on
+ * @variations: The array of variations to normalize
+ * @variations_length: The number of variations to normalize
+ * @coords: (out) (array length=coords_length): The array of normalized coordinates 
+ * @coords_length: The length of the coordinate array
+ *
+ * Normalizes all of the coordinates in the given list of variation axes.
  *
  * Since: 1.4.2
  **/
@@ -200,6 +294,17 @@
 
 /**
  * hb_ot_var_normalize_coords:
+ * @face: The #hb_face_t to work on
+ * @coords_length: The length of the coordinate array
+ * @design_coords: The design-space coordinates to normalize
+ * @normalized_coords: (out): The normalized coordinates
+ *
+ * Normalizes the given design-space coordinates. The minimum and maximum
+ * values for the axis are mapped to the interval [-1,1], with the default
+ * axis value mapped to 0.
+ *
+ * Any additional scaling defined in the face's `avar` table is also
+ * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar
  *
  * Since: 1.4.2
  **/
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index df89bc5..ce201d3 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -24,7 +24,7 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb-ot.h> instead."
 #endif
 
@@ -35,11 +35,40 @@
 
 HB_BEGIN_DECLS
 
-
+/**
+ * HB_OT_TAG_VAR_AXIS_ITALIC:
+ *
+ * Registered tag for the roman/italic axis.
+ */
 #define HB_OT_TAG_VAR_AXIS_ITALIC	HB_TAG('i','t','a','l')
+
+/**
+ * HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE:
+ *
+ * Registered tag for the optical-size axis.
+ * <note>Note: The optical-size axis supersedes the OpenType `size` feature.</note>
+ */
 #define HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE	HB_TAG('o','p','s','z')
+
+/**
+ * HB_OT_TAG_VAR_AXIS_SLANT:
+ *
+ * Registered tag for the slant axis
+ */
 #define HB_OT_TAG_VAR_AXIS_SLANT	HB_TAG('s','l','n','t')
+
+/**
+ * HB_OT_TAG_VAR_AXIS_WIDTH:
+ *
+ * Registered tag for the width axis.
+ */
 #define HB_OT_TAG_VAR_AXIS_WIDTH	HB_TAG('w','d','t','h')
+
+/**
+ * HB_OT_TAG_VAR_AXIS_WEIGHT:
+ *
+ * Registered tag for the weight axis.
+ */
 #define HB_OT_TAG_VAR_AXIS_WEIGHT	HB_TAG('w','g','h','t')
 
 
@@ -63,21 +92,37 @@
  * hb_ot_var_axis_flags_t:
  * @HB_OT_VAR_AXIS_FLAG_HIDDEN: The axis should not be exposed directly in user interfaces.
  *
+ * Flags for #hb_ot_var_axis_info_t.
+ *
  * Since: 2.2.0
  */
 typedef enum { /*< flags >*/
   HB_OT_VAR_AXIS_FLAG_HIDDEN	= 0x00000001u,
 
+  /*< private >*/
   _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_var_axis_flags_t;
 
 /**
  * hb_ot_var_axis_info_t:
+ * @axis_index: Index of the axis in the variation-axis array
+ * @tag: The #hb_tag_t tag identifying the design variation of the axis
+ * @name_id: The `name` table Name ID that provides display names for the axis
+ * @flags: The #hb_ot_var_axis_flags_t flags for the axis
+ * @min_value: The mininum value on the variation axis that the font covers
+ * @default_value: The position on the variation axis corresponding to the font's defaults
+ * @max_value: The maximum value on the variation axis that the font covers
+ * 
+ * Data type for holding variation-axis values.
+ *
+ * The minimum, default, and maximum values are in un-normalized, user scales.
+ *
+ * <note>Note: at present, the only flag defined for @flags is
+ * #HB_OT_VAR_AXIS_FLAG_HIDDEN.</note>
  *
  * Since: 2.2.0
  */
-typedef struct hb_ot_var_axis_info_t
-{
+typedef struct hb_ot_var_axis_info_t {
   unsigned int			axis_index;
   hb_tag_t			tag;
   hb_ot_name_id_t		name_id;
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index a4d6b06..811e139 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -48,7 +48,7 @@
   }
 
   public:
-  HBGlyphID	glyph;
+  HBGlyphID16	glyph;
   FWORD		vertOriginY;
 
   public:
@@ -84,7 +84,7 @@
     this->defaultVertOriginY = defaultVertOriginY;
     this->vertYOrigins.len = it.len ();
 
-    for (const auto _ : it) c->copy (_);
+    c->copy_all (it);
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -122,10 +122,11 @@
   }
 
   protected:
-  FixedVersion<>	version;		/* Version of VORG table. Set to 0x00010000u. */
-  FWORD			defaultVertOriginY;	/* The default vertical origin. */
-  SortedArrayOf<VertOriginMetric>
-			vertYOrigins;		/* The array of vertical origins. */
+  FixedVersion<>version;	/* Version of VORG table. Set to 0x00010000u. */
+  FWORD		defaultVertOriginY;
+				/* The default vertical origin. */
+  SortedArray16Of<VertOriginMetric>
+		vertYOrigins;	/* The array of vertical origins. */
 
   public:
   DEFINE_SIZE_ARRAY(8, vertYOrigins);
diff --git a/src/hb-pool.hh b/src/hb-pool.hh
index 83875db..dcf8f66 100644
--- a/src/hb-pool.hh
+++ b/src/hb-pool.hh
@@ -41,9 +41,7 @@
   {
     next = nullptr;
 
-    + hb_iter (chunks)
-    | hb_apply ([] (chunk_t *_) { ::free (_); })
-    ;
+    for (chunk_t *_ : chunks) hb_free (_);
 
     chunks.fini ();
   }
@@ -53,7 +51,7 @@
     if (unlikely (!next))
     {
       if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
-      chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t));
+      chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t));
       if (unlikely (!chunk)) return nullptr;
       chunks.push (chunk);
       next = chunk->thread ();
@@ -67,7 +65,7 @@
     return obj;
   }
 
-  void free (T* obj)
+  void release (T* obj)
   {
     * (T**) obj = next;
     next = obj;
diff --git a/src/hb-priority-queue.hh b/src/hb-priority-queue.hh
new file mode 100644
index 0000000..7d799ae
--- /dev/null
+++ b/src/hb-priority-queue.hh
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef HB_PRIORITY_QUEUE_HH
+#define HB_PRIORITY_QUEUE_HH
+
+#include "hb.hh"
+#include "hb-vector.hh"
+
+/*
+ * hb_priority_queue_t
+ *
+ * Priority queue implemented as a binary heap. Supports extract minimum
+ * and insert operations.
+ */
+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;
+  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)
+  {
+    heap.push (item_t (priority, value));
+    bubble_up (heap.length - 1);
+  }
+
+  item_t pop_minimum ()
+  {
+    item_t result = heap[0];
+
+    heap[0] = heap[heap.length - 1];
+    heap.shrink (heap.length - 1);
+    bubble_down (0);
+
+    return result;
+  }
+
+  const item_t& minimum ()
+  {
+    return heap[0];
+  }
+
+  bool is_empty () const { return heap.length == 0; }
+  explicit operator bool () const { return !is_empty (); }
+  unsigned int get_population () const { return heap.length; }
+
+  /* Sink interface. */
+  hb_priority_queue_t& operator << (item_t item)
+  { insert (item.first, item.second); return *this; }
+
+ private:
+
+  static constexpr unsigned parent (unsigned index)
+  {
+    return (index - 1) / 2;
+  }
+
+  static constexpr unsigned left_child (unsigned index)
+  {
+    return 2 * index + 1;
+  }
+
+  static constexpr unsigned right_child (unsigned index)
+  {
+    return 2 * index + 2;
+  }
+
+  void bubble_down (unsigned index)
+  {
+    unsigned left = left_child (index);
+    unsigned right = right_child (index);
+
+    bool has_left = left < heap.length;
+    if (!has_left)
+      // If there's no left, then there's also no right.
+      return;
+
+    bool has_right = right < heap.length;
+    if (heap[index].first <= heap[left].first
+        && (!has_right || heap[index].first <= heap[right].first))
+      return;
+
+    if (!has_right || heap[left].first < heap[right].first)
+    {
+      swap (index, left);
+      bubble_down (left);
+      return;
+    }
+
+    swap (index, right);
+    bubble_down (right);
+  }
+
+  void bubble_up (unsigned index)
+  {
+    if (index == 0) return;
+
+    unsigned parent_index = parent (index);
+    if (heap[parent_index].first <= heap[index].first)
+      return;
+
+    swap (index, parent_index);
+    bubble_up (parent_index);
+  }
+
+  void swap (unsigned a, unsigned b)
+  {
+    item_t temp = heap[a];
+    heap[a] = heap[b];
+    heap[b] = temp;
+  }
+};
+
+#endif /* HB_PRIORITY_QUEUE_HH */
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
new file mode 100644
index 0000000..26faa56
--- /dev/null
+++ b/src/hb-repacker.hh
@@ -0,0 +1,1194 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef HB_REPACKER_HH
+#define HB_REPACKER_HH
+
+#include "hb-open-type.hh"
+#include "hb-map.hh"
+#include "hb-priority-queue.hh"
+#include "hb-serialize.hh"
+#include "hb-vector.hh"
+
+/*
+ * For a detailed writeup on the overflow resolution algorithm see:
+ * docs/repacker.md
+ */
+
+struct graph_t
+{
+  struct vertex_t
+  {
+    vertex_t () :
+        distance (0),
+        space (0),
+        parents (),
+        start (0),
+        end (0),
+        priority(0) {}
+
+    void fini () {
+      obj.fini ();
+      parents.fini ();
+    }
+
+    hb_serialize_context_t::object_t obj;
+    int64_t distance;
+    int64_t space;
+    hb_vector_t<unsigned> parents;
+    unsigned start;
+    unsigned end;
+    unsigned priority;
+
+    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.links.length;
+    }
+
+    void raise_priority ()
+    {
+      priority++;
+    }
+
+    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), 0x7FFFFFFFFF);
+      return (modified_distance << 22) | (0x003FFFFF & order);
+    }
+
+    int64_t distance_modifier () const
+    {
+      if (!priority) return 0;
+      int64_t table_size = obj.tail - obj.head;
+      return -(table_size - table_size / (1 << hb_min(priority, 16u)));
+    }
+  };
+
+  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;
+      for (unsigned i = 0; i < v->obj.links.length; i++)
+        // Fix indices to account for removed nil object.
+        v->obj.links[i].objidx--;
+    }
+  }
+
+  ~graph_t ()
+  {
+    vertices_.fini_deep ();
+  }
+
+  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.
+   */
+  void serialize (hb_serialize_context_t* c) const
+  {
+    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) return;
+
+      memcpy (start, vertices_[i].obj.head, size);
+
+      for (const auto& link : vertices_[i].obj.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 ();
+  }
+
+  /*
+   * 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.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_deep ();
+  }
+
+  /*
+   * 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 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.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_deep ();
+  }
+
+  /*
+   * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
+   */
+  bool assign_32bit_spaces ()
+  {
+    unsigned root_index = root_idx ();
+    hb_set_t visited;
+    hb_set_t roots;
+    for (unsigned i = 0; i <= root_index; i++)
+    {
+      for (auto& l : vertices_[i].obj.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 (!roots.next (&next)) break;
+
+      hb_set_t connected_roots;
+      find_connected_nodes (next, roots, visited, connected_roots);
+      isolate_subgraph (connected_roots);
+
+      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_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);
+    }
+
+    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.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.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).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->parents.reset ();
+
+    unsigned clone_idx = vertices_.length - 2;
+    for (const auto& l : child.obj.links)
+    {
+      clone->obj.links.push (l);
+      vertices_[l.objidx].parents.push (clone_idx);
+    }
+
+    check_success (!clone->obj.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.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.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);
+      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 (unsigned i = 0; i < parent.obj.links.length; i++)
+    {
+      auto& l = parent.obj.links[i];
+      if (l.objidx != child_idx)
+        continue;
+
+      reassign_link (l, parent_idx, clone_idx);
+    }
+
+    return true;
+  }
+
+  /*
+   * Raises the sorting priority of all children.
+   */
+  void 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;
+    for (unsigned i = 0; i < parent.links.length; i++)
+      vertices_[parent.links[i].objidx].raise_priority ();
+  }
+
+  /*
+   * 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--)
+    {
+      for (const auto& link : vertices_[parent_idx].obj.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 ();
+    for (const auto& o : overflows)
+    {
+      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.links.length,
+                 space_for (o.parent),
+                 o.child,
+                 child.incoming_edges (),
+                 child.obj.links.length,
+                 space_for (o.child));
+    }
+  }
+
+  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 (unsigned index)
+  {
+    auto& node = vertices_[index];
+    num_roots_for_space_.push (1);
+    num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
+    node.space = num_roots_for_space_.length - 1;
+  }
+
+  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:
+
+  /*
+   * Returns the numbers of incoming edges that are 32bits wide.
+   */
+  unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
+  {
+    unsigned count = 0;
+    hb_set_t visited;
+    for (unsigned p : vertices_[node_idx].parents)
+    {
+      if (visited.has (p)) continue;
+      visited.add (p);
+
+      for (const auto& l : vertices_[p].obj.links)
+      {
+        if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
+        {
+          count++;
+          parents.add (p);
+        }
+      }
+    }
+    return count;
+  }
+
+  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.links)
+      {
+        vertices_[l.objidx].parents.push (p);
+      }
+    }
+
+    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 fibonaacci 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.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);
+  }
+
+  /*
+   * 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)
+    {
+      for (unsigned j = 0; j < vertices_[i].obj.links.length; j++)
+      {
+        auto& link = vertices_[i].obj.links[j];
+        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]);
+      }
+    }
+  }
+
+  /*
+   * 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 (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
+      {
+        auto& link = (*sorted_graph)[i].obj.links[j];
+        link.objidx = id_map[link.objidx];
+      }
+    }
+  }
+
+  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);
+  }
+
+  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 (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.links)
+      find_connected_nodes (l.objidx, targets, visited, connected);
+
+    for (unsigned p : v.parents)
+      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_;
+ private:
+  bool parents_invalid;
+  bool distance_invalid;
+  bool positions_invalid;
+  bool successful;
+  hb_vector_t<unsigned> num_roots_for_space_;
+};
+
+static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
+                                      graph_t& sorted_graph)
+{
+  for (int i = overflows.length - 1; i >= 0; i--)
+  {
+    const graph_t::overflow_record_t& r = overflows[i];
+    unsigned root = 0;
+    unsigned space = sorted_graph.space_for (r.parent, &root);
+    if (!space) continue;
+    if (sorted_graph.num_roots_for_space (space) <= 1) continue;
+
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Overflow in space %d moving subgraph %d to space %d.",
+               space,
+               root,
+               sorted_graph.next_space ());
+
+    hb_set_t roots;
+    roots.add (root);
+    sorted_graph.isolate_subgraph (roots);
+    for (unsigned new_root : roots)
+      sorted_graph.move_to_new_space (new_root);
+    return true;
+  }
+  return false;
+}
+
+static bool _process_overflows (const hb_vector_t<graph_t::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 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;
+      return true;
+    }
+
+    if (child.is_leaf () && !priority_bumped_parents.has (r.parent))
+    {
+      // This object is too far from it's parent, attempt to move it closer.
+      //
+      // TODO(garretrieger): initially limiting this to leaf's since they can be
+      //                     moved closer with fewer consequences. However, this can
+      //                     likely can be used for non-leafs as well.
+      // TODO(garretrieger): add a maximum priority, don't try to raise past this.
+      // TODO(garretrieger): also try lowering priority of the parent. Make it
+      //                     get placed further up in the ordering, closer to it's children.
+      //                     this is probably preferable if the total size of the parent object
+      //                     is < then the total size of the children (and the parent can be moved).
+      //                     Since in that case moving the parent will cause a smaller increase in
+      //                     the length of other offsets.
+      sorted_graph.raise_childrens_priority (r.parent);
+      priority_bumped_parents.add (r.parent);
+      resolution_attempted = true;
+      continue;
+    }
+
+    // TODO(garretrieger): add additional offset resolution strategies
+    // - Promotion to extension lookups.
+    // - Table splitting.
+  }
+
+  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 void
+hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed,
+                      hb_tag_t table_tag,
+                      hb_serialize_context_t* c,
+                      unsigned max_rounds = 10) {
+  // 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 ())
+  {
+    sorted_graph.serialize (c);
+    return;
+  }
+
+  sorted_graph.sort_shortest_distance ();
+
+  if ((table_tag == HB_OT_TAG_GPOS
+       ||  table_tag == HB_OT_TAG_GSUB)
+      && sorted_graph.will_overflow ())
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
+    if (sorted_graph.assign_32bit_spaces ())
+      sorted_graph.sort_shortest_distance ();
+  }
+
+  unsigned round = 0;
+  hb_vector_t<graph_t::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);
+
+    hb_set_t priority_bumped_parents;
+
+    if (!_try_isolating_subgraphs (overflows, sorted_graph))
+    {
+      if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
+      {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
+        break;
+      }
+    }
+
+    sorted_graph.sort_shortest_distance ();
+  }
+
+  if (sorted_graph.in_error ())
+  {
+    c->err (HB_SERIALIZE_ERROR_OTHER);
+    return;
+  }
+
+  if (sorted_graph.will_overflow ())
+  {
+    c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
+    return;
+  }
+  sorted_graph.serialize (c);
+}
+
+#endif /* HB_REPACKER_HH */
diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh
index 7859c6a..2e536c7 100644
--- a/src/hb-sanitize.hh
+++ b/src/hb-sanitize.hh
@@ -73,7 +73,7 @@
  * === The sanitize() contract ===
  *
  * The sanitize() method of each object type shall return true if it's safe to
- * call other methods of the object, and false otherwise.
+ * call other methods of the object, and %false otherwise.
  *
  * Note that what sanitize() checks for might align with what the specification
  * describes as valid table data, but does not have to be.  In particular, we
@@ -105,7 +105,7 @@
 #define HB_SANITIZE_MAX_EDITS 32
 #endif
 #ifndef HB_SANITIZE_MAX_OPS_FACTOR
-#define HB_SANITIZE_MAX_OPS_FACTOR 8
+#define HB_SANITIZE_MAX_OPS_FACTOR 64
 #endif
 #ifndef HB_SANITIZE_MAX_OPS_MIN
 #define HB_SANITIZE_MAX_OPS_MIN 16384
@@ -113,14 +113,16 @@
 #ifndef HB_SANITIZE_MAX_OPS_MAX
 #define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
 #endif
+#ifndef HB_SANITIZE_MAX_SUBTABLES
+#define HB_SANITIZE_MAX_SUBTABLES 0x4000
+#endif
 
 struct hb_sanitize_context_t :
        hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
 {
   hb_sanitize_context_t () :
-	debug_depth (0),
 	start (nullptr), end (nullptr),
-	max_ops (0),
+	max_ops (0), max_subtables (0),
 	writable (false), edit_count (0),
 	blob (nullptr),
 	num_glyphs (65536),
@@ -134,17 +136,23 @@
   static return_t no_dispatch_return_value () { return false; }
   bool stop_sublookup_iteration (const return_t r) const { return !r; }
 
+  bool visit_subtables (unsigned count)
+  {
+    max_subtables += count;
+    return max_subtables < HB_SANITIZE_MAX_SUBTABLES;
+  }
+
   private:
   template <typename T, typename ...Ts> auto
   _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
-  ( obj.sanitize (this, hb_forward<Ts> (ds)...) )
+  ( obj.sanitize (this, std::forward<Ts> (ds)...) )
   template <typename T, typename ...Ts> auto
   _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
-  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  ( obj.dispatch (this, std::forward<Ts> (ds)...) )
   public:
   template <typename T, typename ...Ts> auto
   dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
-  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+  ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
 
 
   void init (hb_blob_t *b)
@@ -189,8 +197,12 @@
   void start_processing ()
   {
     reset_object ();
-    this->max_ops = hb_max ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
-			 (unsigned) HB_SANITIZE_MAX_OPS_MIN);
+    if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR)))
+      this->max_ops = HB_SANITIZE_MAX_OPS_MAX;
+    else
+      this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+				(unsigned) HB_SANITIZE_MAX_OPS_MIN,
+				(unsigned) HB_SANITIZE_MAX_OPS_MAX);
     this->edit_count = 0;
     this->debug_depth = 0;
 
@@ -221,7 +233,7 @@
 	      (this->start <= p &&
 	       p <= this->end &&
 	       (unsigned int) (this->end - p) >= len &&
-	       this->max_ops-- > 0);
+	       (this->max_ops -= len) > 0);
 
     DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
 		     "check_range [%p..%p]"
@@ -374,9 +386,8 @@
     return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
   }
 
-  mutable unsigned int debug_depth;
   const char *start, *end;
-  mutable int max_ops;
+  mutable int max_ops, max_subtables;
   private:
   bool writable;
   unsigned int edit_count;
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
index 4c674b1..5768991 100644
--- a/src/hb-serialize.hh
+++ b/src/hb-serialize.hh
@@ -41,16 +41,29 @@
  * Serialize
  */
 
+enum hb_serialize_error_t {
+  HB_SERIALIZE_ERROR_NONE =            0x00000000u,
+  HB_SERIALIZE_ERROR_OTHER =           0x00000001u,
+  HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u,
+  HB_SERIALIZE_ERROR_OUT_OF_ROOM =     0x00000004u,
+  HB_SERIALIZE_ERROR_INT_OVERFLOW =    0x00000008u,
+  HB_SERIALIZE_ERROR_ARRAY_OVERFLOW =  0x00000010u
+};
+HB_MARK_AS_FLAG_T (hb_serialize_error_t);
+
 struct hb_serialize_context_t
 {
   typedef unsigned objidx_t;
 
-  struct range_t
-  {
-    char *head, *tail;
-  };
+  enum whence_t {
+     Head,	/* Relative to the current object head (default). */
+     Tail,	/* Relative to the current object tail after packed. */
+     Absolute	/* Absolute: from the start of the serialize buffer. */
+   };
 
-  struct object_t : range_t
+
+
+  struct object_t
   {
     void fini () { links.fini (); }
 
@@ -69,18 +82,31 @@
 
     struct link_t
     {
-      bool is_wide: 1;
-      unsigned position : 31;
+      unsigned width: 3;
+      bool is_signed: 1;
+      unsigned whence: 2;
+      unsigned position: 28;
       unsigned bias;
       objidx_t objidx;
     };
 
+    char *head;
+    char *tail;
     hb_vector_t<link_t> links;
     object_t *next;
   };
 
-  range_t snapshot () { range_t s = {head, tail} ; return s; }
+  struct snapshot_t
+  {
+    char *head;
+    char *tail;
+    object_t *current; // Just for sanity check
+    unsigned num_links;
+    hb_serialize_error_t errors;
+  };
 
+  snapshot_t snapshot ()
+  { return snapshot_t { head, tail, current, current->links.length, errors }; }
 
   hb_serialize_context_t (void *start_, unsigned int size) :
     start ((char *) start_),
@@ -104,37 +130,67 @@
     object_pool.fini ();
   }
 
-  bool in_error () const { return !this->successful; }
+  bool in_error () const { return bool (errors); }
+
+  bool successful () const { return !bool (errors); }
+
+  HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
+  HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
+  HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
+  HB_NODISCARD bool only_overflow () const
+  {
+    return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
+        || errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
+        || errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
+  }
+
+  void reset (void *start_, unsigned int size)
+  {
+    start = (char*) start_;
+    end = start + size;
+    reset ();
+    current = nullptr;
+  }
 
   void reset ()
   {
-    this->successful = true;
-    this->ran_out_of_room = false;
+    this->errors = HB_SERIALIZE_ERROR_NONE;
     this->head = this->start;
     this->tail = this->end;
     this->debug_depth = 0;
 
     fini ();
     this->packed.push (nullptr);
+    this->packed_map.init ();
   }
 
-  bool check_success (bool success)
-  { return this->successful && (success || (err_other_error (), false)); }
+  bool check_success (bool success,
+                      hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER)
+  {
+    return successful ()
+        && (success || err (err_type));
+  }
 
   template <typename T1, typename T2>
-  bool check_equal (T1 &&v1, T2 &&v2)
-  { return check_success (v1 == v2); }
+  bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type)
+  {
+    if ((long long) v1 != (long long) v2)
+    {
+      return err (err_type);
+    }
+    return true;
+  }
 
   template <typename T1, typename T2>
-  bool check_assign (T1 &v1, T2 &&v2)
-  { return check_equal (v1 = v2, v2); }
+  bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type)
+  { return check_equal (v1 = v2, v2, err_type); }
 
   template <typename T> bool propagate_error (T &&obj)
   { return check_success (!hb_deref (obj).in_error ()); }
 
   template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os)
-  { return propagate_error (hb_forward<T1> (o1)) &&
-	   propagate_error (hb_forward<Ts> (os)...); }
+  { return propagate_error (std::forward<T1> (o1)) &&
+	   propagate_error (std::forward<Ts> (os)...); }
 
   /* To be called around main operation. */
   template <typename Type>
@@ -154,11 +210,19 @@
 		     "end [%p..%p] serialized %u bytes; %s",
 		     this->start, this->end,
 		     (unsigned) (this->head - this->start),
-		     this->successful ? "successful" : "UNSUCCESSFUL");
+		     successful () ? "successful" : "UNSUCCESSFUL");
 
     propagate_error (packed, packed_map);
 
     if (unlikely (!current)) return;
+    if (unlikely (in_error()))
+    {
+      // Offset overflows that occur before link resolution cannot be handled
+      // by repacking, so set a more general error.
+      if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER);
+      return;
+    }
+
     assert (!current->next);
 
     /* Only "pack" if there exist other objects... Otherwise, don't bother.
@@ -166,7 +230,7 @@
     if (packed.length <= 1)
       return;
 
-    pop_pack ();
+    pop_pack (false);
 
     resolve_links ();
   }
@@ -174,6 +238,8 @@
   template <typename Type = void>
   Type *push ()
   {
+    if (unlikely (in_error ())) return start_embed<Type> ();
+
     object_t *obj = object_pool.alloc ();
     if (unlikely (!obj))
       check_success (false);
@@ -190,15 +256,24 @@
   {
     object_t *obj = current;
     if (unlikely (!obj)) return;
+    if (unlikely (in_error())) return;
+
     current = current->next;
-    revert (*obj);
+    revert (obj->head, obj->tail);
     obj->fini ();
-    object_pool.free (obj);
+    object_pool.release (obj);
   }
-  objidx_t pop_pack ()
+
+  /* Set share to false when an object is unlikely sharable with others
+   * so not worth an attempt, or a contiguous table is serialized as
+   * multiple consecutive objects in the reverse order so can't be shared.
+   */
+  objidx_t pop_pack (bool share=true)
   {
     object_t *obj = current;
     if (unlikely (!obj)) return 0;
+    if (unlikely (in_error())) return 0;
+
     current = current->next;
     obj->tail = head;
     obj->next = nullptr;
@@ -211,11 +286,15 @@
       return 0;
     }
 
-    objidx_t objidx = packed_map.get (obj);
-    if (objidx)
+    objidx_t objidx;
+    if (share)
     {
-      obj->fini ();
-      return objidx;
+      objidx = packed_map.get (obj);
+      if (objidx)
+      {
+	obj->fini ();
+	return objidx;
+      }
     }
 
     tail -= len;
@@ -226,27 +305,47 @@
 
     packed.push (obj);
 
-    if (unlikely (packed.in_error ()))
+    if (unlikely (!propagate_error (packed)))
+    {
+      /* Obj wasn't successfully added to packed, so clean it up otherwise its
+       * links will be leaked. When we use constructor/destructors properly, we
+       * can remove these. */
+      obj->fini ();
       return 0;
+    }
 
     objidx = packed.length - 1;
 
-    packed_map.set (obj, objidx);
+    if (share) packed_map.set (obj, objidx);
+    propagate_error (packed_map);
 
     return objidx;
   }
 
-  void revert (range_t snap)
+  void revert (snapshot_t snap)
   {
-    assert (snap.head <= head);
-    assert (tail <= snap.tail);
-    head = snap.head;
-    tail = snap.tail;
+    // Overflows that happened after the snapshot will be erased by the revert.
+    if (unlikely (in_error () && !only_overflow ())) return;
+    assert (snap.current == current);
+    current->links.shrink (snap.num_links);
+    errors = snap.errors;
+    revert (snap.head, snap.tail);
+  }
+
+  void revert (char *snap_head,
+	       char *snap_tail)
+  {
+    if (unlikely (in_error ())) return;
+    assert (snap_head <= head);
+    assert (tail <= snap_tail);
+    head = snap_head;
+    tail = snap_tail;
     discard_stale_objects ();
   }
 
   void discard_stale_objects ()
   {
+    if (unlikely (in_error ())) return;
     while (packed.length > 1 &&
 	   packed.tail ()->head < tail)
     {
@@ -259,10 +358,41 @@
       assert (packed.tail ()->head == tail);
   }
 
-  template <typename T>
-  void add_link (T &ofs, objidx_t objidx, const void *base = nullptr)
+  // Adds a virtual link from the current object to objidx. A virtual link is not associated with
+  // an actual offset field. They are solely used to enforce ordering constraints between objects.
+  // Adding a virtual link from object a to object b will ensure that object b is always packed after
+  // object a in the final serialized order.
+  //
+  // This is useful in certain situtations where there needs to be a specific ordering in the
+  // final serialization. Such as when platform bugs require certain orderings, or to provide
+  //  guidance to the repacker for better offset overflow resolution.
+  void add_virtual_link (objidx_t objidx)
   {
-    static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
+    if (unlikely (in_error ())) return;
+
+    if (!objidx)
+      return;
+
+    assert (current);
+
+    auto& link = *current->links.push ();
+    if (current->links.in_error ())
+      err (HB_SERIALIZE_ERROR_OTHER);
+
+    link.width = 0;
+    link.objidx = objidx;
+    link.is_signed = 0;
+    link.whence = 0;
+    link.position = 0;
+    link.bias = 0;
+  }
+
+  template <typename T>
+  void add_link (T &ofs, objidx_t objidx,
+		 whence_t whence = Head,
+		 unsigned bias = 0)
+  {
+    if (unlikely (in_error ())) return;
 
     if (!objidx)
       return;
@@ -270,16 +400,36 @@
     assert (current);
     assert (current->head <= (const char *) &ofs);
 
-    if (!base)
-      base = current->head;
-    else
-      assert (current->head <= (const char *) base);
-
     auto& link = *current->links.push ();
-    link.is_wide = sizeof (T) == 4;
-    link.position = (const char *) &ofs - current->head;
-    link.bias = (const char *) base - current->head;
+    if (current->links.in_error ())
+      err (HB_SERIALIZE_ERROR_OTHER);
+
+    link.width = sizeof (T);
     link.objidx = objidx;
+    if (unlikely (!sizeof (T)))
+    {
+      // This link is not associated with an actual offset and exists merely to enforce
+      // an ordering constraint.
+      link.is_signed = 0;
+      link.whence = 0;
+      link.position = 0;
+      link.bias = 0;
+      return;
+    }
+
+    link.is_signed = std::is_signed<hb_unwrap_type (T)>::value;
+    link.whence = (unsigned) whence;
+    link.position = (const char *) &ofs - current->head;
+    link.bias = bias;
+  }
+
+  unsigned to_bias (const void *base) const
+  {
+    if (unlikely (in_error ())) return 0;
+    if (!base) return 0;
+    assert (current);
+    assert (current->head <= (const char *) base);
+    return (const char *) base - current->head;
   }
 
   void resolve_links ()
@@ -292,26 +442,45 @@
     for (const object_t* parent : ++hb_iter (packed))
       for (const object_t::link_t &link : parent->links)
       {
-	const object_t* child = packed[link.objidx];
-	assert (link.bias <= (size_t) (parent->tail - parent->head));
-	unsigned offset = (child->head - parent->head) - link.bias;
+        if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets
 
-	if (link.is_wide)
+	const object_t* child = packed[link.objidx];
+	if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
+	unsigned offset = 0;
+	switch ((whence_t) link.whence) {
+	case Head:     offset = child->head - parent->head; break;
+	case Tail:     offset = child->head - parent->tail; break;
+	case Absolute: offset = (head - start) + (child->head - tail); break;
+	}
+
+	assert (offset >= link.bias);
+	offset -= link.bias;
+	if (link.is_signed)
 	{
-	  auto &off = * ((BEInt<uint32_t, 4> *) (parent->head + link.position));
-	  assert (0 == off);
-	  check_assign (off, offset);
+	  assert (link.width == 2 || link.width == 4);
+	  if (link.width == 4)
+	    assign_offset<int32_t> (parent, link, offset);
+	  else
+	    assign_offset<int16_t> (parent, link, offset);
 	}
 	else
 	{
-	  auto &off = * ((BEInt<uint16_t, 2> *) (parent->head + link.position));
-	  assert (0 == off);
-	  check_assign (off, offset);
+	  assert (link.width == 2 || link.width == 3 || link.width == 4);
+	  if (link.width == 4)
+	    assign_offset<uint32_t> (parent, link, offset);
+	  else if (link.width == 3)
+	    assign_offset<uint32_t, 3> (parent, link, offset);
+	  else
+	    assign_offset<uint16_t> (parent, link, offset);
 	}
       }
   }
 
-  unsigned int length () const { return this->head - current->head; }
+  unsigned int length () const
+  {
+    if (unlikely (!current)) return 0;
+    return this->head - current->head;
+  }
 
   void align (unsigned int alignment)
   {
@@ -327,22 +496,22 @@
   Type *start_embed (const Type &obj) const
   { return start_embed (hb_addressof (obj)); }
 
-  /* Following two functions exist to allow setting breakpoint on. */
-  void err_ran_out_of_room () { this->ran_out_of_room = true; }
-  void err_other_error () { this->successful = false; }
+  bool err (hb_serialize_error_t err_type)
+  {
+    return !bool ((errors = (errors | err_type)));
+  }
 
   template <typename Type>
-  Type *allocate_size (unsigned int size)
+  Type *allocate_size (size_t size)
   {
-    if (unlikely (!this->successful)) return nullptr;
+    if (unlikely (in_error ())) return nullptr;
 
-    if (this->tail - this->head < ptrdiff_t (size))
+    if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
     {
-      err_ran_out_of_room ();
-      this->successful = false;
+      err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
       return nullptr;
     }
-    memset (this->head, 0, size);
+    hb_memset (this->head, 0, size);
     char *ret = this->head;
     this->head += size;
     return reinterpret_cast<Type *> (ret);
@@ -367,7 +536,7 @@
 
   template <typename Type, typename ...Ts> auto
   _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
-  (Type *, src.copy (this, hb_forward<Ts> (ds)...))
+  (Type *, src.copy (this, std::forward<Ts> (ds)...))
 
   template <typename Type> auto
   _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src))
@@ -382,25 +551,34 @@
    * instead of memcpy(). */
   template <typename Type, typename ...Ts>
   Type *copy (const Type &src, Ts&&... ds)
-  { return _copy (src, hb_prioritize, hb_forward<Ts> (ds)...); }
+  { return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); }
   template <typename Type, typename ...Ts>
   Type *copy (const Type *src, Ts&&... ds)
-  { return copy (*src, hb_forward<Ts> (ds)...); }
+  { return copy (*src, std::forward<Ts> (ds)...); }
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator)),
+	   typename ...Ts>
+  void copy_all (Iterator it, Ts&&... ds)
+  { for (decltype (*it) _ : it) copy (_, std::forward<Ts> (ds)...); }
 
   template <typename Type>
   hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
 
   template <typename Type>
-  Type *extend_size (Type *obj, unsigned int size)
+  Type *extend_size (Type *obj, size_t size)
   {
+    if (unlikely (in_error ())) return nullptr;
+
     assert (this->start <= (char *) obj);
     assert ((char *) obj <= this->head);
-    assert ((char *) obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+    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;
     return reinterpret_cast<Type *> (obj);
   }
   template <typename Type>
-  Type *extend_size (Type &obj, unsigned int size)
+  Type *extend_size (Type &obj, size_t size)
   { return extend_size (hb_addressof (obj), size); }
 
   template <typename Type>
@@ -410,20 +588,24 @@
 
   template <typename Type, typename ...Ts>
   Type *extend (Type *obj, Ts&&... ds)
-  { return extend_size (obj, obj->get_size (hb_forward<Ts> (ds)...)); }
+  { return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); }
   template <typename Type, typename ...Ts>
   Type *extend (Type &obj, Ts&&... ds)
-  { return extend (hb_addressof (obj), hb_forward<Ts> (ds)...); }
+  { return extend (hb_addressof (obj), std::forward<Ts> (ds)...); }
 
   /* Output routines. */
   hb_bytes_t copy_bytes () const
   {
-    assert (this->successful);
+    assert (successful ());
     /* Copy both items from head side and tail side... */
     unsigned int len = (this->head - this->start)
 		     + (this->end  - this->tail);
 
-    char *p = (char *) malloc (len);
+    // If len is zero don't hb_malloc as the memory won't get properly
+    // cleaned up later.
+    if (!len) return hb_bytes_t ();
+
+    char *p = (char *) hb_malloc (len);
     if (unlikely (!p)) return hb_bytes_t ();
 
     memcpy (p, this->start, this->head - this->start);
@@ -438,14 +620,25 @@
     hb_bytes_t b = copy_bytes ();
     return hb_blob_create (b.arrayZ, b.length,
 			   HB_MEMORY_MODE_WRITABLE,
-			   (char *) b.arrayZ, free);
+			   (char *) b.arrayZ, hb_free);
+  }
+
+  const hb_vector_t<object_t *>& object_graph() const
+  { return packed; }
+
+  private:
+  template <typename T, unsigned Size = sizeof (T)>
+  void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
+  {
+    auto &off = * ((BEInt<T, Size> *) (parent->head + link.position));
+    assert (0 == off);
+    check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
   }
 
   public: /* TODO Make private. */
   char *start, *head, *tail, *end;
   unsigned int debug_depth;
-  bool successful;
-  bool ran_out_of_room;
+  hb_serialize_error_t errors;
 
   private:
 
@@ -462,5 +655,4 @@
   hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
 };
 
-
 #endif /* HB_SERIALIZE_HH */
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index b97526f..7d4979b 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -87,6 +87,8 @@
     }
   }
   template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+  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++)
@@ -96,6 +98,8 @@
     }
     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 (hb_codepoint_t g) const
   { return !!(mask & mask_for (g)); }
@@ -135,12 +139,16 @@
     tail.add_array (array, count, stride);
   }
   template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+  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;
   }
+  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 (hb_codepoint_t g) const
   {
@@ -160,15 +168,17 @@
  * There is not much science to this: it's a result of intuition
  * and testing.
  */
-typedef hb_set_digest_combiner_t
-<
-  hb_set_digest_lowest_bits_t<unsigned long, 4>,
+using hb_set_digest_t =
   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_lowest_bits_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_t;
+;
 
 
 #endif /* HB_SET_DIGEST_HH */
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 10638a7..204dbb5 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -30,11 +30,11 @@
 /**
  * SECTION:hb-set
  * @title: hb-set
- * @short_description: Object representing a set of integers
+ * @short_description: Objects representing a set of integers
  * @include: hb.h
  *
  * Set objects represent a mathematical set of integer values.  They are
- * used in non-shaping API to query certain set of characters or glyphs,
+ * used in non-shaping APIs to query certain sets of characters or glyphs,
  * or other integer values.
  **/
 
@@ -42,7 +42,9 @@
 /**
  * hb_set_create: (Xconstructor)
  *
- * Return value: (transfer full):
+ * Creates a new, initially empty set.
+ *
+ * Return value: (transfer full): The new #hb_set_t
  *
  * Since: 0.9.2
  **/
@@ -62,21 +64,25 @@
 /**
  * hb_set_get_empty:
  *
- * Return value: (transfer full):
+ * Fetches the singleton empty #hb_set_t.
+ *
+ * Return value: (transfer full): The empty #hb_set_t
  *
  * Since: 0.9.2
  **/
 hb_set_t *
 hb_set_get_empty ()
 {
-  return const_cast<hb_set_t *> (&Null(hb_set_t));
+  return const_cast<hb_set_t *> (&Null (hb_set_t));
 }
 
 /**
  * hb_set_reference: (skip)
- * @set: a set.
+ * @set: A set
  *
- * Return value: (transfer full):
+ * Increases the reference count on a set.
+ *
+ * Return value: (transfer full): The set
  *
  * Since: 0.9.2
  **/
@@ -88,7 +94,11 @@
 
 /**
  * hb_set_destroy: (skip)
- * @set: a set.
+ * @set: A set
+ *
+ * Decreases the reference count on a set. When
+ * the reference count reaches zero, the set is
+ * destroyed, freeing all memory.
  *
  * Since: 0.9.2
  **/
@@ -99,18 +109,20 @@
 
   set->fini_shallow ();
 
-  free (set);
+  hb_free (set);
 }
 
 /**
  * hb_set_set_user_data: (skip)
- * @set: a set.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @set: A set
+ * @key: The user-data key to set
+ * @data: A pointer to the user data to set
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
  *
- * Return value:
+ * Attaches a user-data key/data pair to the specified set.
+ *
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -126,10 +138,13 @@
 
 /**
  * hb_set_get_user_data: (skip)
- * @set: a set.
- * @key:
+ * @set: A set
+ * @key: The user-data key to query
  *
- * Return value: (transfer none):
+ * Fetches the user data associated with the specified key,
+ * attached to the specified set.
+ *
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -143,31 +158,50 @@
 
 /**
  * hb_set_allocation_successful:
- * @set: a set.
+ * @set: A set
  *
- * 
+ * Tests whether memory allocation for a set was successful.
  *
- * Return value: 
+ * Return value: %true if allocation succeeded, %false otherwise
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_set_allocation_successful (const hb_set_t  *set)
 {
-  return set->successful;
+  return !set->in_error ();
+}
+
+/**
+ * hb_set_copy:
+ * @set: A set
+ *
+ * Allocate a copy of @set.
+ *
+ * Return value: Newly-allocated set.
+ *
+ * Since: 2.8.2
+ **/
+hb_set_t *
+hb_set_copy (const hb_set_t *set)
+{
+  hb_set_t *copy = hb_set_create ();
+  copy->set (*set);
+  return copy;
 }
 
 /**
  * hb_set_clear:
- * @set: a set.
+ * @set: A set
  *
- * 
+ * Clears out the contents of a set.
  *
  * Since: 0.9.2
  **/
 void
 hb_set_clear (hb_set_t *set)
 {
+  /* Immutible-safe. */
   set->clear ();
 }
 
@@ -175,9 +209,9 @@
  * hb_set_is_empty:
  * @set: a set.
  *
- * 
+ * Tests whether a set is empty (contains no elements).
  *
- * Return value: 
+ * Return value: %true if @set is empty
  *
  * Since: 0.9.7
  **/
@@ -189,12 +223,12 @@
 
 /**
  * hb_set_has:
- * @set: a set.
- * @codepoint: 
+ * @set: A set
+ * @codepoint: The element to query
  *
- * 
+ * Tests whether @codepoint belongs to @set.
  *
- * Return value: 
+ * Return value: %true if @codepoint is in @set, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -207,10 +241,10 @@
 
 /**
  * hb_set_add:
- * @set: a set.
- * @codepoint: 
+ * @set: A set
+ * @codepoint: The element to add to @set
  *
- * 
+ * Adds @codepoint to @set.
  *
  * Since: 0.9.2
  **/
@@ -218,16 +252,18 @@
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
+  /* Immutible-safe. */
   set->add (codepoint);
 }
 
 /**
  * hb_set_add_range:
- * @set: a set.
- * @first: 
- * @last: 
+ * @set: A set
+ * @first: The first element to add to @set
+ * @last: The final element to add to @set
  *
- * 
+ * Adds all of the elements from @first to @last
+ * (inclusive) to @set.
  *
  * Since: 0.9.7
  **/
@@ -236,15 +272,16 @@
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
+  /* Immutible-safe. */
   set->add_range (first, last);
 }
 
 /**
  * hb_set_del:
- * @set: a set.
- * @codepoint: 
+ * @set: A set
+ * @codepoint: Removes @codepoint from @set
  *
- * 
+ * Removes @codepoint from @set.
  *
  * Since: 0.9.2
  **/
@@ -252,16 +289,21 @@
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
+  /* Immutible-safe. */
   set->del (codepoint);
 }
 
 /**
  * hb_set_del_range:
- * @set: a set.
- * @first: 
- * @last: 
+ * @set: A set
+ * @first: The first element to remove from @set
+ * @last: The final element to remove from @set
  *
- * 
+ * Removes all of the elements from @first to @last
+ * (inclusive) from @set.
+ *
+ * If @last is #HB_SET_VALUE_INVALID, then all values
+ * greater than or equal to @first are removed.
  *
  * Since: 0.9.7
  **/
@@ -270,17 +312,19 @@
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
+  /* Immutible-safe. */
   set->del_range (first, last);
 }
 
 /**
  * hb_set_is_equal:
- * @set: a set.
- * @other: other set.
+ * @set: A set
+ * @other: Another 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
  **/
@@ -288,17 +332,17 @@
 hb_set_is_equal (const hb_set_t *set,
 		 const hb_set_t *other)
 {
-  return set->is_equal (other);
+  return set->is_equal (*other);
 }
 
 /**
  * hb_set_is_subset:
- * @set: a set.
- * @larger_set: other set.
+ * @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
  **/
@@ -306,15 +350,15 @@
 hb_set_is_subset (const hb_set_t *set,
 		  const hb_set_t *larger_set)
 {
-  return set->is_subset (larger_set);
+  return set->is_subset (*larger_set);
 }
 
 /**
  * hb_set_set:
- * @set: a set.
- * @other: 
+ * @set: A set
+ * @other: Another set
  *
- * 
+ * Makes the contents of @set equal to the contents of @other.
  *
  * Since: 0.9.2
  **/
@@ -322,15 +366,16 @@
 hb_set_set (hb_set_t       *set,
 	    const hb_set_t *other)
 {
-  set->set (other);
+  /* Immutible-safe. */
+  set->set (*other);
 }
 
 /**
  * hb_set_union:
- * @set: a set.
- * @other: 
+ * @set: A set
+ * @other: Another set
  *
- * 
+ * Makes @set the union of @set and @other.
  *
  * Since: 0.9.2
  **/
@@ -338,15 +383,16 @@
 hb_set_union (hb_set_t       *set,
 	      const hb_set_t *other)
 {
-  set->union_ (other);
+  /* Immutible-safe. */
+  set->union_ (*other);
 }
 
 /**
  * hb_set_intersect:
- * @set: a set.
- * @other: 
+ * @set: A set
+ * @other: Another set
  *
- * 
+ * Makes @set the intersection of @set and @other.
  *
  * Since: 0.9.2
  **/
@@ -354,15 +400,16 @@
 hb_set_intersect (hb_set_t       *set,
 		  const hb_set_t *other)
 {
-  set->intersect (other);
+  /* Immutible-safe. */
+  set->intersect (*other);
 }
 
 /**
  * hb_set_subtract:
- * @set: a set.
- * @other: 
+ * @set: A set
+ * @other: Another set
  *
- * 
+ * Subtracts the contents of @other from @set.
  *
  * Since: 0.9.2
  **/
@@ -370,15 +417,17 @@
 hb_set_subtract (hb_set_t       *set,
 		 const hb_set_t *other)
 {
-  set->subtract (other);
+  /* Immutible-safe. */
+  set->subtract (*other);
 }
 
 /**
  * hb_set_symmetric_difference:
- * @set: a set.
- * @other: 
+ * @set: A set
+ * @other: Another set
  *
- * 
+ * Makes @set the symmetric difference of @set
+ * and @other.
  *
  * Since: 0.9.2
  **/
@@ -386,33 +435,32 @@
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other)
 {
-  set->symmetric_difference (other);
+  /* Immutible-safe. */
+  set->symmetric_difference (*other);
 }
 
-#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_set_invert:
- * @set: a set.
+ * @set: A set
  *
- * 
+ * Inverts the contents of @set.
  *
- * Since: 0.9.10
- *
- * Deprecated: 1.6.1
+ * Since: 3.0.0
  **/
 void
-hb_set_invert (hb_set_t *set HB_UNUSED)
+hb_set_invert (hb_set_t *set)
 {
+  /* Immutible-safe. */
+  set->invert ();
 }
-#endif
 
 /**
  * hb_set_get_population:
- * @set: a set.
+ * @set: A set
  *
- * Returns the number of numbers in the set.
+ * Returns the number of elements in the set.
  *
- * Return value: set population.
+ * Return value: The population of @set
  *
  * Since: 0.9.7
  **/
@@ -424,11 +472,11 @@
 
 /**
  * hb_set_get_min:
- * @set: a set.
+ * @set: A set
  *
- * Finds the minimum number in the set.
+ * Finds the smallest element in the set.
  *
- * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ * Return value: minimum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
  *
  * Since: 0.9.7
  **/
@@ -440,11 +488,11 @@
 
 /**
  * hb_set_get_max:
- * @set: a set.
+ * @set: A set
  *
- * Finds the maximum number in the set.
+ * Finds the largest element in the set.
  *
- * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ * Return value: maximum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
  *
  * Since: 0.9.7
  **/
@@ -456,14 +504,15 @@
 
 /**
  * hb_set_next:
- * @set: a set.
- * @codepoint: (inout):
+ * @set: A set
+ * @codepoint: (inout): Input = Code point to query
+ *             Output = Code point retrieved
  *
- * Gets the next number in @set that is greater than current value of @codepoint.
+ * Fetches the next element in @set that is greater than current value of @codepoint.
  *
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: whether there was a next value.
+ * Return value: %true if there was a next value, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -476,14 +525,15 @@
 
 /**
  * hb_set_previous:
- * @set: a set.
- * @codepoint: (inout):
+ * @set: A set
+ * @codepoint: (inout): Input = Code point to query
+ *             Output = Code point retrieved
  *
- * Gets the previous number in @set that is lower than current value of @codepoint.
+ * Fetches the previous element in @set that is lower than current value of @codepoint.
  *
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: whether there was a previous value.
+ * Return value: %true if there was a previous value, %false otherwise
  *
  * Since: 1.8.0
  **/
@@ -496,16 +546,17 @@
 
 /**
  * hb_set_next_range:
- * @set: a set.
- * @first: (out): output first codepoint in the range.
- * @last: (inout): input current last and output last codepoint in the range.
+ * @set: A set
+ * @first: (out): The first code point in the range
+ * @last: (inout): Input = The current last code point in the range
+ *         Output = The last code point in the range
  *
- * Gets the next consecutive range of numbers in @set that
+ * Fetches the next consecutive range of elements in @set that
  * are greater than current value of @last.
  *
- * Set @last to %HB_SET_VALUE_INVALID to get started.
+ * Set @last to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: whether there was a next range.
+ * Return value: %true if there was a next range, %false otherwise
  *
  * Since: 0.9.7
  **/
@@ -519,16 +570,17 @@
 
 /**
  * hb_set_previous_range:
- * @set: a set.
- * @first: (inout): input current first and output first codepoint in the range.
- * @last: (out): output last codepoint in the range.
+ * @set: A set
+ * @first: (inout): Input = The current first code point in the range
+ *         Output = The first code point in the range
+ * @last: (out): The last code point in the range
  *
- * Gets the previous consecutive range of numbers in @set that
- * are less than current value of @first.
+ * Fetches the previous consecutive range of elements in @set that
+ * are greater than current value of @last.
  *
- * Set @first to %HB_SET_VALUE_INVALID to get started.
+ * Set @first to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: whether there was a previous range.
+ * Return value: %true if there was a previous range, %false otherwise
  *
  * Since: 1.8.0
  **/
diff --git a/src/hb-set.h b/src/hb-set.h
index ed0e05d..423225b 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,11 +36,24 @@
 HB_BEGIN_DECLS
 
 
-/*
+/**
+ * HB_SET_VALUE_INVALID:
+ *
+ * Unset #hb_set_t value.
+ *
  * Since: 0.9.21
  */
 #define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
 
+/**
+ * hb_set_t:
+ *
+ * Data type for holding a set of integers. #hb_set_t's are
+ * used to gather and contain glyph IDs, Unicode code
+ * points, and various other collections of discrete 
+ * values.
+ *
+ **/
 typedef struct hb_set_t hb_set_t;
 
 
@@ -72,12 +85,18 @@
 HB_EXTERN hb_bool_t
 hb_set_allocation_successful (const hb_set_t *set);
 
+HB_EXTERN hb_set_t *
+hb_set_copy (const hb_set_t *set);
+
 HB_EXTERN void
 hb_set_clear (hb_set_t *set);
 
 HB_EXTERN hb_bool_t
 hb_set_is_empty (const hb_set_t *set);
 
+HB_EXTERN void
+hb_set_invert (hb_set_t *set);
+
 HB_EXTERN hb_bool_t
 hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint);
diff --git a/src/hb-set.hh b/src/hb-set.hh
index 36d11c0..8841427 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -28,355 +29,80 @@
 #define HB_SET_HH
 
 #include "hb.hh"
-#include "hb-machinery.hh"
+#include "hb-bit-set-invertible.hh"
 
 
-/*
- * hb_set_t
- */
-
-/* TODO Keep a free-list so we can free pages that are completely zeroed.  At that
- * point maybe also use a sentinel value for "all-1" pages? */
-
-struct hb_set_t
+template <typename impl_t>
+struct hb_sparseset_t
 {
-  HB_DELETE_COPY_ASSIGN (hb_set_t);
-  hb_set_t ()  { init (); }
-  ~hb_set_t () { fini (); }
-
-  struct page_map_t
-  {
-    int cmp (const page_map_t &o) const { return (int) o.major - (int) major; }
-
-    uint32_t major;
-    uint32_t index;
-  };
-
-  struct page_t
-  {
-    void init0 () { v.clear (); }
-    void init1 () { v.clear (0xFF); }
-
-    unsigned int len () const
-    { return ARRAY_LENGTH_CONST (v); }
-
-    bool is_empty () const
-    {
-      for (unsigned int i = 0; i < len (); i++)
-	if (v[i])
-	  return false;
-      return true;
-    }
-
-    void add (hb_codepoint_t g) { elt (g) |= mask (g); }
-    void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-    bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
-
-    void add_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);
-      else
-      {
-	*la |= ~(mask (a) - 1);
-	la++;
-
-	memset (la, 0xff, (char *) lb - (char *) la);
-
-	*lb |= ((mask (b) << 1) - 1);
-      }
-    }
-
-    bool is_equal (const page_t *other) const
-    {
-      return 0 == hb_memcmp (&v, &other->v, sizeof (v));
-    }
-
-    unsigned int get_population () const
-    {
-      unsigned int pop = 0;
-      for (unsigned int i = 0; i < len (); i++)
-	pop += hb_popcount (v[i]);
-      return pop;
-    }
-
-    bool next (hb_codepoint_t *codepoint) const
-    {
-      unsigned int m = (*codepoint + 1) & MASK;
-      if (!m)
-      {
-	*codepoint = INVALID;
-	return false;
-      }
-      unsigned int i = m / ELT_BITS;
-      unsigned int j = m & ELT_MASK;
-
-      const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
-      for (const elt_t *p = &vv; i < len (); p = &v[++i])
-	if (*p)
-	{
-	  *codepoint = i * ELT_BITS + elt_get_min (*p);
-	  return true;
-	}
-
-      *codepoint = INVALID;
-      return false;
-    }
-    bool previous (hb_codepoint_t *codepoint) const
-    {
-      unsigned int m = (*codepoint - 1) & MASK;
-      if (m == MASK)
-      {
-	*codepoint = INVALID;
-	return false;
-      }
-      unsigned int i = m / ELT_BITS;
-      unsigned int j = m & ELT_MASK;
-
-      const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1);
-      const elt_t *p = &vv;
-      while (true)
-      {
-	if (*p)
-	{
-	  *codepoint = i * ELT_BITS + elt_get_max (*p);
-	  return true;
-	}
-	if ((int) i <= 0) break;
-	p = &v[--i];
-      }
-
-      *codepoint = INVALID;
-      return false;
-    }
-    hb_codepoint_t get_min () const
-    {
-      for (unsigned int i = 0; i < len (); i++)
-	if (v[i])
-	  return i * ELT_BITS + elt_get_min (v[i]);
-      return INVALID;
-    }
-    hb_codepoint_t get_max () const
-    {
-      for (int i = len () - 1; i >= 0; i--)
-	if (v[i])
-	  return i * ELT_BITS + elt_get_max (v[i]);
-      return 0;
-    }
-
-    typedef unsigned long long elt_t;
-    static constexpr unsigned PAGE_BITS = 512;
-    static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
-
-    static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
-    static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
-
-    typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
-
-    static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
-    static constexpr unsigned ELT_MASK = ELT_BITS - 1;
-    static constexpr unsigned BITS = sizeof (vector_t) * 8;
-    static constexpr unsigned MASK = BITS - 1;
-    static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
-
-    elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
-    elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
-    elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
-
-    vector_t v;
-  };
-  static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
-
   hb_object_header_t header;
-  bool successful; /* Allocations successful */
-  mutable unsigned int population;
-  hb_sorted_vector_t<page_map_t> page_map;
-  hb_vector_t<page_t> pages;
+  impl_t s;
 
-  void init_shallow ()
+  hb_sparseset_t () { init (); }
+  ~hb_sparseset_t () { fini (); }
+
+  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; }
+  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 ()
   {
-    successful = true;
-    population = 0;
-    page_map.init ();
-    pages.init ();
+    for (auto&& item : lst)
+      add (item);
   }
+  template <typename 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 ();
   }
-  void fini_shallow ()
-  {
-    population = 0;
-    page_map.fini ();
-    pages.fini ();
-  }
+  void fini_shallow () { s.fini (); }
   void fini ()
   {
     hb_object_fini (this);
     fini_shallow ();
   }
 
-  bool in_error () const { return !successful; }
+  explicit operator bool () const { return !is_empty (); }
 
-  bool resize (unsigned int count)
-  {
-    if (unlikely (!successful)) return false;
-    if (!pages.resize (count) || !page_map.resize (count))
-    {
-      pages.resize (page_map.length);
-      successful = false;
-      return false;
-    }
-    return true;
-  }
+  void err () { s.err (); }
+  bool in_error () const { return s.in_error (); }
 
-  void reset ()
-  {
-    if (unlikely (hb_object_is_immutable (this)))
-      return;
-    clear ();
-    successful = true;
-  }
+  void reset () { s.reset (); }
+  void clear () { s.clear (); }
+  void invert () { s.invert (); }
+  bool is_empty () const { return s.is_empty (); }
 
-  void clear ()
-  {
-    if (unlikely (hb_object_is_immutable (this)))
-      return;
-    population = 0;
-    page_map.resize (0);
-    pages.resize (0);
-  }
-  bool is_empty () const
-  {
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!pages[i].is_empty ())
-	return false;
-    return true;
-  }
-
-  void dirty () { population = (unsigned int) -1; }
-
-  void add (hb_codepoint_t g)
-  {
-    if (unlikely (!successful)) return;
-    if (unlikely (g == INVALID)) return;
-    dirty ();
-    page_t *page = page_for_insert (g); if (unlikely (!page)) return;
-    page->add (g);
-  }
-  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
-  {
-    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
-    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
-    dirty ();
-    unsigned int ma = get_major (a);
-    unsigned int mb = get_major (b);
-    if (ma == mb)
-    {
-      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
-      page->add_range (a, b);
-    }
-    else
-    {
-      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
-      page->add_range (a, major_start (ma + 1) - 1);
-
-      for (unsigned int m = ma + 1; m < mb; m++)
-      {
-	page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
-	page->init1 ();
-      }
-
-      page = page_for_insert (b); if (unlikely (!page)) return false;
-      page->add_range (major_start (mb), b);
-    }
-    return true;
-  }
+  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); }
 
   template <typename T>
   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
-  {
-    if (unlikely (!successful)) return;
-    if (!count) return;
-    dirty ();
-    hb_codepoint_t g = *array;
-    while (count)
-    {
-      unsigned int m = get_major (g);
-      page_t *page = page_for_insert (g); if (unlikely (!page)) return;
-      unsigned int start = major_start (m);
-      unsigned int end = major_start (m + 1);
-      do
-      {
-	page->add (g);
-
-	array = &StructAtOffsetUnaligned<T> (array, stride);
-	count--;
-      }
-      while (count && (g = *array, start <= g && g < end));
-    }
-  }
+  { s.add_array (array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
 
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename T>
   bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
-  {
-    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
-    if (!count) return true;
-    dirty ();
-    hb_codepoint_t g = *array;
-    hb_codepoint_t last_g = g;
-    while (count)
-    {
-      unsigned int m = get_major (g);
-      page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
-      unsigned int end = major_start (m + 1);
-      do
-      {
-	/* If we try harder we can change the following comparison to <=;
-	 * Not sure if it's worth it. */
-	if (g < last_g) return false;
-	last_g = g;
-	page->add (g);
+  { return s.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 ()); }
 
-	array = (const T *) ((const char *) array + stride);
-	count--;
-      }
-      while (count && (g = *array, g < end));
-    }
-    return true;
-  }
+  void del (hb_codepoint_t g) { s.del (g); }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b) { s.del_range (a, b); }
 
-  void del (hb_codepoint_t g)
-  {
-    /* TODO perform op even if !successful. */
-    if (unlikely (!successful)) return;
-    page_t *page = page_for (g);
-    if (!page)
-      return;
-    dirty ();
-    page->del (g);
-  }
-  void del_range (hb_codepoint_t a, hb_codepoint_t b)
-  {
-    /* TODO perform op even if !successful. */
-    /* TODO Optimize, like add_range(). */
-    if (unlikely (!successful)) return;
-    for (unsigned int i = a; i < b + 1; i++)
-      del (i);
-  }
-  bool get (hb_codepoint_t g) const
-  {
-    const page_t *page = page_for (g);
-    if (!page)
-      return false;
-    return page->get (g);
-  }
+  bool get (hb_codepoint_t g) const { return s.get (g); }
 
   /* Has interface. */
   static constexpr bool SENTINEL = false;
@@ -387,378 +113,60 @@
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
   /* Sink interface. */
-  hb_set_t& operator << (hb_codepoint_t v) { add (v); return *this; }
+  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)
+  { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
-  {
-    hb_codepoint_t c = first - 1;
-    return next (&c) && c <= last;
-  }
-  void set (const hb_set_t *other)
-  {
-    if (unlikely (!successful)) return;
-    unsigned int count = other->pages.length;
-    if (!resize (count))
-      return;
-    population = other->population;
-    memcpy ((void *) pages, (const void *) other->pages, count * pages.item_size);
-    memcpy ((void *) page_map, (const void *) other->page_map, count * page_map.item_size);
-  }
+  { return s.intersects (first, last); }
 
-  bool is_equal (const hb_set_t *other) const
-  {
-    if (get_population () != other->get_population ())
-      return false;
+  void set (const hb_sparseset_t &other) { s.set (other.s); }
 
-    unsigned int na = pages.length;
-    unsigned int nb = other->pages.length;
+  bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); }
 
-    unsigned int a = 0, b = 0;
-    for (; a < na && b < nb; )
-    {
-      if (page_at (a).is_empty ()) { a++; continue; }
-      if (other->page_at (b).is_empty ()) { b++; continue; }
-      if (page_map[a].major != other->page_map[b].major ||
-	  !page_at (a).is_equal (&other->page_at (b)))
-	return false;
-      a++;
-      b++;
-    }
-    for (; a < na; a++)
-      if (!page_at (a).is_empty ()) { return false; }
-    for (; b < nb; b++)
-      if (!other->page_at (b).is_empty ()) { return false; }
+  bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); }
 
-    return true;
-  }
+  void union_ (const hb_sparseset_t &other) { s.union_ (other.s); }
+  void intersect (const hb_sparseset_t &other) { s.intersect (other.s); }
+  void subtract (const hb_sparseset_t &other) { s.subtract (other.s); }
+  void symmetric_difference (const hb_sparseset_t &other) { s.symmetric_difference (other.s); }
 
-  bool is_subset (const hb_set_t *larger_set) const
-  {
-    if (get_population () > larger_set->get_population ())
-      return false;
-
-    /* TODO Optimize to use pages. */
-    hb_codepoint_t c = INVALID;
-    while (next (&c))
-      if (!larger_set->has (c))
-	return false;
-
-    return true;
-  }
-
-  template <typename Op>
-  void process (const Op& op, const hb_set_t *other)
-  {
-    if (unlikely (!successful)) return;
-
-    dirty ();
-
-    unsigned int na = pages.length;
-    unsigned int nb = other->pages.length;
-    unsigned int next_page = na;
-
-    unsigned int count = 0, newCount = 0;
-    unsigned int a = 0, b = 0;
-    for (; a < na && b < nb; )
-    {
-      if (page_map[a].major == other->page_map[b].major)
-      {
-	count++;
-	a++;
-	b++;
-      }
-      else if (page_map[a].major < other->page_map[b].major)
-      {
-	if (Op::passthru_left)
-	  count++;
-	a++;
-      }
-      else
-      {
-	if (Op::passthru_right)
-	  count++;
-	b++;
-      }
-    }
-    if (Op::passthru_left)
-      count += na - a;
-    if (Op::passthru_right)
-      count += nb - b;
-
-    if (count > pages.length)
-      if (!resize (count))
-	return;
-    newCount = count;
-
-    /* Process in-place backward. */
-    a = na;
-    b = nb;
-    for (; a && b; )
-    {
-      if (page_map[a - 1].major == other->page_map[b - 1].major)
-      {
-	a--;
-	b--;
-	count--;
-	page_map[count] = page_map[a];
-	page_at (count).v = op (page_at (a).v, other->page_at (b).v);
-      }
-      else if (page_map[a - 1].major > other->page_map[b - 1].major)
-      {
-	a--;
-	if (Op::passthru_left)
-	{
-	  count--;
-	  page_map[count] = page_map[a];
-	}
-      }
-      else
-      {
-	b--;
-	if (Op::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;
-	}
-      }
-    }
-    if (Op::passthru_left)
-      while (a)
-      {
-	a--;
-	count--;
-	page_map[count] = page_map [a];
-      }
-    if (Op::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;
-      }
-    assert (!count);
-    if (pages.length > newCount)
-      resize (newCount);
-  }
-
-  void union_ (const hb_set_t *other)
-  {
-    process (hb_bitwise_or, other);
-  }
-  void intersect (const hb_set_t *other)
-  {
-    process (hb_bitwise_and, other);
-  }
-  void subtract (const hb_set_t *other)
-  {
-    process (hb_bitwise_sub, other);
-  }
-  void symmetric_difference (const hb_set_t *other)
-  {
-    process (hb_bitwise_xor, other);
-  }
-  bool next (hb_codepoint_t *codepoint) const
-  {
-    if (unlikely (*codepoint == INVALID)) {
-      *codepoint = get_min ();
-      return *codepoint != INVALID;
-    }
-
-    page_map_t map = {get_major (*codepoint), 0};
-    unsigned int i;
-    page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.length && page_map[i].major == map.major)
-    {
-      if (pages[page_map[i].index].next (codepoint))
-      {
-	*codepoint += page_map[i].major * page_t::PAGE_BITS;
-	return true;
-      }
-      i++;
-    }
-    for (; i < page_map.length; i++)
-    {
-      hb_codepoint_t m = pages[page_map[i].index].get_min ();
-      if (m != INVALID)
-      {
-	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
-	return true;
-      }
-    }
-    *codepoint = INVALID;
-    return false;
-  }
-  bool previous (hb_codepoint_t *codepoint) const
-  {
-    if (unlikely (*codepoint == INVALID)) {
-      *codepoint = get_max ();
-      return *codepoint != INVALID;
-    }
-
-    page_map_t map = {get_major (*codepoint), 0};
-    unsigned int i;
-    page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.length && page_map[i].major == map.major)
-    {
-      if (pages[page_map[i].index].previous (codepoint))
-      {
-	*codepoint += page_map[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 ();
-      if (m != INVALID)
-      {
-	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
-	return true;
-      }
-    }
-    *codepoint = INVALID;
-    return false;
-  }
+  bool next (hb_codepoint_t *codepoint) const { return s.next (codepoint); }
+  bool previous (hb_codepoint_t *codepoint) const { return s.previous (codepoint); }
   bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
-  {
-    hb_codepoint_t i;
-
-    i = *last;
-    if (!next (&i))
-    {
-      *last = *first = INVALID;
-      return false;
-    }
-
-    /* TODO Speed up. */
-    *last = *first = i;
-    while (next (&i) && i == *last + 1)
-      (*last)++;
-
-    return true;
-  }
+  { return s.next_range (first, last); }
   bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
-  {
-    hb_codepoint_t i;
+  { return s.previous_range (first, last); }
 
-    i = *first;
-    if (!previous (&i))
-    {
-      *last = *first = INVALID;
-      return false;
-    }
+  unsigned int get_population () const { return s.get_population (); }
+  hb_codepoint_t get_min () const { return s.get_min (); }
+  hb_codepoint_t get_max () const { return s.get_max (); }
 
-    /* TODO Speed up. */
-    *last = *first = i;
-    while (previous (&i) && i == *first - 1)
-      (*first)--;
-
-    return true;
-  }
-
-  unsigned int get_population () const
-  {
-    if (population != (unsigned int) -1)
-      return population;
-
-    unsigned int pop = 0;
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      pop += pages[i].get_population ();
-
-    population = pop;
-    return pop;
-  }
-  hb_codepoint_t get_min () const
-  {
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!page_at (i).is_empty ())
-	return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
-    return INVALID;
-  }
-  hb_codepoint_t get_max () const
-  {
-    unsigned int count = pages.length;
-    for (int i = count - 1; i >= 0; i++)
-      if (!page_at (i).is_empty ())
-	return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max ();
-    return INVALID;
-  }
-
-  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+  static constexpr hb_codepoint_t INVALID = impl_t::INVALID;
 
   /*
    * Iterator implementation.
    */
-  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
-  {
-    static constexpr bool is_sorted_iterator = true;
-    iter_t (const hb_set_t &s_ = Null(hb_set_t)) :
-      s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); }
-
-    typedef hb_codepoint_t __item_t__;
-    hb_codepoint_t __item__ () const { return v; }
-    bool __more__ () const { return v != INVALID; }
-    void __next__ () { s->next (&v); if (l) l--; }
-    void __prev__ () { s->previous (&v); }
-    unsigned __len__ () const { return l; }
-    iter_t end () const { return iter_t (*s); }
-    bool operator != (const iter_t& o) const
-    { return s != o.s || v != o.v; }
-
-    protected:
-    const hb_set_t *s;
-    hb_codepoint_t v;
-    unsigned l;
-  };
-  iter_t iter () const { return iter_t (*this); }
+  using iter_t = typename impl_t::iter_t;
+  iter_t iter () const { return iter_t (this->s); }
   operator iter_t () const { return iter (); }
-
-  protected:
-
-  page_t *page_for_insert (hb_codepoint_t g)
-  {
-    page_map_t map = {get_major (g), pages.length};
-    unsigned int i;
-    if (!page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST))
-    {
-      if (!resize (pages.length + 1))
-	return nullptr;
-
-      pages[map.index].init0 ();
-      memmove (page_map + i + 1,
-	       page_map + i,
-	       (page_map.length - 1 - i) * page_map.item_size);
-      page_map[i] = map;
-    }
-    return &pages[page_map[i].index];
-  }
-  page_t *page_for (hb_codepoint_t g)
-  {
-    page_map_t key = {get_major (g)};
-    const page_map_t *found = page_map.bsearch (key);
-    if (found)
-      return &pages[found->index];
-    return nullptr;
-  }
-  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;
-  }
-  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; }
 };
 
+struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
+{
+  hb_set_t () = default;
+  ~hb_set_t () = default;
+  hb_set_t (hb_set_t& o) = default;
+  hb_set_t& operator= (const hb_set_t& other) = default;
+  hb_set_t& operator= (hb_set_t&& other) = default;
+  hb_set_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_t> (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) {}
+};
+
+static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, "");
+
 
 #endif /* HB_SET_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index ffd723d..6633216 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -37,10 +37,17 @@
  * @short_description: Object representing a shaping plan
  * @include: hb.h
  *
- * Shape plans are not used for shaping directly, but can be access to query
- * certain information about how shaping will perform given a set of input
- * parameters (script, language, direction, features, etc.)
- * Most client would not need to deal with shape plans directly.
+ * Shape plans are an internal mechanism. Each plan contains state
+ * describing how HarfBuzz will shape a particular text segment, based on
+ * the combination of segment properties and the capabilities in the
+ * font face in use.
+ *
+ * Shape plans are not used for shaping directly, but can be queried to
+ * access certain information about how shaping will perform, given a set
+ * of specific input parameters (script, language, direction, features,
+ * etc.).
+ *
+ * Most client programs will not need to deal with shape plans directly.
  **/
 
 
@@ -59,7 +66,7 @@
 			   const char * const            *shaper_list)
 {
   hb_feature_t *features = nullptr;
-  if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
+  if (copy && num_user_features && !(features = (hb_feature_t *) hb_calloc (num_user_features, sizeof (hb_feature_t))))
     goto bail;
 
   this->props = *props;
@@ -123,7 +130,7 @@
 #undef HB_SHAPER_PLAN
 
 bail:
-  ::free (features);
+  ::hb_free (features);
   return false;
 }
 
@@ -164,15 +171,16 @@
 
 /**
  * hb_shape_plan_create: (Xconstructor)
- * @face:
- * @props:
- * @user_features: (array length=num_user_features):
- * @num_user_features:
- * @shaper_list: (array zero-terminated=1):
+ * @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
+ * @num_user_features: The number of user-selected features
+ * @shaper_list: (array zero-terminated=1): List of shapers to try
  *
+ * Constructs a shaping plan for a combination of @face, @user_features, @props,
+ * and @shaper_list.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The shaping plan
  *
  * Since: 0.9.7
  **/
@@ -189,6 +197,24 @@
 				shaper_list);
 }
 
+/**
+ * hb_shape_plan_create2: (Xconstructor)
+ * @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
+ * @num_user_features: The number of user-selected features
+ * @coords: (array length=num_coords): The list of variation-space coordinates
+ * @num_coords: The number of variation-space coordinates
+ * @shaper_list: (array zero-terminated=1): List of shapers to try
+ *
+ * The variable-font version of #hb_shape_plan_create. 
+ * Constructs a shaping plan for a combination of @face, @user_features, @props,
+ * and @shaper_list, plus the variation-space coordinates @coords.
+ *
+ * Return value: (transfer full): The shaping plan
+ *
+ * Since: 1.4.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_create2 (hb_face_t                     *face,
 		       const hb_segment_properties_t *props,
@@ -238,9 +264,9 @@
 #ifndef HB_NO_OT_SHAPE
 bail3:
 #endif
-  shape_plan->key.free ();
+  shape_plan->key.fini ();
 bail2:
-  free (shape_plan);
+  hb_free (shape_plan);
 bail:
   return hb_shape_plan_get_empty ();
 }
@@ -248,25 +274,25 @@
 /**
  * hb_shape_plan_get_empty:
  *
+ * Fetches the singleton empty shaping plan.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The empty shaping plan
  *
  * Since: 0.9.7
  **/
 hb_shape_plan_t *
 hb_shape_plan_get_empty ()
 {
-  return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t));
+  return const_cast<hb_shape_plan_t *> (&Null (hb_shape_plan_t));
 }
 
 /**
  * hb_shape_plan_reference: (skip)
- * @shape_plan: a shape plan.
+ * @shape_plan: A shaping plan
  *
+ * Increases the reference count on the given shaping plan.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): @shape_plan
  *
  * Since: 0.9.7
  **/
@@ -278,9 +304,11 @@
 
 /**
  * hb_shape_plan_destroy: (skip)
- * @shape_plan: a shape plan.
+ * @shape_plan: A shaping plan
  *
- *
+ * Decreases the reference count on the given shaping plan. When the
+ * reference count reaches zero, the shaping plan is destroyed,
+ * freeing all memory.
  *
  * Since: 0.9.7
  **/
@@ -292,21 +320,21 @@
 #ifndef HB_NO_OT_SHAPE
   shape_plan->ot.fini ();
 #endif
-  shape_plan->key.free ();
-  free (shape_plan);
+  shape_plan->key.fini ();
+  hb_free (shape_plan);
 }
 
 /**
  * hb_shape_plan_set_user_data: (skip)
- * @shape_plan: a shape plan.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @shape_plan: A shaping plan
+ * @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 shaping plan. 
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise.
  *
  * Since: 0.9.7
  **/
@@ -322,12 +350,13 @@
 
 /**
  * hb_shape_plan_get_user_data: (skip)
- * @shape_plan: a shape plan.
- * @key:
+ * @shape_plan: A shaping plan
+ * @key: The user-data key to query
  *
+ * Fetches the user data associated with the specified key, 
+ * attached to the specified shaping plan.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.7
  **/
@@ -340,11 +369,11 @@
 
 /**
  * hb_shape_plan_get_shaper:
- * @shape_plan: a shape plan.
+ * @shape_plan: A shaping plan
  *
+ * Fetches the shaper from a given shaping plan.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): The shaper
  *
  * Since: 0.9.7
  **/
@@ -355,26 +384,12 @@
 }
 
 
-/**
- * hb_shape_plan_execute:
- * @shape_plan: a shape plan.
- * @font: a font.
- * @buffer: a buffer.
- * @features: (array length=num_features):
- * @num_features:
- *
- *
- *
- * Return value:
- *
- * Since: 0.9.7
- **/
-hb_bool_t
-hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
-		       hb_font_t          *font,
-		       hb_buffer_t        *buffer,
-		       const hb_feature_t *features,
-		       unsigned int        num_features)
+static bool
+_hb_shape_plan_execute_internal (hb_shape_plan_t    *shape_plan,
+				 hb_font_t          *font,
+				 hb_buffer_t        *buffer,
+				 const hb_feature_t *features,
+				 unsigned int        num_features)
 {
   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
 		  "num_features=%d shaper_func=%p, shaper_name=%s",
@@ -386,9 +401,10 @@
     return true;
 
   assert (!hb_object_is_immutable (buffer));
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 
-  if (unlikely (hb_object_is_inert (shape_plan)))
+  buffer->assert_unicode ();
+
+  if (unlikely (!hb_object_is_valid (shape_plan)))
     return false;
 
   assert (shape_plan->face_unsafe == font->face);
@@ -412,6 +428,36 @@
 
   return false;
 }
+/**
+ * hb_shape_plan_execute:
+ * @shape_plan: A shaping plan
+ * @font: The #hb_font_t to use
+ * @buffer: The #hb_buffer_t to work upon
+ * @features: (array length=num_features): Features to enable
+ * @num_features: The number of features to enable
+ *
+ * Executes the given shaping plan on the specified buffer, using
+ * the given @font and @features.
+ *
+ * Return value: %true if success, %false otherwise.
+ *
+ * Since: 0.9.7
+ **/
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
+{
+  bool ret = _hb_shape_plan_execute_internal (shape_plan, font, buffer,
+					      features, num_features);
+
+  if (ret && buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
+    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+
+  return ret;
+}
 
 
 /*
@@ -420,15 +466,16 @@
 
 /**
  * hb_shape_plan_create_cached:
- * @face:
- * @props:
- * @user_features: (array length=num_user_features):
- * @num_user_features:
- * @shaper_list: (array zero-terminated=1):
+ * @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
+ * @num_user_features: The number of user-selected features
+ * @shaper_list: (array zero-terminated=1): List of shapers to try
  *
+ * Creates a cached shaping plan suitable for reuse, for a combination
+ * of @face, @user_features, @props, and @shaper_list.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The shaping plan
  *
  * Since: 0.9.7
  **/
@@ -445,6 +492,25 @@
 				       shaper_list);
 }
 
+/**
+ * hb_shape_plan_create_cached2:
+ * @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
+ * @num_user_features: The number of user-selected features
+ * @coords: (array length=num_coords): The list of variation-space coordinates
+ * @num_coords: The number of variation-space coordinates
+ * @shaper_list: (array zero-terminated=1): List of shapers to try
+ *
+ * The variable-font version of #hb_shape_plan_create_cached. 
+ * Creates a cached shaping plan suitable for reuse, for a combination
+ * of @face, @user_features, @props, and @shaper_list, plus the
+ * variation-space coordinates @coords.
+ *
+ * Return value: (transfer full): The shaping plan
+ *
+ * Since: 1.4.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_create_cached2 (hb_face_t                     *face,
 			      const hb_segment_properties_t *props,
@@ -463,7 +529,7 @@
 retry:
   hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
 
-  bool dont_cache = hb_object_is_inert (face);
+  bool dont_cache = !hb_object_is_valid (face);
 
   if (likely (!dont_cache))
   {
@@ -494,7 +560,7 @@
   if (unlikely (dont_cache))
     return shape_plan;
 
-  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) hb_calloc (1, sizeof (hb_face_t::plan_node_t));
   if (unlikely (!node))
     return shape_plan;
 
@@ -504,7 +570,7 @@
   if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
   {
     hb_shape_plan_destroy (shape_plan);
-    free (node);
+    hb_free (node);
     goto retry;
   }
   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index b62ae7c..fc7c041 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,6 +36,20 @@
 
 HB_BEGIN_DECLS
 
+/**
+ * hb_shape_plan_t:
+ *
+ * Data type for holding a shaping plan. 
+ *
+ * Shape plans contain information about how HarfBuzz will shape a
+ * particular text segment, based on the segment's properties and the
+ * capabilities in the font face in use.
+ *
+ * Shape plans can be queried about how shaping will perform, given a set
+ * of specific input parameters (script, language, direction, features,
+ * etc.).
+ *
+ **/
 typedef struct hb_shape_plan_t hb_shape_plan_t;
 
 HB_EXTERN hb_shape_plan_t *
diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh
index 6da7edb..8cb4ddb 100644
--- a/src/hb-shape-plan.hh
+++ b/src/hb-shape-plan.hh
@@ -55,7 +55,7 @@
 			 unsigned int                   num_coords,
 			 const char * const            *shaper_list);
 
-  HB_INTERNAL void free () { ::free ((void *) user_features); }
+  HB_INTERNAL void fini () { hb_free ((void *) user_features); }
 
   HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index cf4e152..c1f619c 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -48,9 +48,7 @@
  **/
 
 
-#if HB_USE_ATEXIT
-static void free_static_shaper_list ();
-#endif
+static inline void free_static_shaper_list ();
 
 static const char *nil_shaper_list[] = {nullptr};
 
@@ -59,7 +57,7 @@
 {
   static const char ** create ()
   {
-    const char **shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
+    const char **shaper_list = (const char **) hb_calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
     if (unlikely (!shaper_list))
       return nullptr;
 
@@ -69,25 +67,21 @@
       shaper_list[i] = shapers[i].name;
     shaper_list[i] = nullptr;
 
-#if HB_USE_ATEXIT
-    atexit (free_static_shaper_list);
-#endif
+    hb_atexit (free_static_shaper_list);
 
     return shaper_list;
   }
   static void destroy (const char **l)
-  { free (l); }
+  { hb_free (l); }
   static const char ** get_null ()
   { return nil_shaper_list; }
 } static_shaper_list;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_shaper_list ()
 {
   static_shaper_list.free_instance ();
 }
-#endif
 
 
 /**
@@ -111,10 +105,10 @@
  * hb_shape_full:
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @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) (allow-none): a %NULL-terminated
+ * @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
@@ -139,8 +133,6 @@
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
 
-  if (res)
-    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
   return res;
 }
 
@@ -148,7 +140,7 @@
  * hb_shape:
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @features: (array length=num_features) (nullable): an array of user
  *    specified #hb_feature_t or %NULL
  * @num_features: the length of @features array
  *
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 39507ff..922f8c0 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -26,7 +26,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index 0ea68ad..a11ed83 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -38,9 +38,7 @@
 static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled.");
 #endif
 
-#if HB_USE_ATEXIT
-static void free_static_shapers ();
-#endif
+static inline void free_static_shapers ();
 
 static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_t,
 							  hb_shapers_lazy_loader_t>
@@ -51,7 +49,7 @@
     if (!env || !*env)
       return nullptr;
 
-    hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) calloc (1, sizeof (all_shapers));
+    hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (all_shapers));
     if (unlikely (!shapers))
       return nullptr;
 
@@ -83,23 +81,19 @@
 	p = end + 1;
     }
 
-#if HB_USE_ATEXIT
-    atexit (free_static_shapers);
-#endif
+    hb_atexit (free_static_shapers);
 
     return shapers;
   }
-  static void destroy (const hb_shaper_entry_t *p) { free ((void *) p); }
+  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_shapers;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_shapers ()
 {
   static_shapers.free_instance ();
 }
-#endif
 
 const hb_shaper_entry_t *
 _hb_shapers_get ()
diff --git a/src/hb-shaper.hh b/src/hb-shaper.hh
index 79dc5d0..b4138a3 100644
--- a/src/hb-shaper.hh
+++ b/src/hb-shaper.hh
@@ -102,7 +102,7 @@
 	  static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \
 	}; \
 	\
-	static_assert (true, "") /* Require semicolon. */
+	static_assert (true, "") /* Require semicolon after. */
 
 
 template <typename Object>
diff --git a/src/hb-static.cc b/src/hb-static.cc
index 08a2f21..ec4b241 100644
--- a/src/hb-static.cc
+++ b/src/hb-static.cc
@@ -43,6 +43,7 @@
 /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
 
 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, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00};
@@ -51,6 +52,9 @@
 const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
 
 
+
+/* hb_face_t */
+
 unsigned int
 hb_face_t::load_num_glyphs () const
 {
@@ -73,4 +77,37 @@
   return ret;
 }
 
+
+/* hb_user_data_array_t */
+
+bool
+hb_user_data_array_t::set (hb_user_data_key_t *key,
+			   void *              data,
+			   hb_destroy_func_t   destroy,
+			   hb_bool_t           replace)
+{
+  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;
+}
+
+void *
+hb_user_data_array_t::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;
+}
+
+
 #endif
diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh
index 1c67ab4..e7ac119 100644
--- a/src/hb-string-array.hh
+++ b/src/hb-string-array.hh
@@ -37,6 +37,7 @@
 #define HB_STRING_ARRAY_TYPE_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr_t)
 #define HB_STRING_ARRAY_POOL_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr)
 #define HB_STRING_ARRAY_OFFS_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgidx)
+#define HB_STRING_ARRAY_LENG_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _length)
 
 static const union HB_STRING_ARRAY_TYPE_NAME {
   struct {
@@ -66,6 +67,8 @@
   sizeof (HB_STRING_ARRAY_TYPE_NAME)
 };
 
+static const unsigned int HB_STRING_ARRAY_LENG_NAME = ARRAY_LENGTH_CONST (HB_STRING_ARRAY_OFFS_NAME) - 1;
+
 static inline hb_bytes_t
 HB_STRING_ARRAY_NAME (unsigned int i)
 {
@@ -77,5 +80,6 @@
 #undef HB_STRING_ARRAY_TYPE_NAME
 #undef HB_STRING_ARRAY_POOL_NAME
 #undef HB_STRING_ARRAY_OFFS_NAME
+#undef HB_STRING_ARRAY_LENG_NAME
 
 #endif /* HB_STRING_ARRAY_HH */
diff --git a/src/hb-style.cc b/src/hb-style.cc
new file mode 100644
index 0000000..f1b44ce
--- /dev/null
+++ b/src/hb-style.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_STYLE
+
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-stat-table.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-post-table.hh"
+#include "hb-ot-face.hh"
+
+/**
+ * SECTION:hb-style
+ * @title: hb-style
+ * @short_description: Font Styles
+ * @include: hb.h
+ *
+ * Functions for fetching style information from fonts.
+ **/
+
+static inline float
+_hb_angle_to_ratio (float a)
+{
+  return tanf (a * float (M_PI / 180.));
+}
+#if 0
+static inline float
+_hb_ratio_to_angle (float r)
+{
+  return atanf (r) * float (180. / M_PI);
+}
+#endif
+
+/**
+ * hb_style_get_value:
+ * @font: a #hb_font_t object.
+ * @style_tag: a style tag.
+ *
+ * Searches variation axes of a #hb_font_t object for a specific axis first,
+ * if not set, then tries to get default style values from different
+ * tables of the font.
+ *
+ * Returns: Corresponding axis or default value to a style tag.
+ *
+ * Since: 3.0.0
+ **/
+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));
+
+  hb_face_t *face = font->face;
+
+#ifndef HB_NO_VAR
+  hb_ot_var_axis_info_t axis;
+  if (hb_ot_var_find_axis_info (face, style_tag, &axis))
+  {
+    if (axis.axis_index < font->num_coords) return font->design_coords[axis.axis_index];
+    /* If a face is variable, fvar's default_value is better than STAT records */
+    return axis.default_value;
+  }
+#endif
+
+  if (style_tag == HB_STYLE_TAG_OPTICAL_SIZE && font->ptem)
+    return font->ptem;
+
+  /* STAT */
+  float value;
+  if (face->table.STAT->get_value (style_tag, &value))
+    return value;
+
+  switch ((unsigned) style_tag)
+  {
+  case HB_STYLE_TAG_ITALIC:
+    return face->table.OS2->is_italic () || face->table.head->is_italic () ? 1 : 0;
+  case HB_STYLE_TAG_OPTICAL_SIZE:
+  {
+    unsigned int lower, design, upper;
+    return face->table.OS2->v5 ().get_optical_size (&lower, &upper)
+	   ? (float) (lower + upper) / 2.f
+	   : hb_ot_layout_get_size_params (face, &design, nullptr, nullptr, nullptr, nullptr)
+	   ? design / 10.f
+	   : 12.f;
+  }
+  case HB_STYLE_TAG_SLANT_ANGLE:
+    return face->table.post->table->italicAngle.to_float ();
+  case HB_STYLE_TAG_WIDTH:
+    return face->table.OS2->has_data ()
+	   ? face->table.OS2->get_width ()
+	   : (face->table.head->is_condensed () ? 75 :
+	      face->table.head->is_expanded () ? 125 :
+	      100);
+  case HB_STYLE_TAG_WEIGHT:
+    return face->table.OS2->has_data ()
+	   ? face->table.OS2->usWeightClass
+	   : (face->table.head->is_bold () ? 700 : 400);
+  default:
+    return 0;
+  }
+}
+
+#endif
diff --git a/src/hb-style.h b/src/hb-style.h
new file mode 100644
index 0000000..30a6f2b
--- /dev/null
+++ b/src/hb-style.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_STYLE_H
+#define HB_STYLE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/**
+ * hb_style_tag_t:
+ * @HB_STYLE_TAG_ITALIC: Used to vary between non-italic and italic.
+ * A value of 0 can be interpreted as "Roman" (non-italic); a value of 1 can
+ * be interpreted as (fully) italic.
+ * @HB_STYLE_TAG_OPTICAL_SIZE: Used to vary design to suit different text sizes.
+ * Non-zero. Values can be interpreted as text size, in points.
+ * @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.
+ * @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio.
+ * @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.
+ * @HB_STYLE_TAG_WEIGHT: Used to vary stroke thicknesses or other design details
+ * to give variation from lighter to blacker. Values can be interpreted in direct
+ * comparison to values for usWeightClass in the OS/2 table,
+ * or the CSS font-weight property.
+ *
+ * Defined by [OpenType Design-Variation Axis Tag Registry](https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg).
+ *
+ * Since: 3.0.0
+ **/
+typedef enum
+{
+  HB_STYLE_TAG_ITALIC		= HB_TAG ('i','t','a','l'),
+  HB_STYLE_TAG_OPTICAL_SIZE	= HB_TAG ('o','p','s','z'),
+  HB_STYLE_TAG_SLANT_ANGLE	= HB_TAG ('s','l','n','t'),
+  HB_STYLE_TAG_SLANT_RATIO	= HB_TAG ('S','l','n','t'),
+  HB_STYLE_TAG_WIDTH		= HB_TAG ('w','d','t','h'),
+  HB_STYLE_TAG_WEIGHT		= HB_TAG ('w','g','h','t'),
+
+  /*< private >*/
+  _HB_STYLE_TAG_MAX_VALUE	= HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_style_tag_t;
+
+
+HB_EXTERN float
+hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag);
+
+HB_END_DECLS
+
+#endif /* HB_STYLE_H */
diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc
index c9a880a..711b223 100644
--- a/src/hb-subset-cff-common.cc
+++ b/src/hb-subset-cff-common.cc
@@ -38,13 +38,12 @@
 
 using namespace CFF;
 
-/**
- * hb_plan_subset_cff_fdselect
- * Determine an optimal FDSelect format according to a provided plan.
+
+/* Determine an optimal FDSelect format according to a provided plan.
  *
  * Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
  * along with a font index remapping table
- **/
+ */
 
 bool
 hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
@@ -108,7 +107,7 @@
 	fdmap.add (fd);
       hb_set_destroy (set);
       if (unlikely (fdmap.get_population () != subset_fd_count))
-      	return false;
+	return false;
     }
 
     /* update each font dict index stored as "code" in fdselect_ranges */
@@ -158,7 +157,7 @@
 {
   TRACE_SERIALIZE (this);
   FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
-  if (unlikely (p == nullptr)) return_trace (false);
+  if (unlikely (!p)) return_trace (false);
   p->nRanges () = fdselect_ranges.length;
   for (unsigned int i = 0; i < fdselect_ranges.length; i++)
   {
@@ -169,10 +168,7 @@
   return_trace (true);
 }
 
-/**
- * hb_serialize_cff_fdselect
- * Serialize a subset FDSelect format planned above.
- **/
+/* Serialize a subset FDSelect format planned above. */
 bool
 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
 			   const unsigned int num_glyphs,
@@ -184,7 +180,7 @@
 {
   TRACE_SERIALIZE (this);
   FDSelect *p = c->allocate_min<FDSelect> ();
-  if (unlikely (p == nullptr)) return_trace (false);
+  if (unlikely (!p)) return_trace (false);
   p->format = fdselect_format;
   size -= FDSelect::min_size;
 
@@ -194,7 +190,7 @@
   case 0:
   {
     FDSelect0 *p = c->allocate_size<FDSelect0> (size);
-    if (unlikely (p == nullptr)) return_trace (false);
+    if (unlikely (!p)) return_trace (false);
     unsigned int range_index = 0;
     unsigned int fd = fdselect_ranges[range_index++].code;
     for (unsigned int i = 0; i < num_glyphs; i++)
diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh
index 3c66119..7fd96ca 100644
--- a/src/hb-subset-cff-common.hh
+++ b/src/hb-subset-cff-common.hh
@@ -44,7 +44,7 @@
 
   void encode_byte (unsigned char b)
   {
-    if (unlikely (buff.push (b) == &Crap(unsigned char)))
+    if (unlikely (buff.push (b) == &Crap (unsigned char)))
       set_error ();
   }
 
@@ -110,7 +110,11 @@
   void copy_str (const byte_str_t &str)
   {
     unsigned int  offset = buff.length;
-    buff.resize (offset + str.length);
+    if (unlikely (!buff.resize (offset + str.length)))
+    {
+      set_error ();
+      return;
+    }
     if (unlikely (buff.length < offset + str.length))
     {
       set_error ();
@@ -128,26 +132,17 @@
   bool    error;
 };
 
-struct cff_sub_table_offsets_t {
-  cff_sub_table_offsets_t () : privateDictsOffset (0)
+struct cff_sub_table_info_t {
+  cff_sub_table_info_t ()
+    : fd_array_link (0),
+      char_strings_link (0)
   {
-    topDictInfo.init ();
-    FDSelectInfo.init ();
-    FDArrayInfo.init ();
-    charStringsInfo.init ();
-    globalSubrsInfo.init ();
-    localSubrsInfos.init ();
+    fd_select.init ();
   }
 
-  ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); }
-
-  table_info_t     topDictInfo;
-  table_info_t     FDSelectInfo;
-  table_info_t     FDArrayInfo;
-  table_info_t     charStringsInfo;
-  unsigned int  privateDictsOffset;
-  table_info_t     globalSubrsInfo;
-  hb_vector_t<table_info_t>  localSubrsInfos;
+  table_info_t     fd_select;
+  objidx_t     	   fd_array_link;
+  objidx_t     	   char_strings_link;
 };
 
 template <typename OPSTR=op_str_t>
@@ -155,40 +150,26 @@
 {
   bool serialize (hb_serialize_context_t *c,
 		  const OPSTR &opstr,
-		  const cff_sub_table_offsets_t &offsets) const
+		  const cff_sub_table_info_t &info) const
   {
     TRACE_SERIALIZE (this);
 
     switch (opstr.op)
     {
       case OpCode_CharStrings:
-	return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
+	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
 
       case OpCode_FDArray:
-	return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
+	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
 
       case OpCode_FDSelect:
-	return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
+	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
 
       default:
 	return_trace (copy_opstr (c, opstr));
     }
     return_trace (true);
   }
-
-  unsigned int calculate_serialized_size (const OPSTR &opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_CharStrings:
-      case OpCode_FDArray:
-      case OpCode_FDSelect:
-	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-	return opstr.str.length;
-    }
-  }
 };
 
 struct cff_font_dict_op_serializer_t : op_serializer_t
@@ -202,33 +183,17 @@
     if (opstr.op == OpCode_Private)
     {
       /* serialize the private dict size & offset as 2-byte & 4-byte integers */
-      if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) ||
-		    !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
-	return_trace (false);
-
-      /* serialize the opcode */
-      HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-      if (unlikely (p == nullptr)) return_trace (false);
-      *p = OpCode_Private;
-
-      return_trace (true);
+      return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) &&
+		    Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute));
     }
     else
     {
       HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
-      if (unlikely (d == nullptr)) return_trace (false);
+      if (unlikely (!d)) return_trace (false);
       memcpy (d, &opstr.str[0], opstr.str.length);
     }
     return_trace (true);
   }
-
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    if (opstr.op == OpCode_Private)
-      return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
-    else
-      return opstr.str.length;
-  }
 };
 
 struct cff_private_dict_op_serializer_t : op_serializer_t
@@ -238,7 +203,7 @@
 
   bool serialize (hb_serialize_context_t *c,
 		  const op_str_t &opstr,
-		  const unsigned int subrsOffset) const
+		  objidx_t subrs_link) const
   {
     TRACE_SERIALIZE (this);
 
@@ -246,31 +211,15 @@
       return true;
     if (opstr.op == OpCode_Subrs)
     {
-      if (desubroutinize || (subrsOffset == 0))
+      if (desubroutinize || !subrs_link)
 	return_trace (true);
       else
-	return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset));
+	return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
     }
     else
       return_trace (copy_opstr (c, opstr));
   }
 
-  unsigned int calculate_serialized_size (const op_str_t &opstr,
-					  bool has_localsubr=true) const
-  {
-    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
-      return 0;
-    if (opstr.op == OpCode_Subrs)
-    {
-      if (desubroutinize || !has_localsubr)
-	return 0;
-      else
-	return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op);
-    }
-    else
-      return opstr.str.length;
-  }
-
   protected:
   const bool  desubroutinize;
   const bool  drop_hints;
@@ -300,17 +249,20 @@
       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) flat_charstrings[i].push (endchar_op);
-      	continue;
+	/* add an endchar only charstring for a missing glyph if CFF1 */
+	if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
+	continue;
       }
       const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
-      	return false;
+	return false;
       cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
       interp.env.init (str, acc, fd);
-      flatten_param_t  param = { flat_charstrings[i], plan->drop_hints };
+      flatten_param_t  param = {
+        flat_charstrings[i],
+        (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      };
       if (unlikely (!interp.interpret (param)))
 	return false;
     }
@@ -456,7 +408,7 @@
   bool    vsindex_dropped;
   bool    has_prefix_;
   op_code_t	prefix_op_;
-  number_t 	prefix_num_;
+  number_t	prefix_num_;
 
   private:
   typedef parsed_values_t<parsed_cs_op_t> SUPER;
@@ -467,7 +419,8 @@
   void init (unsigned int len_ = 0)
   {
     SUPER::init ();
-    resize (len_);
+    if (unlikely (!resize (len_)))
+      return;
     for (unsigned int i = 0; i < length; i++)
       (*this)[i].init ();
   }
@@ -516,19 +469,19 @@
   template <typename ENV>
   void set_current_str (ENV &env, bool calling)
   {
-    parsed_cs_str_t  *parsed_str = get_parsed_str_for_context (env.context);
-    if (likely (parsed_str != nullptr))
+    parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
+    if (unlikely (!parsed_str))
     {
-      /* If the called subroutine is parsed partially but not completely yet,
-       * it must be because we are calling it recursively.
-       * Handle it as an error. */
-      if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
-      	env.set_error ();
-      else
-      	current_parsed_str = parsed_str;
-    }
-    else
       env.set_error ();
+      return;
+    }
+    /* If the called subroutine is parsed partially but not completely yet,
+     * it must be because we are calling it recursively.
+     * Handle it as an error. */
+    if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
+      env.set_error ();
+    else
+      current_parsed_str = parsed_str;
   }
 
   parsed_cs_str_t	*current_parsed_str;
@@ -583,11 +536,16 @@
 
   void init (unsigned int fdCount)
   {
-    local_remaps.resize (fdCount);
+    if (unlikely (!local_remaps.resize (fdCount))) return;
     for (unsigned int i = 0; i < fdCount; i++)
       local_remaps[i].init ();
   }
 
+  bool in_error()
+  {
+    return local_remaps.in_error ();
+  }
+
   void create (subr_closures_t& closures)
   {
     global_remap.create (closures.global_closure);
@@ -646,10 +604,19 @@
 
     parsed_charstrings.init (plan->num_output_glyphs ());
     parsed_global_subrs.init (acc.globalSubrs->count);
-    parsed_local_subrs.resize (acc.fdCount);
+
+    if (unlikely (remaps.in_error()
+                  || parsed_charstrings.in_error ()
+                  || parsed_global_subrs.in_error ())) {
+      return false;
+    }
+
+    if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
+
     for (unsigned int i = 0; i < acc.fdCount; i++)
     {
       parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
+      if (unlikely (parsed_local_subrs[i].in_error ())) return false;
     }
     if (unlikely (!closures.valid))
       return false;
@@ -659,11 +626,11 @@
     {
       hb_codepoint_t  glyph;
       if (!plan->old_gid_for_new_gid (i, &glyph))
-      	continue;
+	continue;
       const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
-      	return false;
+	return false;
 
       cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
       interp.env.init (str, acc, fd);
@@ -672,16 +639,16 @@
       param.init (&parsed_charstrings[i],
 		  &parsed_global_subrs,  &parsed_local_subrs[fd],
 		  closures.global_closure, closures.local_closures[fd],
-		  plan->drop_hints);
+		  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 
       if (unlikely (!interp.interpret (param)))
 	return false;
 
-      /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
-      SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]);
+      /* 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]);
     }
 
-    if (plan->drop_hints)
+    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++)
@@ -696,7 +663,7 @@
 	param.init (&parsed_charstrings[i],
 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
 		    closures.global_closure, closures.local_closures[fd],
-		    plan->drop_hints);
+                    plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 
 	drop_hints_param_t  drop;
 	if (drop_hints_in_str (parsed_charstrings[i], param, drop))
@@ -721,7 +688,7 @@
 	param.init (&parsed_charstrings[i],
 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
 		    closures.global_closure, closures.local_closures[fd],
-		    plan->drop_hints);
+                    plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
 	collect_subr_refs_in_str (parsed_charstrings[i], param);
       }
     }
@@ -740,13 +707,13 @@
       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;
+	/* 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);
       if (unlikely (fd >= acc.fdCount))
-      	return false;
+	return false;
       if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
 	return false;
     }
@@ -900,11 +867,11 @@
     {
       parsed_cs_op_t  &csop = str.values[pos];
       if (csop.op == OpCode_return)
-      	break;
+	break;
       if (!csop.for_drop ())
       {
-      	drop.all_dropped = false;
-      	break;
+	drop.all_dropped = false;
+	break;
       }
     }
 
@@ -986,7 +953,7 @@
   }
 
   protected:
-  const ACC   			&acc;
+  const ACC			&acc;
   const hb_subset_plan_t	*plan;
 
   subr_closures_t		closures;
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index e9e0757..b4e2412 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -64,29 +64,25 @@
   static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
 };
 
-struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t
+struct cff1_sub_table_info_t : cff_sub_table_info_t
 {
-  cff1_sub_table_offsets_t ()
-    : cff_sub_table_offsets_t (),
-      nameIndexOffset (0),
-      encodingOffset (0)
-  {
-    stringIndexInfo.init ();
-    charsetInfo.init ();
+  cff1_sub_table_info_t ()
+    : cff_sub_table_info_t (),
+      encoding_link (0),
+      charset_link (0)
+   {
     privateDictInfo.init ();
   }
 
-  unsigned int  nameIndexOffset;
-  table_info_t	stringIndexInfo;
-  unsigned int  encodingOffset;
-  table_info_t	charsetInfo;
+  objidx_t	encoding_link;
+  objidx_t	charset_link;
   table_info_t	privateDictInfo;
 };
 
 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
 {
-  void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t))
+  void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t))
   {
     SUPER::init ();
     base = base_;
@@ -117,13 +113,13 @@
 
 struct top_dict_modifiers_t
 {
-  top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_,
-			   const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
-    : offsets (offsets_),
+  top_dict_modifiers_t (const cff1_sub_table_info_t &info_,
+			const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
+    : info (info_),
       nameSIDs (nameSIDs_)
   {}
 
-  const cff1_sub_table_offsets_t &offsets;
+  const cff1_sub_table_info_t &info;
   const unsigned int	(&nameSIDs)[name_dict_values_t::ValCount];
 };
 
@@ -139,22 +135,20 @@
     switch (op)
     {
       case OpCode_charset:
-	return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset));
+	if (mod.info.charset_link)
+	  return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute));
+	else
+	  goto fall_back;
 
       case OpCode_Encoding:
-	return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset));
+	if (mod.info.encoding_link)
+	  return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute));
+	else
+	  goto fall_back;
 
       case OpCode_Private:
-	{
-	  if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size)))
-	    return_trace (false);
-	  if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset)))
-	    return_trace (false);
-	  HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-	  if (unlikely (p == nullptr)) return_trace (false);
-	  *p = OpCode_Private;
-	}
-	break;
+	return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) &&
+		      Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute));
 
       case OpCode_version:
       case OpCode_Notice:
@@ -165,7 +159,7 @@
       case OpCode_PostScript:
       case OpCode_BaseFontName:
       case OpCode_FontName:
-	return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
+	return_trace (FontDict::serialize_int2_op (c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
 
       case OpCode_ROS:
 	{
@@ -180,86 +174,29 @@
 			UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
 			copy_opstr (c, supp_op));
 	}
+      fall_back:
       default:
-	return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets));
+	return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info));
     }
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const
-  {
-    op_code_t op = opstr.op;
-    switch (op)
-    {
-      case OpCode_charset:
-      case OpCode_Encoding:
-	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
-
-      case OpCode_Private:
-	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
-
-      case OpCode_version:
-      case OpCode_Notice:
-      case OpCode_Copyright:
-      case OpCode_FullName:
-      case OpCode_FamilyName:
-      case OpCode_Weight:
-      case OpCode_PostScript:
-      case OpCode_BaseFontName:
-      case OpCode_FontName:
-	return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
-
-      case OpCode_ROS:
-	return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */;
-
-      default:
-	return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr);
-    }
-  }
-};
-
-struct font_dict_values_mod_t
-{
-  void init (const cff1_font_dict_values_t *base_,
-	     unsigned int fontName_,
-	     const table_info_t &privateDictInfo_)
-  {
-    base = base_;
-    fontName = fontName_;
-    privateDictInfo = privateDictInfo_;
-  }
-
-  unsigned get_count () const { return base->get_count (); }
-
-  const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
-
-  const cff1_font_dict_values_t    *base;
-  table_info_t		   privateDictInfo;
-  unsigned int		fontName;
 };
 
 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
 {
   bool serialize (hb_serialize_context_t *c,
 		  const op_str_t &opstr,
-		  const font_dict_values_mod_t &mod) const
+		  const cff1_font_dict_values_mod_t &mod) const
   {
     TRACE_SERIALIZE (this);
 
     if (opstr.op == OpCode_FontName)
-      return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName));
+      return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName));
     else
       return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
   }
 
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    if (opstr.op == OpCode_FontName)
-      return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
-    else
-      return SUPER::calculate_serialized_size (opstr);
-  }
-
   private:
   typedef cff_font_dict_op_serializer_t SUPER;
 };
@@ -331,7 +268,7 @@
 struct range_list_t : hb_vector_t<code_pair_t>
 {
   /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
-  bool finalize (unsigned int last_glyph)
+  bool complete (unsigned int last_glyph)
   {
     bool  two_byte = false;
     for (unsigned int i = (*this).length; i > 0; i--)
@@ -402,7 +339,7 @@
   cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
     : subr_subsetter_t (acc_, plan_) {}
 
-  static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
+  static void complete_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
   {
     /* insert width at the beginning of the charstring as necessary */
     if (env.has_width)
@@ -414,8 +351,8 @@
     param.current_parsed_str->set_parsed ();
     for (unsigned int i = 0; i < env.callStack.get_count (); i++)
     {
-      parsed_cs_str_t  *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
-      if (likely (parsed_str != nullptr))
+      parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
+      if (likely (parsed_str))
 	parsed_str->set_parsed ();
       else
 	env.set_error ();
@@ -425,16 +362,13 @@
 
 struct cff_subset_plan {
   cff_subset_plan ()
-    : final_size (0),
-      offsets (),
+    : info (),
       orig_fdcount (0),
       subset_fdcount (1),
       subset_fdselect_format (0),
       drop_hints (false),
       desubroutinize(false)
   {
-    topdict_sizes.init ();
-    topdict_sizes.resize (1);
     topdict_mod.init ();
     subset_fdselect_ranges.init ();
     fdmap.init ();
@@ -452,7 +386,6 @@
 
   ~cff_subset_plan ()
   {
-    topdict_sizes.fini ();
     topdict_mod.fini ();
     subset_fdselect_ranges.fini ();
     fdmap.fini ();
@@ -466,15 +399,19 @@
     sidmap.fini ();
   }
 
-  unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+  void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
   {
     const Encoding *encoding = acc.encoding;
-    unsigned int  size0, size1, supp_size;
+    unsigned int  size0, size1;
     hb_codepoint_t  code, last_code = CFF_UNDEF_CODE;
     hb_vector_t<hb_codepoint_t> supp_codes;
 
-    subset_enc_code_ranges.resize (0);
-    supp_size = 0;
+    if (unlikely (!subset_enc_code_ranges.resize (0)))
+    {
+      plan->check_success (false);
+      return;
+    }
+
     supp_codes.init ();
 
     subset_enc_num_codes = plan->num_output_glyphs () - 1;
@@ -484,7 +421,7 @@
       hb_codepoint_t  old_glyph;
       if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
       {
-      	/* Retain the code for the old missing glyph ID */
+	/* Retain the code for the old missing glyph ID */
 	old_glyph = glyph;
       }
       code = acc.glyph_to_code (old_glyph);
@@ -501,7 +438,7 @@
       }
       last_code = code;
 
-      if (encoding != &Null(Encoding))
+      if (encoding != &Null (Encoding))
       {
 	hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph);
 	encoding->get_supplement_codes (sid, supp_codes);
@@ -510,12 +447,11 @@
 	  code_pair_t pair = { supp_codes[i], sid };
 	  subset_enc_supp_codes.push (pair);
 	}
-	supp_size += SuppEncoding::static_size * supp_codes.length;
       }
     }
     supp_codes.fini ();
 
-    subset_enc_code_ranges.finalize (glyph);
+    subset_enc_code_ranges.complete (glyph);
 
     assert (subset_enc_num_codes <= 0xFF);
     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
@@ -525,26 +461,26 @@
       subset_enc_format = 0;
     else
       subset_enc_format = 1;
-
-    return Encoding::calculate_serialized_size (
-			subset_enc_format,
-			subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes,
-			subset_enc_supp_codes.length);
   }
 
-  unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+  void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
   {
     unsigned int  size0, size_ranges;
     hb_codepoint_t  sid, last_sid = CFF_UNDEF_CODE;
 
-    subset_charset_ranges.resize (0);
+    if (unlikely (!subset_charset_ranges.resize (0)))
+    {
+      plan->check_success (false);
+      return;
+    }
+
     unsigned int glyph;
     for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
     {
       hb_codepoint_t  old_glyph;
       if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
       {
-      	/* Retain the SID for the old missing glyph ID */
+	/* Retain the SID for the old missing glyph ID */
 	old_glyph = glyph;
       }
       sid = acc.glyph_to_sid (old_glyph);
@@ -560,7 +496,7 @@
       last_sid = sid;
     }
 
-    bool two_byte = subset_charset_ranges.finalize (glyph);
+    bool two_byte = subset_charset_ranges.complete (glyph);
 
     size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
     if (!two_byte)
@@ -574,10 +510,6 @@
       subset_charset_format = 1;
     else
       subset_charset_format = 2;
-
-    return Charset::calculate_serialized_size (
-			subset_charset_format,
-			subset_charset_format? subset_charset_ranges.length: plan->num_output_glyphs ());
   }
 
   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
@@ -594,7 +526,7 @@
       }
     }
 
-    if (acc.fdArray != &Null(CFF1FDArray))
+    if (acc.fdArray != &Null (CFF1FDArray))
       for (unsigned int i = 0; i < orig_fdcount; i++)
 	if (fdmap.has (i))
 	  (void)sidmap.add (acc.fontDicts[i].fontName);
@@ -609,18 +541,17 @@
     hb_codepoint_t old_glyph;
     if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
 
-    final_size = 0;
     num_glyphs = plan->num_output_glyphs ();
     orig_fdcount = acc.fdCount;
-    drop_hints = plan->drop_hints;
-    desubroutinize = plan->desubroutinize;
+    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;
+	continue;
       if (new_glyph != old_glyph) {
 	gid_renum = true;
 	break;
@@ -630,13 +561,6 @@
     subset_charset = gid_renum || !acc.is_predef_charset ();
     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
 
-    /* CFF header */
-    final_size += OT::cff1::static_size;
-
-    /* Name INDEX */
-    offsets.nameIndexOffset = final_size;
-    final_size += acc.nameIndex->get_size ();
-
     /* top dict INDEX */
     {
       /* Add encoding/charset to a (copy of) top dict as necessary */
@@ -650,25 +574,16 @@
 	if (need_to_add_set)
 	  topdict_mod.add_op (OpCode_charset);
       }
-      offsets.topDictInfo.offset = final_size;
-      cff1_top_dict_op_serializer_t topSzr;
-      unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
-      offsets.topDictInfo.offSize = calcOffSize(topDictSize);
-      if (unlikely (offsets.topDictInfo.offSize > 4))
-      	return false;
-      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t>
-						(offsets.topDictInfo.offSize,
-						 &topdict_mod, 1, topdict_sizes, topSzr);
     }
 
     /* Determine re-mapping of font index as fdmap among other info */
-    if (acc.fdSelect != &Null(CFF1FDSelect))
+    if (acc.fdSelect != &Null (CFF1FDSelect))
     {
 	if (unlikely (!hb_plan_subset_cff_fdselect (plan,
 				  orig_fdcount,
 				  *acc.fdSelect,
 				  subset_fdcount,
-				  offsets.FDSelectInfo.size,
+				  info.fd_select.size,
 				  subset_fdselect_format,
 				  subset_fdselect_ranges,
 				  fdmap)))
@@ -683,20 +598,13 @@
       if (unlikely (!collect_sids_in_dicts (acc)))
 	return false;
       if (unlikely (sidmap.get_population () > 0x8000))	/* assumption: a dict won't reference that many strings */
-      	return false;
-      if (subset_charset)
-	offsets.charsetInfo.size = plan_subset_charset (acc, plan);
+	return false;
+
+      if (subset_charset) plan_subset_charset (acc, plan);
 
       topdict_mod.reassignSIDs (sidmap);
     }
 
-    /* String INDEX */
-    {
-      offsets.stringIndexInfo.offset = final_size;
-      offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
-      final_size += offsets.stringIndexInfo.size;
-    }
-
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
@@ -704,9 +612,6 @@
 		    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
 	return false;
-
-      /* no global/local subroutines */
-      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0);
     }
     else
     {
@@ -723,131 +628,48 @@
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
 	return false;
 
-      /* global subrs */
-      unsigned int dataSize = subset_globalsubrs.total_size ();
-      offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
-      if (unlikely (offsets.globalSubrsInfo.offSize > 4))
-      	return false;
-      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
-
       /* local subrs */
-      if (!offsets.localSubrsInfos.resize (orig_fdcount))
-	return false;
       if (!subset_localsubrs.resize (orig_fdcount))
 	return false;
       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
       {
 	subset_localsubrs[fd].init ();
-	offsets.localSubrsInfos[fd].init ();
 	if (fdmap.has (fd))
 	{
 	  if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
 	    return false;
-
-	  unsigned int dataSize = subset_localsubrs[fd].total_size ();
-	  if (dataSize > 0)
-	  {
-	    offsets.localSubrsInfos[fd].offset = final_size;
-	    offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-	    if (unlikely (offsets.localSubrsInfos[fd].offSize > 4))
-	      return false;
-	    offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
-	  }
 	}
       }
     }
 
-    /* global subrs */
-    offsets.globalSubrsInfo.offset = final_size;
-    final_size += offsets.globalSubrsInfo.size;
-
     /* Encoding */
-    if (!subset_encoding)
-      offsets.encodingOffset = acc.topDict.EncodingOffset;
-    else
-    {
-      offsets.encodingOffset = final_size;
-      final_size += plan_subset_encoding (acc, plan);
-    }
-
-    /* Charset */
-    if (!subset_charset && acc.is_predef_charset ())
-      offsets.charsetInfo.offset = acc.topDict.CharsetOffset;
-    else
-      offsets.charsetInfo.offset = final_size;
-    final_size += offsets.charsetInfo.size;
-
-    /* FDSelect */
-    if (acc.fdSelect != &Null(CFF1FDSelect))
-    {
-      offsets.FDSelectInfo.offset = final_size;
-      final_size += offsets.FDSelectInfo.size;
-    }
-
-    /* FDArray (FDIndex) */
-    if (acc.fdArray != &Null(CFF1FDArray)) {
-      offsets.FDArrayInfo.offset = final_size;
-      cff1_font_dict_op_serializer_t fontSzr;
-      unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
-	if (fdmap.has (i))
-	  dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
-
-      offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
-      if (unlikely (offsets.FDArrayInfo.offSize > 4))
-      	return false;
-      final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
-    }
-
-    /* CharStrings */
-    {
-      offsets.charStringsInfo.offset = final_size;
-      unsigned int dataSize = subset_charstrings.total_size ();
-      offsets.charStringsInfo.offSize = calcOffSize (dataSize);
-      if (unlikely (offsets.charStringsInfo.offSize > 4))
-      	return false;
-      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
-    }
+    if (subset_encoding)
+      plan_subset_encoding (acc, plan);
 
     /* private dicts & local subrs */
-    offsets.privateDictInfo.offset = final_size;
-    for (unsigned int i = 0; i < orig_fdcount; i++)
-    {
-      if (fdmap.has (i))
-      {
-	bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-	cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints);
-	unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-	table_info_t  privInfo = { final_size, priv_size, 0 };
-	font_dict_values_mod_t fontdict_mod;
-	if (!acc.is_CID ())
-	  fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo );
-	else
-	  fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
-	fontdicts_mod.push (fontdict_mod);
-	final_size += privInfo.size;
-
-	if (!plan->desubroutinize && has_localsubrs)
-	{
-	  offsets.localSubrsInfos[i].offset = final_size;
-	  final_size += offsets.localSubrsInfos[i].size;
-	}
-      }
-    }
-
     if (!acc.is_CID ())
-      offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
+      fontdicts_mod.push (cff1_font_dict_values_mod_t ());
+    else
+    {
+      + hb_iter (acc.fontDicts)
+      | hb_filter ([&] (const cff1_font_dict_values_t &_)
+	{ return fdmap.has (&_ - &acc.fontDicts[0]); } )
+      | hb_map ([&] (const cff1_font_dict_values_t &_)
+	{
+	  cff1_font_dict_values_mod_t mod;
+	  mod.init (&_, sidmap[_.fontName]);
+	  return mod;
+	})
+      | hb_sink (fontdicts_mod)
+      ;
+    }
 
     return ((subset_charstrings.length == plan->num_output_glyphs ())
 	   && (fontdicts_mod.length == subset_fdcount));
   }
 
-  unsigned int get_final_size () const  { return final_size; }
-
-  unsigned int	      final_size;
-  hb_vector_t<unsigned int>	topdict_sizes;
   cff1_top_dict_values_mod_t	topdict_mod;
-  cff1_sub_table_offsets_t	offsets;
+  cff1_sub_table_info_t		info;
 
   unsigned int    num_glyphs;
   unsigned int    orig_fdcount;
@@ -862,7 +684,7 @@
   str_buff_vec_t		subset_charstrings;
   str_buff_vec_t		subset_globalsubrs;
   hb_vector_t<str_buff_vec_t>	subset_localsubrs;
-  hb_vector_t<font_dict_values_mod_t>  fontdicts_mod;
+  hb_vector_t<cff1_font_dict_values_mod_t>  fontdicts_mod;
 
   bool		drop_hints;
 
@@ -883,16 +705,166 @@
   bool		desubroutinize;
 };
 
-static inline bool _write_cff1 (const cff_subset_plan &plan,
-				const OT::cff1::accelerator_subset_t  &acc,
-				unsigned int num_glyphs,
-				unsigned int dest_sz,
-				void *dest)
+static bool _serialize_cff1 (hb_serialize_context_t *c,
+			     cff_subset_plan &plan,
+			     const OT::cff1::accelerator_subset_t  &acc,
+			     unsigned int num_glyphs)
 {
-  hb_serialize_context_t c (dest, dest_sz);
+  /* private dicts & local subrs */
+  for (int i = (int)acc.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])))
+	  subrs_link = c->pop_pack ();
+	else
+	{
+	  c->pop_discard ();
+	  return false;
+	}
+      }
 
-  OT::cff1 *cff = c.start_serialize<OT::cff1> ();
-  if (unlikely (!c.extend_min (*cff)))
+      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);
+      /* 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)))
+      {
+	unsigned fd = plan.fdmap[i];
+	plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
+	plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack ();
+      }
+      else
+      {
+	c->pop_discard ();
+	return false;
+      }
+    }
+  }
+
+  if (!acc.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 ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* FDArray (FD Index) */
+  if (acc.fdArray != &Null (CFF1FDArray))
+  {
+    CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
+    if (unlikely (!fda)) return false;
+    c->push ();
+    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)))
+      plan.info.fd_array_link = c->pop_pack (false);
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* FDSelect */
+  if (acc.fdSelect != &Null (CFF1FDSelect))
+  {
+    c->push ();
+    if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
+					   plan.subset_fdselect_format, plan.info.fd_select.size,
+					   plan.subset_fdselect_ranges)))
+      plan.info.fd_select.link = c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* Charset */
+  if (plan.subset_charset)
+  {
+    Charset *dest = c->start_embed<Charset> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c,
+				 plan.subset_charset_format,
+				 plan.num_glyphs,
+				 plan.subset_charset_ranges)))
+      plan.info.charset_link = c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* Encoding */
+  if (plan.subset_encoding)
+  {
+    Encoding *dest = c->start_embed<Encoding> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c,
+				 plan.subset_enc_format,
+				 plan.subset_enc_num_codes,
+				 plan.subset_enc_code_ranges,
+				 plan.subset_enc_supp_codes)))
+      plan.info.encoding_link = c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* global subrs */
+  {
+    c->push ();
+    CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
+    if (unlikely (!dest)) return false;
+    if (likely (dest->serialize (c, plan.subset_globalsubrs)))
+      c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* String INDEX */
+  {
+    CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
+      c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  OT::cff1 *cff = c->allocate_min<OT::cff1> ();
+  if (unlikely (!cff))
     return false;
 
   /* header */
@@ -902,222 +874,55 @@
   cff->offSize = 4; /* unused? */
 
   /* name INDEX */
-  {
-    assert (cff->nameIndex == (unsigned) (c.head - c.start));
-    CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
-      return false;
-    }
-  }
+  if (unlikely (!(*acc.nameIndex).copy (c))) return false;
 
   /* top dict INDEX */
   {
-    assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
-    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict>> ();
-    if (dest == nullptr) return false;
+    /* serialize singleton TopDict */
+    TopDict *top = c->start_embed<TopDict> ();
+    if (!top) return false;
+    c->push ();
     cff1_top_dict_op_serializer_t topSzr;
-    top_dict_modifiers_t  modifier (plan.offsets, plan.topDictModSIDs);
-    if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
-				    &plan.topdict_mod, 1,
-				    plan.topdict_sizes, topSzr, modifier)))
+    unsigned top_size = 0;
+    top_dict_modifiers_t  modifier (plan.info, plan.topDictModSIDs);
+    if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier)))
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
+      top_size = c->length ();
+      c->pop_pack (false);
+    }
+    else
+    {
+      c->pop_discard ();
       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)));
   }
-
-  /* String INDEX */
-  {
-    assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
-    CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
-      return false;
-    }
-  }
-
-  /* global subrs */
-  {
-    assert (plan.offsets.globalSubrsInfo.offset != 0);
-    assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
-
-    CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
-      return false;
-    }
-  }
-
-  /* Encoding */
-  if (plan.subset_encoding)
-  {
-    assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
-    Encoding *dest = c.start_embed<Encoding> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c,
-				    plan.subset_enc_format,
-				    plan.subset_enc_num_codes,
-				    plan.subset_enc_code_ranges,
-				    plan.subset_enc_supp_codes)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
-      return false;
-    }
-  }
-
-  /* Charset */
-  if (plan.subset_charset)
-  {
-    assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
-    Charset *dest = c.start_embed<Charset> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c,
-				    plan.subset_charset_format,
-				    plan.num_glyphs,
-				    plan.subset_charset_ranges)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
-      return false;
-    }
-  }
-
-  /* FDSelect */
-  if (acc.fdSelect != &Null(CFF1FDSelect))
-  {
-    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
-
-    if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *acc.fdSelect, acc.fdCount,
-					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
-					      plan.subset_fdselect_ranges)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
-      return false;
-    }
-  }
-
-  /* FDArray (FD Index) */
-  if (acc.fdArray != &Null(CFF1FDArray))
-  {
-    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
-    CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
-    if (unlikely (fda == nullptr)) return false;
-    cff1_font_dict_op_serializer_t  fontSzr;
-    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
-				   plan.fontdicts_mod,
-				   fontSzr)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
-      return false;
-    }
-  }
-
-  /* CharStrings */
-  {
-    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
-    CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
-    if (unlikely (cs == nullptr)) return false;
-    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
-      return false;
-    }
-  }
-
-  /* private dicts & local subrs */
-  assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
-  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
-  {
-    if (plan.fdmap.has (i))
-    {
-      PrivateDict  *pd = c.start_embed<PrivateDict> ();
-      if (unlikely (pd == nullptr)) return false;
-      unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
-      bool result;
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
-      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
-      result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
-      if (unlikely (!result))
-      {
-	DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
-	return false;
-      }
-      if (plan.offsets.localSubrsInfos[i].size > 0)
-      {
-	CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
-	if (unlikely (dest == nullptr)) return false;
-	if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
-	{
-	  DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
-	  return false;
-	}
-      }
-    }
-  }
-
-  assert (c.head == c.end);
-  c.end_serialize ();
-
-  return true;
 }
 
-static inline bool
+static bool
 _hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
-		const char		*data,
-		hb_subset_plan_t	*plan,
-		hb_blob_t		**prime /* OUT */)
+		hb_subset_context_t	*c)
 {
   cff_subset_plan cff_plan;
 
-  if (unlikely (!cff_plan.create (acc, plan)))
+  if (unlikely (!cff_plan.create (acc, c->plan)))
   {
     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
     return false;
   }
 
-  unsigned int  cff_prime_size = cff_plan.get_final_size ();
-  char *cff_prime_data = (char *) calloc (1, cff_prime_size);
-
-  if (unlikely (!_write_cff1 (cff_plan, acc, plan->num_output_glyphs (),
-			      cff_prime_size, cff_prime_data))) {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
-    free (cff_prime_data);
-    return false;
-  }
-
-  *prime = hb_blob_create (cff_prime_data,
-			   cff_prime_size,
-			   HB_MEMORY_MODE_READONLY,
-			   cff_prime_data,
-			   free);
-  return true;
+  return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
 }
 
-/**
- * hb_subset_cff1:
- * Subsets the CFF table according to a provided plan.
- *
- * Return value: subsetted cff table.
- **/
 bool
-hb_subset_cff1 (hb_subset_plan_t *plan,
-		hb_blob_t       **prime /* OUT */)
+hb_subset_cff1 (hb_subset_context_t *c)
 {
-  hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
-  const char *data = hb_blob_get_data(cff_blob, nullptr);
-
   OT::cff1::accelerator_subset_t acc;
-  acc.init(plan->source);
-  bool result = likely (acc.is_valid ()) &&
-			_hb_subset_cff1 (acc, data, plan, prime);
-  hb_blob_destroy (cff_blob);
+  acc.init (c->plan->source);
+  bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
   acc.fini ();
 
   return result;
diff --git a/src/hb-subset-cff1.hh b/src/hb-subset-cff1.hh
index 1ec8678..aaf5def 100644
--- a/src/hb-subset-cff1.hh
+++ b/src/hb-subset-cff1.hh
@@ -32,7 +32,6 @@
 #include "hb-subset-plan.hh"
 
 HB_INTERNAL bool
-hb_subset_cff1 (hb_subset_plan_t *plan,
-	       hb_blob_t	**cff_prime /* OUT */);
+hb_subset_cff1 (hb_subset_context_t *c);
 
 #endif /* HB_SUBSET_CFF1_HH */
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 7edc3f5..896ae64 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -38,43 +38,31 @@
 
 using namespace CFF;
 
-struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t
+struct cff2_sub_table_info_t : cff_sub_table_info_t
 {
-  cff2_sub_table_offsets_t ()
-    : cff_sub_table_offsets_t (),
-      varStoreOffset (0)
+  cff2_sub_table_info_t ()
+    : cff_sub_table_info_t (),
+      var_store_link (0)
   {}
 
-  unsigned int  varStoreOffset;
+  objidx_t  var_store_link;
 };
 
 struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
 {
   bool serialize (hb_serialize_context_t *c,
 		  const op_str_t &opstr,
-		  const cff2_sub_table_offsets_t &offsets) const
+		  const cff2_sub_table_info_t &info) const
   {
     TRACE_SERIALIZE (this);
 
     switch (opstr.op)
     {
       case OpCode_vstore:
-	return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
+	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link));
 
       default:
-	return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets));
-    }
-  }
-
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_vstore:
-	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-	return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr);
+	return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info));
     }
   }
 };
@@ -116,8 +104,8 @@
       const blend_arg_t &arg = env.argStack[i];
       if (arg.blending ())
       {
-      	if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues))))
-      	{
+	if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues))))
+	{
 	  env.set_error ();
 	  return;
 	}
@@ -144,8 +132,8 @@
       if (unlikely (!((arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
 	      (arg1.deltas.length == env.get_region_count ())))))
       {
-      	env.set_error ();
-      	return;
+	env.set_error ();
+	return;
       }
       encoder.encode_num (arg1);
     }
@@ -232,7 +220,7 @@
   cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
     : subr_subsetter_t (acc_, plan_) {}
 
-  static void finalize_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 &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 ())
@@ -246,9 +234,9 @@
 
 struct cff2_subset_plan {
   cff2_subset_plan ()
-    : final_size (0),
-      orig_fdcount (0),
+    : orig_fdcount (0),
       subset_fdcount(1),
+      subset_fdselect_size (0),
       subset_fdselect_format (0),
       drop_hints (false),
       desubroutinize (false)
@@ -258,7 +246,6 @@
     subset_charstrings.init ();
     subset_globalsubrs.init ();
     subset_localsubrs.init ();
-    privateDictInfos.init ();
   }
 
   ~cff2_subset_plan ()
@@ -268,27 +255,15 @@
     subset_charstrings.fini_deep ();
     subset_globalsubrs.fini_deep ();
     subset_localsubrs.fini_deep ();
-    privateDictInfos.fini ();
   }
 
   bool create (const OT::cff2::accelerator_subset_t &acc,
 	      hb_subset_plan_t *plan)
   {
-    final_size = 0;
     orig_fdcount = acc.fdArray->count;
 
-    drop_hints = plan->drop_hints;
-    desubroutinize = plan->desubroutinize;
-
-    /* CFF2 header */
-    final_size += OT::cff2::static_size;
-
-    /* top dict */
-    {
-      cff2_top_dict_op_serializer_t topSzr;
-      offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr);
-      final_size += offsets.topDictInfo.size;
-    }
+    drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
+    desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
 
     if (desubroutinize)
     {
@@ -297,9 +272,6 @@
 		    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
 	return false;
-
-      /* no global/local subroutines */
-      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0);
     }
     else
     {
@@ -316,115 +288,41 @@
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
 	return false;
 
-      /* global subrs */
-      unsigned int dataSize = subset_globalsubrs.total_size ();
-      offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
-      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
-
       /* local subrs */
-      if (!offsets.localSubrsInfos.resize (orig_fdcount))
-	return false;
       if (!subset_localsubrs.resize (orig_fdcount))
 	return false;
       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
       {
 	subset_localsubrs[fd].init ();
-	offsets.localSubrsInfos[fd].init ();
 	if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
 	  return false;
-
-	unsigned int dataSize = subset_localsubrs[fd].total_size ();
-	if (dataSize > 0)
-	{
-	  offsets.localSubrsInfos[fd].offset = final_size;
-	  offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-	  offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
-	}
       }
     }
 
-    /* global subrs */
-    offsets.globalSubrsInfo.offset = final_size;
-    final_size += offsets.globalSubrsInfo.size;
-
-    /* variation store */
-    if (acc.varStore != &Null(CFF2VariationStore))
-    {
-      offsets.varStoreOffset = final_size;
-      final_size += acc.varStore->get_size ();
-    }
-
     /* FDSelect */
-    if (acc.fdSelect != &Null(CFF2FDSelect))
+    if (acc.fdSelect != &Null (CFF2FDSelect))
     {
-      offsets.FDSelectInfo.offset = final_size;
       if (unlikely (!hb_plan_subset_cff_fdselect (plan,
-				  orig_fdcount,
-				  *(const FDSelect *)acc.fdSelect,
-				  subset_fdcount,
-				  offsets.FDSelectInfo.size,
-				  subset_fdselect_format,
-				  subset_fdselect_ranges,
-				  fdmap)))
+						  orig_fdcount,
+						  *(const FDSelect *)acc.fdSelect,
+						  subset_fdcount,
+						  subset_fdselect_size,
+						  subset_fdselect_format,
+						  subset_fdselect_ranges,
+						  fdmap)))
 	return false;
-
-      final_size += offsets.FDSelectInfo.size;
     }
     else
       fdmap.identity (1);
 
-    /* FDArray (FDIndex) */
-    {
-      offsets.FDArrayInfo.offset = final_size;
-      cff_font_dict_op_serializer_t fontSzr;
-      unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
-	if (fdmap.has (i))
-	  dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
-
-      offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
-      final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
-    }
-
-    /* CharStrings */
-    {
-      offsets.charStringsInfo.offset = final_size;
-      unsigned int dataSize = subset_charstrings.total_size ();
-      offsets.charStringsInfo.offSize = calcOffSize (dataSize);
-      final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
-    }
-
-    /* private dicts & local subrs */
-    offsets.privateDictsOffset = final_size;
-    for (unsigned int i = 0; i < orig_fdcount; i++)
-    {
-      if (fdmap.has (i))
-      {
-	bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-	cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints);
-	unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-	table_info_t  privInfo = { final_size, priv_size, 0 };
-	privateDictInfos.push (privInfo);
-	final_size += privInfo.size;
-
-	if (!plan->desubroutinize && has_localsubrs)
-	{
-	  offsets.localSubrsInfos[i].offset = final_size;
-	  final_size += offsets.localSubrsInfos[i].size;
-	}
-      }
-    }
-
     return true;
   }
 
-  unsigned int get_final_size () const  { return final_size; }
-
-  unsigned int	final_size;
-  cff2_sub_table_offsets_t offsets;
+  cff2_sub_table_info_t info;
 
   unsigned int    orig_fdcount;
   unsigned int    subset_fdcount;
+  unsigned int	  subset_fdselect_size;
   unsigned int    subset_fdselect_format;
   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
 
@@ -433,23 +331,113 @@
   str_buff_vec_t	    subset_charstrings;
   str_buff_vec_t	    subset_globalsubrs;
   hb_vector_t<str_buff_vec_t> subset_localsubrs;
-  hb_vector_t<table_info_t>  privateDictInfos;
 
   bool	    drop_hints;
   bool	    desubroutinize;
 };
 
-static inline bool _write_cff2 (const cff2_subset_plan &plan,
-				const OT::cff2::accelerator_subset_t  &acc,
-				unsigned int num_glyphs,
-				unsigned int dest_sz,
-				void *dest)
+static bool _serialize_cff2 (hb_serialize_context_t *c,
+			     cff2_subset_plan &plan,
+			     const OT::cff2::accelerator_subset_t  &acc,
+			     unsigned int num_glyphs)
 {
-  hb_serialize_context_t c (dest, dest_sz);
+  /* private dicts & local subrs */
+  hb_vector_t<table_info_t>  private_dict_infos;
+  if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
 
-  OT::cff2 *cff2 = c.start_serialize<OT::cff2> ();
-  if (unlikely (!c.extend_min (*cff2)))
-    return false;
+  for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+  {
+    if (plan.fdmap.has (i))
+    {
+      objidx_t	subrs_link = 0;
+
+      if (plan.subset_localsubrs[i].length > 0)
+      {
+	CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
+	if (unlikely (!dest)) return false;
+	c->push ();
+	if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
+	  subrs_link = c->pop_pack ();
+	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)))
+      {
+	unsigned fd = plan.fdmap[i];
+	private_dict_infos[fd].size = c->length ();
+	private_dict_infos[fd].link = c->pop_pack ();
+      }
+      else
+      {
+	c->pop_discard ();
+	return false;
+      }
+    }
+  }
+
+  /* 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 ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* FDSelect */
+  if (acc.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)))
+      plan.info.fd_select.link = c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  /* FDArray (FD Index) */
+  {
+    c->push ();
+    CFF2FDArray *fda = c->start_embed<CFF2FDArray> ();
+    if (unlikely (!fda)) return false;
+    cff_font_dict_op_serializer_t fontSzr;
+    auto it =
+    + hb_zip (+ hb_iter (acc.fontDicts)
+	      | hb_filter ([&] (const cff2_font_dict_values_t &_)
+		{ return plan.fdmap.has (&_ - &acc.fontDicts[0]); }),
+	      hb_iter (private_dict_infos))
+    ;
+    if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
+    plan.info.fd_array_link = c->pop_pack ();
+  }
+
+  /* variation store */
+  if (acc.varStore != &Null (CFF2VariationStore))
+  {
+    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 ();
+  }
+
+  OT::cff2 *cff2 = c->allocate_min<OT::cff2> ();
+  if (unlikely (!cff2)) return false;
 
   /* header */
   cff2->version.major = 0x02;
@@ -458,175 +446,39 @@
 
   /* top dict */
   {
-    assert (cff2->topDict == (unsigned) (c.head - c.start));
-    cff2->topDictSize = plan.offsets.topDictInfo.size;
     TopDict &dict = cff2 + cff2->topDict;
     cff2_top_dict_op_serializer_t topSzr;
-    if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
-      return false;
-    }
+    if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false;
+    cff2->topDictSize = c->head - (const char *)&dict;
   }
 
   /* global subrs */
   {
-    assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
-    CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
-      return false;
-    }
+    CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
+    if (unlikely (!dest)) return false;
+    return dest->serialize (c, plan.subset_globalsubrs);
   }
-
-  /* variation store */
-  if (acc.varStore != &Null(CFF2VariationStore))
-  {
-    assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
-    CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
-    if (unlikely (!dest->serialize (&c, acc.varStore)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store");
-      return false;
-    }
-  }
-
-  /* FDSelect */
-  if (acc.fdSelect != &Null(CFF2FDSelect))
-  {
-    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
-
-    if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
-					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
-					      plan.subset_fdselect_ranges)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect");
-      return false;
-    }
-  }
-
-  /* FDArray (FD Index) */
-  {
-    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
-    CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
-    if (unlikely (fda == nullptr)) return false;
-    cff_font_dict_op_serializer_t  fontSzr;
-    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
-				   acc.fontDicts, plan.subset_fdcount, plan.fdmap,
-				   fontSzr, plan.privateDictInfos)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
-      return false;
-    }
-  }
-
-  /* CharStrings */
-  {
-    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
-    CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
-    if (unlikely (cs == nullptr)) return false;
-    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings");
-      return false;
-    }
-  }
-
-  /* private dicts & local subrs */
-  assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
-  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
-  {
-    if (plan.fdmap.has (i))
-    {
-      PrivateDict  *pd = c.start_embed<PrivateDict> ();
-      if (unlikely (pd == nullptr)) return false;
-      unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
-      bool result;
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
-      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
-      result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
-      if (unlikely (!result))
-      {
-	DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
-	return false;
-      }
-      if (plan.offsets.localSubrsInfos[i].size > 0)
-      {
-	CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
-	if (unlikely (dest == nullptr)) return false;
-	if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
-	{
-	  DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
-	  return false;
-	}
-      }
-    }
-  }
-
-  assert (c.head == c.end);
-  c.end_serialize ();
-
-  return true;
 }
 
-static inline bool
+static bool
 _hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
-		const char		      *data,
-		hb_subset_plan_t		*plan,
-		hb_blob_t		       **prime /* OUT */)
+		 hb_subset_context_t	*c)
 {
   cff2_subset_plan cff2_plan;
 
-  if (unlikely (!cff2_plan.create (acc, plan)))
-  {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
-    return false;
-  }
-
-  unsigned int  cff2_prime_size = cff2_plan.get_final_size ();
-  char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
-
-  if (unlikely (!_write_cff2 (cff2_plan, acc, plan->num_output_glyphs (),
-			      cff2_prime_size, cff2_prime_data))) {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
-    free (cff2_prime_data);
-    return false;
-  }
-
-  *prime = hb_blob_create (cff2_prime_data,
-			   cff2_prime_size,
-			   HB_MEMORY_MODE_READONLY,
-			   cff2_prime_data,
-			   free);
-  return true;
+  if (unlikely (!cff2_plan.create (acc, c->plan))) return false;
+  return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ());
 }
 
-/**
- * hb_subset_cff2:
- * Subsets the CFF2 table according to a provided plan.
- *
- * Return value: subsetted cff2 table.
- **/
 bool
-hb_subset_cff2 (hb_subset_plan_t *plan,
-		hb_blob_t       **prime /* OUT */)
+hb_subset_cff2 (hb_subset_context_t *c)
 {
-  hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source);
-  const char *data = hb_blob_get_data(cff2_blob, nullptr);
-
   OT::cff2::accelerator_subset_t acc;
-  acc.init(plan->source);
-  bool result = likely (acc.is_valid ()) &&
-		_hb_subset_cff2 (acc, data, plan, prime);
-
-  hb_blob_destroy (cff2_blob);
+  acc.init (c->plan->source);
+  bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c);
   acc.fini ();
 
   return result;
 }
 
-
 #endif
diff --git a/src/hb-subset-cff2.hh b/src/hb-subset-cff2.hh
index a07dc29..f10556d 100644
--- a/src/hb-subset-cff2.hh
+++ b/src/hb-subset-cff2.hh
@@ -32,7 +32,6 @@
 #include "hb-subset-plan.hh"
 
 HB_INTERNAL bool
-hb_subset_cff2 (hb_subset_plan_t *plan,
-	       hb_blob_t       **cff2_prime /* OUT */);
+hb_subset_cff2 (hb_subset_context_t *c);
 
 #endif /* HB_SUBSET_CFF2_HH */
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index d92f33f..4885280 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -30,32 +30,37 @@
 /**
  * hb_subset_input_create_or_fail:
  *
- * Return value: New subset input.
+ * 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 ()
+hb_subset_input_create_or_fail (void)
 {
   hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();
 
   if (unlikely (!input))
     return nullptr;
 
-  input->unicodes = hb_set_create ();
-  input->glyphs = hb_set_create ();
-  input->name_ids = hb_set_create ();
-  hb_set_add_range (input->name_ids, 0, 6);
-  input->drop_tables = hb_set_create ();
-  input->drop_hints = false;
-  input->desubroutinize = false;
-  input->retain_gids = false;
+  for (auto& set : input->sets_iter ())
+    set = hb_set_create ();
+
+  if (input->in_error ())
+  {
+    hb_subset_input_destroy (input);
+    return nullptr;
+  }
+
+  input->flags = HB_SUBSET_FLAGS_DEFAULT;
+
+  hb_set_add_range (input->sets.name_ids, 0, 6);
+  hb_set_add (input->sets.name_languages, 0x0409);
 
   hb_tag_t default_drop_tables[] = {
     // Layout disabled by default
-    HB_TAG ('G', 'S', 'U', 'B'),
-    HB_TAG ('G', 'P', 'O', 'S'),
-    HB_TAG ('G', 'D', 'E', 'F'),
     HB_TAG ('m', 'o', 'r', 'x'),
     HB_TAG ('m', 'o', 'r', 't'),
     HB_TAG ('k', 'e', 'r', 'x'),
@@ -77,132 +82,282 @@
     HB_TAG ('G', 'l', 'o', 'c'),
     HB_TAG ('S', 'i', 'l', 'f'),
     HB_TAG ('S', 'i', 'l', 'l'),
-    // Colour
-    HB_TAG ('s', 'b', 'i', 'x')
+  };
+  input->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));
+
+  //copied from _layout_features_groups in fonttools
+  hb_tag_t default_layout_features[] = {
+    // default shaper
+    // common
+    HB_TAG ('r', 'v', 'r', 'n'),
+    HB_TAG ('c', 'c', 'm', 'p'),
+    HB_TAG ('l', 'i', 'g', 'a'),
+    HB_TAG ('l', 'o', 'c', 'l'),
+    HB_TAG ('m', 'a', 'r', 'k'),
+    HB_TAG ('m', 'k', 'm', 'k'),
+    HB_TAG ('r', 'l', 'i', 'g'),
+
+    //fractions
+    HB_TAG ('f', 'r', 'a', 'c'),
+    HB_TAG ('n', 'u', 'm', 'r'),
+    HB_TAG ('d', 'n', 'o', 'm'),
+
+    //horizontal
+    HB_TAG ('c', 'a', 'l', 't'),
+    HB_TAG ('c', 'l', 'i', 'g'),
+    HB_TAG ('c', 'u', 'r', 's'),
+    HB_TAG ('k', 'e', 'r', 'n'),
+    HB_TAG ('r', 'c', 'l', 't'),
+
+    //vertical
+    HB_TAG ('v', 'a', 'l', 't'),
+    HB_TAG ('v', 'e', 'r', 't'),
+    HB_TAG ('v', 'k', 'r', 'n'),
+    HB_TAG ('v', 'p', 'a', 'l'),
+    HB_TAG ('v', 'r', 't', '2'),
+
+    //ltr
+    HB_TAG ('l', 't', 'r', 'a'),
+    HB_TAG ('l', 't', 'r', 'm'),
+
+    //rtl
+    HB_TAG ('r', 't', 'l', 'a'),
+    HB_TAG ('r', 't', 'l', 'm'),
+
+    //Complex shapers
+    //arabic
+    HB_TAG ('i', 'n', 'i', 't'),
+    HB_TAG ('m', 'e', 'd', 'i'),
+    HB_TAG ('f', 'i', 'n', 'a'),
+    HB_TAG ('i', 's', 'o', 'l'),
+    HB_TAG ('m', 'e', 'd', '2'),
+    HB_TAG ('f', 'i', 'n', '2'),
+    HB_TAG ('f', 'i', 'n', '3'),
+    HB_TAG ('c', 's', 'w', 'h'),
+    HB_TAG ('m', 's', 'e', 't'),
+    HB_TAG ('s', 't', 'c', 'h'),
+
+    //hangul
+    HB_TAG ('l', 'j', 'm', 'o'),
+    HB_TAG ('v', 'j', 'm', 'o'),
+    HB_TAG ('t', 'j', 'm', 'o'),
+
+    //tibetan
+    HB_TAG ('a', 'b', 'v', 's'),
+    HB_TAG ('b', 'l', 'w', 's'),
+    HB_TAG ('a', 'b', 'v', 'm'),
+    HB_TAG ('b', 'l', 'w', 'm'),
+
+    //indic
+    HB_TAG ('n', 'u', 'k', 't'),
+    HB_TAG ('a', 'k', 'h', 'n'),
+    HB_TAG ('r', 'p', 'h', 'f'),
+    HB_TAG ('r', 'k', 'r', 'f'),
+    HB_TAG ('p', 'r', 'e', 'f'),
+    HB_TAG ('b', 'l', 'w', 'f'),
+    HB_TAG ('h', 'a', 'l', 'f'),
+    HB_TAG ('a', 'b', 'v', 'f'),
+    HB_TAG ('p', 's', 't', 'f'),
+    HB_TAG ('c', 'f', 'a', 'r'),
+    HB_TAG ('v', 'a', 't', 'u'),
+    HB_TAG ('c', 'j', 'c', 't'),
+    HB_TAG ('i', 'n', 'i', 't'),
+    HB_TAG ('p', 'r', 'e', 's'),
+    HB_TAG ('a', 'b', 'v', 's'),
+    HB_TAG ('b', 'l', 'w', 's'),
+    HB_TAG ('p', 's', 't', 's'),
+    HB_TAG ('h', 'a', 'l', 'n'),
+    HB_TAG ('d', 'i', 's', 't'),
+    HB_TAG ('a', 'b', 'v', 'm'),
+    HB_TAG ('b', 'l', 'w', 'm'),
   };
 
-  input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
+  input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
 
+  if (input->in_error ())
+  {
+    hb_subset_input_destroy (input);
+    return nullptr;
+  }
   return input;
 }
 
 /**
  * hb_subset_input_reference: (skip)
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
  *
+ * Increases the reference count on @input.
  *
- *
- * Return value:
+ * Return value: @input.
  *
  * Since: 1.8.0
  **/
 hb_subset_input_t *
-hb_subset_input_reference (hb_subset_input_t *subset_input)
+hb_subset_input_reference (hb_subset_input_t *input)
 {
-  return hb_object_reference (subset_input);
+  return hb_object_reference (input);
 }
 
 /**
  * hb_subset_input_destroy:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Decreases the reference count on @input, and if it reaches zero, destroys
+ * @input, freeing all memory.
  *
  * Since: 1.8.0
  **/
 void
-hb_subset_input_destroy (hb_subset_input_t *subset_input)
+hb_subset_input_destroy (hb_subset_input_t *input)
 {
-  if (!hb_object_destroy (subset_input)) return;
+  if (!hb_object_destroy (input)) return;
 
-  hb_set_destroy (subset_input->unicodes);
-  hb_set_destroy (subset_input->glyphs);
-  hb_set_destroy (subset_input->name_ids);
-  hb_set_destroy (subset_input->drop_tables);
+  for (hb_set_t* set : input->sets_iter ())
+    hb_set_destroy (set);
 
-  free (subset_input);
+  hb_free (input);
 }
 
 /**
  * hb_subset_input_unicode_set:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of Unicode code points to retain, the caller should modify the
+ * set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of Unicode code
+ * points.
  *
  * Since: 1.8.0
  **/
 HB_EXTERN hb_set_t *
-hb_subset_input_unicode_set (hb_subset_input_t *subset_input)
+hb_subset_input_unicode_set (hb_subset_input_t *input)
 {
-  return subset_input->unicodes;
+  return input->sets.unicodes;
 }
 
 /**
  * hb_subset_input_glyph_set:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of glyph IDs to retain, the caller should modify the set as
+ * needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of glyph IDs.
  *
  * Since: 1.8.0
  **/
 HB_EXTERN hb_set_t *
-hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
+hb_subset_input_glyph_set (hb_subset_input_t *input)
 {
-  return subset_input->glyphs;
-}
-
-HB_EXTERN hb_set_t *
-hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
-{
-  return subset_input->name_ids;
-}
-
-HB_EXTERN hb_set_t *
-hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input)
-{
-  return subset_input->drop_tables;
-}
-
-HB_EXTERN void
-hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
-				hb_bool_t drop_hints)
-{
-  subset_input->drop_hints = drop_hints;
-}
-
-HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
-{
-  return subset_input->drop_hints;
-}
-
-HB_EXTERN void
-hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-				    hb_bool_t desubroutinize)
-{
-  subset_input->desubroutinize = desubroutinize;
-}
-
-HB_EXTERN hb_bool_t
-hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input)
-{
-  return subset_input->desubroutinize;
+  return input->sets.glyphs;
 }
 
 /**
- * hb_subset_input_set_retain_gids:
- * @subset_input: a subset_input.
- * @retain_gids: If true the subsetter will not renumber glyph ids.
- * Since: 2.4.0
+ * hb_subset_input_set:
+ * @input: a #hb_subset_input_t object.
+ * @set_type: a #hb_subset_sets_t set type.
+ *
+ * Gets the set of the specified type.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of the specified type.
+ *
+ * Since: 2.9.1
  **/
-HB_EXTERN void
-hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
-				 hb_bool_t retain_gids)
+HB_EXTERN hb_set_t *
+hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type)
 {
-  subset_input->retain_gids = retain_gids;
+  return input->sets_iter () [set_type];
 }
 
 /**
- * hb_subset_input_get_retain_gids:
- * Returns: value of retain_gids.
- * Since: 2.4.0
+ * hb_subset_input_get_flags:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets all of the subsetting flags in the input object.
+ *
+ * Return value: the subsetting flags bit field.
+ *
+ * Since: 2.9.0
  **/
-HB_EXTERN hb_bool_t
-hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
+HB_EXTERN hb_subset_flags_t
+hb_subset_input_get_flags (hb_subset_input_t *input)
 {
-  return subset_input->retain_gids;
+  return (hb_subset_flags_t) input->flags;
+}
+
+/**
+ * hb_subset_input_set_flags:
+ * @input: a #hb_subset_input_t object.
+ * @value: bit field of flags
+ *
+ * Sets all of the flags in the input object to the values specified by the bit
+ * field.
+ *
+ * Since: 2.9.0
+ **/
+HB_EXTERN void
+hb_subset_input_set_flags (hb_subset_input_t *input,
+			   unsigned value)
+{
+  input->flags = (hb_subset_flags_t) value;
+}
+
+/**
+ * hb_subset_input_set_user_data: (skip)
+ * @input: a #hb_subset_input_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 input object.
+ *
+ * Return value: %true if success, %false otherwise
+ *
+ * Since: 2.9.0
+ **/
+hb_bool_t
+hb_subset_input_set_user_data (hb_subset_input_t  *input,
+			       hb_user_data_key_t *key,
+			       void *		   data,
+			       hb_destroy_func_t   destroy,
+			       hb_bool_t	   replace)
+{
+  return hb_object_set_user_data (input, key, data, destroy, replace);
+}
+
+/**
+ * hb_subset_input_get_user_data: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @key: The user-data key to query
+ *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified subset input object.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 2.9.0
+ **/
+void *
+hb_subset_input_get_user_data (const hb_subset_input_t *input,
+			       hb_user_data_key_t     *key)
+{
+  return hb_object_get_user_data (input, key);
 }
diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh
index f6dd4ac..07c0e22 100644
--- a/src/hb-subset-input.hh
+++ b/src/hb-subset-input.hh
@@ -31,28 +31,53 @@
 #include "hb.hh"
 
 #include "hb-subset.h"
+#include "hb-map.hh"
+#include "hb-set.hh"
 
 #include "hb-font.hh"
 
+HB_MARK_AS_FLAG_T (hb_subset_flags_t);
+
 struct hb_subset_input_t
 {
   hb_object_header_t header;
 
-  hb_set_t *unicodes;
-  hb_set_t *glyphs;
-  hb_set_t *name_ids;
-  hb_set_t *drop_tables;
+  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;
+  };
 
-  bool drop_hints;
-  bool desubroutinize;
-  bool retain_gids;
-  /* TODO
-   *
-   * features
-   * lookups
-   * name_ids
-   * ...
-   */
+  union {
+    sets_t sets;
+    hb_set_t* set_ptrs[sizeof (sets_t) / sizeof (hb_set_t*)];
+  };
+
+  unsigned flags;
+
+  inline unsigned num_sets () const
+  {
+    return sizeof (set_ptrs) / sizeof (hb_set_t*);
+  }
+
+  inline hb_array_t<hb_set_t*> sets_iter ()
+  {
+    return hb_array_t<hb_set_t*> (set_ptrs, num_sets ());
+  }
+
+  bool in_error () const
+  {
+    for (unsigned i = 0; i < num_sets (); i++)
+    {
+      if (unlikely (set_ptrs[i]->in_error ()))
+        return true;
+    }
+    return false;
+  }
 };
 
 
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index f4912f8..1e195ff 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -30,10 +30,18 @@
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-gdef-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-var-fvar-table.hh"
 #include "hb-ot-stat-table.hh"
+#include "hb-ot-math-table.hh"
 
+
+typedef hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> script_langsys_map;
 #ifndef HB_NO_SUBSET_CFF
 static inline void
 _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
@@ -49,27 +57,164 @@
 }
 #endif
 
-#ifndef HB_NO_SUBSET_LAYOUT
-static inline void
-_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
+static void
+_remap_palette_indexes (const hb_set_t *palette_indexes,
+			hb_map_t       *mapping /* OUT */)
 {
+  unsigned new_idx = 0;
+  for (unsigned palette_index : palette_indexes->iter ())
+  {
+    if (palette_index == 0xFFFF)
+    {
+      mapping->set (palette_index, palette_index);
+      continue;
+    }
+    mapping->set (palette_index, new_idx);
+    new_idx++;
+  }
+}
+
+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);
+
+}
+
+#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 */)
+{
+  hb_vector_t<hb_tag_t> features;
+  if (!features.alloc (table.get_feature_count () + 1))
+    return;
+
+  for (unsigned i = 0; i < table.get_feature_count (); i++)
+  {
+    hb_tag_t tag = table.get_feature_tag (i);
+    if (tag && layout_features_to_retain->has (tag))
+      features.push (tag);
+  }
+
+  if (!features)
+    return;
+
+  // The collect function needs a null element to signal end of the array.
+  features.push (0);
+
+  if (features.get_size () == table.get_feature_count () + 1)
+  {
+    // Looking for all features, trigger the faster collection method.
+    layout_collect_func (face,
+                         T::tableTag,
+                         nullptr,
+                         nullptr,
+                         nullptr,
+                         indices);
+    return;
+  }
+
+  layout_collect_func (face,
+                       T::tableTag,
+		       nullptr,
+		       nullptr,
+		       features.arrayZ,
+		       indices);
+}
+
+template <typename T>
+static inline void
+_closure_glyphs_lookups_features (hb_face_t	     *face,
+				  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)
+{
+  hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
+  hb_tag_t table_tag = table->tableTag;
   hb_set_t lookup_indices;
-  hb_ot_layout_collect_lookups (face,
-				HB_OT_TAG_GSUB,
-				nullptr,
-				nullptr,
-				nullptr,
-				&lookup_indices);
-  hb_ot_layout_lookups_substitute_closure (face,
-					   &lookup_indices,
-					   gids_to_retain);
+  _collect_layout_indices<T> (face,
+                              *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,
+					     gids_to_retain);
+  table->closure_lookups (face,
+			  gids_to_retain,
+			 &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);
+  hb_map_t duplicate_feature_map;
+  table->find_duplicate_features (lookups, &feature_indices, &duplicate_feature_map);
+
+  feature_indices.clear ();
+  table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
+  _remap_indexes (&feature_indices, features);
+
+  table.destroy ();
+}
+
+#endif
+
+#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)
+{
+  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 (!gdef->has_data ())
+  {
+    gdef.destroy ();
+    gpos.destroy ();
+    return;
+  }
+  OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups);
+  gdef->collect_variation_indices (&c);
+
+  if (hb_ot_layout_has_positioning (face))
+    gpos->collect_variation_indices (&c);
+
+  gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
+
+  gdef.destroy ();
+  gpos.destroy ();
 }
 #endif
 
 static inline void
-_cmap_closure (hb_face_t           *face,
-	       const hb_set_t      *unicodes,
-	       hb_set_t            *glyphset)
+_cmap_closure (hb_face_t	   *face,
+	       const hb_set_t	   *unicodes,
+	       hb_set_t		   *glyphset)
 {
   OT::cmap::accelerator_t cmap;
   cmap.init (face);
@@ -77,6 +222,50 @@
   cmap.fini ();
 }
 
+static void _colr_closure (hb_face_t *face,
+                           hb_map_t *layers_map,
+                           hb_map_t *palettes_map,
+                           hb_set_t *glyphs_colred)
+{
+  OT::COLR::accelerator_t colr;
+  colr.init (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 ());
+
+  colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
+  _remap_indexes (&layer_indices, layers_map);
+  _remap_palette_indexes (&palette_indices, palettes_map);
+  colr.fini ();
+}
+
+static inline void
+_math_closure (hb_face_t           *face,
+               hb_set_t            *glyphset)
+{
+  hb_blob_ptr_t<OT::MATH> math = hb_sanitize_context_t ().reference_table<OT::MATH> (face);
+  if (math->has_data ())
+    math->closure_glyphs (glyphset);
+  math.destroy ();
+}
+
+
 static inline void
 _remove_invalid_gids (hb_set_t *glyphs,
 		      unsigned int num_glyphs)
@@ -90,48 +279,115 @@
 }
 
 static void
-_populate_gids_to_retain (hb_subset_plan_t* plan,
-			  const hb_set_t *unicodes,
-			  const hb_set_t *input_glyphs_to_retain,
-			  bool close_over_gsub)
+_populate_unicodes_to_retain (const hb_set_t *unicodes,
+                              const hb_set_t *glyphs,
+                              hb_subset_plan_t *plan)
 {
   OT::cmap::accelerator_t cmap;
-  OT::glyf::accelerator_t glyf;
-  OT::cff1::accelerator_t cff;
   cmap.init (plan->source);
+
+  constexpr static const int size_threshold = 4096;
+
+  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))
+      {
+        DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+        continue;
+      }
+
+      plan->codepoint_to_glyph->set (cp, gid);
+    }
+  }
+  else
+  {
+    hb_map_t unicode_glyphid_map;
+    cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
+
+    for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
+	 + unicode_glyphid_map.iter ())
+    {
+      if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second))
+	continue;
+
+      plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
+    }
+
+    /* 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 ())
+    {
+      if (gid >= plan->source->get_num_glyphs ())
+	break;
+      plan->_glyphset_gsub->add (gid);
+    }
+  }
+
+  + plan->codepoint_to_glyph->keys ()   | hb_sink (plan->unicodes);
+  + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub);
+
+  cmap.fini ();
+}
+
+static void
+_populate_gids_to_retain (hb_subset_plan_t* plan,
+			  bool close_over_gsub,
+			  bool close_over_gpos,
+			  bool close_over_gdef)
+{
+  OT::glyf::accelerator_t glyf;
+#ifndef HB_NO_SUBSET_CFF
+  OT::cff1::accelerator_t cff;
+#endif
   glyf.init (plan->source);
+#ifndef HB_NO_SUBSET_CFF
   cff.init (plan->source);
+#endif
 
   plan->_glyphset_gsub->add (0); // Not-def
-  hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
-
-  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-  while (unicodes->next (&cp))
-  {
-    hb_codepoint_t gid;
-    if (!cmap.get_nominal_glyph (cp, &gid))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-      continue;
-    }
-    plan->unicodes->add (cp);
-    plan->codepoint_to_glyph->set (cp, gid);
-    plan->_glyphset_gsub->add (gid);
-  }
 
   _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
 
 #ifndef HB_NO_SUBSET_LAYOUT
   if (close_over_gsub)
-    // Add all glyphs needed for GSUB substitutions.
-    _gsub_closure (plan->source, plan->_glyphset_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);
 #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 ());
+
+  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 ());
+
   // Populate a full set of glyphs to retain by adding all referenced
   // composite glyphs.
-  hb_codepoint_t gid = HB_SET_VALUE_INVALID;
-  while (plan->_glyphset_gsub->next (&gid))
+  for (hb_codepoint_t gid : cur_glyphset.iter ())
   {
     glyf.add_gid_and_children (gid, plan->_glyphset);
 #ifndef HB_NO_SUBSET_CFF
@@ -142,18 +398,29 @@
 
   _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);
+#endif
+
+#ifndef HB_NO_SUBSET_CFF
   cff.fini ();
+#endif
   glyf.fini ();
-  cmap.fini ();
 }
 
 static void
 _create_old_gid_to_new_gid_map (const hb_face_t *face,
-				bool             retain_gids,
-				const hb_set_t  *all_gids_to_retain,
-				hb_map_t        *glyph_map, /* OUT */
-				hb_map_t        *reverse_glyph_map, /* OUT */
-				unsigned int    *num_glyphs /* OUT */)
+				bool		 retain_gids,
+				const hb_set_t	*all_gids_to_retain,
+				hb_map_t	*glyph_map, /* OUT */
+				hb_map_t	*reverse_glyph_map, /* OUT */
+				unsigned int	*num_glyphs /* OUT */)
 {
   if (!retain_gids)
   {
@@ -186,7 +453,7 @@
 _nameid_closure (hb_face_t *face,
 		 hb_set_t  *nameids)
 {
-#ifndef HB_NO_STAT
+#ifndef HB_NO_STYLE
   face->table.STAT->collect_name_ids (nameids);
 #endif
 #ifndef HB_NO_VAR
@@ -196,43 +463,73 @@
 
 /**
  * hb_subset_plan_create:
+ * @face: font face to create the plan for.
+ * @input: a #hb_subset_input_t input.
+ *
  * Computes a plan for subsetting the supplied face according
  * to a provided input. The plan describes
  * which tables and glyphs should be retained.
  *
- * Return value: New subset plan.
+ * Return value: (transfer full): New subset plan. Destroy with
+ * hb_subset_plan_destroy().
  *
  * Since: 1.7.5
  **/
 hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t         *face,
-		       hb_subset_input_t *input)
+hb_subset_plan_create (hb_face_t	 *face,
+		       const hb_subset_input_t *input)
 {
-  hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
+  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->drop_hints = input->drop_hints;
-  plan->desubroutinize = input->desubroutinize;
-  plan->retain_gids = input->retain_gids;
+  plan->successful = true;
+  plan->flags = input->flags;
   plan->unicodes = hb_set_create ();
-  plan->name_ids = hb_set_reference (input->name_ids);
+  plan->name_ids = hb_set_copy (input->sets.name_ids);
   _nameid_closure (face, plan->name_ids);
-  plan->drop_tables = hb_set_reference (input->drop_tables);
+  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->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->unicodes,
-			    input->glyphs,
-			    !input->drop_tables->has (HB_OT_TAG_GSUB));
+			    !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->retain_gids,
+                                  input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
 				  plan->_glyphset,
 				  plan->glyph_map,
 				  plan->reverse_glyph_map,
@@ -243,6 +540,10 @@
 
 /**
  * hb_subset_plan_destroy:
+ * @plan: a #hb_subset_plan_t
+ *
+ * Decreases the reference count on @plan, and if it reaches zero, destroys
+ * @plan, freeing all memory.
  *
  * Since: 1.7.5
  **/
@@ -253,7 +554,11 @@
 
   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);
@@ -261,6 +566,35 @@
   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_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);
 
-  free (plan);
+  if (plan->gsub_langsys)
+  {
+    for (auto _ : plan->gsub_langsys->iter ())
+      hb_set_destroy (_.second);
+
+    hb_object_destroy (plan->gsub_langsys);
+    plan->gsub_langsys->fini_shallow ();
+    hb_free (plan->gsub_langsys);
+  }
+
+  if (plan->gpos_langsys)
+  {
+    for (auto _ : plan->gpos_langsys->iter ())
+      hb_set_destroy (_.second);
+
+    hb_object_destroy (plan->gpos_langsys);
+    plan->gpos_langsys->fini_shallow ();
+    hb_free (plan->gpos_langsys);
+  }
+
+  hb_free (plan);
 }
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index af2337e..c30feeb 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -39,9 +39,8 @@
 {
   hb_object_header_t header;
 
-  bool drop_hints : 1;
-  bool desubroutinize : 1;
-  bool retain_gids : 1;
+  bool successful;
+  unsigned flags;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
@@ -49,6 +48,18 @@
   // name_ids we would like to retain
   hb_set_t *name_ids;
 
+  // name_languages we would like to retain
+  hb_set_t *name_languages;
+
+  //layout features which will be preserved
+  hb_set_t *layout_features;
+
+  //glyph ids requested to retain
+  hb_set_t *glyphs_requested;
+
+  // Tables which should not be processed, just pass them through.
+  hb_set_t *no_subset_tables;
+
   // Tables which should be dropped.
   hb_set_t *drop_tables;
 
@@ -66,9 +77,39 @@
   unsigned int _num_output_glyphs;
   hb_set_t *_glyphset;
   hb_set_t *_glyphset_gsub;
+  hb_set_t *_glyphset_mathed;
+
+  //active lookups we'd like to retain
+  hb_map_t *gsub_lookups;
+  hb_map_t *gpos_lookups;
+
+  //active langsys we'd like to retain
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gsub_langsys;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gpos_langsys;
+
+  //active features after removing redundant langsys and prune_features
+  hb_map_t *gsub_features;
+  hb_map_t *gpos_features;
+
+  //active layers/palettes we'd like to retain
+  hb_map_t *colrv1_layers;
+  hb_map_t *colr_palettes;
+
+  //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;
 
  public:
 
+  bool in_error () const { return !successful; }
+
+  bool check_success(bool success)
+  {
+    successful = (successful && success);
+    return successful;
+  }
+
   /*
    * The set of input glyph ids which will be retained in the subset.
    * Does NOT include ids kept due to retain_gids. You probably want to use
@@ -143,12 +184,15 @@
   add_table (hb_tag_t tag,
 	     hb_blob_t *contents)
   {
-    hb_blob_t *source_blob = source->reference_table (tag);
-    DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
-	      HB_UNTAG(tag),
-	      hb_blob_get_length (contents),
-	      hb_blob_get_length (source_blob));
-    hb_blob_destroy (source_blob);
+    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",
+		HB_UNTAG(tag),
+		hb_blob_get_length (contents),
+		hb_blob_get_length (source_blob));
+      hb_blob_destroy (source_blob);
+    }
     return hb_face_builder_add_table (dest, tag, contents);
   }
 };
@@ -157,7 +201,7 @@
 
 HB_INTERNAL hb_subset_plan_t *
 hb_subset_plan_create (hb_face_t           *face,
-		       hb_subset_input_t   *input);
+		       const hb_subset_input_t   *input);
 
 HB_INTERNAL void
 hb_subset_plan_destroy (hb_subset_plan_t *plan);
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index ec2f889..048bdf1 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -37,96 +37,120 @@
 #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 "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
+#include "hb-ot-post-table-v2subset.hh"
 #include "hb-ot-cff1-table.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-gvar-table.hh"
+#include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-math-table.hh"
+#include "hb-repacker.hh"
 
+/**
+ * SECTION:hb-subset
+ * @title: hb-subset
+ * @short_description: Subsets font files.
+ * @include: hb-subset.h
+ *
+ * Subsetting reduces the codepoint coverage of font files and removes all data
+ * that is no longer needed. A subset input describes the desired subset. The input is
+ * provided along with a font to the subsetting operation. Output is a new font file
+ * containing only the data specified in the input.
+ *
+ * Currently most outline and bitmap tables are supported: glyf, CFF, CFF2, sbix,
+ * COLR, and CBDT/CBLC. This also includes fonts with variable outlines via OpenType
+ * variations. Notably EBDT/EBLC and SVG are not supported. Layout subsetting is supported
+ * only for OpenType Layout tables (GSUB, GPOS, GDEF). Notably subsetting of graphite or AAT tables
+ * is not yet supported.
+ *
+ * Fonts with graphite or AAT tables may still be subsetted but will likely need to use the
+ * retain glyph ids option and configure the subset to pass through the layout tables untouched.
+ */
 
-HB_UNUSED static inline unsigned int
-_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
-				  unsigned int table_len);
-static inline unsigned int
-_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
-				  unsigned int table_len)
+static unsigned
+_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
 {
-  unsigned int src_glyphs = plan->source->get_num_glyphs ();
-  unsigned int dst_glyphs = plan->glyphset ()->get_population ();
+  unsigned src_glyphs = plan->source->get_num_glyphs ();
+  unsigned dst_glyphs = plan->glyphset ()->get_population ();
 
   if (unlikely (!src_glyphs))
     return 512 + table_len;
 
-  return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
+  return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
+}
+
+/*
+ * Repack the serialization buffer if any offset overflows exist.
+ */
+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 ();
+
+  hb_vector_t<char> buf;
+  int buf_size = c.end - c.start;
+  if (unlikely (!buf.alloc (buf_size)))
+    return nullptr;
+
+  hb_serialize_context_t repacked ((void *) buf, buf_size);
+  hb_resolve_overflows (c.object_graph (), tag, &repacked);
+
+  if (unlikely (repacked.in_error ()))
+    // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset
+    //                     portion.
+    return nullptr;
+
+  return repacked.copy_blob ();
 }
 
 template<typename TableType>
-static bool
-_subset2 (hb_subset_plan_t *plan)
+static
+bool
+_try_subset (const TableType *table,
+             hb_vector_t<char>* buf,
+             unsigned buf_size,
+             hb_subset_context_t* c /* OUT */)
 {
-  bool result = false;
-  hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
-  const TableType *table = source_blob->as<TableType> ();
+  c->serializer->start_serialize<TableType> ();
+  if (c->serializer->in_error ()) return false;
 
-  hb_tag_t tag = TableType::tableTag;
-  if (source_blob->data)
+  bool needed = table->subset (c);
+  if (!c->serializer->ran_out_of_room ())
   {
-    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 int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
-    if (unlikely (!buf.alloc (buf_size)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
-      hb_blob_destroy (source_blob);
-      return false;
-    }
-  retry:
-    hb_serialize_context_t serializer ((void *) buf, buf_size);
-    serializer.start_serialize<TableType> ();
-    hb_subset_context_t c (plan, &serializer);
-    bool needed = table->subset (&c);
-    if (serializer.ran_out_of_room)
-    {
-      buf_size += (buf_size >> 1) + 32;
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
-      if (unlikely (!buf.alloc (buf_size)))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
-	hb_blob_destroy (source_blob);
-	return false;
-      }
-      goto retry;
-    }
-    serializer.end_serialize ();
-
-    result = !serializer.in_error ();
-
-    if (result)
-    {
-      if (needed)
-      {
-	hb_blob_t *dest_blob = serializer.copy_blob ();
-	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
-	result = c.plan->add_table (tag, dest_blob);
-	hb_blob_destroy (dest_blob);
-      }
-      else
-      {
-	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
-      }
-    }
+    c->serializer->end_serialize ();
+    return needed;
   }
-  else
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
 
-  hb_blob_destroy (source_blob);
-  DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
-  return result;
+  buf_size += (buf_size >> 1) + 32;
+  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
+             HB_UNTAG (c->table_tag), buf_size);
+
+  if (unlikely (!buf->alloc (buf_size)))
+  {
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
+               HB_UNTAG (c->table_tag), buf_size);
+    return needed;
+  }
+
+  c->serializer->reset (buf->arrayZ, buf_size);
+  return _try_subset (table, buf, buf_size, c);
 }
 
 template<typename TableType>
@@ -137,102 +161,76 @@
   const TableType *table = source_blob->as<TableType> ();
 
   hb_tag_t tag = TableType::tableTag;
-  hb_bool_t result = false;
-  if (source_blob->data)
-    result = table->subset (plan);
-  else
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
+  if (!source_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);
+    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);
+  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);
+    return false;
+  }
+
+  bool needed = false;
+  hb_serialize_context_t serializer (buf.arrayZ, buf_size);
+  {
+    hb_subset_context_t c (source_blob, plan, &serializer, tag);
+    needed = _try_subset (table, &buf, buf_size, &c);
+  }
   hb_blob_destroy (source_blob);
-  DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
+
+  if (serializer.in_error () && !serializer.only_offset_overflow ())
+  {
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag));
+    return false;
+  }
+
+  if (!needed)
+  {
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
+    return true;
+  }
+
+  bool result = false;
+  hb_blob_t *dest_blob = _repack (tag, serializer);
+  if (dest_blob)
+  {
+    DEBUG_MSG (SUBSET, nullptr,
+               "OT::%c%c%c%c final subset table size: %u bytes.",
+               HB_UNTAG (tag), dest_blob->length);
+    result = plan->add_table (tag, dest_blob);
+    hb_blob_destroy (dest_blob);
+  }
+
+  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s",
+             HB_UNTAG (tag), result ? "success" : "FAILED!");
   return result;
 }
 
-
 static bool
-_subset_table (hb_subset_plan_t *plan,
-	       hb_tag_t          tag)
+_is_table_present (hb_face_t *source, hb_tag_t tag)
 {
-  DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag));
-  bool result = true;
-  switch (tag) {
-    case HB_OT_TAG_glyf:
-      result = _subset2<const OT::glyf> (plan);
-      break;
-    case HB_OT_TAG_hdmx:
-      result = _subset2<const OT::hdmx> (plan);
-      break;
-    case HB_OT_TAG_name:
-      result = _subset2<const OT::name> (plan);
-      break;
-    case HB_OT_TAG_head:
-      // TODO that won't work well if there is no glyf
-      DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf");
-      result = true;
-      break;
-    case HB_OT_TAG_hhea:
-      DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx");
-      return true;
-    case HB_OT_TAG_hmtx:
-      result = _subset2<const OT::hmtx> (plan);
-      break;
-    case HB_OT_TAG_vhea:
-      DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx");
-      return true;
-    case HB_OT_TAG_vmtx:
-      result = _subset2<const OT::vmtx> (plan);
-      break;
-    case HB_OT_TAG_maxp:
-      result = _subset2<const OT::maxp> (plan);
-      break;
-    case HB_OT_TAG_loca:
-      DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
-      return true;
-    case HB_OT_TAG_cmap:
-      result = _subset2<const OT::cmap> (plan);
-      break;
-    case HB_OT_TAG_OS2:
-      result = _subset2<const OT::OS2> (plan);
-      break;
-    case HB_OT_TAG_post:
-      result = _subset2<const OT::post> (plan);
-      break;
-
-#ifndef HB_NO_SUBSET_CFF
-    case HB_OT_TAG_cff1:
-      result = _subset<const OT::cff1> (plan);
-      break;
-    case HB_OT_TAG_cff2:
-      result = _subset<const OT::cff2> (plan);
-      break;
-    case HB_OT_TAG_VORG:
-      result = _subset2<const OT::VORG> (plan);
-      break;
-#endif
-
-#ifndef HB_NO_SUBSET_LAYOUT
-    case HB_OT_TAG_GDEF:
-      result = _subset2<const OT::GDEF> (plan);
-      break;
-    case HB_OT_TAG_GSUB:
-      result = _subset2<const OT::GSUB> (plan);
-      break;
-    case HB_OT_TAG_GPOS:
-      result = _subset2<const OT::GPOS> (plan);
-      break;
-#endif
-
-    default:
-      hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
-      if (likely (source_table))
-	result = plan->add_table (tag, source_table);
-      else
-	result = false;
-      hb_blob_destroy (source_table);
-      break;
+  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))
+  {
+    for (unsigned i = 0; i < num_tables; ++i)
+      if (table_tags[i] == tag)
+	return true;
+    offset += num_tables;
   }
-  DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED");
-  return result;
+  return false;
 }
 
 static bool
@@ -241,69 +239,140 @@
   if (plan->drop_tables->has (tag))
     return true;
 
-  switch (tag) {
-    case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
-    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 */
-    case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
-    case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
-      return plan->drop_hints;
+  switch (tag)
+  {
+  case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
+  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 */
+  case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */
+  case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */
+    return plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
 
 #ifdef HB_NO_SUBSET_LAYOUT
     // Drop Layout Tables if requested.
-    case HB_OT_TAG_GDEF:
-    case HB_OT_TAG_GPOS:
-    case HB_OT_TAG_GSUB:
-    case HB_TAG ('m', 'o', 'r', 'x'):
-    case HB_TAG ('m', 'o', 'r', 't'):
-    case HB_TAG ('k', 'e', 'r', 'x'):
-    case HB_TAG ('k', 'e', 'r', 'n'):
-      return true;
+  case HB_OT_TAG_GDEF:
+  case HB_OT_TAG_GPOS:
+  case HB_OT_TAG_GSUB:
+  case HB_TAG ('m','o','r','x'):
+  case HB_TAG ('m','o','r','t'):
+  case HB_TAG ('k','e','r','x'):
+  case HB_TAG ('k','e','r','n'):
+    return true;
 #endif
 
-    default:
-      return false;
+  default:
+    return false;
+  }
+}
+
+static bool
+_passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
+{
+  hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
+  bool result = plan->add_table (tag, source_table);
+  hb_blob_destroy (source_table);
+  return result;
+}
+
+static bool
+_subset_table (hb_subset_plan_t *plan, hb_tag_t 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_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);
+  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_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_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_CBDT: return true; /* skip CBDT, handled by CBLC */
+  case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan);
+
+#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);
+#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);
+#endif
+
+  default:
+    if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
+      return _passthrough (plan, tag);
+
+    // Drop table
+    return true;
   }
 }
 
 /**
- * hb_subset:
+ * hb_subset_or_fail:
  * @source: font face data to be subset.
  * @input: input to use for the subsetting.
  *
- * Subsets a font according to provided input.
+ * Subsets a font according to provided input. Returns nullptr
+ * if the subset operation fails.
+ *
+ * Since: 2.9.0
  **/
 hb_face_t *
-hb_subset (hb_face_t *source,
-	   hb_subset_input_t *input)
+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);
+    return nullptr;
+  }
 
-  hb_tag_t table_tags[32];
-  unsigned int offset = 0, count;
-  bool success = true;
   hb_set_t tags_set;
-  do {
-    count = ARRAY_LENGTH (table_tags);
-    hb_face_get_table_tags (source, offset, &count, table_tags);
-    for (unsigned int i = 0; i < count; i++)
+  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))
+  {
+    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))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag));
-	continue;
-      }
+      if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
       tags_set.add (tag);
-      success = success && _subset_table (plan, tag);
+      success = _subset_table (plan, tag);
+      if (unlikely (!success)) goto end;
     }
-    offset += count;
-  } while (success && count == ARRAY_LENGTH (table_tags));
+    offset += num_tables;
+  }
+end:
 
-  hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty ();
+  hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
+
   hb_subset_plan_destroy (plan);
   return result;
 }
diff --git a/src/hb-subset.h b/src/hb-subset.h
index 960afef..1c65a4d 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -31,57 +31,119 @@
 
 HB_BEGIN_DECLS
 
-/*
- * hb_subset_input_t
+/**
+ * hb_subset_input_t:
  *
  * Things that change based on the input. Characters to keep, etc.
  */
 
 typedef struct hb_subset_input_t hb_subset_input_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
+ * the produced subset. Otherwise hinting instructions will be retained.
+ * @HB_SUBSET_FLAGS_RETAIN_GIDS: If set glyph indices will not be modified in
+ * the produced subset. If glyphs are dropped their indices will be retained
+ * as an empty glyph.
+ * @HB_SUBSET_FLAGS_DESUBROUTINIZE: If set and subsetting a CFF font the
+ * subsetter will attempt to remove subroutines from the CFF glyphs.
+ * @HB_SUBSET_FLAGS_NAME_LEGACY: If set non-unicode name records will be
+ * retained in the subset.
+ * @HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG:	If set the subsetter will set the
+ * OVERLAP_SIMPLE flag on each simple glyph.
+ * @HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED: If set the subsetter will not
+ * drop unrecognized tables and instead pass them through untouched.
+ * @HB_SUBSET_FLAGS_NOTDEF_OUTLINE: If set the notdef glyph outline will be
+ * retained in the final subset.
+ * @HB_SUBSET_FLAGS_GLYPH_NAMES: If set the PS glyph names will be retained
+ * in the final subset.
+ * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
+ * OS/2 will not be recalculated.
+ *
+ * List of boolean properties that can be configured on the subset input.
+ *
+ * Since: 2.9.0
+ **/
+typedef enum { /*< flags >*/
+  HB_SUBSET_FLAGS_DEFAULT =		     0x00000000u,
+  HB_SUBSET_FLAGS_NO_HINTING =		     0x00000001u,
+  HB_SUBSET_FLAGS_RETAIN_GIDS =		     0x00000002u,
+  HB_SUBSET_FLAGS_DESUBROUTINIZE =	     0x00000004u,
+  HB_SUBSET_FLAGS_NAME_LEGACY =		     0x00000008u,
+  HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG =	     0x00000010u,
+  HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED = 0x00000020u,
+  HB_SUBSET_FLAGS_NOTDEF_OUTLINE =	     0x00000040u,
+  HB_SUBSET_FLAGS_GLYPH_NAMES =		     0x00000080u,
+  HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES =  0x00000100u,
+} hb_subset_flags_t;
+
+/**
+ * hb_subset_sets_t:
+ * @HB_SUBSET_SETS_GLYPH_INDEX: the set of glyph indexes to retain in the subset.
+ * @HB_SUBSET_SETS_UNICODE: the set of unicode codepoints to retain in the subset.
+ * @HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG: the set of table tags which specifies tables that should not be
+ * subsetted.
+ * @HB_SUBSET_SETS_DROP_TABLE_TAG: the set of table tags which specifies tables which will be dropped
+ * in the subset.
+ * @HB_SUBSET_SETS_NAME_ID: the set of name ids that will be retained.
+ * @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.
+ *
+ * List of sets that can be configured on the subset input.
+ *
+ * Since: 2.9.1
+ **/
+typedef enum {
+  HB_SUBSET_SETS_GLYPH_INDEX = 0,
+  HB_SUBSET_SETS_UNICODE,
+  HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG,
+  HB_SUBSET_SETS_DROP_TABLE_TAG,
+  HB_SUBSET_SETS_NAME_ID,
+  HB_SUBSET_SETS_NAME_LANG_ID,
+  HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+} hb_subset_sets_t;
+
 HB_EXTERN hb_subset_input_t *
 hb_subset_input_create_or_fail (void);
 
 HB_EXTERN hb_subset_input_t *
-hb_subset_input_reference (hb_subset_input_t *subset_input);
+hb_subset_input_reference (hb_subset_input_t *input);
 
 HB_EXTERN void
-hb_subset_input_destroy (hb_subset_input_t *subset_input);
+hb_subset_input_destroy (hb_subset_input_t *input);
 
-HB_EXTERN hb_set_t *
-hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
-
-HB_EXTERN hb_set_t *
-hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
-
-HB_EXTERN hb_set_t *
-hb_subset_input_nameid_set (hb_subset_input_t *subset_input);
-
-HB_EXTERN hb_set_t *
-hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input);
-
-HB_EXTERN void
-hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
-				hb_bool_t drop_hints);
 HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
+hb_subset_input_set_user_data (hb_subset_input_t  *input,
+			       hb_user_data_key_t *key,
+			       void *		   data,
+			       hb_destroy_func_t   destroy,
+			       hb_bool_t	   replace);
+
+HB_EXTERN void *
+hb_subset_input_get_user_data (const hb_subset_input_t *input,
+			       hb_user_data_key_t	   *key);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_unicode_set (hb_subset_input_t *input);
+
+HB_EXTERN hb_set_t *
+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_subset_flags_t
+hb_subset_input_get_flags (hb_subset_input_t *input);
 
 HB_EXTERN void
-hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-				    hb_bool_t desubroutinize);
-HB_EXTERN hb_bool_t
-hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
+hb_subset_input_set_flags (hb_subset_input_t *input,
+			   unsigned value);
 
-HB_EXTERN void
-hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
-				 hb_bool_t retain_gids);
-HB_EXTERN hb_bool_t
-hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
-
-/* hb_subset () */
 HB_EXTERN hb_face_t *
-hb_subset (hb_face_t *source, hb_subset_input_t *input);
-
+hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
 
 HB_END_DECLS
 
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index b8dd07a..98c5f06 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -45,24 +45,28 @@
   private:
   template <typename T, typename ...Ts> auto
   _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
-  ( obj.subset (this, hb_forward<Ts> (ds)...) )
+  ( obj.subset (this, std::forward<Ts> (ds)...) )
   template <typename T, typename ...Ts> auto
   _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
-  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  ( obj.dispatch (this, std::forward<Ts> (ds)...) )
   public:
   template <typename T, typename ...Ts> auto
   dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
-  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+  ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
 
+  hb_blob_t *source_blob;
   hb_subset_plan_t *plan;
   hb_serialize_context_t *serializer;
-  unsigned int debug_depth;
+  hb_tag_t table_tag;
 
-  hb_subset_context_t (hb_subset_plan_t *plan_,
-		       hb_serialize_context_t *serializer_) :
+  hb_subset_context_t (hb_blob_t *source_blob_,
+		       hb_subset_plan_t *plan_,
+		       hb_serialize_context_t *serializer_,
+		       hb_tag_t table_tag_) :
+		        source_blob (source_blob_),
 			plan (plan_),
 			serializer (serializer_),
-			debug_depth (0) {}
+			table_tag (table_tag_) {}
 };
 
 
diff --git a/src/hb-ucd-table.hh b/src/hb-ucd-table.hh
index 8b7d648..1a4c89c 100644
--- a/src/hb-ucd-table.hh
+++ b/src/hb-ucd-table.hh
@@ -4,7 +4,7 @@
  *
  *   ./gen-ucd-table.py ucd.nounihan.grouped.xml
  *
- * on file with this description: Unicode 12.1.0
+ * on file with this description: Unicode 14.0.0
  */
 
 #ifndef HB_UCD_TABLE_HH
@@ -13,7 +13,7 @@
 #include "hb.hh"
 
 static const hb_script_t
-_hb_ucd_sc_map[153] =
+_hb_ucd_sc_map[162] =
 {
                    HB_SCRIPT_COMMON,              HB_SCRIPT_INHERITED,
                   HB_SCRIPT_UNKNOWN,                 HB_SCRIPT_ARABIC,
@@ -91,7 +91,11 @@
               HB_SCRIPT_MEDEFAIDRIN,            HB_SCRIPT_OLD_SOGDIAN,
                   HB_SCRIPT_SOGDIAN,                HB_SCRIPT_ELYMAIC,
               HB_SCRIPT_NANDINAGARI, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG,
-                   HB_SCRIPT_WANCHO,
+                   HB_SCRIPT_WANCHO,             HB_SCRIPT_CHORASMIAN,
+              HB_SCRIPT_DIVES_AKURU,    HB_SCRIPT_KHITAN_SMALL_SCRIPT,
+                   HB_SCRIPT_YEZIDI,           HB_SCRIPT_CYPRO_MINOAN,
+               HB_SCRIPT_OLD_UYGHUR,                 HB_SCRIPT_TANGSA,
+                     HB_SCRIPT_TOTO,               HB_SCRIPT_VITHKUQI,
 };
 static const uint16_t
 _hb_ucd_dm1_p0_map[825] =
@@ -862,7 +866,7 @@
    HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu),
 };
 static const uint64_t
-_hb_ucd_dm2_u64_map[387] =
+_hb_ucd_dm2_u64_map[388] =
 {
      HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u),
      HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u),
@@ -1051,156 +1055,156 @@
   HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu),
   HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu),
   HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu),HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu),
-   HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u),
-   HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u),
+  HB_CODEPOINT_ENCODE3 (0x11935u, 0x11930u, 0x11938u), HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u),
 };
 
 #ifndef HB_OPTIMIZE_SIZE
 
 static const uint8_t
-_hb_ucd_u8[32102] =
+_hb_ucd_u8[33120] =
 {
     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, 28,
-   29, 26, 30, 31, 32, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 34, 35, 35, 35, 35,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 38, 39, 40,
-   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
-   26, 57, 58, 59, 59, 59, 59, 59, 26, 26, 60, 59, 59, 59, 59, 59,
-   59, 59, 26, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 26, 62, 59, 63, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 64, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 66, 67, 59, 59, 59, 59, 68, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 69, 70, 71, 72, 73, 74, 59, 59,
-   75, 76, 59, 59, 77, 59, 78, 79, 80, 81, 73, 82, 83, 84, 59, 59,
+   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, 85, 26, 26, 26, 26, 26, 26, 26, 86, 87, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 88, 26, 26, 26, 26, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 89, 59, 59, 59, 59, 59, 59, 26, 90, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   91, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93,
+   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,
@@ -1253,7 +1257,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,  2, 21, 21,
+   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,
@@ -1273,9 +1277,9 @@
    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,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,
-    2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    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,
@@ -1306,7 +1310,7 @@
     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,  2, 12, 10,  2,  2,  2,  2,  7,  7,  2,  7,
+    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,
@@ -1317,21 +1321,21 @@
    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,  2,  7, 12, 12,
+    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,  2,  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,  2,  7,  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,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+   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,  2, 10, 10,  2,  7,  7,  7,  7,  7,  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,
@@ -1341,6 +1345,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,
@@ -1384,17 +1389,17 @@
     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,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
-    7,  7, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    7,  7, 12, 12, 12, 21, 21,  2,  2,  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,  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,
@@ -1415,12 +1420,13 @@
    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,  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,  2,  2,  2,  2,
+   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,  2,  2,  2,
+   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,
@@ -1439,7 +1445,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,
-   12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12,
     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,
@@ -1462,6 +1467,7 @@
    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,
@@ -1505,9 +1511,7 @@
    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,  2, 26, 26, 26, 26, 26, 26, 26, 26,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+   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,
@@ -1522,6 +1526,7 @@
    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,
@@ -1554,10 +1559,11 @@
     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,
-    2,  2,  9,  5,  9,  9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  7,  6,  6,  5,  7,  7,  7,  7,  7,
+    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,  2,  2,  2,  2,
+    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,
@@ -1585,7 +1591,7 @@
     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,  2,  2,  2,  2,  2,  2,  2,  2,
+    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,
@@ -1597,12 +1603,12 @@
     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,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   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,  2,
-    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 23, 26,  2,  2,
+    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,
@@ -1625,6 +1631,7 @@
    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,
@@ -1638,7 +1645,14 @@
     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,
@@ -1668,22 +1682,26 @@
     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,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
+   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,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  2,  2,
+   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,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   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,  2,  2,
+   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,
@@ -1702,7 +1720,7 @@
    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,  2, 21,  2, 21, 12,  7,
+   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,
@@ -1713,11 +1731,15 @@
    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,  2,  2,  2,  2,  2,  2,  2,
+   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,
@@ -1746,6 +1768,7 @@
    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,
@@ -1759,17 +1782,20 @@
    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,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    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, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,
    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,
@@ -1807,15 +1833,18 @@
    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,
-   12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
     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,
@@ -1832,1068 +1861,1106 @@
     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,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
+   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, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26,
-   26, 26,  2, 26, 26, 26, 26,  2,  2,  2, 26, 26, 26, 26, 26, 26,
-   26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26,  2,  2,  2, 26, 26,
-   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26,
-   26, 26, 26, 26,  2,  2,  2,  2, 26, 26, 26,  2,  2,  2,  2,  2,
-    7,  7,  2,  2,  2,  2,  2,  2,  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,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,
-   14,  0,  0, 15,  0,  0,  0, 16, 17, 18, 19, 20, 21, 22,  0,  0,
-   23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24, 25,  0,  0,
-   26,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  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, 27,  0, 28, 29, 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, 32,  0,  0, 33,  0,
-    0, 34, 35, 36,  0,  0,  0,  0,  0,  0, 37,  0,  0, 38,  0, 39,
-   40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,  0, 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, 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, 53, 54,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 56, 57,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   58, 54, 59,  0,  0,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,
-    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  9, 10, 11, 12,  0,  0,  0,  0, 13,  0,  0, 14, 15,
-    0, 16,  0,  0,  0,  0,  0, 17, 18,  0,  0, 19,  0, 20, 21,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,
-    0,  0,  0,  0,  0,  0,  0, 27, 28, 29,  0,  0,  0, 30, 31, 32,
-    0,  0,  0,  0,  0, 30, 31,  0,  0, 33,  0,  0,  0, 30, 31,  0,
-    0,  0,  0,  0,  0, 30, 31,  0,  0,  0,  0,  0,  0, 30, 31,  0,
-    0,  0,  0,  0,  0,  0, 31,  0,  0,  0,  0,  0,  0,  0, 31, 34,
-    0,  0,  0,  0,  0, 30, 31,  0,  0,  0,  0,  0,  0, 35, 31,  0,
-    0,  0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0, 37, 38,  0,
-    0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0, 41,  0, 42,  0,  0,
-    0, 43, 44,  0,  0,  0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0,
-    0,  0, 47,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,  0, 49,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 50,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0, 51,  0,  0,  0,  0,  0,  0,  0,  0, 52,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0,  0,  0,  0,
-   54, 55,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0, 57, 49,  0,
-   58, 59,  0,  0, 60,  0,  0,  0, 61, 62,  0,  0,  0, 63,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 64, 65, 66,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 67, 68,  1, 69,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 70, 71, 72,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 73, 74,  0,  0,  0,  0,  0,  0,
-    0, 75,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0, 76,  0,  0,  0,
-    0,  0,  0, 77,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   73, 78,  0, 79,  0,  0,  0,  0,  0, 74, 80,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 49,  0,  1, 74,  0,  0, 81,  0,  0, 82,
-    0,  0,  0,  0,  0, 83, 54,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 84, 85,  0,  0, 80,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 31,  0,  0, 86,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 87,  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, 47,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 88,  0,  0,  0,  0,  0,  0,  0,
-    0, 89,  0,  0,  0,  0,  0,  0,  0,  0, 90,  0,  0, 91,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 92,  0,  0,  0, 93,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 94, 88,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 80,  0,
-    0, 75,  0,  0,  0, 95,  0,  0,  0,  0, 96,  0,  0, 97,  0,  0,
-    0, 83,  0,  0,  0,  0, 98,  0,  0,  0,  0,  0,  0, 99,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,100,  0,  0,  0,  0,101, 31,  0,
-  102,103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,104, 33,
-    0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 75,106,  0,  0,  0,  0,  0,  0, 75,  0,  0,
-    0,  0,  0,  0,  0,107,  0,  0,  0,  0,  0,  0,108,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 95,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0, 54,  0,  0,  0,  0, 49,109,  0,
-    0,  0,  0,110,  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,111,  0,
-    0,  0,  0,109,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,112,  0,  0,  0,113,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,114,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  115,116,117,  0,118,  0,  0,  0,  0,  0,  0,  0,  0,  0,119,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,120,121,122,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,123,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,124,  0,  0,  0,  0,  0,  0,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,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  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,230,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,230,230,230,230,230,230,230,230,  0,  0,  0,230,230,230,
-  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
-  230,230, 30, 31, 32,  0,  0,  0,  0,  0,  0,  0,  0,  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,  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,  0,  0,  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,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,230,230,230,230,230,230,230,220,230,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,
-  230,230,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,  0,  0,  0,  0,  0,
-    0,  0,  0,220,220,220,  0,  0,  0,  0,  0,  0,  0,220,230,230,
-  230,230,230,230,230,230,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,  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,  9,  0,  0,  0,230,220,230,230,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,  0,  0,  0, 84,
-   91,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  9,  9,  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,103,103,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,107,107,107,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,118,118,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,122,122,122,122,  0,  0,  0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,
-  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  7,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,  0,  9,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,228,  0,  0,  0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,
-  230,230,230,230,230,230,230,  0,  0,220,230,230,230,230,230,220,
-  220,220,220,220,220,230,230,220,  0,  0,  0,  0,  0,  0,  7,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,230,220,230,230,230,230,230,230,230,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,  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,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,230,230,230,230,230,230,230,230,
-  232,228,228,220,  0,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,  0,  0,  0,  0,  0,  0,  0,
+  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,
-    0,  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,218,228,232,222,224,224,  0,  0,  0,  0,  0,  0,
-    0,  0,  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,
-    0,  0,  0,  0,  0,  0,  0,  0,230,230,  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,220,220,220,  0,  0,  0,  0,  0,  9,  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,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,  0,  0,  0,  0,  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,220,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,220,  0,230,  0,  0,  0,  0,  0,  0,
-    0,  0,230,  1,220,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,230,
-  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,
-  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  220,220,230,230,230,220,230,220,220,220,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  9,  7,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,
-    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  7,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  7,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  230,230,230,230,230,230,230,  0,  0,  0,230,230,230,230,230,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
-    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  7,  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,
-    9,  7,  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,  9,  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,  7,  0,  9,  9,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
-  230,  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,  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,  0,  0,  0,  0,
-    0,  0,  0,  0,230,230,230,230,  0,  0,  0,  0,230,230,230,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
-  230,  0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,
-  230,230,230,  0,  0,230,230,230,230,230,230,230,  0,230,230,  0,
-  230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,230,230,230,230,220,220,220,220,220,220,
-  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,
-  230,230,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,
+    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,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,
+   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,  0,  0,  0,  0,  0,  0,  7,  1,  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,
-    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, 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,  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, 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, 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, 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,  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,  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,  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,  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,  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, 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,
-   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, 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,  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, 27, 28, 28, 29, 30, 31, 32,
-   33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
-   33, 33, 33, 33, 33, 34, 35, 35, 35, 35, 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, 56, 57, 58, 35, 35, 35,
-   35, 35, 59, 59, 60, 35, 35, 35, 35, 35, 35, 35, 61, 62, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 63, 64,
-   35, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 66, 68,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 69, 70, 35, 35, 35, 35, 71, 35, 35, 35, 35, 35, 35, 35,
-   35, 35, 72, 73, 74, 75, 76, 77, 35, 35, 78, 79, 35, 35, 80, 35,
-   81, 82, 83, 84, 17, 85, 86, 87, 35, 35, 25, 25, 25, 25, 25, 25,
+    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, 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, 88, 25, 25,
-   25, 25, 25, 25, 25, 89, 90, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-   25, 91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92,
-   35, 35, 35, 35, 35, 35, 25, 93, 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, 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, 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, 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, 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, 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, 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, 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,
-   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, 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, 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, 35, 35, 35,
-   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 94,  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,  0,  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,  2,  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,  2,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
-    3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  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,  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,  2, 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,  2, 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,  2,  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,  2, 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,
-    2, 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,  2, 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, 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,
+   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,
-   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,  2, 45, 45, 45, 45, 45, 45,
-   45,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 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,  2, 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,  2,  2,  2,  2, 62, 62, 62, 62,
-   62, 62, 62, 62, 62, 62, 62, 62, 62,  2,  2,  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,  1,  1,  1,  1,
-    1,  1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  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,  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,  2,  0,  0,  0,  0,  0,  0,  0,  0, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2, 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, 13, 13, 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, 26, 26, 26, 26,
-   26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  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,
+   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, 19, 19, 19,  0,  0,  0, 19, 19, 19, 19, 19,  2,  2, 19, 19,
-   19, 19, 19,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
-    2,  2,  2, 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,  2,  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,  2,  2,  2,  2,  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,  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,  0,  0,  2,  2,  3,  3,
+   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,  3,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  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,  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,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, 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,  3,  3,  3,  3,
-    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  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,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,  2,  2,  2,  2,
-    2,  2,  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,  2,  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,  2,  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,100,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,  2,  2,  2, 36, 36, 36,
+    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,  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,  2,137,  2,137,137,137,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,  2,  2,  2,  2,  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,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,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,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, 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, 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,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,  0,  0,
-    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,136,136,136,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 17, 15, 15, 15,
+   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,  2, 15, 15, 15,  2,
+   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,
-   17, 17, 17, 17,  2,  2,  2,  2,  2,  2,  2,  2,139,139,139,139,
+    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,139,139,139,139,139,139,  2,  2,  2,  2,105,105,105,105,
+  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,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,  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,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  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,  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,
+  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,  0,  0,  0,  0,  0,  0,  0,  2,  2,  0,  0,131,131,131,131,
+    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,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, 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,
+  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,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,152,152,152,152,
+  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,
-  152,152,152,152,152,152,  2,  2,  2,  2,  2,152,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,
+    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,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,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,
-    0,  0,  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, 15,  0,  0,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  2,  2,
+  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,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  2,  0,
-    0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,
-    2,  0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,
-    2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,
-    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13, 13, 13,
-   13, 13, 13,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13, 13, 13,
-   13,  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, 13,  2,  2,  2,
-    2,  2,  2,  2,  2,  2,  2,  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, 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, 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, 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,
@@ -2943,14 +3010,15 @@
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  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, 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,  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,
+    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,
@@ -2996,8 +3064,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, 69, 70, 71,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 68, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -3070,11 +3138,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, 71, 72, 73, 74,
-   75, 76, 77, 78, 79,  0,
+    0,  0,  0,  0,  0,  0, 72, 73, 74, 75, 76, 77, 78, 79, 80,  0,
 };
 static const uint16_t
-_hb_ucd_u16[11168] =
+_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,
@@ -3084,186 +3151,196 @@
     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,  72,  72,  72,  48,  73,  72,  74,  75,  32,
+    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,  72,  72, 140,  48, 141, 142, 143, 144,  72,  72,
-   145, 146, 147, 148, 149,  48, 150, 151, 152, 153,  32, 154, 155, 156,  72,  72,
-    48,  48, 157, 158, 159, 160, 161, 162, 163, 164,   9,   9, 165,  11,  11, 166,
+   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, 167, 168,  48,  48, 167,  48,  48, 169, 170, 171,  48,  48,
-    48, 170,  48,  48,  48, 172, 173, 174,  48, 175,   9,   9,   9,   9,   9, 176,
-   177,  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, 178,  48, 179, 180,  48,  48,  48,  48, 181, 182,
-   183, 184,  48, 185,  48, 186, 183, 187,  48,  48,  48, 188, 189, 190, 191, 192,
-   193, 191,  48,  48, 194,  48,  48, 195, 196,  48, 197,  48,  48,  48,  48, 198,
-    48, 199, 200, 201, 202,  48, 203, 204,  48,  48, 205,  48, 206, 207, 208, 208,
-    48, 209,  48,  48,  48, 210, 211, 212, 191, 191, 213, 214,  72,  72,  72,  72,
-   215,  48,  48, 216, 217, 159, 218, 219, 220,  48, 221,  64,  48,  48, 222, 223,
-    48,  48, 224, 225, 226,  64,  48, 227, 228,   9,   9, 229, 230, 231, 232, 233,
-    11,  11, 234,  27,  27,  27, 235, 236,  11, 237,  27,  27,  32,  32,  32, 238,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 239,  13,  13,  13,  13,  13,  13,
-   240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249,
-   250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260,  72, 261, 262, 263,
-   264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276,
-   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
-   278, 208, 279, 208, 208, 208, 208, 280, 208, 281, 277, 282, 208, 283, 284, 208,
-   208, 208, 285,  72, 286,  72, 269, 269, 269, 287, 208, 208, 208, 208, 288, 269,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 289, 290, 208, 208, 291,
-   208, 208, 208, 208, 208, 208, 292, 208, 208, 208, 208, 208, 208, 208, 208, 208,
-   208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
-   277, 277, 277, 277, 277, 277, 277, 277, 298, 299, 277, 277, 277, 300, 277, 301,
-   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
-   208, 208, 208, 277, 302, 208, 208, 303, 208, 304, 208, 208, 208, 208, 208, 208,
-     9,   9, 305,  11,  11, 306, 307, 308,  13,  13,  13,  13,  13,  13, 309, 310,
+    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,  72,  72,  72, 208, 321, 208, 208, 208, 208, 208, 322,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323,  72, 324,
-   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 177,  48,  48,  48,  48, 330,
-   331,  48,  48, 136,  48,  48,  48,  48, 199, 332,  48,  71, 208, 208, 322,  48,
-   208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+   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, 198, 208, 208, 208, 208,
+    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,  48,  48,  48,  48,  48,  48,  48,  72,
-    48, 337,  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,
-    48,  48,  48,  48,  48,  48,  48,  48, 150, 208, 208, 208, 285,  48,  48, 227,
+   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,
-   338,  48, 339,  72,  13,  13, 340, 341,  13, 342,  48,  48,  48,  48, 343, 344,
-    31, 345, 346, 347,  13,  13,  13, 348, 349, 350, 351, 352, 353,  72,  72, 354,
-   355,  48, 356, 357,  48,  48,  48, 358, 359,  48,  48, 360, 361, 191,  32, 362,
-    64,  48, 363,  48, 364, 365,  48, 150,  76,  48,  48, 366, 367, 368, 369, 370,
-    48,  48, 371, 372, 373, 374,  48, 375,  48,  48,  48, 376, 377, 378, 379, 380,
-   381, 382, 315,  11,  11, 383, 384,  11,  11,  11,  11,  11,  48,  48, 385, 191,
+    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,  48,  48,  48,  48, 386,  48, 387,  48,  48, 205,
-   388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
-   388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+    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,  48,  48,  48, 203,  48,  48,  48,  48,  48,  48, 206,  72,  72,
-   390, 391, 392, 393, 394,  48,  48,  48,  48,  48,  48, 395, 396, 397,  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, 398,  72,  48,  48,  48,  48, 399,  48,  48, 400,  72,  72, 401,
-    32, 402,  32, 403, 404, 405, 406, 407,  48,  48,  48,  48,  48,  48,  48, 408,
-   409,   2,   3,   4,   5, 410, 411, 412,  48, 413,  48, 199, 414, 415, 416, 417,
-   418,  48, 171, 419, 203, 203,  72,  72,  48,  48,  48,  48,  48,  48,  48,  71,
-   420, 269, 269, 421, 270, 270, 270, 422, 423, 324, 424,  72,  72, 208, 208, 425,
-    72,  72,  72,  72,  72,  72,  72,  72,  48, 150,  48,  48,  48, 100, 426, 427,
-    48,  48, 428,  48, 429,  48,  48, 430,  48, 431,  48,  48, 432, 433,  72,  72,
-     9,   9, 434,  11,  11,  48,  48,  48,  48, 203, 191,   9,   9, 435,  11, 436,
-    48,  48, 400,  48,  48,  48, 437,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    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, 314,  48, 198, 400,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   438,  48,  48, 439,  48, 440,  48, 441,  48, 199, 442,  72,  72,  72,  48, 443,
-    48, 444,  48, 445,  72,  72,  72,  72,  48,  48,  48, 446, 269, 447, 269, 269,
-   448, 449,  48, 450, 451, 452,  48, 453,  48, 454,  72,  72, 455,  48, 456, 457,
-    48,  48,  48, 458,  48, 459,  48, 460,  48, 461, 462,  72,  72,  72,  72,  72,
-    48,  48,  48,  48, 195,  72,  72,  72,   9,   9,   9, 463,  11,  11,  11, 464,
-    48,  48, 465, 191,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72, 269, 466,  72,  72,  72,  72,  72,  72,  72,  72,
-    48, 454, 467,  48,  62, 468,  72,  72,  72,  72,  72,  72,  72,  72,  48, 314,
-   469,  48,  48, 470, 471, 447, 472, 473, 220,  48,  48, 474, 475,  48, 195, 191,
-   476,  48, 477, 478, 479,  48,  48, 480, 220,  48,  48, 481, 482, 483, 484, 485,
-    48,  97, 486, 487,  72,  72,  72,  72, 488, 489, 490,  48,  48, 491, 492, 191,
-   493,  83,  84, 494, 495, 496, 497, 498,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48,  48, 499, 500, 501,  72,  72,  48,  48,  48, 502, 503, 191,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 504, 505, 506, 507,  72,  72,
-    48,  48,  48, 508, 509, 191, 510,  72,  48,  48, 511, 512, 191,  72,  72,  72,
-    48, 172, 513, 514,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48, 486, 515,  72,  72,  72,  72,  72,  72,   9,   9,  11,  11, 147, 516,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72, 517,  48,  48, 518, 519,  72,
-   520,  48,  48, 521, 522, 523,  48,  48, 524, 525, 526,  72,  48,  48,  48, 195,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    84,  48, 504, 527, 528, 147, 174, 529,  48, 530, 531, 532,  72,  72,  72,  72,
-   533,  48,  48, 534, 535, 191, 536,  48, 537, 538, 191,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 539,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72, 269, 540, 541, 542,
+    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, 206,  72,  72,  72,  72,  72,  72,
-   270, 270, 270, 270, 270, 270, 543, 544,  48,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48, 386,  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,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48, 199, 545,  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,  72,  72,
-    48,  48,  48,  48, 314,  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,  72,
-    48,  48,  48, 195,  48, 199, 368,  72,  72,  72,  72,  72,  72,  48, 203, 546,
-    48,  48,  48, 547, 548, 549, 550, 551,  48,  72,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,   9,   9,  11,  11, 269, 552,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48, 553, 554, 555, 555, 556, 557,  72,  72,  72,  72, 558,  72,
+    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,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 400,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 559,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48, 199,  72,  72,  72, 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, 205,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48,  48,  48,  71, 150, 195, 561, 562,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323,
-   208, 208, 563, 208, 208, 208, 564, 565, 566, 208, 567, 208, 208, 208, 568,  72,
-   208, 208, 208, 208, 569,  72,  72,  72,  72,  72,  72,  72,  72,  72, 269, 570,
-   208, 208, 208, 208, 208, 285, 269, 451,  72,  72,  72,  72,  72,  72,  72,  72,
-     9, 571,  11, 572, 573, 574, 240,   9, 575, 576, 577, 578, 579,   9, 571,  11,
-   580, 581,  11, 582, 583, 584, 585,   9, 586,  11,   9, 571,  11, 572, 573,  11,
-   240,   9, 575, 585,   9, 586,  11,   9, 571,  11, 587,   9, 588, 589, 590, 591,
-    11, 592,   9, 593, 594, 595, 596,  11, 597,   9, 598,  11, 599, 600, 600, 600,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
-    32,  32,  32, 601,  32,  32, 602, 603, 604, 605,  45,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   606, 607, 608,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48, 150, 609, 610,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 611, 612,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 613, 614,  72,  72,
-     9,   9, 575,  11, 615, 368,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72, 484, 269, 269, 616, 617,  72,  72,  72,  72,
-   484, 269, 618, 619,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   620,  48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205,  72,  72,  72, 629,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323,
-   174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631,  72,  72,  72, 632, 208,
-   633, 208, 208, 324, 568, 634, 323,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 635,
-   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323, 631, 286,
-   208, 208, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 568, 324,  72,
-   324, 208, 208, 208, 636, 175, 208, 208, 636, 208, 637,  72,  72,  72,  72,  72,
-   638, 208, 208, 208, 208, 208, 208, 639, 208, 208, 640, 208, 641, 208, 208, 208,
-   208, 208, 208, 208, 208, 322, 637, 642, 633, 323,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 314,  72,  72,
+    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, 204,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
-    48, 203,  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, 643,  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,  72,
-    48, 203,  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,  72,  72,  72,  72,
-   644,  72, 645, 645, 645, 645, 645, 645,  72,  72,  72,  72,  72,  72,  72,  72,
-    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  72,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 646,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
-   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 647,
+    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,
@@ -3272,14 +3349,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,  45,  45,  45,  27,  46,  45,  47,  48,  27,
-    49,  49,  49,  49,  49,  50,  51,  49,  52,  53,  54,  55,  56,  57,  58,  59,
-    60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
-    76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
-    92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107,
-   108, 109, 110, 110, 111, 112, 113, 110, 114, 115, 116, 117, 118, 119, 120, 121,
-   122, 123, 123, 124, 123, 125,  45,  45, 126, 127, 128, 129, 130, 131,  45,  45,
-   132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137,  45,  45,
+    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,
@@ -3290,169 +3367,181 @@
    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, 195,  45,  45,  45,  45,
+   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, 217,
+     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, 218,  11,  11, 218, 219,  11, 220,  11,  11,  11, 221, 221, 222,  11, 223,
-   224,   0,   0,   0,   0,   0, 225, 226, 227, 228,   0,   0,  45,   8,   8, 229,
+    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,  45, 235,  45,   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, 240, 239, 239, 240,   4,   4, 241, 241, 241, 241, 241, 241, 241, 242,
-   139, 139, 140, 243, 243, 243, 244, 245, 143, 246, 247, 247, 247, 247,  14,  14,
-     0,   0,   0,   0,   0,  45,  45,  45, 248, 249, 248, 248, 248, 248, 248, 250,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251,  45, 252,
+   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, 266,   0,   0, 267, 260,
-   142, 265,   0,   0,   0,   0, 142, 268,   0,   0,   0,   0,   0, 260, 260, 269,
-   260, 260, 260, 260, 260, 270,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   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, 251,   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,  45,
-   271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
-   271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
-   271, 271, 271, 271, 271, 271, 271, 271, 272, 271, 271, 271, 273, 274, 274, 274,
-   275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275,
-   275, 275, 276,  45,  14,  14,  14,  14,  14,  14, 277, 277, 277, 277, 277, 278,
-     0,   0, 279,   4,   4,   4,   4,   4, 280,   4,   4,   4, 281,  45,  45, 282,
-   283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290,  49,  49,
+   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, 247,   4,   4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
+   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,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   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,  45,  45,
-   320, 321,  21, 322, 323,  27,  27,  27,  27,  27,  27,  27, 324,  47,  27,  27,
+   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, 325,  45,  27,  27,  27,  27, 326,  27,  27, 327,  45,  45, 328,
+    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,  45,  45, 342, 342, 342, 342, 342, 342, 342, 346,
-   347,   0,   0, 348,  11,  11,  11,  11, 349, 252, 350,  45,  45,   0,   0, 351,
-    45,  45,  45,  45,  45,  45,  45,  45, 352, 353, 354, 354, 354, 355, 356, 252,
-   357, 357, 358, 359, 360, 361, 361, 362, 363, 364, 365, 365, 366, 367,  45,  45,
-   368, 368, 368, 368, 368, 369, 369, 369, 370, 371, 372, 373, 373, 374, 373, 375,
-   376, 376, 377, 378, 378, 378, 379,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
-   380, 380, 380, 381, 380, 382, 383,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392,  45,  45,  45, 393, 394,
-   395, 396, 397, 398,  45,  45,  45,  45, 399, 399, 400, 401, 400, 402, 400, 400,
-   403, 404, 405, 406, 407, 407, 408, 408, 409, 409,  45,  45, 410, 410, 411, 412,
-   413, 413, 413, 414, 415, 416, 417, 418, 419, 420, 421,  45,  45,  45,  45,  45,
-   422, 422, 422, 422, 423,  45,  45,  45, 424, 424, 424, 425, 424, 424, 424, 426,
-   427, 427, 428, 429,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  27, 430,  45,  45,  45,  45,  45,  45,  45,  45,
-   431, 431, 432, 433, 433, 434,  45,  45,  45,  45,  45,  45,  45,  45, 435, 436,
-   437, 437, 437, 437, 438, 439, 437, 440, 441, 441, 441, 441, 442, 443, 444, 445,
-   446, 446, 446, 447, 448, 449, 449, 450, 451, 451, 451, 451, 452, 451, 453, 454,
-   455, 456, 455, 457,  45,  45,  45,  45, 458, 459, 460, 461, 461, 461, 462, 463,
-   464, 465, 466, 467, 468, 469, 470, 471,  45,  45,  45,  45,  45,  45,  45,  45,
-   472, 472, 472, 472, 472, 473,  45,  45, 474, 474, 474, 474, 475, 476,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45, 477, 477, 477, 478, 477, 479,  45,  45,
-   480, 480, 480, 480, 481, 482, 483,  45, 484, 484, 484, 485, 486,  45,  45,  45,
-   487, 488, 489, 487,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   490, 490, 490, 491,  45,  45,  45,  45,  45,  45, 492, 492, 492, 492, 492, 493,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 494, 495, 495, 494, 496,  45,
-   497, 497, 497, 497, 498, 499, 499, 499, 499, 499, 500,  45, 501, 501, 501, 502,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   503, 504, 504, 505, 506, 504, 507, 508, 508, 509, 510, 511,  45,  45,  45,  45,
-   512, 513, 513, 514, 515, 516, 517, 518, 519, 520, 521,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 522, 523,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 524, 524, 524, 525,
-   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
-   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
-   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
-   526, 526, 526, 526, 526, 526, 526, 526, 526, 527,  45,  45,  45,  45,  45,  45,
-   526, 526, 526, 526, 526, 526, 528, 529, 526, 526, 526, 526, 526, 526, 526, 526,
-   526, 526, 526, 526, 530,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531,
-   531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531,
-   531, 531, 532, 533,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534,
-   534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534,
-   534, 534, 534, 534, 535,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   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, 277, 277, 277, 277, 277, 277,
-   277, 277, 277, 536, 537, 538, 539,  45,  45,  45,  45,  45,  45, 540, 541, 542,
-   543, 543, 543, 543, 544, 545, 546, 547, 543,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45, 548, 548, 548, 548, 548, 549,  45,  45,  45,  45,  45,  45,
-   550, 550, 550, 550, 551, 550, 550, 550, 552, 550,  45,  45,  45,  45, 553,  45,
-   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
-   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
-   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
-   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555,
-   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 556,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   557, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
-   257, 558,  45,  45,  45, 559, 560, 561, 561, 561, 561, 561, 561, 561, 561, 561,
-   561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   563, 563, 563, 563, 563, 563, 564, 565, 566, 567, 267,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 568,
-     0,   0, 569,   0,   0,   0, 570, 571, 572,   0, 573,   0,   0,   0, 574,  45,
-    11,  11,  11,  11, 575,  45,  45,  45,  45,  45,  45,  45,  45,  45,   0, 267,
-     0,   0,   0,   0,   0, 234,   0, 574,  45,  45,  45,  45,  45,  45,  45,  45,
-     0,   0,   0,   0,   0, 225,   0,   0,   0, 576, 577, 578, 579,   0,   0,   0,
-   580, 581,   0, 582, 583, 584,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 238,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 585,   0,   0,   0,
-   586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586,
-   586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586,
-   586, 586, 586, 586, 586, 586, 586, 586, 587, 588, 589,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   590, 591, 592,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   593, 593, 594, 595, 596,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 597, 597, 597, 598,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 601,  45,  45,
-   602, 602, 602, 602, 603, 604,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45, 334,   0,   0,   0, 605,  45,  45,  45,  45,
-   334,   0,   0, 606,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   607,  27, 608, 609, 610, 611, 612, 613, 614, 615, 616, 615,  45,  45,  45, 324,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-     0,   0, 252,   0,   0,   0,   0,   0,   0, 267, 227, 334, 334, 334,   0, 568,
-   617,   0,   0,   0,   0,   0, 617,   0,   0,   0, 617,  45,  45,  45, 618,   0,
-   619,   0,   0, 252, 574, 620, 568,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   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, 568, 617, 235,
-     0,   0,   0,   0,   0,   0,   0, 267,   0,   0,   0,   0,   0, 574, 252,  45,
-   252,   0,   0,   0, 621, 285,   0,   0, 621,   0, 606,  45,  45,  45,  45,  45,
-   622,   0,   0,   0,   0,   0,   0, 623,   0,   0, 624,   0, 625,   0,   0,   0,
-     0,   0,   0,   0,   0, 267, 606, 626, 627, 568,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 628,  45,  45,
+     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, 629, 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, 630, 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, 631,  45,
-   248, 318,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
-   632,  45,   0,   0,   0,   0,   0,   0,  45,  45,  45,  45,  45,  45,  45,  45,
+   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,
@@ -3727,14 +3816,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,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,1948,1949,
-  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     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,1955,1956,1957,1959,1958,
-  1960,   0,   0,   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,
@@ -3801,7 +3894,7 @@
 static inline uint_fast8_t
 _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[14026+(((_hb_ucd_u8[13034+(((_hb_ucd_u8[12544+(u>>4>>4)])<<4)+((u>>4)&15u))])<<4)+((u)&15u))]:0;
+  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)
@@ -3811,59 +3904,59 @@
 static inline int_fast16_t
 _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16170+(((_hb_ucd_b4(16042+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
+  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[18924+(((_hb_ucd_u16[3008+(((_hb_ucd_u8[17130+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
+  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[6048+(((_hb_ucd_u8[29052+(u>>6)])<<6)+((u)&63u))]:0;
+  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[17198] =
+_hb_ucd_u8[17936] =
 {
     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
-    7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 14, 14, 14, 15,
-   16, 17, 18, 19, 20, 21, 22, 21, 23, 21, 21, 21, 21, 24,  7,  7,
-   25, 26, 21, 21, 21, 21, 27, 28, 21, 21, 29, 30, 31, 32, 33, 34,
+    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, 35,  7, 36, 37,  7, 38,  7,  7,  7, 39, 21, 40,
-   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, 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, 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, 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, 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, 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,
-   41, 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,
-   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, 42,
-   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, 43,
+    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,
@@ -3873,41 +3966,44 @@
    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,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91,
-   92, 34, 34, 34, 34, 34, 34, 34, 34, 93, 34, 34, 94, 95, 96, 97,
-   98, 99,100,101,102,103,104,105, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,106,
+   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,
-  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
-  108,108, 34, 34,109,110,111,112, 34, 34,113,114,115,116,117,118,
-  119,120,121,122,123,124,125,126,127,128,129,123, 34, 34,130,123,
-  131,132,133,134,135,136,137,138,139,140,141,123,142,123,143,144,
-  145,146,147,148,149,150,151,123,152,153,123,154,155,156,157,123,
-  158,159,123,160,161,162,123,123,163,164,165,166,123,167,123,168,
-   34, 34, 34, 34, 34, 34, 34,169,170, 34,171,123,123,123,123,123,
-  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
-   34, 34, 34, 34, 34, 34, 34, 34,172,123,123,123,123,123,123,123,
-  123,123,123,123,123,123,123,123, 34, 34, 34, 34,173,123,123,123,
-   34, 34, 34, 34,174,175,176,177,123,123,123,123,178,179,180,181,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,182,
-   34, 34, 34, 34, 34,183,123,123,123,123,123,123,123,123,123,123,
-   34, 34,184, 34, 34,185,123,123,123,123,123,123,123,123,123,123,
-  123,123,123,123,123,123,123,123,186,187,123,123,123,123,123,123,
-   69,188,189,190,191,192,193,123,194,195,196,197,198,199,200,201,
-   69, 69, 69, 69,202,203,123,123,123,123,123,123,123,123,123,123,
-  204,123,205,123,123,206,123,123,123,123,123,123,123,123,123,123,
-   34,207,208,123,123,123,123,123,209,210,211,123,212,213,123,123,
-  214,215,216,217,218,123, 69,219, 69, 69, 69, 69, 69,220,221,222,
-  223,224,225,226,227,228,123,123,123,123,123,123,123,123,123,123,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,229, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,230, 34,
-  231, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,232, 34, 34,
-   34, 34, 34, 34, 34, 34, 34,233,123,123,123,123,123,123,123,123,
-   34, 34, 34, 34,234,123,123,123,123,123,123,123,123,123,123,123,
-  235,123,236,237,123,123,123,123,123,123,123,123,123,123,123,123,
-  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,238,
-  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,239,
+  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,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,
+  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,
     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,
@@ -3944,260 +4040,271 @@
    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,
-   44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 44,
-   44, 57, 43, 43, 43, 43, 43, 43, 43, 82, 43, 43, 43, 43, 43, 43,
-   43, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 83, 71, 84,
-   85, 43, 43, 43, 83, 84, 85, 84, 70, 43, 43, 43, 36, 36, 36, 36,
-   36, 43,  2,  7,  7,  7,  7,  7, 86, 36, 36, 36, 36, 36, 36, 36,
-   70, 84, 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, 84,
-   85, 43, 80, 87, 88, 87, 85, 61, 44, 44, 44, 87, 44, 44, 36, 62,
+   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, 83, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 84,
-   85, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61,
+   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, 83, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
-   61, 36, 62, 36, 36, 44, 71, 84, 85, 43, 43, 57, 83, 87, 85, 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, 84, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 85,
-   85, 43, 80, 87, 88, 87, 85, 44, 44, 44, 44, 83, 44, 44, 36, 62,
+   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, 84, 83, 88, 44, 84, 88, 84, 85, 44,
-   61, 44, 44, 87, 44, 44, 44, 44, 27, 89, 67, 67, 56, 90, 44, 44,
-   83, 84, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 44, 62, 43, 83, 84, 88, 43, 80, 43, 43, 44,
-   44, 44, 57, 80, 36, 61, 44, 44, 44, 44, 44, 91, 27, 27, 27, 89,
-   70, 84, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 85,
-   84, 84, 88, 83, 88, 84, 43, 44, 44, 44, 87, 88, 44, 44, 44, 61,
-   62, 61, 44, 44, 44, 44, 44, 44, 43, 84, 62, 36, 36, 36, 61, 36,
-   36, 36, 36, 36, 36, 70, 71, 84, 85, 43, 80, 84, 88, 84, 85, 77,
-   44, 44, 36, 92, 27, 27, 27, 93, 27, 27, 27, 27, 89, 36, 36, 36,
-   44, 84, 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, 87,
-   84, 43, 80, 80, 84, 84, 84, 84, 44, 84, 64, 44, 44, 44, 44, 44,
-   62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 94,
+   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, 61, 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,
-   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, 77, 67,  2,  2,  2,  2,  2,  2,
-    2, 95, 95, 67, 43, 67, 67, 67,  7,  7,  7,  7,  7, 27, 27, 27,
-   27, 27, 50, 50, 50,  4,  4, 84, 36, 36, 36, 36, 62, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 61, 44, 57, 43, 43, 43, 43, 43, 43, 83,
-   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, 90, 67,
-    2,  2, 95, 67, 21, 64, 44, 44, 36, 36, 36, 36, 36, 92, 85, 43,
-   83, 43, 43, 43, 85, 83, 85, 71,  7,  7,  7,  7,  7,  2,  2,  2,
-   36, 36, 36, 84, 43, 36, 36, 43, 71, 84, 96, 92, 84, 84, 84, 36,
-   70, 43, 71, 36, 36, 36, 36, 36, 36, 83, 85, 83, 84, 84, 85, 92,
-    7,  7,  7,  7,  7, 84, 85, 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, 97, 27, 27, 27,
-   27, 27, 27, 27, 27, 27, 98, 44, 67, 67, 67, 67, 67, 44, 44, 44,
-   11, 11, 11, 44, 16, 16, 16, 44, 99, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 77, 72,100, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36,101,102, 44, 36, 36, 36, 36, 36, 63,  2,103,
-  104, 36, 36, 36, 61, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
-   36, 43, 80, 44, 44, 44, 44, 44, 36, 43, 60, 64, 44, 44, 44, 44,
-   36, 43, 44, 44, 44, 44, 44, 44, 61, 43, 44, 44, 44, 44, 44, 44,
-   36, 36, 43, 85, 43, 43, 43, 84, 84, 84, 84, 83, 85, 43, 43, 43,
-   43, 43,  2, 86,  2, 66, 70, 44,  7,  7,  7,  7,  7, 44, 44, 44,
-   27, 27, 27, 27, 27, 44, 44, 44,  2,  2,  2,105,  2, 59, 43, 68,
-   36,106, 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, 83, 84, 85, 83, 84, 44, 44, 84, 83, 84, 84, 85, 43, 44, 44,
-   90, 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, 98, 44, 67,
-   67, 67, 67, 67, 67, 67, 67, 67, 36, 36, 36, 70, 83, 85, 44,  2,
-   36, 36, 92, 83, 43, 43, 43, 80, 83, 83, 85, 43, 43, 43, 83, 84,
-   84, 85, 43, 43, 43, 43, 80, 57,  2,  2,  2, 86,  2,  2,  2, 44,
-   43, 43, 43, 43, 43, 43, 43,107, 43, 43, 96, 36, 36, 36, 36, 36,
-   36, 36, 83, 43, 43, 83, 83, 84, 84, 83, 96, 36, 36, 36, 44, 44,
-   95, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 90, 44,
-   43, 96, 36, 36, 36, 36, 36, 36, 92, 43, 43, 84, 43, 85, 43, 36,
-   36, 36, 36, 83, 43, 84, 85, 85, 43, 84, 44, 44, 44, 44,  2,  2,
-   36, 36, 84, 84, 84, 84, 43, 43, 43, 43, 84, 43, 44, 91,  2,  2,
+   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,
+   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,108, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+   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,
-   83, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 92, 43, 61, 44, 44,
+   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,109, 40, 40,
-   43, 43, 43, 43, 43, 57, 43, 43, 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,110,110,110,110, 16, 16,108, 16, 11, 11,111,112,
-   41, 16,108, 16, 11, 11,111, 41, 16, 16, 44, 16, 11, 11,113, 41,
-   16, 16, 16, 16, 11, 11,114, 41, 44, 16,108, 16, 11, 11,111,115,
-  116,116,116,116,116,117, 65, 65,118,118,118,  2,119,120,119,120,
-    2,  2,  2,  2,121, 65, 65,122,  2,  2,  2,  2,123,124,  2,125,
-  126,  2,127,128,  2,  2,  2,  2,  2,  9,126,  2,  2,  2,  2,129,
-   65, 65, 68, 65, 65, 65, 65, 65,130, 44, 27, 27, 27,  8,127,131,
-   27, 27, 27, 27, 27,  8,127,102, 40, 40, 40, 40, 40, 40, 81, 44,
-   20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,132, 51,
-  133, 51,133, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
-   67,134, 67,135, 67, 34, 11, 16, 11, 32,135, 67, 49, 11, 11, 67,
-   67, 67,134,134,134, 11, 11,136, 11, 11, 35, 36, 39, 67, 16, 11,
-    8,  8, 49, 16, 16, 26, 67,137, 27, 27, 27, 27, 27, 27, 27, 27,
-  103,103,103,103,103,103,103,103,103,138,139,103,140, 67, 44, 44,
-    8,  8,141, 67, 67,  8, 67, 67,141, 26, 67,141, 67, 67, 67,141,
-   67, 67, 67, 67, 67, 67, 67,  8, 67,141,141, 67, 67, 67, 67, 67,
+   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,142,143, 67, 67,
-   67, 67, 67, 67, 67, 67,141, 67, 67, 67, 67, 67, 67, 26,  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, 90, 44, 44, 44, 44,
-   67, 67, 67, 67, 67, 90, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67,
+    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,127,144,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
-    8,127,145,145,145,145,145,145,145,145,145,145,144,  8,  8,  8,
+    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,141, 26,  8,  8,141, 67, 67, 67, 44, 67, 67, 67, 67, 67,
-   67, 67, 67, 44, 67, 67, 67, 67, 11, 11, 11, 11, 11, 11, 11, 47,
-   16, 16, 16, 16, 16, 16, 16,108, 32, 11, 32, 34, 34, 34, 34, 11,
-   32, 32, 34, 16, 16, 16, 40, 11, 32, 32,137, 67, 67,135, 34,146,
-   43, 32, 44, 44, 91,  2, 97,  2, 16, 16, 16,147, 44, 44,147, 44,
+    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,119,119,  2,123,124,119,  2,  2,  2,  2,  6,  2,105,119,  2,
-  119,  4,  4,  4,  4,  2,  2, 86,  2,  2,  2,  2,  2,118,  2,  2,
-  105,148,  2,  2,  2,  2,  2,  2, 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,149,150,  4,  4,  4,  4,
-    4, 67,  4,  4,  4,  4,151,152,153,103,103,103,103, 43, 43, 84,
-  154, 40, 40, 67,103,155, 63, 67, 36, 36, 36, 61, 57,156,157, 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, 67, 67, 67, 67, 90,
-   27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27,
-  158, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36,159,  2,  7,  7,  7,  7,  7, 36, 44, 44,
-   32, 32, 32, 32, 32, 32, 32, 70, 51,160, 43, 43, 43, 43, 43, 86,
-   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36,103,103,103,103,103,
-   43,  2,  2,  2, 44, 44, 44, 44, 41, 41, 41,157, 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,161, 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, 44, 32, 11, 47, 44, 44, 44, 44,
-   44, 44, 44, 62, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
-   36, 92, 85, 83, 67, 67, 44, 44, 27, 27, 27, 67,162, 44, 44, 44,
-   36, 36,  2,  2, 44, 44, 44, 44, 84, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 84, 84, 84, 84, 84, 84, 84, 84, 43, 44, 44, 44, 44,  2,
+    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, 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, 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, 84, 44, 44, 44, 44, 44, 91,
-   36, 70, 84, 43, 43, 84, 43, 84,163,  2,  2,  2,  2,  2,  2, 52,
+   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, 83,
-   85, 83, 85, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 83, 44,
-    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 92, 83, 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,106,  2, 36, 36, 36, 36, 36, 92, 43, 84,
-    2,106,164, 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,112, 40, 40,
-   16, 16, 16, 16, 44, 44, 44, 44, 36, 92, 85, 84, 83,163, 85, 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,
-  165,165,165,165,165,165,165,165,166,166,166,166,166,166,166,166,
-   16, 16, 16,108, 44, 44, 44, 44, 44,147, 16, 16, 44, 44, 62, 71,
-   36, 36, 36, 36,167, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+  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, 44, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36,145, 44, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,162, 44,
-    2,  2,  2,168,128, 44, 44, 44,  6,169,170,145,145,145,145,145,
-  145,145,128,168,128,  2,125,171,  2, 64,  2,  2,151,145,145,128,
-    2,172,  8,173, 66,  2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 61, 79, 91,  2,  3,  2,  4,  5,  6,  2,
-   16, 16, 16, 16, 16, 17, 18,127,128,  4,  2, 36, 36, 36, 36, 36,
+   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,174, 56,175, 26,  8,141, 90, 44, 44, 44, 44, 79, 65, 67, 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,176, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
-  103,103,140, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90,
-   90, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 50, 44,
-  177, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 44, 44,
-   27, 27, 44, 44, 44, 44, 62, 36,150, 36, 36, 36, 36,178, 44, 44,
-   36, 36, 36, 43, 43, 80, 44, 44, 36, 36, 36, 36, 36, 36, 36, 91,
-   36, 36, 44, 44, 36, 36, 36, 36,179,103,103, 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, 44, 44, 44, 44, 44, 91,
+    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, 91, 27, 27, 27, 27, 36, 36, 36, 77,158, 27, 27, 27,
-   44, 44, 44,176, 27, 27, 27, 27, 36, 61, 36, 44, 44,176, 27, 27,
-   36, 36, 36, 27, 27, 27, 44, 91, 36, 36, 36, 36, 36, 44, 44, 91,
+   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, 98, 44, 44, 44,
-    2,  2,  2,  2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,180, 30,
-   36, 36, 36, 36, 36, 36,180, 27, 36, 36, 36, 36, 78, 36, 36, 36,
-   36, 36, 70, 80, 44,176, 27, 27,  2,  2,  2, 64, 44, 44, 44, 44,
-   36, 36, 36, 44, 91,  2,  2,  2, 36, 36, 36, 44, 27, 27, 27, 27,
-   36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 91,  2, 64, 44,
-   44, 44, 44, 44,176, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
-   16,108, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
-   27, 27, 27, 27, 27, 27, 27, 98, 27, 27, 27, 93, 44, 44, 44, 44,
-  177, 27, 30,  2,  2, 44, 44, 44, 85, 96, 36, 36, 36, 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, 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, 44, 44, 44, 44, 44, 44, 44, 57,
-   84, 85, 43, 83, 85, 60,181,  2,  2, 44, 44, 44, 44, 44, 79, 44,
-   43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 85, 43,
-   43, 43, 80,  7,  7,  7,  7,  7,  2,  2, 92, 88, 44, 44, 44, 44,
-   36, 70,  2, 61, 44, 44, 44, 44, 36, 92, 84, 43, 43, 43, 43, 83,
-   96, 36, 63,  2, 59, 43, 60, 44,  7,  7,  7,  7,  7, 63, 63,  2,
-  176, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44,
-   36, 36, 36, 36, 36, 36, 84, 85, 43, 84, 83, 43,  2,  2,  2, 80,
+   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, 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,
-   84, 85, 43, 43, 43, 80, 44, 44, 43, 84, 62, 36, 36, 36, 61, 62,
-   61, 36, 62, 36, 36, 57, 71, 84, 83, 84, 88, 87, 88, 87, 84, 44,
-   61, 44, 44, 87, 44, 44, 62, 36, 36, 84, 44, 43, 43, 43, 80, 44,
-   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 92, 84, 43, 43, 43, 43,
-   84, 43, 83, 71, 36, 63,  2,  2,  7,  7,  7,  7,  7, 91, 91, 71,
-   84, 85, 43, 43, 83, 83, 84, 85, 83, 43, 36, 72, 44, 44, 44, 44,
-   36, 36, 36, 36, 36, 36, 36, 92, 84, 43, 43, 44, 84, 84, 43, 85,
+   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,
-   84, 85, 43, 43, 43, 83, 85, 85, 60,  2, 61, 44, 44, 44, 44, 44,
-    2,  2,  2,  2,  2,  2, 64, 44, 36, 36, 36, 36, 36, 70, 85, 84,
-   43, 43, 43, 85, 61, 44, 44, 44, 84, 43, 43, 85, 43, 43, 44, 44,
-    7,  7,  7,  7,  7, 27,  2, 95, 43, 43, 43, 43, 85, 60, 44, 44,
-   27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 44, 36, 36, 36,
-   92, 84, 43, 43, 44, 43, 84, 84, 71, 72, 88, 44, 44, 44, 44, 44,
-   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 83, 70, 43, 60,
-    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 83, 85, 43, 36, 36,
-   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 83, 43,  2, 72,  2,
-    2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 85,
+   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, 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, 87, 43, 43, 43,
-   83, 43, 85, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 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, 84, 84, 88,
-   43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,163, 64, 44, 44, 44,
-   27, 27, 89, 67, 67, 67, 56, 20,162, 67, 67, 67, 67, 67, 67, 67,
-   67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,178,
-    2,  2, 64, 44, 44, 44, 44, 44, 65, 65, 65, 65, 68, 44, 44, 44,
-   43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60,  2,  2, 67, 67,
-   40, 40, 95, 44, 44, 44, 44, 44,  7,  7,  7,  7,  7,176, 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,
-   92, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
-   84, 84, 84, 84, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40,
-   40, 86, 44, 44, 44, 44, 44, 44, 36, 61, 44, 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, 67, 67, 67, 90, 55, 67, 67, 67,
-   67, 67,182, 85, 43, 67,182, 84, 84,183, 65, 65, 65, 82, 43, 43,
-   43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67,
-   67, 67, 67, 67, 90, 44, 44, 44, 67, 43, 76, 44, 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,
+   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,
+   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, 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,108, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 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,147,147, 16, 16, 16,147, 16, 16, 16, 16, 16,
+   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,
@@ -4211,50 +4318,51 @@
     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,
    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, 43, 43,
-    7,  7,  7,  7,  7, 44, 44, 94, 36, 36, 61,176, 27, 27, 27, 27,
-   43, 43, 43, 80, 44, 44, 44, 44, 16, 16, 43, 43, 43, 74, 44, 44,
-   27, 27, 27, 27, 27, 27,158, 27,184, 27, 98, 44, 44, 44, 44, 44,
-   27, 27, 27, 27, 27, 27, 27,158, 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,
-   55, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44,
-   44, 44, 44, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 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, 44, 44, 67, 67, 67, 67, 67, 67, 67, 44,
-   67, 67, 67, 67, 67, 67, 55, 67, 67, 55, 67, 90, 44, 67, 67, 67,
-   67, 90, 55, 67, 67, 90, 44, 67, 67, 67, 67, 67, 67, 90, 55, 67,
-   67, 67, 44, 44, 67, 90, 44, 44, 36, 44, 44, 44, 44, 44, 44, 44,
-   79, 44, 44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 65, 65, 65,
-  166,166,166,166,166,166,166, 44,166,166,166,166,166,166,166,  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,  2,  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,  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, 17, 21,  7,  6, 11,  2,  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, 15,  6, 18,  6, 12, 11, 11, 12,  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, 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, 23, 26, 10, 21,  6, 10,  4,  4,  3,  3,  7, 25,
-   21, 22, 17, 16, 16, 22, 16, 16, 25, 17, 25,  2, 25, 24, 23,  2,
-    2, 15, 12, 15, 14,  2, 21, 14,  7, 15, 21,  1, 26, 10, 10,  1,
+    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, 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, 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,
+  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,
@@ -4266,52 +4374,53 @@
     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,  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,
-   35,  0,  0,  0,  0,  0,  0,  0,  0,  0, 36, 37,  0,  0,  0,  0,
-    0,  0, 38, 39,  0,  0, 40,  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,  0,  0, 21, 22,
-    0, 23, 24,  0,  0, 23, 25, 26,  0, 23, 25,  0,  0, 23, 25,  0,
-    0, 23, 25,  0,  0,  0, 25,  0,  0,  0, 27,  0,  0, 23, 25,  0,
-    0, 28, 25,  0,  0,  0, 29,  0,  0, 30, 31,  0,  0, 32, 33,  0,
-   34, 35,  0, 36, 37,  0, 38,  0,  0, 39,  0,  0, 40,  0,  0,  0,
+   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, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   42, 42,  0,  0,  0,  0, 43,  0,  0,  0,  0,  0,  0, 44,  0,  0,
-    0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0, 47,  0, 48,  0,  0,
-    0, 49, 50, 51,  0, 52,  0, 53,  0, 54,  0,  0,  0,  0, 55, 56,
-    0,  0,  0,  0,  0,  0, 57, 58,  0,  0,  0,  0,  0,  0, 59, 60,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 61,
-    0,  0,  0, 62,  0,  0,  0, 63,  0, 64,  0,  0, 65,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66, 67,  0,  0, 68,
-    0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,  0,  0,  0, 50, 70,
-    0, 71, 72,  0,  0, 73, 74,  0,  0,  0,  0,  0,  0, 75, 76, 77,
-    0,  0,  0,  0,  0,  0,  0, 25,  0,  0,  0,  0,  0,  0,  0,  0,
-   78,  0,  0,  0,  0,  0,  0,  0,  0, 79,  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, 80,  0,  0,  0,  0,  0,  0,  0, 81,
-    0,  0,  0, 82,  0,  0,  0,  0, 83, 84,  0,  0,  0,  0,  0, 85,
+    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, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 87,  0,  0,  0,  0,  0,  0,  0, 69, 62,  0, 88,  0,  0,
-   89, 90,  0, 73,  0,  0, 91,  0,  0, 92,  0,  0,  0,  0,  0, 93,
-    0, 94, 25, 95,  0,  0,  0,  0,  0,  0, 96,  0,  0,  0, 97,  0,
-    0,  0,  0,  0,  0, 62, 98,  0,  0, 62,  0,  0,  0, 99,  0,  0,
-    0,100,  0,  0,  0,  0,  0,  0,  0, 88,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 74,  0, 42,101,  0,102,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,
-    0,  0,103,  0,104,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,
-    0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  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,108,109,110,  0,  0,  0,  0,111,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,112,113,  0,  0,  0,  0,  0,  0,
-    0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,114,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,115,  0,
-    0,  0,116,  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,
@@ -4322,592 +4431,622 @@
     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, 52,  1,  1,  1, 53, 21, 43, 54, 55, 21, 35,  1,
-    0,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0, 57, 58, 59,  0,  0,
-    0,  0,  0, 57,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 60,
-    0,  0,  0, 57,  0, 61,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63,
-    0,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,
-    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67,  0,
-    0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,
-    0,  0,  0,  0,  0, 70, 71,  0,  0,  0,  0,  0, 72, 73, 74, 75,
-   76, 77,  0,  0,  0,  0,  0,  0,  0, 78,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 79, 80,  0,  0,  0,  0, 47,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,  0, 63,  0,  0,
-    0,  0,  0,  0, 64,  0,  0, 81,  0,  0, 82,  0,  0,  0,  0,  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,
-   63,  0,  0,  0,  0, 49,  1, 85,  0,  0,  0,  0,  1, 54, 15, 41,
-    0,  0,  0,  0,  0, 56,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,
-    0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 86,  0,  0,  0,  0,  0,
-    0, 87,  0,  0, 86,  0,  0,  0,  0,  0,  0,  0,  0, 79,  0,  0,
-    0,  0,  0,  0, 88,  9, 12,  4, 89,  8, 90, 47,  0, 59, 50,  0,
-   21,  1, 21, 91, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93, 94, 95,
-    0,  0,  0,  0, 96,  1, 97, 59, 81, 98, 99,  4, 59,  0,  0,  0,
-    0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,
-    1,  1,  1,  1,  1,  1,  1,  1,  0,  0,100,101,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,102,  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, 64,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1, 50,  0,  0,  0,
-    0,  0, 52, 69,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,
-    0,  0,  0,  0, 79,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,103,104, 59, 38, 81,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,
+   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,
+   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, 88,  0,
-    0,  0,  0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,107, 62,
-    0,108,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
-    0,109, 14, 54, 84,  0,  0,  0,  0,  0,  0,  0,  0,  0,110,  0,
-   88,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63,  0,  0,
-   63,  0, 87,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,110,  0,  0,
-    0,  0,111,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 79, 56,
-    0, 38,  1, 59,  1, 59,  0,  0, 64, 87,  0,  0,  0,  0,  0, 60,
-  112,  0,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,112,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,
-    0, 62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,
-   87,113,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,
-    0,  0,  0,  0,  8, 90,  0,  0,  0,  0,  0,  0,  1, 88,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,114,  0,115,116,117,118,  0, 52,  4,
-  119, 49, 23,  0,  0,  0,  0,  0,  0,  0, 38, 50,  0,  0,  0,  0,
-   38, 59,  0,  0,  0,  0,  0,  0,  1, 88,  1,  1,  1,  1, 39,  1,
-   48,103, 88,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,
-    0,  0,  0,  0,  4,119,  0,  0,  0,  1,120,  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,
-    0,  0,  0,220,230,230,  0,220,230,220,220,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,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,
-  220,  0,  0,  0,230,  0,  0,220,  0,  0,  9,  9,  0,  0,  7,  0,
-  230,230,230,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,
-  202,230,230,230,230,230,232,228,228,220,  0,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,230,  0,230,230,
+   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,  9,  7,  0,  0,  7,  9,  0,
-    0,  0,  9,  7,  9,  9,  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,
+    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,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 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,  0,  0,
-    0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0, 37, 38,
-    0,  0,  0,  0,  1,  2, 39, 40,  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, 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,  9, 10, 11, 12, 12, 12, 12, 13, 14,
-   14, 14, 14, 15, 16, 17, 18, 19, 20, 14, 21, 14, 22, 14, 14, 14,
-   14, 23, 24, 24, 25, 26, 14, 14, 14, 14, 27, 28, 14, 14, 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, 35,  7, 36, 37,  7, 38,  7,  7,
-    7, 39, 14, 40, 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, 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, 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, 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,
-   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, 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, 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, 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, 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, 14, 41,  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,
+   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, 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,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 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,
    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, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70, 70, 70, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82,
-   83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 32, 32,
+   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, 32, 32, 32, 32, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97, 97, 97, 70, 70, 98, 99,100,101,102,102,
-  103,104,105,106,107,108,109,110,111,112, 97,113,114,115,116,117,
-  118, 97,119,119,120, 97,121,122,123,124,125,126,127,128,129,130,
-  131, 97,132, 97,133,134,135,136,137,138,139,140,141, 97,142,143,
-   97,144,145,146,147, 97,148,149, 97,150,151,152, 97, 97,153,154,
-  155,156, 97,157, 97,158,159,159,159,159,159,159,159,160,161,159,
-  162, 97, 97, 97, 97, 97,163,163,163,163,163,163,163,163,164, 97,
-   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,165,165,
-  165,165,166, 97, 97, 97,167,167,167,167,168,169,170,171, 97, 97,
-   97, 97,172,173,174,175,176,176,176,176,176,176,176,176,176,176,
-  176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
-  176,176,176,176,176,177,176,176,176,176,176,178, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97,179,180,181,182,182,183, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,184,185,
-   97, 97, 97, 97, 97, 97, 59,186,187,188,189,190,191, 97,192,193,
-  194, 59, 59,195, 59,196,197,197,197,197,197,198, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97,199, 97,200, 97, 97,201, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97,202,203,204, 97, 97, 97, 97, 97,205,206,
-  207, 97,208,209, 97, 97,210,211,212,213,214, 97, 59, 59, 59, 59,
-   59, 59, 59,215,216,217,218,219,220,221,222,223, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70,224, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70, 70,225, 70,226, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   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,
+   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, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
-   70, 70, 70,227, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 97, 97,
-   97, 97, 97, 97, 97, 97, 70, 70, 70, 70,229, 97, 97, 97, 97, 97,
-   97, 97, 97, 97, 97, 97,230, 97,231,232,  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,  0,
-    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,  2,  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,  2,  3,  3,  3,  3,
-    3,  3,  3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  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,  2, 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,  2, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
-    2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2,  2,  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,  2,  2,  2,  2,  2,  2, 16,  2, 16, 16,
-   16, 16,  2,  2, 16, 16,  2, 16, 16,  2,  2,  2,  2,  2, 20, 20,
-   20, 20,  2, 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,  2,  2,
-    2,  2, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 20, 20,  2,  2,
-   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,  2, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2, 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,  2, 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,  2,  2,  2,  2, 62, 62,
-   62, 62, 62,  2,  2,  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,  1,  1,  2,  1,  1,  1,  1,  1,  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,  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,  2, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2, 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, 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,
+  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, 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, 26, 26, 26,  2,  2,  2,  2,  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,  2,  2, 19, 19, 19, 19, 19,  2,  2,  2,
-    2,  2,  2,  2,  2, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-   60, 60,  2,  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, 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,
-    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,
-    3,  3,  3,  3,  3,  3,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,
-    0,  2,  0,  0,  0,  0,  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,  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,110,110,
-  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
-  110,110,110,110,  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,  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,  3,  3,
-    3,  3,  3,  3,  3,  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,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,  2,  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, 96, 96,
-   96, 96, 96, 96, 96,  2,111,111,111,111,111,111,111,111,111,111,
-  111,111,111,111,111,  2,100,100,100,100,100,100,100,100,100,100,
-  100,100,100,100,  2,  2,  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,  2,137,  2,137,137,137,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,  2,  2,  2,  2,  2,  2,  2,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,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,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, 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, 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,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,  0,  0,  2,  2,  2,  2,136,136,
-  136,136,136,136,136,136,136,136,136,  2,  2,  2,  2,  2, 17, 15,
-   15, 15, 15, 15, 15, 15, 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,  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,  0,  2,
-    2,  2,  2,  2,  2,  2,  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,  0,  0,  0,  2,  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,  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,152,152,
-  152,152,152,152,152,152,152,152,  2,  2,  2,  2,  2,152,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,  0,  0,
-    0,  0,  0,  2,  2,  2,  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,  0,  0,  0,  2,  2,  2,  0,  0, 13, 13,
-   13, 13, 13, 13, 13,  2, 13, 13, 13, 13, 13,  2,  2,  2, 13,  2,
-    2,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2, 16, 50,
-   84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91, 85, 85,
-  220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15,  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,
+   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,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  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,
-   40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  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,
-   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, 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, 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, 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,  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,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  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,  0,  0,  0,  0,  0,
-    0,  0,  0,  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,  0,  0,
-    0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,168,169,  0,  0,  0,  0,170,171,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,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,
-    0,  0,  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,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[8944] =
+_hb_ucd_u16[9200] =
 {
      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,
@@ -4917,118 +5056,123 @@
     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,  72,  72,  72,  48,  73,  72,  74,  75,  32,
+    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,  72,  72, 140,  48, 141, 142, 143, 144,  72,  72,
-   145, 146, 147, 148, 149,  48, 150, 151, 152, 153,  32, 154, 155, 156,  72,  72,
-    48,  48, 157, 158, 159, 160, 161, 162, 163, 164,   9,   9, 165,  11,  11, 166,
-    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 167, 168,  48,  48,
-   167,  48,  48, 169, 170, 171,  48,  48,  48, 170,  48,  48,  48, 172, 173, 174,
-    48, 175,   9,   9,   9,   9,   9, 176, 177,  48,  48,  48,  48,  48,  48,  48,
-    48,  48,  48,  48,  48,  48, 178,  48, 179, 180,  48,  48,  48,  48, 181, 182,
-   183, 184,  48, 185,  48, 186, 183, 187,  48,  48,  48, 188, 189, 190, 191, 192,
-   193, 191,  48,  48, 194,  48,  48, 195, 196,  48, 197,  48,  48,  48,  48, 198,
-    48, 199, 200, 201, 202,  48, 203, 204,  48,  48, 205,  48, 206, 207, 208, 208,
-    48, 209,  48,  48,  48, 210, 211, 212, 191, 191, 213, 214,  72,  72,  72,  72,
-   215,  48,  48, 216, 217, 159, 218, 219, 220,  48, 221,  64,  48,  48, 222, 223,
-    48,  48, 224, 225, 226,  64,  48, 227, 228,   9,   9, 229, 230, 231, 232, 233,
-    11,  11, 234,  27,  27,  27, 235, 236,  11, 237,  27,  27,  32,  32,  32, 238,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 239,  13,  13,  13,  13,  13,  13,
-   240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249,
-   250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260,  72, 261, 262, 263,
-   264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276,
-   277, 277, 277, 277, 277, 277, 277, 277, 278, 208, 279, 208, 208, 208, 208, 280,
-   208, 281, 277, 282, 208, 283, 284, 208, 208, 208, 285,  72, 286,  72, 269, 269,
-   269, 287, 208, 208, 208, 208, 288, 269, 208, 208, 208, 208, 208, 208, 208, 208,
-   208, 208, 208, 289, 290, 208, 208, 291, 208, 208, 208, 208, 208, 208, 292, 208,
-   208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277,
-   298, 299, 277, 277, 277, 300, 277, 301, 208, 208, 208, 277, 302, 208, 208, 303,
-   208, 304, 208, 208, 208, 208, 208, 208,   9,   9, 305,  11,  11, 306, 307, 308,
+   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,  72,  72,  72,
-   208, 321, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 323,  72, 324,
-   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 177,  48,  48,  48,  48, 330,
-   331,  48,  48, 136,  48,  48,  48,  48, 199, 332,  48,  71, 208, 208, 322,  48,
-   208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208,
-    48,  48,  48, 198, 208, 208, 208, 208,  48,  48,  48,  48,  48,  48,  48,  72,
-    48, 337,  48,  48,  48,  48,  48,  48, 150, 208, 208, 208, 285,  48,  48, 227,
-   338,  48, 339,  72,  13,  13, 340, 341,  13, 342,  48,  48,  48,  48, 343, 344,
-    31, 345, 346, 347,  13,  13,  13, 348, 349, 350, 351, 352, 353,  72,  72, 354,
-   355,  48, 356, 357,  48,  48,  48, 358, 359,  48,  48, 360, 361, 191,  32, 362,
-    64,  48, 363,  48, 364, 365,  48, 150,  76,  48,  48, 366, 367, 368, 369, 370,
-    48,  48, 371, 372, 373, 374,  48, 375,  48,  48,  48, 376, 377, 378, 379, 380,
-   381, 382, 315,  11,  11, 383, 384,  11,  11,  11,  11,  11,  48,  48, 385, 191,
-    48,  48, 386,  48, 387,  48,  48, 205, 388, 388, 388, 388, 388, 388, 388, 388,
-   389, 389, 389, 389, 389, 389, 389, 389,  48,  48,  48,  48,  48,  48, 203,  48,
-    48,  48,  48,  48,  48, 206,  72,  72, 390, 391, 392, 393, 394,  48,  48,  48,
-    48,  48,  48, 395, 396, 397,  48,  48,  48,  48,  48, 398,  72,  48,  48,  48,
-    48, 399,  48,  48, 400,  72,  72, 401,  32, 402,  32, 403, 404, 405, 406, 407,
-    48,  48,  48,  48,  48,  48,  48, 408, 409,   2,   3,   4,   5, 410, 411, 412,
-    48, 413,  48, 199, 414, 415, 416, 417, 418,  48, 171, 419, 203, 203,  72,  72,
-    48,  48,  48,  48,  48,  48,  48,  71, 420, 269, 269, 421, 270, 270, 270, 422,
-   423, 324, 424,  72,  72, 208, 208, 425,  72,  72,  72,  72,  72,  72,  72,  72,
-    48, 150,  48,  48,  48, 100, 426, 427,  48,  48, 428,  48, 429,  48,  48, 430,
-    48, 431,  48,  48, 432, 433,  72,  72,   9,   9, 434,  11,  11,  48,  48,  48,
-    48, 203, 191,   9,   9, 435,  11, 436,  48,  48, 400,  48,  48,  48, 437,  72,
-    48,  48,  48, 314,  48, 198, 400,  72, 438,  48,  48, 439,  48, 440,  48, 441,
-    48, 199, 442,  72,  72,  72,  48, 443,  48, 444,  48, 445,  72,  72,  72,  72,
-    48,  48,  48, 446, 269, 447, 269, 269, 448, 449,  48, 450, 451, 452,  48, 453,
-    48, 454,  72,  72, 455,  48, 456, 457,  48,  48,  48, 458,  48, 459,  48, 460,
-    48, 461, 462,  72,  72,  72,  72,  72,  48,  48,  48,  48, 195,  72,  72,  72,
-     9,   9,   9, 463,  11,  11,  11, 464,  48,  48, 465, 191,  72,  72,  72,  72,
-    72,  72,  72,  72,  72,  72, 269, 466,  48, 454, 467,  48,  62, 468,  72,  72,
-    72,  72,  72,  72,  72,  72,  48, 314, 469,  48,  48, 470, 471, 447, 472, 473,
-   220,  48,  48, 474, 475,  48, 195, 191, 476,  48, 477, 478, 479,  48,  48, 480,
-   220,  48,  48, 481, 482, 483, 484, 485,  48,  97, 486, 487,  72,  72,  72,  72,
-   488, 489, 490,  48,  48, 491, 492, 191, 493,  83,  84, 494, 495, 496, 497, 498,
-    48,  48,  48, 499, 500, 501,  72,  72,  48,  48,  48, 502, 503, 191,  72,  72,
-    48,  48, 504, 505, 506, 507,  72,  72,  48,  48,  48, 508, 509, 191, 510,  72,
-    48,  48, 511, 512, 191,  72,  72,  72,  48, 172, 513, 514,  72,  72,  72,  72,
-    48,  48, 486, 515,  72,  72,  72,  72,  72,  72,   9,   9,  11,  11, 147, 516,
-    72,  72, 517,  48,  48, 518, 519,  72, 520,  48,  48, 521, 522, 523,  48,  48,
-   524, 525, 526,  72,  48,  48,  48, 195,  84,  48, 504, 527, 528, 147, 174, 529,
-    48, 530, 531, 532,  72,  72,  72,  72, 533,  48,  48, 534, 535, 191, 536,  48,
-   537, 538, 191,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 539,
-    72,  72,  72,  72, 269, 540, 541, 542,  48, 206,  72,  72,  72,  72,  72,  72,
-   270, 270, 270, 270, 270, 270, 543, 544,  48,  48,  48,  48, 386,  72,  72,  72,
-    48,  48, 199, 545,  72,  72,  72,  72,  48,  48,  48,  48, 314,  72,  72,  72,
-    48,  48,  48, 195,  48, 199, 368,  72,  72,  72,  72,  72,  72,  48, 203, 546,
-    48,  48,  48, 547, 548, 549, 550, 551,  48,  72,  72,  72,  72,  72,  72,  72,
-    72,  72,  72,  72,   9,   9,  11,  11, 269, 552,  72,  72,  72,  72,  72,  72,
-    48,  48,  48,  48, 553, 554, 555, 555, 556, 557,  72,  72,  72,  72, 558,  72,
-    48,  48,  48,  48,  48,  48,  48, 400,  48,  48,  48,  48,  48,  48,  48, 559,
-    48, 199,  72,  72,  72, 559, 560,  48,  48,  48,  48,  48,  48,  48,  48, 205,
-    48,  48,  48,  48,  48,  48,  71, 150, 195, 561, 562,  72,  72,  72,  72,  72,
-   208, 208, 208, 208, 208, 208, 208, 323, 208, 208, 563, 208, 208, 208, 564, 565,
-   566, 208, 567, 208, 208, 208, 568,  72, 208, 208, 208, 208, 569,  72,  72,  72,
-    72,  72,  72,  72,  72,  72, 269, 570, 208, 208, 208, 208, 208, 285, 269, 451,
-     9, 571,  11, 572, 573, 574, 240,   9, 575, 576, 577, 578, 579,   9, 571,  11,
-   580, 581,  11, 582, 583, 584, 585,   9, 586,  11,   9, 571,  11, 572, 573,  11,
-   240,   9, 575, 585,   9, 586,  11,   9, 571,  11, 587,   9, 588, 589, 590, 591,
-    11, 592,   9, 593, 594, 595, 596,  11, 597,   9, 598,  11, 599, 600, 600, 600,
-    32,  32,  32, 601,  32,  32, 602, 603, 604, 605,  45,  72,  72,  72,  72,  72,
-   606, 607, 608,  72,  72,  72,  72,  72,  48,  48, 150, 609, 610,  72,  72,  72,
-    72,  72,  72,  72,  48,  48, 611, 612,  48,  48,  48,  48, 613, 614,  72,  72,
-     9,   9, 575,  11, 615, 368,  72,  72,  72,  72,  72,  72,  72,  72,  72, 484,
-   269, 269, 616, 617,  72,  72,  72,  72, 484, 269, 618, 619,  72,  72,  72,  72,
-   620,  48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205,  72,  72,  72, 629,
-   208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323,
-   174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631,  72,  72,  72, 632, 208,
-   633, 208, 208, 324, 568, 634, 323,  72, 208, 208, 208, 208, 208, 208, 208, 635,
-   208, 208, 208, 208, 208, 323, 631, 286, 208, 208, 208, 208, 208, 208, 208, 322,
-   208, 208, 208, 208, 208, 568, 324,  72, 324, 208, 208, 208, 636, 175, 208, 208,
-   636, 208, 637,  72,  72,  72,  72,  72, 638, 208, 208, 208, 208, 208, 208, 639,
-   208, 208, 640, 208, 641, 208, 208, 208, 208, 208, 208, 208, 208, 322, 637, 642,
-   633, 323,  72,  72,  72,  72,  72,  72,  48,  48,  48,  48,  48, 314,  72,  72,
-    48,  48,  48, 204,  48,  48,  48,  48,  48, 203,  48,  48,  48,  48,  48,  48,
-    48,  48, 643,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 100,  72,
-    48, 203,  72,  72,  72,  72,  72,  72, 644,  72, 645, 645, 645, 645, 645, 645,
-    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  72,
-   389, 389, 389, 389, 389, 389, 389, 646, 389, 389, 389, 389, 389, 389, 389, 647,
+    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, 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, 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,  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,
+    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,
+    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,
      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,
@@ -5043,223 +5187,233 @@
     31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  29,  31,  31,  31,  31,
     37,  38,  37,  37,  37,  37,  37,  37,  37,  39,  31,  31,  31,  31,  31,  31,
     40,  40,  40,  40,  40,  40,  41,  26,  42,  42,  42,  42,  42,  42,  42,  43,
-    44,  44,  44,  44,  44,  45,  44,  46,  47,  47,  47,  48,  37,  49,  26,  26,
-    26,  26,  26,  26,  31,  31,  50,  51,  26,  26,  52,  31,  53,  31,  31,  31,
-    54,  54,  54,  54,  54,  54,  54,  54,  54,  54,  55,  54,  56,  54,  54,  54,
-    57,  58,  59,  60,  60,  61,  62,  63,  58,  64,  65,  66,  67,  60,  60,  68,
-    69,  70,  71,  72,  72,  73,  74,  75,  70,  76,  77,  78,  79,  72,  80,  26,
-    81,  82,  83,  84,  84,  85,  86,  87,  82,  88,  89,  26,  90,  84,  91,  92,
-    93,  94,  95,  96,  96,  97,  98,  99,  94, 100, 101, 102, 103,  96,  96,  26,
-   104, 105, 106, 107, 108, 105, 109, 110, 105, 106, 111,  26, 112, 109, 109, 113,
-   114, 115, 116, 114, 114, 116, 114, 117, 115, 118, 119, 120, 121, 114, 122, 114,
-   123, 124, 125, 123, 123, 125, 126, 127, 124, 128, 129, 130, 131, 123, 132,  26,
-   133, 134, 135, 136, 136, 136, 136, 136, 134, 135, 137, 136, 138, 136, 136, 136,
-   139, 140, 141, 142, 140, 140, 143, 144, 141, 145, 146, 140, 147, 140, 148,  26,
-   149, 150, 150, 150, 150, 150, 150, 151, 150, 150, 150, 152,  26,  26,  26,  26,
-   153, 154, 155, 155, 156, 155, 155, 157, 158, 157, 155, 159,  26,  26,  26,  26,
-   160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160, 162, 161, 160,
-   160, 160, 160, 161, 160, 160, 160, 163, 160, 163, 164, 165,  26,  26,  26,  26,
-   166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166,
-   166, 166, 166, 166, 167, 167, 167, 167, 168, 169, 167, 167, 167, 167, 167, 170,
-   171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
-   172, 172, 172, 172, 172, 172, 172, 172, 172, 173, 174, 173, 172, 172, 172, 172,
-   172, 173, 172, 172, 172, 172, 173, 174, 173, 172, 174, 172, 172, 172, 172, 172,
-   172, 172, 173, 172, 172, 172, 172, 172, 172, 172, 172, 175, 172, 172, 172, 176,
-   172, 172, 172, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179,
-   180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180,
-   181, 181, 181, 182, 183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 183, 185,
-   186, 187, 188,  26, 189, 189, 190,  26, 191, 191, 192,  26, 193, 194, 195,  26,
-   196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 197, 196, 198, 196, 198,
-   199, 200, 201, 202, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 203,
-   201, 201, 201, 201, 201, 204, 180, 180, 180, 180, 180, 180, 180, 180, 205,  26,
-   206, 206, 206, 207, 206, 208, 206, 208, 209, 206, 210, 210, 210, 211, 212,  26,
-   213, 213, 213, 213, 213, 214, 213, 213, 213, 215, 213, 216, 196, 196, 196, 196,
-   217, 217, 217, 218, 219, 219, 219, 219, 219, 219, 219, 220, 219, 219, 219, 221,
-   219, 222, 219, 222, 219, 223,   9, 224,  26,  26,  26,  26,  26,  26,  26,  26,
-   225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 225, 225, 225, 225, 225, 227,
-   228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 230, 231,
-   232, 232, 232, 232, 232, 232, 232, 233, 232, 234, 235, 235, 235, 235, 235, 235,
-    18, 236, 167, 167, 167, 167, 167, 237, 228,  26, 238,   9, 239, 240, 241, 242,
-     2,   2,   2,   2, 243, 244,   2,   2,   2,   2,   2, 245, 246, 247,   2, 248,
-     2,   2,   2,   2,   2,   2,   2, 249,   9,   9,   9,   9,   9,   9,   9, 250,
-    14,  14, 251, 251,  14,  14,  14,  14, 251, 251,  14, 252,  14,  14,  14, 251,
-    14,  14,  14,  14,  14,  14, 253,  14, 253,  14, 254, 255,  14,  14, 256, 257,
-     0, 258,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 259,   0, 260, 261,
-     0, 262,   2, 263,   0,   0,   0,   0,  26,  26,   9,   9,   9,   9, 264,  26,
-     0,   0,   0,   0, 265, 266,   4,   0,   0, 267,   0,   0,   2,   2,   2,   2,
-     2, 268,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    44,  44,  44,  44,  44,  45,  44,  46,  47,  47,  47,  48,  37,  49,  31,  31,
+    31,  50,  51,  31,  31,  31,  31,  31,  31,  31,  31,  31,  52,  31,  31,  31,
+    53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  54,  53,  55,  53,  53,  53,
+    56,  57,  58,  59,  59,  60,  61,  62,  57,  63,  64,  65,  66,  59,  59,  67,
+    68,  69,  70,  71,  71,  72,  73,  74,  69,  75,  76,  77,  78,  71,  79,  26,
+    80,  81,  82,  83,  83,  84,  85,  86,  81,  87,  88,  26,  89,  83,  90,  91,
+    92,  93,  94,  95,  95,  96,  97,  98,  93,  99, 100, 101, 102,  95,  95,  26,
+   103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110,  26, 111, 108, 108, 112,
+   113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
+   122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130,  26,
+   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, 262,  26,  26,  26,   0, 269,  26,  26,   0,   0,   0,   0,
-   270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 271,   0,
-     0,   0, 272,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-   273, 273, 273, 273, 273, 274, 273, 273, 273, 273, 273, 274,   2,   2,   2,   2,
-    17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 275, 276,
-   167, 167, 167, 167, 168, 169, 277, 277, 277, 277, 277, 277, 277, 278, 279, 278,
-   172, 172, 174,  26, 174, 174, 174, 174, 174, 174, 174, 174,  18,  18,  18,  18,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  26,  26,  26,  26,  26,  26,
-   280, 280, 280, 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 282,  26,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283,  26,  26,  26,   0, 284,
-   285,   0,   0,   0, 286, 287,   0, 288, 289, 290, 290, 290, 290, 290, 290, 290,
-   290, 290, 291, 292, 293, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 295,
-   296, 297, 297, 297, 297, 297, 298, 171, 171, 171, 171, 171, 171, 171, 171, 171,
-   171, 299,   0,   0, 297, 297, 297, 300,   0,   0,   0,   0, 284,  26, 294, 294,
-   171, 171, 171, 299,   0,   0,   0,   0,   0,   0,   0,   0, 171, 171, 171, 301,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 294, 294, 294, 294, 294, 302,
-   294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294,   0,   0,   0,   0,   0,
-   280, 280, 280, 280, 280, 280, 283,  26,   0,   0,   0,   0,   0,   0,   0,   0,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,  26,  26,
-   303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303,
-   303, 304, 303, 303, 303, 303, 303, 303, 305,  26, 306, 306, 306, 306, 306, 306,
-   307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
-   307, 307, 307, 307, 307, 308,  26,  26,  18,  18,  18,  18,  18,  18,  18,  18,
-    18,  18,  18,  18, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309,  26,
-     0,   0,   0,   0, 310,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
-     2, 311,   2,   2,   2,   2,   2,   2, 312,  26,  26,  26,  26,  26, 313,   2,
-   314, 314, 314, 314, 314, 315,   0, 316, 317, 317, 317, 317, 317, 317, 317,  26,
-   318, 318, 318, 318, 318, 318, 318, 318, 319, 320, 318, 321,  54,  54,  54,  54,
-   322, 322, 322, 322, 322, 323, 324, 324, 324, 324, 325, 326, 171, 171, 171, 327,
-   328, 328, 328, 328, 328, 328, 328, 328, 328, 329, 328, 330, 166, 166, 166, 331,
-   332, 332, 332, 332, 332, 332, 333,  26, 332, 334, 332, 335, 166, 166, 166, 166,
-   336, 336, 336, 336, 336, 336, 336, 336, 337,  26,  26, 338, 339, 339, 340,  26,
-   341, 341, 341,  26, 174, 174,   2,   2,   2,   2,   2, 342, 343,  26, 178, 178,
-   178, 178, 178, 178, 178, 178, 178, 178, 339, 339, 339, 339, 339, 344, 339, 345,
-   171, 171, 171, 171, 346,  26, 171, 171, 299, 347, 171, 171, 171, 171, 171, 346,
+     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,
+   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,
+   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,
     26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283, 280, 280,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 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,  52,  31,  31,  31,  31,  31,
+   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,
     31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
-    31,  31,  31,  31,  31,  31,  31, 356,  26,  26,  31,  31,  31,  31,  31,  31,
-    31,  31, 357,  31,  31,  31,  31,  31,  31,  26,  26,  26,  26,  26,  31,  51,
-     9,   9,   0, 316,   9, 358,   0,   0,   0,   0, 359,   0, 262, 284,  50,  31,
-    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 360,
-   361,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 362, 294, 293, 294,
-   294, 294, 294, 363, 171, 171, 171, 299, 364, 364, 364, 365, 262, 262,  26, 366,
-   367, 368, 367, 367, 369, 367, 367, 370, 367, 371, 367, 371,  26,  26,  26,  26,
-   367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 372,
-   373,   0,   0,   0,   0,   0, 374,   0,  14,  14,  14,  14,  14,  14,  14,  14,
-    14, 257,   0, 284, 375,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 376,
-   377, 377, 377, 378, 379, 379, 379, 379, 379, 379, 380,  26, 381,   0,   0, 284,
-   382, 382, 382, 382, 383, 384, 385, 385, 385, 386, 387, 387, 387, 387, 387, 388,
-   389, 389, 389, 390, 391, 391, 391, 391, 392, 391, 393,  26,  26,  26,  26,  26,
-   394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395,
-   396, 396, 396, 397, 396, 398, 399, 399, 399, 399, 400, 399, 399, 399, 399, 400,
-   401, 401, 401, 401, 401,  26, 402, 402, 402, 402, 402, 402, 403, 404,  26,  26,
-   405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405,
-   405, 405, 405, 405, 405, 405, 406,  26, 405, 405, 407,  26, 405,  26,  26,  26,
-   408, 409, 410, 410, 410, 410, 411, 412, 413, 413, 414, 413, 415, 415, 415, 415,
-   416, 416, 416, 417, 418, 416,  26,  26,  26,  26,  26,  26, 419, 419, 420, 421,
-   422, 422, 422, 423, 424, 424, 424, 425,  26,  26,  26,  26,  26,  26,  26,  26,
-   426, 426, 426, 426, 427, 427, 427, 428, 427, 427, 429, 427, 427, 427, 427, 427,
-   430, 431, 432, 433, 434, 434, 435, 436, 434, 437, 434, 437, 438, 438, 438, 438,
-   439, 439, 439, 439,  26,  26,  26,  26, 440, 440, 440, 440, 441, 442, 441,  26,
-   443, 443, 443, 443, 443, 443, 444, 445, 446, 446, 447, 446, 448, 448, 449, 448,
-   450, 450, 451, 452,  26, 453,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   454, 454, 454, 454, 454, 454, 454, 454, 454, 455,  26,  26,  26,  26,  26,  26,
-   456, 456, 456, 456, 456, 456, 457,  26, 456, 456, 456, 456, 456, 456, 457, 458,
-   459, 459, 459, 459, 459,  26, 459, 460,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  31,  31,  31, 461,
-   462, 462, 462, 462, 462,  26, 463, 463, 463, 463, 463, 464,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 465, 465, 466,  26,
-   467, 467, 467, 467, 467, 467, 467, 467, 467, 468, 469, 467, 467, 467,  26, 470,
-   471, 471, 471, 471, 471, 471, 471, 471, 472, 473, 474, 474, 474, 475, 474, 476,
-   477, 477, 477, 477, 477, 477, 478, 477, 479,  26, 480, 480, 480, 480, 481,  26,
-   482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 482, 482, 484, 140, 485,  26,
-   486, 486, 487, 486, 486, 486, 486, 488,  26,  26,  26,  26,  26,  26,  26,  26,
-   489, 490, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 494, 495, 494, 496,
-   497, 498, 499, 500, 500, 501, 502, 503, 498, 504, 505, 506, 507, 508, 508,  26,
-   509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 510,  26,  26,  26,  26,
-   511, 511, 511, 511, 511, 511, 511, 511, 511,  26, 511, 512,  26,  26,  26,  26,
-   513, 513, 513, 513, 513, 513, 514, 513, 513, 513, 513, 514,  26,  26,  26,  26,
-   515, 515, 515, 515, 515, 515, 515, 515, 516,  26, 515, 517, 201, 518,  26,  26,
-   519, 519, 519, 519, 519, 519, 519, 520, 519, 521,  26,  26,  26,  26,  26,  26,
-   522, 522, 522, 523, 522, 524, 522, 522,  26,  26,  26,  26,  26,  26,  26,  26,
-   525, 525, 525, 525, 525, 525, 525, 526,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 529,
-    26,  26,  26,  26, 530, 531, 530, 530, 530, 530, 530, 531, 532,  26,  26,  26,
-   533, 533, 533, 533, 533, 533, 533, 533, 533,  26, 534, 534, 534, 534, 534, 534,
-   534, 534, 534, 534, 535,  26,  26,  26, 536, 536, 536, 536, 536, 536, 536, 537,
-   538, 539, 538, 538, 538, 538, 540, 538, 541,  26, 538, 538, 538, 542, 543, 543,
-   543, 543, 544, 543, 543, 545, 546,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   547, 548, 549, 549, 549, 549, 547, 550, 549,  26, 549, 551, 552, 553, 554, 554,
-   554, 555, 556, 557, 554, 558,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 559, 559, 559, 560,
-    26,  26,  26,  26,  26,  26,  26,  26, 109, 109, 109, 109, 109, 109, 561, 562,
-   563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563,
-   563, 563, 563, 564,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 565, 566,  26,
-   563, 563, 563, 563, 563, 563, 563, 563, 567,  26,  26,  26,  26,  26,  26,  26,
-   568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568,
-   568, 568, 568, 568, 568, 569, 568, 570,  26,  26,  26,  26,  26,  26,  26,  26,
-   571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
-   571, 571, 571, 571, 571, 571, 571, 571, 572,  26,  26,  26,  26,  26,  26,  26,
-   309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309,
-   309, 309, 309, 309, 309, 309, 309, 573, 574, 574, 574, 575, 574, 576,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 577, 577, 577, 578, 578,  26,
-   579, 579, 579, 579, 579, 579, 579, 579, 580,  26, 579, 581, 581, 579, 579, 582,
-   579, 579,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26, 583, 583, 583, 583, 583, 583, 583, 583,
-   583, 583, 583, 584,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   585, 585, 585, 585, 585, 585, 585, 585, 585, 586, 585, 585, 585, 585, 585, 585,
-   585, 587, 585, 585,  26,  26,  26,  26,  26,  26,  26,  26, 588,  26,  26,  26,
-   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589,
-   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589,  26,
-   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 590,  26,
-   591, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
-   290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
-   290, 290, 290, 291,  26,  26,  26,  26,  26,  26, 592,  26, 593,  26, 594, 594,
-   594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594,
-   594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 595,
-   596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 596, 598,
-   596, 599, 596, 600, 284,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 272,  26,
-     0,   0,   0,   0, 262, 361,   0,   0,   0,   0,   0,   0, 601, 602,   0, 603,
-   604, 605,   0,   0,   0, 606,   0,   0,   0,   0,   0,   0,   0, 607,  26,  26,
-    14,  14,  14,  14,  14,  14,  14,  14, 251,  26,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,   0,   0, 284,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 262,  26,   0,   0,   0, 607,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 259,   0,   0,   0,   0,   0,
-     0,   0,   0, 259, 608, 609,   0, 610, 611,   0,   0,   0,   0,   0,   0,   0,
-   612, 613, 259, 259,   0,   0,   0, 614, 615, 616, 617,   0,   0,   0,   0,   0,
-     0,   0,   0,   0, 272,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0, 271,   0,   0,   0,   0,   0,   0,
-   618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
-   618, 619,  26, 620, 621, 618,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   274, 273, 273, 622, 623, 624,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   625, 625, 625, 625, 625, 626, 625, 627, 625, 628,  26,  26,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26, 629, 629, 629, 629, 629, 629, 629, 630,
-   631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631,
-   631, 631, 631, 631, 631, 631, 631, 631, 632, 631, 633,  26,  26,  26,  26,  26,
-   634, 634, 634, 634, 634, 634, 634, 634, 634, 635, 634, 636,  26,  26,  26,  26,
-    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 361,   0,
-     0,   0,   0,   0,   0,   0, 637,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   361,   0,   0,   0,   0,   0,   0, 272,  26,  26,  26,  26,  26,  26,  26,  26,
-   638,  31,  31,  31, 639, 640, 641, 642, 643, 644, 639, 645, 639, 641, 641, 646,
-    31, 647,  31, 648, 649, 647,  31, 648,  26,  26,  26,  26,  26,  26, 355,  26,
-     0,   0,   0,   0,   0, 284,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0, 284,  26,   0, 262, 361,   0, 361,   0, 361,   0,   0,   0, 272,  26,
-     0, 637,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 637,   0,   0,
-     0,   0,   0,   0,   0, 637,  26,  26,  26,  26,  26,  26, 650,   0,   0,   0,
-   651,  26,   0,   0,   0,   0,   0, 284,   0, 607, 316,  26, 272,  26,  26,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 272,  26,   0, 637,   0, 269,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 284,  26,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 607,   0, 284,  26,  26,
-     0, 284,   0,   0,   0,   0,   0,   0,   0,  26,   0, 316,   0,   0,   0,   0,
-     0,  26,   0,   0,   0, 272,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-     0, 611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 614, 616,
-     0,   0,   0,   0, 613, 652,   0,   0,   0, 613,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 284,  26,   0, 272, 284, 269,
-   269,  26, 272,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 653,  26,  26,  26,  26,  26,
-   280, 280, 280, 280, 280, 280, 654,  26, 280, 280, 280, 280, 280, 280, 280, 280,
-   280, 280, 280, 283, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
-   280, 280, 280, 280, 348,  26, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
-   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 655,  26,  26,  26,
-   280, 280, 280, 283,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
-   656,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    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,
+    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,
+   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,
      9,   9,   9,   9,   9,   9,   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,
@@ -5430,10 +5584,11 @@
      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,   0,   0,   0,   0,   0,   0,1948,1949,
-  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,1957,1959,1958,
-  1960,   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,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,
@@ -5490,12 +5645,12 @@
 static inline uint_fast8_t
 _hb_ucd_gc (unsigned u)
 {
-  return u<1114110u?_hb_ucd_u8[6432+(((_hb_ucd_u8[1248+(((_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[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;
 }
 static inline uint_fast8_t
 _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[8640+(((_hb_ucd_u8[7704+(((_hb_ucd_u8[7048+(((_hb_ucd_u8[6802+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+  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;
 }
 static inline unsigned
 _hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -5505,42 +5660,59 @@
 static inline int_fast16_t
 _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9372+(((_hb_ucd_u8[9252+(((_hb_ucd_b4(9124+_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[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;
 }
 static inline uint_fast8_t
 _hb_ucd_sc (unsigned u)
 {
-  return u<918000u?_hb_ucd_u8[10822+(((_hb_ucd_u16[1920+(((_hb_ucd_u8[10150+(((_hb_ucd_u8[9700+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+  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;
 }
 static inline uint_fast16_t
 _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[5648+(((_hb_ucd_u8[16174+(((_hb_ucd_b4(16078+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0;
+  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;
 }
 
 
 #else
 
 static const uint8_t
-_hb_ucd_u8[13072] =
+_hb_ucd_u8[13602] =
 {
-    0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  5,  5,  7,  8,  9,
-   10, 11, 12, 13, 14, 15, 16,  5, 17, 15, 15, 18, 15, 19, 20, 21,
-    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 23,
-   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, 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, 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, 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, 15, 15, 15, 15, 15, 15, 15, 15,
-   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-   24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
-    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    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,
+   14, 15, 16, 17, 18, 19, 20, 21, 22, 21, 21, 21, 21, 23,  7,  7,
+    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,
+   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, 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, 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, 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, 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, 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,
+   38, 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,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
     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, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41,
@@ -5549,48 +5721,37 @@
    67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67,
    79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34,
    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
    85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90,
    91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
   100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
   100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108,
-   34, 34,109,110,111,112,113,114,115,116,117,111, 34, 34, 34,111,
-  118,119,120,121,122,123,124,125, 34,126,127,111,128,111,129, 34,
-  130,131,132,133,134,135,136,111,137,138,111,139,140,141,142,111,
-  143,144,111,145,146,147,111,111,148,149,150,151,111,152,111,153,
-   34, 34, 34, 34, 34, 34, 34, 34,154, 34, 34,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, 34, 34, 34,155,111,111,111,111,111,111,111,
+   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,
   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,
-  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,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,111,111,
-   34, 34, 34, 34,156,157,158, 34,111,111,111,111,159,160,161,162,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34,162,163,164, 34,111,111,111,111,165,166,167,168,
+   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,
-   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,163,111,111,111,111,111,111,
-   67, 67,164,165,166,128, 65,111,167,168,169,170,171,172,173,174,
-   67, 67, 67, 67,175,176,111,111,111,111,111,111,111,111,111,111,
-  177,111,178,111,111,179,111,111,111,111,111,111,111,111,111,111,
-   34,180,181,111,111,111,111,111,128,182,183,111, 34,184,111,111,
-   67, 67,185, 67, 67,111, 67,186, 67, 67, 67, 67, 67, 67, 67, 67,
-   67, 67, 67, 67, 67, 67,111,111,111,111,111,111,111,111,111,111,
-   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+  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,111,111,111,111,111,111,111,111,
    34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
-  187,111,177,177,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, 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,
     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,
@@ -5616,201 +5777,207 @@
    54, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 55,
    56, 57, 43, 56, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 36, 36,
    36, 58,  2,  2,  2,  2,  2,  2, 59, 59, 59,  8,  9, 60,  2, 61,
-   43, 43, 43, 43, 43, 57, 59,  2, 62, 36, 36, 36, 36, 63, 43, 43,
-    7,  7,  7,  7,  7,  2,  2, 36, 64, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 65, 43, 43, 43, 66, 47, 43, 43, 67, 68, 69, 43, 43, 36,
-    7,  7,  7,  7,  7, 36, 70, 71,  2,  2,  2,  2,  2,  2,  2, 72,
-   63, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 64, 36,
+   43, 43, 43, 43, 43, 57, 62,  2, 63, 36, 36, 36, 36, 64, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 65, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 66, 43, 43, 43, 67, 47, 43, 43, 68, 69, 70, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 71, 72,  2,  2,  2,  2,  2,  2,  2, 73,
+   64, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 65, 36,
    36, 36, 36, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7, 36, 36, 36,
-   36, 36, 36, 36, 36, 63, 43, 43, 43, 43, 40, 21,  2, 40, 68, 20,
-   36, 36, 36, 43, 43, 68, 43, 43, 43, 43, 68, 43, 68, 43, 43, 43,
-    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 63, 43, 43,  2,
-   36, 63, 43, 43, 43, 43, 43, 43, 43, 73, 43, 43, 43, 43, 43, 43,
-   43, 74, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 74, 64, 75,
-   76, 43, 43, 43, 74, 75, 76, 75, 63, 43, 43, 43, 36, 36, 36, 36,
-   36, 43,  2,  7,  7,  7,  7,  7, 77, 36, 36, 36, 36, 36, 36, 36,
-   63, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 75,
-   76, 43, 43, 74, 75, 75, 76, 36, 36, 36, 36, 79, 75, 75, 36, 36,
+   36, 36, 36, 36, 36, 64, 43, 43, 43, 43, 40, 21,  2, 40, 69, 20,
+   36, 36, 36, 43, 43, 69, 43, 43, 43, 43, 69, 43, 69, 43, 43, 43,
+    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 64, 43, 43,  2,
+   36, 36, 36, 36, 74, 36, 36, 36, 59, 59, 59, 59, 43, 43, 43, 43,
+   36, 36, 36, 36, 75, 43, 43, 43, 43, 76, 43, 43, 43, 43, 43, 43,
+   43, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 65, 78,
+   79, 43, 43, 43, 77, 78, 79, 78, 64, 43, 43, 43, 36, 36, 36, 36,
+   36, 43,  2,  7,  7,  7,  7,  7, 80, 36, 36, 36, 36, 36, 36, 36,
+   64, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 78,
+   79, 43, 43, 77, 78, 78, 79, 36, 36, 36, 36, 82, 78, 78, 36, 36,
    36, 43, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 53, 58, 43,
-   43, 74, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 75,
-   76, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 64, 36, 36, 36,
-   36, 36, 36,  7,  7,  7,  7,  7, 43, 36, 63,  2,  2,  2,  2,  2,
-   76, 43, 43, 43, 74, 75, 76, 43, 60, 20, 20, 20, 80, 43, 43, 43,
-   43, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 76,
-   76, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 74, 75, 75, 36, 36,
-   71, 27, 27, 27, 27, 27, 27, 27, 43, 64, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 75, 74, 75, 75, 75, 75, 75, 76, 43,
-   36, 36, 36, 79, 75, 75, 75, 75, 75, 75, 75,  7,  7,  7,  7,  7,
-   27, 81, 61, 61, 53, 61, 61, 61, 74, 75, 64, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 43, 74, 75, 75, 43, 43, 43, 43, 43,
-   43, 43, 43, 43, 36, 36, 36, 36,  7,  7,  7, 82, 27, 27, 27, 81,
-   63, 75, 65, 36, 36, 36, 36, 36, 75, 75, 75, 74, 75, 75, 43, 43,
-   43, 43, 74, 75, 75, 75, 75, 36, 83, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 63, 64, 75, 76, 43, 43, 75, 75, 75, 76, 70,
-   61, 61, 36, 79, 27, 27, 27, 84, 27, 27, 27, 27, 81, 36, 36, 36,
-   75, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74,
-   75, 43, 43, 43, 75, 75, 75, 75,  7, 75,  2,  2,  2,  2,  2,  2,
-   63, 36, 43, 43, 43, 43, 43, 85, 36, 36, 36, 68, 43, 43, 43, 57,
-    7,  7,  7,  7,  7,  2,  2,  2, 63, 36, 43, 43, 43, 43, 64, 36,
+   43, 77, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 78,
+   79, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 65, 36, 36, 36,
+   36, 36, 36,  7,  7,  7,  7,  7, 43, 36, 64,  2,  2,  2,  2,  2,
+   79, 43, 43, 43, 77, 78, 79, 43, 60, 20, 20, 20, 83, 43, 43, 43,
+   43, 78, 81, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 65, 79,
+   79, 43, 43, 77, 78, 78, 79, 43, 43, 43, 43, 77, 78, 78, 36, 36,
+   72, 27, 27, 27, 27, 27, 27, 27, 43, 65, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 78, 77, 78, 78, 78, 78, 78, 79, 43,
+   36, 36, 36, 82, 78, 78, 78, 78, 78, 78, 78,  7,  7,  7,  7,  7,
+   27, 84, 61, 61, 53, 61, 61, 61, 77, 78, 65, 36, 36, 36, 36, 36,
+   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, 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,
+   78, 43, 43, 43, 78, 78, 78, 78,  7, 78,  2,  2,  2,  2,  2,  2,
+   64, 36, 43, 43, 43, 43, 43, 88, 36, 36, 36, 69, 43, 43, 43, 57,
+    7,  7,  7,  7,  7,  2,  2,  2, 64, 36, 43, 43, 43, 43, 65, 36,
    36, 36, 36, 40, 43, 43, 43, 43,  7,  7,  7,  7,  7,  7, 36, 36,
-   70, 61,  2,  2,  2,  2,  2,  2,  2, 86, 86, 61, 43, 61, 61, 61,
-    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 47, 47, 47,  4,  4, 75,
-   63, 43, 43, 43, 43, 43, 43, 74, 43, 43, 57, 43, 36, 36, 63, 43,
-   43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 69, 61, 61, 61, 61,
-    2,  2, 86, 61, 21,  2,  2,  2, 36, 36, 36, 36, 36, 79, 76, 43,
-   74, 43, 43, 43, 76, 74, 76, 64, 36, 36, 36, 75, 43, 36, 36, 43,
-   64, 75, 78, 79, 75, 75, 75, 36, 63, 43, 64, 36, 36, 36, 36, 36,
-   36, 74, 76, 74, 75, 75, 76, 79,  7,  7,  7,  7,  7, 75, 76, 61,
-   16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 63, 43,
-    2,  2,  2,  2, 87, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+   71, 61,  2,  2,  2,  2,  2,  2,  2, 89, 89, 61, 43, 61, 61, 61,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 47, 47, 47,  4,  4, 78,
+   64, 43, 43, 43, 43, 43, 43, 77, 43, 43, 57, 43, 36, 36, 64, 43,
+   43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 70, 61, 61, 61, 61,
+    2,  2, 89, 61, 21,  2,  2,  2, 36, 36, 36, 36, 36, 82, 79, 43,
+   77, 43, 43, 43, 79, 77, 79, 65, 36, 36, 36, 78, 43, 36, 36, 43,
+   65, 78, 81, 82, 78, 78, 78, 36, 64, 43, 65, 36, 36, 36, 36, 36,
+   36, 77, 79, 77, 78, 78, 79, 82,  7,  7,  7,  7,  7, 78, 79, 61,
+   16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 64, 43,
+    2,  2,  2,  2, 90, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
    61, 61, 61, 61, 61, 61, 61, 61, 11, 11, 11, 11, 16, 16, 16, 16,
-   88, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65,
-   89, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 90, 91, 91,
-   36, 36, 36, 36, 36, 58,  2, 92, 93, 36, 36, 36, 36, 36, 36, 36,
-   36, 43, 43, 43, 43, 43, 43, 43, 36, 43, 57,  2,  2,  2,  2,  2,
-   36, 36, 43, 76, 43, 43, 43, 75, 75, 75, 75, 74, 76, 43, 43, 43,
-   43, 43,  2, 77,  2, 60, 63, 43,  7,  7,  7,  7,  7,  7,  7,  7,
-    2,  2,  2, 94,  2, 56, 43, 59, 36, 95, 36, 36, 36, 36, 36, 36,
-   36, 36, 63, 64, 36, 36, 36, 36, 36, 36, 36, 36, 63, 36, 36, 36,
-   43, 74, 75, 76, 74, 75, 75, 75, 75, 74, 75, 75, 76, 43, 43, 43,
-   61, 61,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 27, 27, 61,
-   36, 36, 36, 63, 74, 76, 43,  2, 36, 36, 79, 74, 43, 43, 43, 43,
-   74, 74, 76, 43, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 43, 43,
-    2,  2,  2, 77,  2,  2,  2,  2, 43, 43, 43, 43, 43, 43, 43, 48,
-   48, 48, 48, 48, 48, 48, 48, 48, 43, 43, 78, 36, 36, 36, 36, 36,
-   36, 36, 74, 43, 43, 74, 74, 75, 75, 74, 78, 36, 36, 36, 36, 36,
-   86, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 61, 61,
-   43, 78, 36, 36, 36, 36, 36, 36, 79, 43, 43, 75, 43, 76, 43, 36,
-   36, 36, 36, 74, 43, 75, 76, 76, 43, 75, 75, 75, 75, 75,  2,  2,
-   36, 36, 75, 75, 75, 75, 43, 43, 43, 43, 75, 43, 43, 57,  2,  2,
-    7,  7,  7,  7,  7,  7, 83, 36, 36, 36, 36, 36, 40, 40, 40,  2,
-   43, 57, 43, 43, 43, 43, 43, 43, 74, 43, 43, 43, 64, 36, 63, 36,
-   36, 36, 64, 79, 43, 36, 36, 36, 16, 16, 16, 16, 16, 16, 40, 40,
+   91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 71, 66,
+   92, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, 94, 94,
+   36, 36, 36, 36, 36, 58,  2, 95, 96, 36, 36, 36, 36, 36, 36, 36,
+   36, 43, 77, 78, 78, 78, 78, 81, 36, 43, 97,  2,  2,  2,  2,  2,
+   36, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 79, 43, 43, 43, 78,
+   78, 78, 78, 77, 79, 43, 43, 43, 43, 43,  2, 80,  2, 60, 64, 43,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 98,  2, 56, 43, 76,
+   36, 75, 36, 36, 36, 36, 36, 36, 36, 36, 64, 65, 36, 36, 36, 36,
+   36, 36, 36, 36, 64, 36, 36, 36, 43, 77, 78, 79, 77, 78, 78, 78,
+   78, 77, 78, 78, 79, 43, 43, 43, 61, 61,  2,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7, 27, 27, 61, 36, 36, 36, 64, 77, 79, 43,  2,
+   36, 36, 82, 77, 43, 43, 43, 43, 77, 77, 79, 43, 43, 43, 77, 78,
+   78, 79, 43, 43, 43, 43, 43, 43,  2,  2,  2, 80,  2,  2,  2,  2,
+   43, 43, 43, 43, 43, 43, 43, 99, 43, 43, 81, 36, 36, 36, 36, 36,
+   36, 36, 77, 43, 43, 77, 77, 78, 78, 77, 81, 36, 36, 36, 36, 36,
+   89, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 21,  2,
+   43, 81, 36, 36, 36, 36, 36, 36, 82, 43, 43, 78, 43, 79, 43, 36,
+   36, 36, 36, 77, 43, 78, 79, 79, 43, 78, 78, 78, 78, 78,  2,  2,
+   36, 36, 78, 78, 78, 78, 43, 43, 43, 43, 78, 43, 43, 57,  2,  2,
+    7,  7,  7,  7,  7,  7, 86, 36, 36, 36, 36, 36, 40, 40, 40,  2,
+   43, 57, 43, 43, 43, 43, 43, 43, 77, 43, 43, 43, 65, 36, 64, 36,
+   36, 36, 65, 82, 43, 36, 36, 36, 16, 16, 16, 16, 16, 16, 40, 40,
    40, 40, 40, 40, 40, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16,
-   16, 16, 16, 16, 16, 96, 40, 40, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 16,100, 40, 40, 32, 32, 32, 16, 16, 16, 16, 32,
    16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 16, 34, 11, 11, 11,
-   16, 16, 16, 16, 97, 97, 97, 97, 16, 16, 16, 16, 11, 11, 98, 99,
-   41, 16, 16, 16, 11, 11, 98, 41, 16, 16, 16, 16, 11, 11,100, 41,
-  101,101,101,101,101,102, 59, 59, 51, 51, 51,  2,103,104,103,104,
-    2,  2,  2,  2,105, 59, 59,106,  2,  2,  2,  2,107,108,  2,109,
-  110,  2,111,112,  2,  2,  2,  2,  2,  9,110,  2,  2,  2,  2,113,
-   59, 59, 59, 59, 59, 59, 59, 59,114, 40, 27, 27, 27,  8,111,115,
-   27, 27, 27, 27, 27,  8,111, 91, 20, 20, 20, 20, 20, 20, 20, 20,
-   43, 43, 43, 43, 43, 43,116, 48,117, 48,117, 43, 43, 43, 43, 43,
-   61,118, 61,119, 61, 34, 11, 16, 11, 32,119, 61, 46, 11, 11, 61,
-   61, 61,118,118,118, 11, 11,120, 11, 11, 35, 36, 39, 61, 16, 11,
-    8,  8, 46, 16, 16, 26, 61,121, 92, 92, 92, 92, 92, 92, 92, 92,
-   92,122,123, 92,124, 61, 61, 61,  8,  8,125, 61, 61,  8, 61, 61,
-  125, 26, 61,125, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 61,  8,
-   61,125,125, 61, 61, 61, 61, 61, 61, 61,  8,  8,  8,  8,  8,  8,
+   16, 16, 16, 16,101,101,101,101, 16, 16, 16, 16, 11, 11,102,103,
+   41, 16, 16, 16, 11, 11,102, 41, 16, 16, 16, 16, 11, 11,104, 41,
+  105,105,105,105,105,106, 59, 59, 51, 51, 51,  2,107,108,107,108,
+    2,  2,  2,  2,109, 59, 59,110,  2,  2,  2,  2,111,112,  2,113,
+  114,  2,115,116,  2,  2,  2,  2,  2,  9,114,  2,  2,  2,  2,117,
+   59, 59, 59, 59, 59, 59, 59, 59,118, 40, 27, 27, 27,  8,115,119,
+   27, 27, 27, 27, 27,  8,115, 94, 20, 20, 20, 20, 20, 20, 20, 20,
+   43, 43, 43, 43, 43, 43,120, 48, 99, 48, 99, 43, 43, 43, 43, 43,
+   61,121, 61,122, 61, 34, 11, 16, 11, 32,122, 61, 46, 11, 11, 61,
+   61, 61,121,121,121, 11, 11,123, 11, 11, 35, 36, 39, 61, 16, 11,
+    8,  8, 46, 16, 16, 26, 61,124, 95, 95, 95, 95, 95, 95, 95, 95,
+   95,125,126, 95,127, 61, 61, 61,  8,  8,128, 61, 61,  8, 61, 61,
+  128, 26, 61,128, 61, 61, 61,128, 61, 61, 61, 61, 61, 61, 61,  8,
+   61,128,128, 61, 61, 61, 61, 61, 61, 61,  8,  8,  8,  8,  8,  8,
     8,  8,  8,  8,  8,  8,  8,  8, 61, 61, 61, 61,  4,  4, 61, 61,
-    8, 61, 61, 61,126,127, 61, 61, 61, 61, 61, 61, 61, 61,125, 61,
+    8, 61, 61, 61,129,130, 61, 61, 61, 61, 61, 61, 61, 61,128, 61,
    61, 61, 61, 61, 61, 26,  8,  8,  8,  8, 61, 61, 61, 61, 61, 61,
    61, 61, 61, 61, 61, 61,  8,  8,  8, 61, 61, 61, 61, 61, 61, 61,
    27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27,
    61, 61, 61, 26, 61, 61, 61, 61, 26, 61, 61, 61, 61, 61, 61, 61,
    61, 61, 61, 61,  8,  8,  8,  8, 61, 61, 61, 61, 61, 61, 61, 26,
    61, 61, 61, 61,  4,  4,  4,  4,  4,  4,  4, 27, 27, 27, 27, 27,
-   27, 27, 61, 61, 61, 61, 61, 61,  8,  8,111,128,  8,  8,  8,  8,
-    8,  8,  8,  4,  4,  4,  4,  4,  8,111,129,129,129,129,129,129,
-  129,129,129,129,128,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
-    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,125, 26,  8,  8,125, 61,
+   27, 27, 61, 61, 61, 61, 61, 61,  8,  8,115,131,  8,  8,  8,  8,
+    8,  8,  8,  4,  4,  4,  4,  4,  8,115,132,132,132,132,132,132,
+  132,132,132,132,131,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
+    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,128, 26,  8,  8,128, 61,
    32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11,
-   32, 32,121, 61, 61,119, 34,130, 43, 32, 16, 16, 50,  2, 87,  2,
-   36, 36, 36, 36, 36, 36, 36, 95,  2,  2,  2,  2,  2,  2,  2, 56,
-    2,103,103,  2,107,108,103,  2,  2,  2,  2,  6,  2, 94,103,  2,
-  103,  4,  4,  4,  4,  2,  2, 77,  2,  2,  2,  2,  2, 51,  2,  2,
-   94,131,  2,  2,  2,  2,  2,  2,  1,  2,132,133,  4,  4,  4,  4,
-    4, 61,  4,  4,  4,  4,134, 91,135, 92, 92, 92, 92, 43, 43, 75,
-  136, 40, 40, 61, 92,137, 58, 61, 71, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 63,138,139, 62, 36, 36, 36, 36, 36, 58, 40, 62,
+   32, 32,124, 61, 61,122, 34,133, 43, 32, 16, 16, 50,  2, 90,  2,
+   36, 36, 36, 36, 36, 36, 36, 75,  2,  2,  2,  2,  2,  2,  2, 56,
+    2,107,107,  2,111,112,107,  2,  2,  2,  2,  6,  2, 98,107,  2,
+  107,  4,  4,  4,  4,  2,  2, 80,  2,  2,  2,  2,  2, 51,  2,  2,
+   98,134,  2,  2,  2,  2,  2,  2, 61,  2,135,132,132,132,136, 51,
+   51, 51, 51, 51, 51, 51, 51, 51,  1,  2,137,138,  4,  4,  4,  4,
+    4, 61,  4,  4,  4,  4,139, 94,140, 95, 95, 95, 95, 43, 43, 78,
+  141, 40, 40, 61, 95,142, 58, 61, 72, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 64,143,144, 63, 36, 36, 36, 36, 36, 58, 40, 63,
    61, 27, 27, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 61, 61, 61,
-   61, 61, 61, 61, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 27,
-   36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,141,  2,
-   32, 32, 32, 32, 32, 32, 32, 63, 48,142, 43, 43, 43, 43, 43, 77,
-   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36, 92, 92, 92, 92, 92,
-   43,  2,  2,  2,  2,  2,  2,  2, 41, 41, 41,139, 40, 40, 40, 40,
+   61, 61, 61, 61, 27, 27, 27, 27,145, 27, 27, 27, 27, 27, 27, 27,
+   36, 36, 75, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,146,  2,
+   32, 32, 32, 32, 32, 32, 32, 64, 48,147, 43, 43, 43, 43, 43, 80,
+   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36, 95, 95, 95, 95, 95,
+   43,  2,  2,  2,  2,  2,  2,  2, 41, 41, 41,144, 40, 40, 40, 40,
    41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32,
-   44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,143, 34, 35,
+   44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,148, 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, 16, 32, 11, 11, 11, 11, 11, 11,
-   11, 11, 11,144, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36,
-   36, 79, 76, 74, 61, 61, 61, 61, 27, 27, 27, 61,145, 61, 61, 61,
-   36, 36,  2,  2,  2,  2,  2,  2, 75, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 75, 75, 75, 75, 75, 75, 75, 75, 43, 43, 43, 43, 43,  2,
-   43, 36, 36, 36,  2, 65, 65, 63, 36, 36, 36, 43, 43, 43, 43,  2,
-   36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,146,
-   36, 63, 75, 43, 43, 75, 43, 75,146,  2,  2,  2,  2,  2,  2, 77,
-    7,  7,  7,  7,  7,  7,  7,  2, 36, 36, 63, 62, 36, 36, 36, 36,
-   36, 36, 36, 36, 63, 43, 43, 74, 76, 74, 76, 43, 43, 43, 43, 43,
-   36, 63, 36, 36, 36, 36, 74, 75,  7,  7,  7,  7,  7,  7,  2,  2,
-   62, 36, 36, 70, 61, 79, 74, 36, 64, 43, 64, 63, 64, 36, 36, 43,
-   36, 36, 36, 36, 36, 36, 95,  2, 36, 36, 36, 36, 36, 79, 43, 75,
-    2, 95,147, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16, 99, 40, 40,
-   36, 79, 76, 75, 74,146, 76, 43,148,148,148,148,148,148,148,148,
-  149,149,149,149,149,149,149,149, 16, 16, 16, 16, 16, 16, 35, 64,
-   36, 36, 36, 36,150, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
-   41,151, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,129,
-  152,152,152,152,152,152,152,152, 36, 36, 36, 36, 36, 36,145, 61,
-    2,  2,  2,153,112,  2,  2,  2,  6,154,155,129,129,129,129,129,
-  129,129,112,153,112,  2,109,156,  2,  2,  2,  2,134,129,129,112,
-    2,157,  8,  8, 60,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36,158,
-    2,  2,  3,  2,  4,  5,  6,  2, 16, 16, 16, 16, 16, 17, 18,111,
-  112,  4,  2, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 40, 20,159, 53, 20, 26,  8,125, 61,
-   61, 61, 61, 61,160, 59, 61, 61,  2,  2,  2, 87, 27, 27, 27, 27,
-   27, 27, 27, 81, 61, 61, 61, 61, 92, 92,124, 27, 81, 61, 61, 61,
+   11, 11, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 34, 16, 16, 16,
+   32, 16, 16, 32, 32, 16, 16, 16, 16, 40,149, 35, 40, 35, 36, 36,
+   36, 65, 36, 65, 36, 64, 36, 36, 36, 82, 79, 77, 61, 61, 43, 43,
+   27, 27, 27, 61,150, 61, 61, 61, 36, 36,  2,  2,  2,  2,  2,  2,
+   78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 78, 78, 78, 78, 78, 78,
+   78, 78, 43, 43, 43, 43, 43,  2, 43, 36, 36, 36,  2, 66, 66, 64,
+   36, 36, 36, 43, 43, 43, 43,  2, 36, 36, 36, 64, 43, 43, 43, 43,
+   43, 78, 78, 78, 78, 78, 78, 97, 36, 64, 78, 43, 43, 78, 43, 78,
+   97,  2,  2,  2,  2,  2,  2, 80,  7,  7,  7,  7,  7,  7,  7,  2,
+   36, 36, 64, 63, 36, 36, 36, 36, 36, 36, 36, 36, 64, 43, 43, 77,
+   79, 77, 79, 43, 43, 43, 43, 43, 36, 64, 36, 36, 36, 36, 77, 78,
+    7,  7,  7,  7,  7,  7,  2,  2, 63, 36, 36, 71, 61, 82, 77, 36,
+   65, 43, 65, 64, 65, 36, 36, 43, 36, 36, 36, 36, 36, 36, 75,  2,
+   36, 36, 36, 36, 36, 82, 43, 78,  2, 75,151, 43, 43, 43, 43, 43,
+   16, 16, 16, 16, 16,103, 40, 40, 16, 16, 16, 16,100, 41, 41, 41,
+   36, 82, 79, 78, 77, 97, 79, 43,152,152,152,152,152,152,152,152,
+  153,153,153,153,153,153,153,153, 16, 16, 16, 16, 16, 16, 35, 65,
+   36, 36, 36, 36,154, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+   41, 74, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,132,
+   36, 36, 36, 36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 36,150, 61,
+    2,  2,  2,135,116,  2,  2,  2,  6,155,156,132,132,132,132,132,
+  132,132,116,135,116,  2,113,157,  2,  2,  2,  2,139,132,132,116,
+    2,158,  8,  8, 60,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36,159,
+    2,  2,  3,  2,  4,  5,  6,  2, 16, 16, 16, 16, 16, 17, 18,115,
+  116,  4,  2, 36, 36, 36, 36, 36, 63, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 40, 20,160, 53, 20, 26,  8,128, 61,
+   61, 61, 61, 61,161, 59, 61, 61,  2,  2,  2, 90, 27, 27, 27, 27,
+   27, 27, 27, 84, 61, 61, 61, 61, 95, 95,127, 27, 84, 61, 61, 61,
    61, 61, 61, 61, 61, 27, 61, 61, 61, 61, 61, 61, 61, 61, 47, 43,
-  161,161,161,161,161,161,161,161,162, 27, 27, 27, 27, 27, 27, 27,
-   27, 27, 27, 27, 27, 27, 84, 36,133, 36, 36, 36, 36, 92, 92, 92,
-   36, 36, 36, 36, 36, 36, 36, 58,163, 92, 92, 92, 92, 92, 92, 92,
-   36, 36, 36, 58, 27, 27, 27, 27, 36, 36, 36, 70,140, 27, 27, 27,
-   36, 36, 36,164, 27, 27, 27, 27, 36, 36, 36, 36, 36,164, 27, 27,
-   36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36,
-   63, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 43, 43, 43, 43,
-   36, 36, 36, 36, 36, 36,164, 30, 36, 36, 36, 36, 36, 36,164, 27,
-   36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 43, 43,162, 27, 27,
-   36, 36, 36, 36, 58,  2,  2,  2, 36, 36, 36, 36, 27, 27, 27, 27,
-   16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 43, 43, 43, 43, 43, 43,
-   27, 27, 27, 84, 36, 36, 36, 36,162, 27, 30,  2,  2,  2,  2,  2,
-   76, 78, 36, 36, 36, 36, 36, 36, 43, 43, 43, 57,  2,  2,  2,  2,
+  162,162,162,162,162,162,162,162,163, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 87, 36,138, 36, 36, 36, 36, 95, 95, 95,
+   36, 36, 36, 36, 36, 36, 36, 58,164, 95, 95, 95, 95, 95, 95, 95,
+   11, 11, 11, 32, 16, 16, 16, 16, 36, 36, 36, 58, 27, 27, 27, 27,
+   36, 36, 36, 71,145, 27, 27, 27, 36, 36, 36,165, 27, 27, 27, 27,
+   36, 36, 36, 36, 36,165, 27, 27, 36, 36, 36, 27, 27, 27, 27, 30,
+   36, 36, 36, 36, 36, 36, 27, 36, 64, 43, 43, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,165, 30,
+   36, 36, 36, 36, 36, 36,165, 27, 36, 36, 36, 36, 72, 36, 36, 36,
+   36, 36, 64, 43, 43,163, 27, 27, 36, 36, 36, 36, 58,  2,  2,  2,
+   36, 36, 36, 36, 27, 27, 27, 27, 16, 16, 16, 16, 16, 27, 27, 27,
+   36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 64,166, 51,
+   27, 27, 27, 87, 36, 36, 36, 36,163, 27, 30,  2,  2,  2,  2,  2,
+   36, 43, 43,  2,  2,  2,  2,  2, 36, 36,165, 27, 27, 27, 27, 27,
+   79, 81, 36, 36, 36, 36, 36, 36, 43, 43, 43, 57,  2,  2,  2,  2,
     2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7,  7,  7,  7,
-    7,  7,  7,  7,  7,  7,  7,165, 75, 76, 43, 74, 76, 57, 72,  2,
-    2,  2,  2,  2,  2,  2, 72, 59, 36, 36, 36, 63, 43, 43, 76, 43,
-   43, 43, 43,  7,  7,  7,  7,  7,  2,  2, 79, 75, 75, 75, 75, 75,
-   36, 63,  2, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 43, 74,
-   78, 36, 58,  2, 56, 43, 57,  2,  7,  7,  7,  7,  7, 58, 58,  2,
-   87, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 75, 76,
-   43, 75, 74, 43,  2,  2,  2, 43, 36, 36, 36, 36, 36, 36, 36, 63,
-   74, 75, 75, 75, 75, 75, 75, 75, 36, 36, 36, 79, 75, 75, 78, 36,
-   36, 75, 75, 43, 43, 43, 43, 43, 36, 36, 79, 75, 43, 43, 43, 43,
-   75, 43, 74, 64, 36, 58,  2,  2,  7,  7,  7,  7,  7, 82,  2, 64,
-   75, 76, 43, 43, 74, 74, 75, 76, 74, 43, 36, 65, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 75, 75, 43, 76,
+   65, 64, 65, 36, 36, 36, 36, 64, 78, 79, 43, 77, 79, 57, 73,  2,
+    2, 43, 43, 43, 43, 43, 67, 59, 36, 36, 36, 64, 43, 43, 79, 43,
+   43, 43, 43,  7,  7,  7,  7,  7,  2,  2, 82, 81, 36, 36, 36, 36,
+   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,
+   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,
+   78, 79, 43, 43, 77, 77, 78, 79, 77, 43, 36, 66, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 82, 78, 43, 43, 43, 78, 78, 43, 79,
    57,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 43, 43,
-   75, 76, 43, 43, 43, 74, 76, 76, 57,  2, 36, 36, 36, 36, 36, 36,
-   36, 36, 36, 36, 36, 63, 76, 75, 43, 43, 43, 76, 36, 36, 36, 36,
-   75, 43, 43, 76, 43, 43, 43, 43,  7,  7,  7,  7,  7, 27,  2, 86,
-   43, 43, 43, 43, 76, 57,  2,  2, 27, 27, 27, 27, 27, 27, 27, 84,
-   79, 75, 43, 43, 43, 43, 75, 75, 64, 65, 75, 75, 75, 75, 75, 75,
-   75, 75, 75, 75, 75, 75, 75, 75, 63, 43, 43, 43, 43, 64, 36, 36,
-   36, 63, 43, 43, 74, 63, 43, 57,  2,  2,  2, 56, 43, 43, 43, 43,
-   63, 43, 43, 74, 76, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43,
-   43, 43, 43, 74, 43,  2, 65,  2, 43, 43, 43, 43, 43, 43, 43, 76,
+   78, 79, 43, 43, 43, 77, 79, 79, 57,  2, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 64, 79, 78, 43, 43, 43, 79, 58,  2,  2,  2,
+   78, 43, 43, 79, 43, 43, 43, 43,  7,  7,  7,  7,  7, 27,  2, 89,
+   43, 43, 43, 43, 79, 57,  2,  2, 27, 27, 27, 27, 27, 27, 27, 87,
+   78, 78, 78, 78, 78, 79, 77, 65, 81, 79,  2,  2,  2,  2,  2,  2,
+   82, 78, 43, 43, 43, 43, 78, 78, 65, 66, 78, 78, 78, 78, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 64, 43, 43, 43, 43, 65, 36, 36,
+   36, 64, 43, 43, 77, 64, 43, 57,  2,  2,  2, 56, 43, 43, 43, 43,
+   64, 43, 43, 77, 79, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43,
+   43, 43, 43, 77, 43,  2, 66,  2, 43, 43, 43, 43, 43, 43, 43, 79,
    58,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36,
-   43, 43, 43, 43, 74, 43, 43, 43, 74, 43, 76, 43, 43, 43, 43, 43,
-   43, 43, 43, 63, 43, 43, 43, 43, 36, 36, 36, 36, 36, 75, 75, 75,
-   43, 74, 76, 76, 36, 36, 36, 36, 36, 63, 74,146,  2,  2,  2,  2,
-   27, 27, 81, 61, 61, 61, 53, 20,145, 61, 61, 61, 61, 61, 61, 61,
+   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, 43, 43, 57,  2,  2, 61, 61, 40, 40, 86, 61, 61, 61, 61, 61,
-    7,  7,  7,  7,  7,166, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36,
-   27, 27, 27, 30,  2,  2,  2,  2, 79, 75, 75, 75, 75, 75, 75, 75,
-   75, 75, 75, 75, 75, 75, 75, 76, 43, 67, 40, 40, 40, 40, 40, 40,
-   40, 77, 40, 40, 40, 40, 40, 40, 36, 36, 36, 36, 36, 36, 47, 57,
-   61, 61,167, 76, 43, 61,167, 75, 75,168, 59, 59, 59, 73, 43, 43,
-   43, 69, 47, 43, 43, 43, 61, 61, 61, 61, 61, 61, 61, 43, 43, 61,
-   61, 43, 69, 61, 61, 61, 61, 61, 11, 11, 11, 11, 11, 16, 16, 16,
+   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,
+   78, 78, 78, 78, 78, 78, 78, 79, 43, 68, 40, 40, 40, 40, 40, 40,
+   40, 80, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 47, 57,
+   61, 61,168, 79, 43, 61,168, 78, 78,169, 59, 59, 59, 76, 43, 43,
+   43, 70, 47, 43, 43, 43, 61, 61, 61, 61, 61, 61, 61, 43, 43, 61,
+   61, 43, 70, 61, 61, 61, 61, 61, 11, 11, 11, 11, 11, 16, 16, 16,
    16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
    11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
    11, 11, 11, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16, 16,
@@ -5819,204 +5986,209 @@
    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, 16,  7, 43, 43, 43, 69, 61, 47, 43, 43,
-   43, 43, 43, 43, 43, 43, 69, 61, 61, 61, 47, 61, 61, 61, 61, 61,
-   61, 61, 69, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2, 56, 43, 43,
-   43, 43, 43, 67, 40, 40, 40, 40,  7,  7,  7,  7,  7,  7,  7, 70,
-   36, 36, 36, 36, 36, 36, 43, 43,  7,  7,  7,  7,  7,  7,  7,169,
-   16, 16, 43, 43, 43, 67, 40, 40, 27, 27, 27, 27, 27, 27,140, 27,
-  170, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,140,
-   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,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1, 12,  6,
-    6, 12, 12, 26,  7, 26, 26,  7, 21,  1,  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, 17, 21,  7,  6,  5,  6,  8,  8,  8, 24,  5, 24,
+   16, 33, 16, 16, 16, 32, 16,  7, 43, 43, 43, 70, 61, 47, 43, 43,
+   43, 43, 43, 43, 43, 43, 70, 61, 61, 61, 47, 61, 61, 61, 61, 61,
+   61, 61, 70, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2, 56, 43, 43,
+   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, 11, 12,  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,
-   26,  6,  7, 14, 17, 22, 26, 14, 17,  6, 14,  6, 12, 24, 24,  6,
-   26, 15,  6, 21, 11, 21, 24,  9,  9,  7, 23, 26, 10, 21,  6, 10,
-    4,  4,  3,  3,  7, 25, 24,  7, 22, 22, 21, 22, 17, 16, 16, 22,
-   16, 16, 25, 17,  7,  1, 25, 24, 26,  1,  2,  2, 12, 15, 21, 14,
-    7, 15, 13, 12, 13, 15, 26, 10, 10,  1, 13, 23, 23, 15,  0,  1,
-    2,  3,  4,  5,  6,  7,  8,  9,  9, 10, 11,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9, 12, 13,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 14, 15, 16,  9,
-   17, 18, 19, 20, 21, 22,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9, 23,  9,  9,  9,  9,  9,  9,  9,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 24,  9,  9,
-    9,  9, 25,  9,  9,  9, 26,  9, 27,  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,  0, 14, 15, 16,
-   15, 17, 15, 18, 15, 18, 15, 18,  0, 18,  0, 19, 15, 18, 20, 18,
-    0, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,  0, 31,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 32,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 33,  0,  0, 34,  0,  0, 35,  0, 36,  0,
-    0,  0, 37, 38, 39,  0, 40, 41, 42, 43, 44,  0,  0, 45,  0,  0,
-    0, 46,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47,  0,  0,
+   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, 48,  0, 49,
-    0, 50,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0, 52,  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,  0,  0,  0,  0, 56,  0,  0, 57, 58, 59,
-   60, 61,  0,  0, 62, 63,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 65,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0, 67,  0,  0,  0, 68,  0, 69,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0, 70,  0,  0, 71,  0,  0,  0,  0,  0,  0,  0,  0, 72,  0,
-    0,  0,  0,  0,  0,  0,  0, 73,  0,  0,  0, 74, 75,  0, 76, 60,
-    0, 77, 78,  0,  0, 79, 80, 81,  0,  0,  0, 82,  0, 83,  0,  0,
-   49, 84, 49,  0, 85,  0, 86,  0,  0,  0, 75,  0,  0,  0,  0,  0,
-    0, 87, 88, 89, 90,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0, 91,
-   92,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 93, 94,  0,  0,  0,  0,  0, 95,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 96,
-   97,  0,  0, 98,  0,  0,  0,  0,  0,  0, 99,  0,  0,  0, 94,  0,
-    0,  0,  0,  0,  0,100,  0,  0,  0,  0,  0,  0,  0,101,  0,102,
-    0,  0,  0,  0,  0,  0,  0,  0,  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, 28, 29,  0,  0,  0, 30, 31, 32,  0,  0, 31,  0,
-    0, 33, 31,  0,  0,  0, 31, 34,  0,  0,  0,  0,  0, 35, 36,  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, 41,  0, 42,  0,  0,  0, 43, 44,  0,  0,  0, 45,  0,
-    0,  0,  0,  0,  0, 46, 47,  0,  0,  0,  0, 48,  0,  0,  0, 49,
-    0, 49,  0, 50,  0,  0,  0,  0, 51,  0,  0,  0,  0, 52,  0, 53,
-    0,  0,  0,  0, 54, 55,  0,  0,  0, 56,  0,  0,  0, 57, 49,  0,
-   58, 59,  0,  0, 60,  0,  0,  0, 61, 62,  0,  0,  0, 63,  0, 64,
-   65, 66, 67, 68,  1, 69,  0, 70, 71, 72,  0,  0, 73, 74,  0,  0,
-    0, 75,  0,  0,  1,  1,  0,  0, 76,  0,  0, 77,  0,  0,  0,  0,
-   73, 78,  0, 79,  0,  0,  0,  0,  0, 74, 80,  0,  0,  0, 49,  0,
-    1, 74,  0,  0, 81,  0,  0, 82,  0,  0,  0,  0,  0, 83, 54,  0,
-    0,  0,  0,  0,  0, 84, 85,  0,  0, 80,  0,  0, 31,  0,  0, 86,
-    0,  0,  0,  0, 87,  0,  0,  0,  0, 47,  0,  0, 88,  0,  0,  0,
-    0, 89, 90,  0,  0, 91,  0,  0, 92,  0,  0,  0, 93,  0, 94, 88,
-    0,  0, 80,  0,  0, 75,  0,  0,  0, 95, 96,  0,  0, 97, 98,  0,
-    0,  0,  0,  0,  0, 99,  0,  0,100,  0,  0,  0,  0,101, 31,  0,
-  102,103,104, 33,  0,  0,105,  0,  0,  0,106,  0,  0,  0,  0,  0,
-    0,107,  0,  0,108,  0,  0,  0, 54,  0,  0,  0,  0, 49,109,  0,
-    0,  0,  0,110,  0,  0,111,  0,  0,  0,  0,109,  0,  0,  0,  0,
-    0,112,  0,  0,  0,113,  0,114,  0,  0,  0,  0,115,116,117,  0,
-  118,  0,119,  0,  0,  0,120,121,122,  0,  0,  0,123,  0,  0,124,
-    0,  0,125,  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, 52,  1,  1,  1, 53, 21, 43, 54, 55, 21, 35,  1,  0,  0,
-    0, 56,  0,  0,  0, 57, 58, 59,  0,  0,  0,  0,  0, 60,  0, 61,
-    0,  0,  0,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65,  0,  0,  0,
-   66,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0,  0, 69,  0,  0, 70,
-   71,  0, 72, 73, 74, 75, 76, 77,  0,  0,  0, 78,  0,  0,  0, 79,
-   80,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 63,  0,  0, 64,  0,
-    0, 81,  0,  0, 82,  0,  0,  0, 83,  0,  0, 19, 84,  0, 63,  0,
-    0,  0,  0, 49,  1, 85,  1, 54, 15, 41,  0, 56,  0,  0,  0,  0,
-   19, 10,  1,  0,  0,  0,  0,  0, 86,  0,  0, 87,  0,  0, 86,  0,
-    0,  0,  0, 79,  0,  0, 88,  9, 12,  4, 89,  8, 90, 47,  0, 59,
-   50,  0, 21,  1, 21, 91, 92,  1,  1,  1,  1, 93, 94, 95, 96,  1,
-   97, 59, 81, 98, 99,  4, 59,  0,  0,  0,  0,  0,  0, 19, 50,  0,
-    0,  0,  0,  0,  0, 62,  0,  0,100,101,  0,  0,102,  0,  0,  1,
-    1, 50,  0,  0,  0, 38,  0, 64,  0,  0,  0,  0, 52, 69, 62,  0,
-    0,  0, 79,  0,  0,  0,103,104, 59, 38, 81,  0,  0,  0,  0,  0,
-    0,105,  1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 88,  0,  0,  0,
-    0,106,  0,  0,107, 62,  0,108,  0,  0,  0,  1,  0,  0,  0,109,
-   14, 54,  0,  0,110,  0, 88,  0,  0,  0, 62, 63,  0,  0, 63,  0,
-   87,  0,  0,110,  0,  0,  0,  0,111,  0,  0,  0, 79, 56,  0, 38,
-    1, 59,  1, 59,  0,  0, 64, 87,  0,  0,112,  0,  0,  0, 56,  0,
-    0,  0,  0,112,  0,  0,  0,  0, 62,  0,  0, 62,  0,  0,  0,  0,
-   57,  0, 87,113,  0,  0,  8, 90,  0,  0,  1, 88,  0,  0,  0,  0,
-    0,114,  0,115,116,117,118,  0, 52,  4,119, 49, 23,  0,  0,  0,
-   38, 50, 38, 59,  0,  0,  1, 88,  1,  1,  1,  1, 39,  1, 48,103,
-   88,  0,  0,  0,  0,  1,  4,119,  0,  0,  0,  1,120,  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,  0,  0,
-    0,220,230,230,  0,220,230,220,220,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,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,220,  0,
-    0,  0,230,  0,  0,220,  0,  0,  9,  9,  0,  0,  7,  0,230,230,
-  230,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,202,230,
-  230,230,230,230,232,228,228,220,  0,230,233,220,230,220,230,230,
+    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,
+    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,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,  9,  7,  0,  0,  7,  9,  0,  0,  0,
-    9,  7,  9,  9,  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, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17,
+  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, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 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,  3,  3,  3,  3,  3,
-    3,  3, 24,  3,  3,  3,  3,  3,  3,  3,  3, 25,  3,  3, 26, 27,
-    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, 19, 56, 31,  0,  0,  0,  0,  0,  0,  0, 57, 14,  0,
-    0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,  0, 58, 59,  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,  1,  0,  1,  1,  8, 21, 21,  9,  0,  4,  5,  8,  9,  1,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 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, 12, 19, 12, 20, 12, 12, 12, 12, 21,
-   22, 22, 22, 23, 12, 12, 12, 12, 24, 25, 12, 12, 26, 27, 28, 29,
-   30, 31,  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, 32,
-   12, 33, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 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,
@@ -6038,7 +6210,7 @@
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-   12, 12, 34,  0,  0,  1,  2,  2,  2,  3,  4,  5,  6,  7,  8,  9,
+   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,
@@ -6052,298 +6224,315 @@
    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, 87,
-  104,104,104, 87,105,106,107,108,109,110,111,112,113,114,115, 87,
-   89, 87,116,117,118,119,120,121,122,123,124, 87,125,126, 87,127,
-  128,129,130, 87,131,132, 87,133,134,135, 87, 87,136,137,138,139,
-   87,140, 87, 21,141,141,141,141,141,141,141,141,141,141,141, 87,
-   87, 87, 87, 87,142,142,142,142,142,142,142,142,142, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,143,143,143,143,
-  143, 87, 87, 87,144,144,144,144,145,146,147,147, 87, 87, 87, 87,
-  148,148,149,150,151,151,151,151,151,151,151,151,151,151,151,151,
-  151,151,151,151,151,151,151,151,151,151, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87,152,153,154,155,155,155, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,156,157, 87, 87,
-   87, 87, 87, 87, 56, 56,158,159, 51, 56, 56, 87, 56, 56, 56, 56,
-   56, 56, 56, 56,160,160,160,160,160,160, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87,161, 87,162, 87, 87,163, 87, 87, 87, 87, 87, 87,
-   87, 87, 87, 87,164,164,165, 87, 87, 87, 87, 87, 56, 56, 56, 87,
-   89, 89, 87, 87, 56, 56, 56, 56,166, 87, 56, 56, 56, 56, 56, 56,
-   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87, 87, 87,
+   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, 56, 87,167,167,  0,  1,  2,  2,  0,  1,  2,  2,
+   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, 17, 18, 19, 19,
-   19, 19, 19, 19, 20, 21, 22, 22, 23, 24, 22, 25, 22, 22, 22, 22,
-   22, 26, 22, 22, 27, 27, 27, 27, 27, 22, 22, 22, 28, 28, 28, 28,
-   29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 27, 27, 22, 22, 22, 22,
-   22, 22, 32, 22, 33, 33, 33, 33, 33, 34, 35, 33, 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, 44,
-   44, 44, 44, 44, 45, 45, 45, 46, 45, 45, 45, 45, 47, 47, 47, 47,
-   47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
-   48, 49, 48, 48, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51,
-   51, 51, 51, 52, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54,
-   54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56,
-   56, 56, 56, 56, 57, 57, 58, 58, 58, 58, 59, 58, 60, 60, 61, 62,
-   63, 63, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 66, 67, 67, 67,
-   67, 67, 67, 67, 67, 67, 67, 56, 56, 56, 56, 56, 68, 68, 68, 68,
-   68, 69, 69, 69, 70, 70, 70, 70, 70, 70, 65, 65, 71, 71, 72, 72,
-   72, 72, 72, 72, 72, 72, 72,  8,  8,  8,  8,  8, 73, 73, 73, 73,
-   73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76,
-   76, 77, 77, 77, 13, 51, 51, 51, 74, 78, 79, 80,  4,  4, 81,  4,
-    4, 82, 83, 84,  4,  4,  4, 85,  8,  8,  8,  8, 11, 11, 11, 11,
-   11, 11, 11, 11, 86,  0,  0,  0,  0,  0,  0, 87,  0,  4,  0,  0,
-    0,  8,  8,  8,  0,  0, 88, 89, 90,  0,  4,  4,  6,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 91, 91, 91, 91,
-   91, 91, 91, 91, 92, 92, 92, 92, 92, 92,  4,  4, 93, 93, 93, 93,
-   93, 93, 93, 93, 51, 51, 51, 94, 94, 94, 94, 94, 54, 54, 54, 54,
-   54, 54, 13, 13, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
-   95, 95, 95,  0, 96,  0, 97, 98, 99,100,100,100,100,101,102,103,
-  103,103,103,104,105,105,105,106, 53, 53, 53, 53, 53,  0,105,105,
-    0,  0,  0,103, 53, 53,  0,  0,  0,  0, 53,107,  0,  0,  0,  0,
-    0,103,103,108,103,103,103,103,103,109,  0,  0, 95, 95, 95, 95,
-    0,  0,  0,  0,110,110,110,110,110,110,110,110,110,110,110,110,
-  110,111,111,111,112,112,112,112,112,112,112,112,112,112,112,112,
-   13, 13, 13, 13, 13, 13,113,113,113,113,113,113,  0,  0,114,  4,
-    4,  4,  4,  4,115,  4,  4,  4,  4,  4,  4,  4,116,116,116,  0,
-  117,117,117,117,118,118,118,118,118,118, 33, 33,119,119,120,121,
-  121,121, 53, 53,122,122,122,122,123,122, 50, 50,124,124,124,124,
-  124,124, 50, 50,125,125,125,125,125,125,126,126, 54, 54, 54,  4,
-    4,127,128, 55, 55, 55, 55, 55,126,126,126,126,129,129,129,129,
-  129,129,129,129,  4,130, 19, 19, 19, 22, 22, 22, 22, 22, 22, 22,
-   22, 22, 22, 22, 22, 22, 22,131,  0, 22, 22, 22,  8,  0,132,  0,
-    0,  0,  0, 22, 22, 22, 22, 22, 22, 22, 22,133,  0,  0,  1,  2,
-    1,  2,134,102,103,135, 53, 53, 53, 53,  0,  0,136,136,136,136,
-  136,136,136,136,  0,  0,  0,  0, 11, 11, 11, 11, 11,  0, 11, 11,
-   11,  0,  0,137,138,138,139,139,139,139,140,  0,141,141,141,142,
-  142,143,143,143,144,144,145,145,145,145,145,145,146,146,146,146,
-  146,147,147,147,148,148,148,149,149,149,149,149,150,150,150,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,174,174,174,174,174,175,175,175,175,
-  175,175,175,175,176,176,176,176,176,176,176,176,177,177,177,177,
-  177,178,178,178,179,179,179,179,179,180,180,180,181,181,181,181,
-  181,181,182, 44,183,183,183,183,183,183,183,183,184,184,184,185,
-  185,185,185,185,186,186,186,187,186,186,186,186,188,188,188,188,
-  188,188,188,188,189,189,189,189,189,189,189,189,190,190,190,190,
-  190,190,190,190,191,191,191,191,191,191, 67, 67,192,192,192,192,
-  192,192,192,192,193,193,193,193,193,193,193,193,194,194,194,194,
-  194,194,194,194,195,195,195,195,195,195,195,195,196,196,196,196,
-  196,196,196,196,197,197,197,197,197,198,198,198,198,198,198,198,
-  199,199,199,199,200,200,200,200,200,200,200,201,201,201,201,201,
-  201,201,201,201,202,202,202,202,202,202,203,203,203,203,203,203,
-  203,203,203,203,204,204,204,204,204,204,204,204,205,205,205,205,
-  205,205,205,205,206,206,206,206,206,206,206,206,207,207,207,207,
-  207,207,207,207,113,113,113,113,113,113,113,113,113,113,113,113,
-  208,208,208,208,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,212,212,212,212,212,212,213,  0,214,214,214,214,
-  214,214,214,214,215,100,100,100,100,100,100,100,100,100,100,100,
-  100,100,100,100,100,100,100,100,100,100,216,217,217,217,217,217,
-  217,217,217,217,218,218,218,218,218,218,218,218,218,218,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,219,220,221,  0,222,  0,
-    0,  0,  0,  0,223,223,223,223,223,223,223,223, 92, 92, 92, 92,
-   92, 92, 92, 92,224,224,224,224,224,224,224,224,225,225,225,225,
-  225,225,225,225,226,226,226,226,226,226,226,226,227,227,227,227,
-  227,227,227,227,228,  0,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,
+   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,
+   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,
+   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,
+   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, 17, 17, 18, 17, 19, 20, 20, 20,
-   20, 20, 20, 20, 21, 22, 21, 23, 21, 21, 24, 24, 21, 21, 21, 21,
-   23, 21, 25,  7,  7, 26, 21, 21, 27, 21, 21, 21, 21, 21, 21, 22,
+   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, 32, 32, 32, 33, 21, 21, 21, 34, 34, 34, 34, 35, 36, 34, 34,
-   34, 37, 34, 34, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40,
+   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, 47, 47, 47, 47, 47, 47, 47, 48,
-   49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 50, 53, 53, 53, 53,
-   54, 54, 54, 54, 54, 54, 55, 54, 56, 56, 56, 56, 57, 57, 57, 57,
-   58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61,
-   61, 61, 62, 63, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66,  0,  0,
-   67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 71, 72, 72,
+   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, 82, 82, 82, 83,  7,  7,  7,
-   84,  7, 85, 86,  0, 85, 87,  0,  2, 88, 89,  2,  2,  2,  2, 90,
-   91, 88, 92,  2,  2,  2, 93,  2,  2,  2,  2, 94,  0,  0,  0, 87,
-    1,  0,  0, 95,  0, 96, 97,  0,  4,  0,  0,  0,  0,  0,  0,  4,
-   98, 98, 98, 98, 99, 99, 99, 99, 13, 13, 13, 13,100,100,100,100,
-  101,101,101,101,  0,102,  0,  0,103,101,104,105,  0,  0,101,  0,
-  106,107,107,107,107,107,107,107,107,107,108,106,109,110,110,110,
-  110,110,110,110,110,110,111,109,112,112,112,112,113, 56, 56, 56,
-   56, 56, 56,114,110,110,110,111,110,110,  0,  0,115,115,115,115,
-  116,116,116,116,117,117,117,117,118,118,118,118, 97,  2,  2,  2,
-    2,  2, 95,  2,119,119,119,119,120,120,120,120,121,121,121,121,
-  122,122,122,122,122,122,122,123,124,124,124,124,125,125,125,125,
-  125,125,125,126,127,127,127,127,128,128,128,128,129,129,129,129,
-    2,  2,  3,  2,  2,130,  2,  2,131,131,131,131,132, 17, 17, 19,
-   21, 21, 21,133,  7,  7,  7,134, 21, 21, 21, 24,  0,135,110,110,
-  110,110,110,136,137,137,137,137,  0,  0,  0,138,139,139,139,139,
-  140,140,140,140, 85,  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, 46, 46, 46,
-  183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,
-  186,186,187,186,188,188,188,188,189,189,189,189,190,190,190,190,
-  191,191,191,191,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,  0,  0,  0,214,214,214,214,
-  215,107,107,107,107,110,110,110,216,216,216,216,217,217,217,217,
-    0,218, 87,  0,  0,  0,218,  7, 83,138,  7,  0,  0,  0,219, 87,
-  220,220,220,220,221,221,221,221,222,222,222,222,223,223,223,223,
-  224,224,224,224,225,  0,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19,
+   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,  0,  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,  2,  2,  2,  2, 19, 19, 19,  4,  3,  3,  0,  0,
+    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,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,147,147,147,147,
-  148,148,148,148,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,
+  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,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,
-   80, 80, 80, 80,127,127,127,127,115,115,115,115,103,103,103,103,
-  119,119,119,119,146,146,146,146, 99, 99, 99, 99,136,139,  0,  0,
+  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,
-  152,152,152,152,113,113,113,113,132,132,132,132, 15,  0,  0,  0,
-   16, 50, 84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91,
-   85, 85,220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
-   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15,
-    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,
+  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,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  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, 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, 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, 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, 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,  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,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  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,  0,  0,  0,
-    0,  0,  0,  0,  0,  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,
-    0,  0,  0,  0,  0,  0,  0,  0,  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,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,168,169,  0,  0,  0,  0,170,171,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  172,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,  0,  0,  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,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[4800] =
+_hb_ucd_u16[4888] =
 {
      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,
@@ -6353,319 +6542,332 @@
     13,  13,  13,  35,   9,  42,  11,  11,  43,  44,  32,  45,  46,  47,  47,  48,
     49,  50,  47,  47,  51,  32,  52,  53,  47,  47,  47,  47,  47,  54,  55,  56,
     57,  58,  47,  32,  59,  47,  47,  47,  47,  47,  60,  53,  61,  47,  62,  63,
-    47,  64,  65,  66,  47,  67,  47,  47,  47,  47,  47,  47,  47,  68,  69,  32,
-    70,  47,  47,  71,  72,  73,  74,  75,  76,  47,  47,  77,  78,  79,  80,  81,
-    82,  47,  47,  83,  84,  85,  86,  87,  82,  47,  47,  77,  88,  47,  80,  89,
-    90,  47,  47,  91,  92,  93,  80,  94,  95,  47,  47,  96,  97,  98,  99, 100,
-   101,  47,  47, 102, 103, 104,  80, 105, 106,  47,  47,  91, 107, 108,  80, 109,
-    90,  47,  47, 110, 111, 112,  80, 113, 114,  47,  47,  47, 115, 116,  99, 117,
-    47,  47,  47, 118, 119, 120,  66,  66,  47,  47,  47, 121, 122, 123,  47,  47,
-   124, 125, 126, 127,  47,  47,  47, 128, 129,  32,  32, 130, 131, 132,  66,  66,
-    47,  47, 133, 134, 120, 135, 136, 137, 138, 139,   9,   9,   9,  11,  11, 140,
-    47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47, 141, 142, 143,
-    47, 144,   9,   9,   9,   9,   9, 145, 146,  47,  47,  47,  47,  47,  47,  47,
-    47,  47,  47,  47,  47,  47, 147,  47, 148, 149,  47,  47,  47,  47, 150, 151,
-    47, 152,  47, 153,  47, 152,  47, 152,  47,  47,  47, 154, 155, 156, 157, 143,
-   158, 157,  47,  47, 159,  47,  47,  47, 160,  47, 161,  47,  47,  47,  47,  47,
-    47,  47, 162, 163, 164,  47,  47,  47,  47,  47,  47,  47,  47, 165, 144, 144,
-    47, 166,  47,  47,  47, 167, 168, 169, 157, 157, 170, 171, 172, 172, 172, 172,
-   173,  47,  47, 174, 175, 120, 176, 177, 178,  47, 179,  61,  47,  47, 180, 181,
-    47,  47, 182, 183, 184,  61,  47, 185,  11,   9,   9,   9,  66, 186, 187, 188,
-    11,  11, 189,  27,  27,  27, 190, 191,  11, 192,  27,  27,  32,  32,  32,  32,
-    13,  13,  13,  13,  13,  13,  13,  13,  13, 193,  13,  13,  13,  13,  13,  13,
-   194, 194, 194, 194, 194, 195, 194,  11, 196, 196, 196, 197, 198, 199, 199, 198,
-   200, 201, 202, 203, 204, 205, 206, 207, 208,  27, 209, 209, 209, 210, 211,  32,
-   212, 213, 214, 215, 216, 143, 217, 217, 218, 219, 220, 144, 221, 222, 144, 223,
-   224, 224, 224, 224, 224, 224, 224, 224, 225, 144, 226, 144, 144, 144, 144, 227,
-   144, 228, 224, 229, 144, 230, 231, 144, 144, 144, 144, 144, 144, 144, 143, 143,
-   143, 232, 144, 144, 144, 144, 233, 143, 144, 144, 144, 144, 144, 144, 144, 144,
-   144, 144, 144, 234, 235, 144, 144, 236, 144, 144, 144, 144, 144, 144, 237, 144,
-   144, 144, 144, 144, 144, 144, 238, 239, 143, 240, 144, 144, 241, 224, 242, 224,
-   243, 244, 224, 224, 224, 245, 224, 246, 144, 144, 144, 224, 247, 144, 144, 144,
-     9,   9,   9,  11,  11,  11, 248, 249,  13,  13,  13,  13,  13,  13, 250, 251,
-    11,  11,  11,  47,  47,  47, 252, 253,  47,  47,  47,  47,  47,  47,  32,  32,
-   254, 255, 256, 257, 258,  66,  66,  66, 259, 260, 261, 262, 263,  47,  47,  47,
-    47, 264, 146,  47,  47,  47,  47, 265,  47, 266,  47,  47, 144, 144, 144,  47,
-   144, 144, 267, 144, 268, 269, 144, 144, 267, 144, 144, 269, 144, 144, 144, 144,
-    47,  47,  47,  47, 144, 144, 144, 144,  47, 270,  47,  47,  47,  47,  47,  47,
-    47, 144, 144, 144, 144,  47,  47, 185, 271,  47,  61,  47,  13,  13, 272, 273,
-    13, 274,  47,  47,  47,  47, 275, 276,  31, 277, 278, 279,  13,  13,  13, 280,
-   281, 282, 283, 284, 285,   9,   9, 286, 287,  47, 288, 289,  47,  47,  47, 290,
-   291,  47,  47, 292, 293, 157,  32, 294,  61,  47, 295,  47, 296, 297,  47,  47,
-    70,  47,  47, 298, 299, 300, 301,  61,  47,  47, 302, 303, 304, 305,  47, 306,
-    47,  47,  47, 307,  58, 308, 309, 310,  47,  47,  47,  11,  11, 311,  11,  11,
-    11,  11,  11,  11,  47,  47, 312, 157, 313, 313, 313, 313, 313, 313, 313, 313,
-   314, 314, 314, 314, 314, 314, 314, 314,  11, 315, 316,  47,  47,  47,  47,  47,
-    47,  47,  47, 317,  31, 318,  47,  47,  47,  47,  47, 319, 320,  47,  47,  47,
-    47,  47,  47,  47,  47,  47,  47, 321,  32, 322,  32, 323, 324, 325, 326,  47,
-    47,  47,  47,  47,  47,  47,  47, 327, 328,   2,   3,   4,   5, 329, 330, 331,
-    47, 332,  47,  47,  47,  47, 333, 334, 335, 143, 143, 336, 217, 217, 217, 337,
-   338, 144, 144, 144, 144, 144, 144, 339, 340, 340, 340, 340, 340, 340, 340, 340,
-    47,  47,  47,  47,  47,  47, 341, 143,  47,  47, 342,  47, 343,  47,  47,  60,
-    47, 344,  47,  47,  47, 345, 217, 217,   9,   9, 145,  11,  11,  47,  47,  47,
-    47,  47, 157,   9,   9, 145,  11,  11,  47,  47,  47,  47,  47,  47, 344,  66,
-    47,  47,  47,  47,  47, 346,  47, 347,  47,  47, 348, 143, 143, 143,  47, 349,
-    47, 350,  47, 344,  66,  66,  66,  66,  47,  47,  47, 351, 143, 143, 143, 143,
-   352,  47,  47, 353, 143,  66,  47, 354,  47, 355, 143, 143, 356,  47, 357,  66,
-    47,  47,  47, 358,  47, 359,  47, 359,  47, 358, 142, 143, 143, 143, 143, 143,
-     9,   9,   9,   9,  11,  11,  11, 360,  47,  47, 361, 157, 157, 157, 157, 157,
-   143, 143, 143, 143, 143, 143, 143, 143,  47, 355, 362,  47,  60, 363,  66,  66,
-   364,  47,  47, 353, 365, 366, 367, 368, 178,  47,  47, 369, 370,  47,  47, 157,
-    95,  47, 371, 372, 373,  47,  47, 374, 178,  47,  47, 375, 376, 377, 378, 143,
-    47,  47, 379, 380,  32,  32,  32,  32,  47,  47, 358,  47,  47, 381, 169, 157,
-    90,  47,  47, 110, 382, 383, 384,  32,  47,  47,  47, 385, 386, 387,  47,  47,
-    47,  47,  47, 388, 389, 157, 157, 157,  47,  47, 390, 391, 392, 393,  32,  32,
-    47,  47,  47, 394, 395, 157,  66,  66,  47,  47, 396, 397, 157, 157, 157, 157,
-    47, 141, 398, 399, 144, 144, 144, 144,  47,  47, 379, 400,  66,  66,  66,  66,
-     9,   9,   9,   9,  11,  11, 126, 401,  47,  47,  47,  47,  47, 402, 403, 404,
-   405,  47,  47, 406, 407, 408,  47,  47, 409, 410,  66,  66,  47,  47,  47,  47,
-    47,  47, 390, 411, 412, 126, 143, 413,  47, 152, 414, 415,  32,  32,  32,  32,
-    47,  47,  47, 352, 416, 157,  47,  47, 417, 418, 157, 157, 157, 157, 157, 157,
-    47,  47,  47,  47,  47,  47,  47, 419, 143, 143, 143, 143, 143, 420, 421, 422,
-   217, 217, 217, 217, 217, 217, 217,  66,  47,  47,  47, 206, 206, 206, 206, 206,
-    47,  47,  47,  47,  47,  47, 300,  66,  47,  47,  47,  47,  47,  47,  47, 423,
-    47,  47,  47, 424, 425, 426, 427,  47,   9,   9,   9,   9,   9,   9,  11,  11,
-   143, 428,  66,  66,  66,  66,  66,  66,  47,  47,  47,  47, 381, 429, 404, 404,
-   430, 431,  27,  27,  27,  27, 432,  27,  47, 433, 206, 206, 206, 206, 206, 206,
-   144, 144, 144, 144, 144, 144, 434, 435, 436, 144, 437, 144, 144, 144, 144, 144,
-   144, 144, 144, 144, 438, 144, 144, 144,   9, 439,  11, 440, 441,  11, 194,   9,
-   442, 443,   9, 444,  11,   9, 439,  11, 440, 441,  11, 194,   9, 442, 443,   9,
-   444,  11,   9, 439,  11, 440, 441,  11, 194,   9, 442, 443,   9, 444,  11,   9,
-   439,  11, 194,   9, 445, 446, 447, 448,  11, 449,   9, 450, 451, 452, 453,  11,
-   454,   9, 455,  11, 456, 157, 157, 157,  32,  32,  32, 457,  32,  32, 458, 459,
-   460, 461,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
-    47,  47,  47, 462, 463, 144, 144, 144,  47,  47,  47,  47,  47,  47, 464, 465,
-    47,  47,  47,  47, 348,  32,  32,  32,   9,   9, 442,  11, 466, 300,  66,  66,
-   143, 143, 467, 468, 143, 143, 143, 143, 143, 143, 469, 143, 143, 143, 143, 143,
-    47,  47,  47,  47,  47,  47,  47, 224, 143, 144, 144, 144, 144, 144, 144, 144,
-   144, 144, 144, 144, 144, 144, 144, 470, 206, 206, 206, 206, 206, 206, 206, 206,
+    47,  64,  65,  66,  47,  67,  47,  47,  68,  69,  47,  47,  70,  32,  71,  32,
+    72,  47,  47,  73,  74,  75,  76,  77,  78,  47,  47,  79,  80,  81,  82,  83,
+    84,  47,  47,  85,  86,  87,  88,  89,  84,  47,  47,  79,  90,  47,  82,  91,
+    92,  47,  47,  93,  94,  95,  82,  96,  97,  47,  47,  98,  99, 100, 101, 102,
+   103,  47,  47, 104, 105, 106,  82, 107, 108,  47,  47,  93, 109, 110,  82, 111,
+   112,  47,  47, 113, 114, 115,  82, 116,  92,  47,  47,  47, 117, 118, 101, 119,
+    47,  47,  47, 120, 121, 122,  66,  66,  47,  47,  47, 123, 124, 125,  47,  47,
+   126, 127, 128, 129,  47,  47,  47, 130, 131,  32,  32, 132, 133, 134,  66,  66,
+    47,  47, 135, 136, 122, 137, 138, 139, 140, 141,   9,   9,   9,  11,  11, 142,
+    47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47, 143, 144, 145,
+    47, 146,   9,   9,   9,   9,   9, 147, 148,  47,  47,  47,  47,  47,  47,  47,
+    47,  47,  47,  47,  47,  47, 149,  47, 150, 151,  47,  47,  47,  47, 152, 153,
+    47, 154,  47, 155,  47, 156,  47, 156,  47,  47,  47, 157, 158, 159, 160, 145,
+   161, 160,  47,  47, 162,  47,  47,  47, 163,  47, 164,  47,  47,  47,  47,  47,
+    47,  47, 165, 166, 167,  47,  47,  47,  47,  47,  47,  47,  47, 168, 146, 146,
+    47, 169,  47,  47,  47, 170, 171, 172, 160, 160, 173, 174,  32,  32,  32,  32,
+   175,  47,  47, 176, 177, 122, 178, 179, 180,  47, 181,  61,  47,  47, 182, 183,
+    47,  47, 184, 185, 186,  61,  47, 187,  11,   9,   9,   9,  66, 188, 189, 190,
+    11,  11, 191,  27,  27,  27, 192, 193,  11, 194,  27,  27,  32,  32,  32,  32,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 195,  13,  13,  13,  13,  13,  13,
+   196, 196, 196, 196, 196, 197, 196,  11, 198, 198, 198, 199, 200, 201, 201, 200,
+   202, 203, 204, 205, 206, 207, 208, 209, 210,  27, 211, 211, 211, 212, 213,  32,
+   214, 215, 216, 217, 218, 145, 219, 219, 220, 221, 222, 146, 223, 224, 146, 225,
+   226, 226, 226, 226, 226, 226, 226, 226, 227, 146, 228, 146, 146, 146, 146, 229,
+   146, 230, 226, 231, 146, 232, 233, 146, 146, 146, 146, 146, 146, 146, 145, 145,
+   145, 234, 146, 146, 146, 146, 235, 145, 146, 146, 146, 146, 146, 146, 146, 146,
+   146, 146, 146, 236, 237, 146, 146, 238, 146, 146, 146, 146, 146, 146, 239, 146,
+   146, 146, 146, 146, 146, 146, 240, 241, 145, 242, 146, 146, 243, 226, 244, 226,
+   245, 246, 226, 226, 226, 247, 226, 248, 146, 146, 146, 226, 249, 146, 146, 146,
+     9,   9,   9,  11,  11,  11, 250, 251,  13,  13,  13,  13,  13,  13, 252, 253,
+    11,  11,  11,  47,  47,  47, 254, 255,  47,  47,  47,  47,  47,  47,  32,  32,
+   256, 257, 258, 259, 260, 261, 262, 262, 263, 264, 265, 266, 267,  47,  47,  47,
+    47, 268, 148,  47,  47,  47,  47, 269,  47, 270,  47,  47, 146, 146, 146,  47,
+   146, 146, 271, 146, 272, 273, 146, 146, 271, 146, 146, 273, 146, 146, 146, 146,
+    47,  47,  47,  47, 146, 146, 146, 146,  47, 274,  47,  47,  47,  47,  47,  47,
+    47, 146, 146, 146, 146,  47,  47, 187, 275,  47,  61,  47,  13,  13, 276, 277,
+    13, 278,  47,  47,  47,  47, 279, 280,  31, 281, 282, 283,  13,  13,  13, 284,
+   285, 286, 287, 288, 289, 290,  11, 291, 292,  47, 293, 294,  47,  47,  47, 295,
+   296,  47,  47, 297, 298, 160,  32, 299,  61,  47, 300,  47, 301, 302,  47,  47,
+    72,  47,  47, 303, 304, 305, 306,  61,  47,  47, 307, 308, 309, 310,  47, 311,
+    47,  47,  47, 312,  58, 313, 314, 315,  47,  47,  47,  11,  11, 316, 317,  11,
+    11,  11,  11,  11,  47,  47, 318, 160, 319, 319, 319, 319, 319, 319, 319, 319,
+   320, 320, 320, 320, 320, 320, 320, 320,  11, 321, 322,  47,  47,  47,  47,  47,
+    47,  47,  47, 323,  31, 324,  47,  47,  47,  47,  47, 325, 146,  47,  47,  47,
+    47,  47,  47,  47, 326, 146, 146, 327,  32, 328,  32, 329, 330, 331, 332,  47,
+    47,  47,  47,  47,  47,  47,  47, 333, 334,   2,   3,   4,   5, 335, 336, 337,
+    47, 338,  47,  47,  47,  47, 339, 340, 341, 145, 145, 342, 219, 219, 219, 343,
+   344, 146, 146, 146, 146, 146, 146, 345, 346, 346, 346, 346, 346, 346, 346, 346,
+    47,  47,  47,  47,  47,  47, 347, 145,  47,  47, 348,  47, 349,  47,  47,  60,
+    47, 350,  47,  47,  47, 351, 219, 219,   9,   9, 147,  11,  11,  47,  47,  47,
+    47,  47, 160,   9,   9, 147,  11,  11,  47,  47,  47,  47,  47,  47, 350,   9,
+     9, 352,  11,  11,  11,  11,  11,  11,  27,  27,  27,  27,  27,  27,  27,  27,
+    47,  47,  47,  47,  47, 353,  47, 354,  47,  47, 355, 145, 145, 145,  47, 356,
+    47, 357,  47, 350,  66,  66,  66,  66,  47,  47,  47, 358, 145, 145, 145, 145,
+   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,
+    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,
+    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,
+   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,
+     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,
-   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,   0,   0,   0,   0,   0,   0,1948,1949,
-  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,1957,1959,1958,
-  1960,   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, 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] =
+_hb_ucd_i16[196] =
 {
-      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,
+      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<1114112u?_hb_ucd_u8[4840+(((_hb_ucd_u8[1072+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+  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;
 }
 static inline uint_fast8_t
 _hb_ucd_ccc (unsigned u)
 {
-  return u<125259u?_hb_ucd_u8[6670+(((_hb_ucd_u8[6166+(((_hb_ucd_u8[5754+(((_hb_ucd_u8[5306+(((_hb_ucd_u8[5182+(u>>2>>2>>2>>4)])<<4)+((u>>2>>2>>2)&15u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+  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;
 }
 static inline unsigned
 _hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -6675,17 +6877,17 @@
 static inline int_fast16_t
 _hb_ucd_bmg (unsigned u)
 {
-  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7538+(((_hb_ucd_u8[7314+(((_hb_ucd_u8[7218+(((_hb_ucd_b4(7154+_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;
+  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;
 }
 static inline uint_fast8_t
 _hb_ucd_sc (unsigned u)
 {
-  return u<918016u?_hb_ucd_u8[11048+(((_hb_ucd_u8[10132+(((_hb_ucd_u8[8788+(((_hb_ucd_u8[8228+(((_hb_ucd_u8[7778+(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[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;
 }
 static inline uint_fast16_t
 _hb_ucd_dm (unsigned u)
 {
-  return u<195102u?_hb_ucd_u16[1504+(((_hb_ucd_u8[12048+(((_hb_ucd_b4(11952+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0;
+  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;
 }
 
 #endif
diff --git a/src/hb-ucd.cc b/src/hb-ucd.cc
index b29f2a9..baea224 100644
--- a/src/hb-ucd.cc
+++ b/src/hb-ucd.cc
@@ -136,20 +136,22 @@
   if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
   {
     uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
-    uint32_t *v = (uint32_t*) hb_bsearch (&k, _hb_ucd_dm2_u32_map,
-					  ARRAY_LENGTH (_hb_ucd_dm2_u32_map),
-					  sizeof (*_hb_ucd_dm2_u32_map),
-					  _cmp_pair_11_7_14);
+    const uint32_t *v = hb_bsearch (k,
+				    _hb_ucd_dm2_u32_map,
+				    ARRAY_LENGTH (_hb_ucd_dm2_u32_map),
+				    sizeof (*_hb_ucd_dm2_u32_map),
+				    _cmp_pair_11_7_14);
     if (likely (!v)) return false;
     u = HB_CODEPOINT_DECODE3_11_7_14_3 (*v);
   }
   else
   {
     uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
-    uint64_t *v = (uint64_t*) hb_bsearch (&k, _hb_ucd_dm2_u64_map,
-					  ARRAY_LENGTH (_hb_ucd_dm2_u64_map),
-					  sizeof (*_hb_ucd_dm2_u64_map),
-					  _cmp_pair);
+    const uint64_t *v = hb_bsearch (k,
+				    _hb_ucd_dm2_u64_map,
+				    ARRAY_LENGTH (_hb_ucd_dm2_u64_map),
+				    sizeof (*_hb_ucd_dm2_u64_map),
+				    _cmp_pair);
     if (likely (!v)) return false;
     u = HB_CODEPOINT_DECODE3_3 (*v);
   }
@@ -201,9 +203,7 @@
 }
 
 
-#if HB_USE_ATEXIT
 static void free_static_ucd_funcs ();
-#endif
 
 static struct hb_ucd_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucd_unicode_funcs_lazy_loader_t>
 {
@@ -220,21 +220,17 @@
 
     hb_unicode_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ucd_funcs);
-#endif
+    hb_atexit (free_static_ucd_funcs);
 
     return funcs;
   }
 } static_ucd_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ucd_funcs ()
 {
   static_ucd_funcs.free_instance ();
 }
-#endif
 
 hb_unicode_funcs_t *
 hb_ucd_get_unicode_funcs ()
diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh
index 1ff79c9..c216379 100644
--- a/src/hb-unicode-emoji-table.hh
+++ b/src/hb-unicode-emoji-table.hh
@@ -6,14 +6,14 @@
  *
  * on file with this header:
  *
- * # emoji-data.txt
- * # Date: 2019-01-15, 12:10:05 GMT
- * # © 2019 Unicode®, Inc.
+ * # emoji-data-14.0.0.txt
+ * # Date: 2021-08-26, 17:22:22 GMT
+ * # © 2021 Unicode®, Inc.
  * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
  * # For terms of use, see http://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Version: 12.0
+ * # Used with Emoji Version 14.0 and subsequent minor revisions (if any)
  * #
  * # For documentation and usage, see http://www.unicode.org/reports/tr51
  */
@@ -24,36 +24,42 @@
 #include "hb-unicode.hh"
 
 static const uint8_t
-_hb_emoji_u8[448] =
+_hb_emoji_u8[544] =
 {
-    0,  0,  0,  0, 33,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   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,
-    0,  0,  0,  0,  0,  0,  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,118,
-    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,  0,  2,  0,  0,  3,
-    0,  0,  0,  0,  0,  0,  4,  5,  6,  7,  8,  7,  9, 10, 11,  0,
-    0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0,  0,
-    7,  7,  7, 14, 15, 16, 17, 18, 19, 20,  7,  7,  7,  7,  7, 21,
-    7,  7,  7,  7, 22, 23,  7,  7,  7, 24,  7, 14,  0, 25,  0, 26,
-   27, 28, 29, 14, 30, 31,  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,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,  1,  0,  2,  0,  0,
-    0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,254,  7,  3,
-    0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0, 56,
-  159,255,243,255,255,255,255,255,255,255,255,255,255,255,255,255,
-   31,  0,255,255,255,255,255,255, 31,255,  3,  0,  0,  0,  8,  0,
-    0,  0, 24,  0,120,  0,  0,  0,  0,  0, 96,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0, 16,  0, 96,  0,  0,  8,  0,  0,  0,  0,
-  255,255,255,255,255,255,255,127,  0, 96,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,240,  1, 64,  0,  0,254,  3,  0,224,255,255,
-  255,255,255,255, 31,  0,  0,  0,254,127,  0,  0,  0,  0,252,115,
-    0,254,255,255,255,255,255,255,255,255,255,255,255,255,255,  3,
-  255,255,255,255,255,255,255, 31,192,255,255,255,255,255,255,255,
-  255,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,127,
-    0,  0,224,255,255,255,255,127,  0,112,  0,  0,  0,  0,  0,  0,
-    0,127,  0,124,  0,  0,  0,  0,  0,127,  0,  0,  0,192,255,255,
-    0,240,255,255,255,255,255,243,159,255,255,255,255,255,255,255,
+    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,
 };
 
 static inline unsigned
@@ -69,7 +75,7 @@
 static inline uint_fast8_t
 _hb_emoji_is_Extended_Pictographic (unsigned u)
 {
-  return u<131069u?_hb_emoji_b1(192+_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(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;
 }
 
 
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 08a4054..83ead63 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -40,11 +40,16 @@
  * @include: hb.h
  *
  * Unicode functions are used to access Unicode character properties.
- * Client can pass its own Unicode functions to HarfBuzz, or access
- * the built-in Unicode functions that come with HarfBuzz.
+ * With these functions, client programs can query various properties from
+ * the Unicode Character Database for any code point, such as General
+ * Category (gc), Script (sc), Canonical Combining Class (ccc), etc.
  *
- * With the Unicode functions, one can query variour Unicode character
- * properties, such as General Category, Script, Combining Class, etc.
+ * Client programs can optionally pass in their own Unicode functions
+ * that implement the same queries. The set of functions available is
+ * defined by the virtual methods in #hb_unicode_funcs_t.
+ *
+ * HarfBuzz provides built-in default functions for each method in
+ * #hb_unicode_funcs_t.
  **/
 
 
@@ -133,6 +138,16 @@
 #include "hb-icu.h"
 #endif
 
+/**
+ * hb_unicode_funcs_get_default:
+ *
+ * Fetches a pointer to the default Unicode-functions structure that is used
+ * when no functions are explicitly set on #hb_buffer_t.
+ *
+ * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure
+ *
+ * Since: 0.9.2
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_default ()
 {
@@ -155,11 +170,11 @@
 
 /**
  * hb_unicode_funcs_create: (Xconstructor)
- * @parent: (nullable):
+ * @parent: (nullable): Parent Unicode-functions structure
  *
+ * Creates a new #hb_unicode_funcs_t structure of Unicode functions.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The Unicode-functions structure
  *
  * Since: 0.9.2
  **/
@@ -203,25 +218,25 @@
 /**
  * hb_unicode_funcs_get_empty:
  *
+ * Fetches the singleton empty Unicode-functions structure.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The empty Unicode-functions structure
  *
  * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty ()
 {
-  return const_cast<hb_unicode_funcs_t *> (&Null(hb_unicode_funcs_t));
+  return const_cast<hb_unicode_funcs_t *> (&Null (hb_unicode_funcs_t));
 }
 
 /**
  * hb_unicode_funcs_reference: (skip)
- * @ufuncs: Unicode functions.
+ * @ufuncs: The Unicode-functions structure
  *
+ * Increases the reference count on a Unicode-functions structure.
  *
- *
- * Return value: (transfer full):
+ * Return value: (transfer full): The Unicode-functions structure
  *
  * Since: 0.9.2
  **/
@@ -233,9 +248,11 @@
 
 /**
  * hb_unicode_funcs_destroy: (skip)
- * @ufuncs: Unicode functions.
+ * @ufuncs: The Unicode-functions structure
  *
- *
+ * Decreases the reference count on a Unicode-functions structure. When
+ * the reference count reaches zero, the Unicode-functions structure is
+ * destroyed, freeing all memory.
  *
  * Since: 0.9.2
  **/
@@ -251,20 +268,20 @@
 
   hb_unicode_funcs_destroy (ufuncs->parent);
 
-  free (ufuncs);
+  hb_free (ufuncs);
 }
 
 /**
  * hb_unicode_funcs_set_user_data: (skip)
- * @ufuncs: Unicode functions.
- * @key:
- * @data:
- * @destroy:
- * @replace:
+ * @ufuncs: The Unicode-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 Unicode-functions structure. 
  *
- *
- * Return value:
+ * Return value: %true if success, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -280,12 +297,13 @@
 
 /**
  * hb_unicode_funcs_get_user_data: (skip)
- * @ufuncs: Unicode functions.
- * @key:
+ * @ufuncs: The Unicode-functions structure
+ * @key: The user-data key to query
  *
+ * Fetches the user-data associated with the specified key,
+ * attached to the specified Unicode-functions structure.
  *
- *
- * Return value: (transfer none):
+ * Return value: (transfer none): A pointer to the user data
  *
  * Since: 0.9.2
  **/
@@ -299,9 +317,10 @@
 
 /**
  * hb_unicode_funcs_make_immutable:
- * @ufuncs: Unicode functions.
+ * @ufuncs: The Unicode-functions structure
  *
- *
+ * Makes the specified Unicode-functions structure
+ * immutable.
  *
  * Since: 0.9.2
  **/
@@ -316,11 +335,12 @@
 
 /**
  * hb_unicode_funcs_is_immutable:
- * @ufuncs: Unicode functions.
+ * @ufuncs: The Unicode-functions structure
  *
+ * Tests whether the specified Unicode-functions structure
+ * is immutable.
  *
- *
- * Return value:
+ * Return value: %true if @ufuncs is immutable, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -332,11 +352,12 @@
 
 /**
  * hb_unicode_funcs_get_parent:
- * @ufuncs: Unicode functions.
+ * @ufuncs: The Unicode-functions structure
  *
+ * Fetches the parent of the Unicode-functions structure
+ * @ufuncs.
  *
- *
- * Return value:
+ * Return value: The parent Unicode-functions structure
  *
  * Since: 0.9.2
  **/
@@ -389,14 +410,18 @@
 
 /**
  * hb_unicode_compose:
- * @ufuncs: Unicode functions.
- * @a:
- * @b:
- * @ab: (out):
+ * @ufuncs: The Unicode-functions structure
+ * @a: The first Unicode code point to compose
+ * @b: The second Unicode code point to compose
+ * @ab: (out): The composition of @a, @b
  *
+ * Fetches the composition of a sequence of two Unicode
+ * code points.
  *
+ * Calls the composition function of the specified
+ * Unicode-functions structure @ufuncs.
  *
- * Return value:
+ * Return value: %true if @a and @b composed, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -411,14 +436,17 @@
 
 /**
  * hb_unicode_decompose:
- * @ufuncs: Unicode functions.
- * @ab:
- * @a: (out):
- * @b: (out):
+ * @ufuncs: The Unicode-functions structure
+ * @ab: Unicode code point to decompose
+ * @a: (out): The first code point of the decomposition of @ab
+ * @b: (out): The second code point of the decomposition of @ab
  *
+ * Fetches the decomposition of a Unicode code point. 
  *
+ * Calls the decomposition function of the specified
+ * Unicode-functions structure @ufuncs.
  *
- * Return value:
+ * Return value: %true if @ab was decomposed, %false otherwise
  *
  * Since: 0.9.2
  **/
@@ -434,13 +462,14 @@
 #ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_unicode_decompose_compatibility:
- * @ufuncs: Unicode functions.
- * @u:
- * @decomposed: (out):
+ * @ufuncs: The Unicode-functions structure
+ * @u: Code point to decompose
+ * @decomposed: (out): Compatibility decomposition of @u
  *
+ * Fetches the compatibility decomposition of a Unicode
+ * code point. Deprecated.
  *
- *
- * Return value:
+ * Return value: length of @decomposed.
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 61b1b0b..c04ee15 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -28,7 +28,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -41,14 +41,51 @@
 
 
 /**
- * HB_UNICODE_MAX
+ * HB_UNICODE_MAX:
+ *
+ * Maximum valid Unicode code point.
  *
  * Since: 1.9.0
  **/
 #define HB_UNICODE_MAX 0x10FFFFu
 
 
-/* hb_unicode_general_category_t */
+/**
+ * hb_unicode_general_category_t:
+ * @HB_UNICODE_GENERAL_CATEGORY_CONTROL:              [Cc]
+ * @HB_UNICODE_GENERAL_CATEGORY_FORMAT:		      [Cf]
+ * @HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED:	      [Cn]
+ * @HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE:	      [Co]
+ * @HB_UNICODE_GENERAL_CATEGORY_SURROGATE:	      [Cs]
+ * @HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER:     [Ll]
+ * @HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER:      [Lm]
+ * @HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER:	      [Lo]
+ * @HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER:     [Lt]
+ * @HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER:     [Lu]
+ * @HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK:	      [Mc]
+ * @HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK:	      [Me]
+ * @HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK:     [Mn]
+ * @HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER:	      [Nd]
+ * @HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER:	      [Nl]
+ * @HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER:	      [No]
+ * @HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION:  [Pc]
+ * @HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION:     [Pd]
+ * @HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION:    [Pe]
+ * @HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION:    [Pf]
+ * @HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION:  [Pi]
+ * @HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION:    [Po]
+ * @HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION:     [Ps]
+ * @HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL:      [Sc]
+ * @HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL:      [Sk]
+ * @HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL:	      [Sm]
+ * @HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL:	      [So]
+ * @HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR:	      [Zl]
+ * @HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR:  [Zp]
+ * @HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR:      [Zs]
+ *
+ * Data type for the "General_Category" (gc) property from
+ * the Unicode Character Database.
+ **/
 
 /* Unicode Character Database property: General_Category (gc) */
 typedef enum
@@ -85,13 +122,74 @@
   HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR		/* Zs */
 } hb_unicode_general_category_t;
 
-/* hb_unicode_combining_class_t */
-
-/* Note: newer versions of Unicode may add new values.  Clients should be ready to handle
- * any value in the 0..254 range being returned from hb_unicode_combining_class().
- */
-
-/* Unicode Character Database property: Canonical_Combining_Class (ccc) */
+/**
+ * hb_unicode_combining_class_t:
+ * @HB_UNICODE_COMBINING_CLASS_NOT_REORDERED: Spacing and enclosing marks; also many vowel and consonant signs, even if nonspacing
+ * @HB_UNICODE_COMBINING_CLASS_OVERLAY: Marks which overlay a base letter or symbol
+ * @HB_UNICODE_COMBINING_CLASS_NUKTA: Diacritic nukta marks in Brahmi-derived scripts
+ * @HB_UNICODE_COMBINING_CLASS_KANA_VOICING: Hiragana/Katakana voicing marks
+ * @HB_UNICODE_COMBINING_CLASS_VIRAMA: Viramas
+ * @HB_UNICODE_COMBINING_CLASS_CCC10: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC11: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC12: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC13: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC14: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC15: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC16: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC17: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC18: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC19: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC20: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC21: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC22: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC23: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC24: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC25: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC26: [Hebrew]
+ * @HB_UNICODE_COMBINING_CLASS_CCC27: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC28: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC29: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC30: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC31: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC32: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC33: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC34: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC35: [Arabic]
+ * @HB_UNICODE_COMBINING_CLASS_CCC36: [Syriac]
+ * @HB_UNICODE_COMBINING_CLASS_CCC84: [Telugu]
+ * @HB_UNICODE_COMBINING_CLASS_CCC91: [Telugu]
+ * @HB_UNICODE_COMBINING_CLASS_CCC103: [Thai]
+ * @HB_UNICODE_COMBINING_CLASS_CCC107: [Thai]
+ * @HB_UNICODE_COMBINING_CLASS_CCC118: [Lao]
+ * @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_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
+ * @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: Marks attached at the top right
+ * @HB_UNICODE_COMBINING_CLASS_BELOW_LEFT: Distinct marks at the bottom left
+ * @HB_UNICODE_COMBINING_CLASS_BELOW: Distinct marks directly below
+ * @HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: Distinct marks at the bottom right
+ * @HB_UNICODE_COMBINING_CLASS_LEFT: Distinct marks to the left
+ * @HB_UNICODE_COMBINING_CLASS_RIGHT: Distinct marks to the right
+ * @HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT: Distinct marks at the top left
+ * @HB_UNICODE_COMBINING_CLASS_ABOVE: Distinct marks directly above
+ * @HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: Distinct marks at the top right
+ * @HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: Distinct marks subtending two bases
+ * @HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: Distinct marks extending above two bases
+ * @HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT: Greek iota subscript only
+ * @HB_UNICODE_COMBINING_CLASS_INVALID: Invalid combining class
+ *
+ * Data type for the Canonical_Combining_Class (ccc) property
+ * from the Unicode Character Database.
+ *
+ * <note>Note: newer versions of Unicode may add new values.
+ * Client programs should be ready to handle any value in the 0..254 range
+ * being returned from hb_unicode_combining_class().</note>
+ *
+ **/
 typedef enum
 {
   HB_UNICODE_COMBINING_CLASS_NOT_REORDERED	= 0,
@@ -176,6 +274,18 @@
  * hb_unicode_funcs_t
  */
 
+/**
+ * hb_unicode_funcs_t:
+ *
+ * Data type containing a set of virtual methods used for
+ * accessing various Unicode character properties.
+ *
+ * HarfBuzz provides a default function for each of the
+ * methods in #hb_unicode_funcs_t. 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.
+ **/
 typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
 
 
@@ -227,40 +337,141 @@
 
 /* typedefs */
 
+/**
+ * hb_unicode_combining_class_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should retrieve the Canonical Combining Class (ccc)
+ * property for a specified Unicode code point. 
+ *
+ * Return value: The #hb_unicode_combining_class_t of @unicode
+ * 
+ **/
 typedef hb_unicode_combining_class_t	(*hb_unicode_combining_class_func_t)	(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      unicode,
 										 void               *user_data);
+
+/**
+ * hb_unicode_general_category_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should retrieve the General Category property for
+ * a specified Unicode code point.
+ * 
+ * Return value: The #hb_unicode_general_category_t of @unicode
+ *
+ **/
 typedef hb_unicode_general_category_t	(*hb_unicode_general_category_func_t)	(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      unicode,
 										 void               *user_data);
+
+/**
+ * hb_unicode_mirroring_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should retrieve the Bi-Directional Mirroring Glyph
+ * code point for a specified Unicode code point.
+ *
+ * <note>Note: If a code point does not have a specified
+ * Bi-Directional Mirroring Glyph defined, the method should
+ * return the original code point.</note>
+ * 
+ * Return value: The #hb_codepoint_t of the Mirroring Glyph for @unicode
+ *
+ **/
 typedef hb_codepoint_t			(*hb_unicode_mirroring_func_t)		(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      unicode,
 										 void               *user_data);
+
+/**
+ * hb_unicode_script_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should retrieve the Script property for a 
+ * specified Unicode code point.
+ *
+ * Return value: The #hb_script_t of @unicode
+ * 
+ **/
 typedef hb_script_t			(*hb_unicode_script_func_t)		(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      unicode,
 										 void               *user_data);
 
+/**
+ * hb_unicode_compose_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @a: The first code point to compose
+ * @b: The second code point to compose
+ * @ab: (out): The composed code point
+ * @user_data: user data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should compose a sequence of two input Unicode code
+ * points by canonical equivalence, returning the composed code
+ * point in a #hb_codepoint_t output parameter (if successful).
+ * The method must return an #hb_bool_t indicating the success
+ * of the composition.
+ * 
+ * Return value: %true is @a,@b composed, %false otherwise
+ *
+ **/
 typedef hb_bool_t			(*hb_unicode_compose_func_t)		(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      a,
 										 hb_codepoint_t      b,
 										 hb_codepoint_t     *ab,
 										 void               *user_data);
+
+/**
+ * hb_unicode_decompose_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @ab: The code point to decompose
+ * @a: (out): The first decomposed code point
+ * @b: (out): The second decomposed code point
+ * @user_data: user data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
+ *
+ * This method should decompose an input Unicode code point,
+ * returning the two decomposed code points in #hb_codepoint_t
+ * 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
+ *
+ **/
 typedef hb_bool_t			(*hb_unicode_decompose_func_t)		(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      ab,
 										 hb_codepoint_t     *a,
 										 hb_codepoint_t     *b,
 										 void               *user_data);
 
-/* setters */
+/* func setters */
 
 /**
  * hb_unicode_funcs_set_combining_class_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_combining_class_func_t.
  *
  * Since: 0.9.2
  **/
@@ -271,12 +482,12 @@
 
 /**
  * hb_unicode_funcs_set_general_category_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_general_category_func_t.
  *
  * Since: 0.9.2
  **/
@@ -287,12 +498,12 @@
 
 /**
  * hb_unicode_funcs_set_mirroring_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_mirroring_func_t.
  *
  * Since: 0.9.2
  **/
@@ -303,12 +514,12 @@
 
 /**
  * hb_unicode_funcs_set_script_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_script_func_t.
  *
  * Since: 0.9.2
  **/
@@ -319,12 +530,12 @@
 
 /**
  * hb_unicode_funcs_set_compose_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_compose_func_t.
  *
  * Since: 0.9.2
  **/
@@ -335,12 +546,12 @@
 
 /**
  * hb_unicode_funcs_set_decompose_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions 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_unicode_decompose_func_t.
  *
  * Since: 0.9.2
  **/
@@ -353,6 +564,13 @@
 
 /**
  * hb_unicode_combining_class:
+ * @ufuncs: The Unicode-functions structure
+ * @unicode: The code point to query
+ *
+ * Retrieves the Canonical Combining Class (ccc) property
+ * of code point @unicode.
+ *
+ * Return value: The #hb_unicode_combining_class_t of @unicode
  *
  * Since: 0.9.2
  **/
@@ -362,6 +580,13 @@
 
 /**
  * hb_unicode_general_category:
+ * @ufuncs: The Unicode-functions structure
+ * @unicode: The code point to query
+ *
+ * Retrieves the General Category (gc) property
+ * of code point @unicode.
+ *
+ * Return value: The #hb_unicode_general_category_t of @unicode
  *
  * Since: 0.9.2
  **/
@@ -371,6 +596,13 @@
 
 /**
  * hb_unicode_mirroring:
+ * @ufuncs: The Unicode-functions structure
+ * @unicode: The code point to query
+ *
+ * Retrieves the Bi-directional Mirroring Glyph code
+ * point defined for code point @unicode.
+ *
+ * Return value: The #hb_codepoint_t of the Mirroring Glyph for @unicode
  *
  * Since: 0.9.2
  **/
@@ -380,6 +612,13 @@
 
 /**
  * hb_unicode_script:
+ * @ufuncs: The Unicode-functions structure
+ * @unicode: The code point to query
+ *
+ * Retrieves the #hb_script_t script to which code
+ * point @unicode belongs.
+ *
+ * Return value: The #hb_script_t of @unicode
  *
  * Since: 0.9.2
  **/
diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh
index 0c355f1..4c28bb0 100644
--- a/src/hb-unicode.hh
+++ b/src/hb-unicode.hh
@@ -121,7 +121,7 @@
   static hb_bool_t
   is_variation_selector (hb_codepoint_t unicode)
   {
-    /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
+    /* U+180B..180D, U+180F MONGOLIAN FREE VARIATION SELECTORs are handled in the
      * Arabic shaper.  No need to match them here. */
     return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
 						   0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
@@ -136,7 +136,7 @@
    * As such, we make exceptions for those four.
    * Also ignoring U+1BCA0..1BCA3. https://github.com/harfbuzz/harfbuzz/issues/503
    *
-   * Unicode 7.0:
+   * Unicode 14.0:
    * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
    * 00AD          # Cf       SOFT HYPHEN
    * 034F          # Mn       COMBINING GRAPHEME JOINER
@@ -145,6 +145,7 @@
    * 17B4..17B5    # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
    * 180B..180D    # Mn   [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
    * 180E          # Cf       MONGOLIAN VOWEL SEPARATOR
+   * 180F          # Mn       MONGOLIAN FREE VARIATION SELECTOR FOUR
    * 200B..200F    # Cf   [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
    * 202A..202E    # Cf   [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
    * 2060..2064    # Cf   [5] WORD JOINER..INVISIBLE PLUS
@@ -289,8 +290,8 @@
 #define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */
 #define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */
 #define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */
-#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */
-#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */
+#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats & qamats qatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam & holam haser for vav*/
 #define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */
 #define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */
 #define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */
@@ -324,10 +325,10 @@
  * Modify Telugu length marks (ccc=84, ccc=91).
  * These are the only matras in the main Indic scripts range that have
  * a non-zero ccc.  That makes them reorder with the Halant (ccc=9).
- * Assign 5 and 6, which are otherwise unassigned.
+ * Assign 4 and 5, which are otherwise unassigned.
  */
-#define HB_MODIFIED_COMBINING_CLASS_CCC84 5 /* length mark */
-#define HB_MODIFIED_COMBINING_CLASS_CCC91 6 /* ai length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 4 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 5 /* ai length mark */
 
 /* Thai
  *
@@ -359,6 +360,13 @@
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
+#define HB_UNICODE_GENERAL_CATEGORY_IS_LETTER(gen_cat) \
+	(FLAG_UNSAFE (gen_cat) & \
+	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER)))
 
 /*
  * Ranges, used for bsearch tables.
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index e93cf7f..3dc4c09 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -44,6 +44,7 @@
 
 #include "hb-uniscribe.h"
 
+#include "hb-ms-feature-ranges.hh"
 #include "hb-open-file.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-layout.h"
@@ -55,7 +56,7 @@
  * @short_description: Windows integration
  * @include: hb-uniscribe.h
  *
- * Functions for using HarfBuzz with the Windows fonts.
+ * Functions for using HarfBuzz with Windows fonts.
  **/
 
 typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
@@ -238,30 +239,26 @@
   }
 };
 
-#if HB_USE_ATEXIT
-static void free_static_uniscribe_shaper_funcs ();
-#endif
+static inline void free_static_uniscribe_shaper_funcs ();
 
 static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t,
 									 hb_uniscribe_shaper_funcs_lazy_loader_t>
 {
   static hb_uniscribe_shaper_funcs_t *create ()
   {
-    hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
+    hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
     if (unlikely (!funcs))
       return nullptr;
 
     funcs->init ();
 
-#if HB_USE_ATEXIT
-    atexit (free_static_uniscribe_shaper_funcs);
-#endif
+    hb_atexit (free_static_uniscribe_shaper_funcs);
 
     return funcs;
   }
   static void destroy (hb_uniscribe_shaper_funcs_t *p)
   {
-    free ((void *) p);
+    hb_free ((void *) p);
   }
   static hb_uniscribe_shaper_funcs_t *get_null ()
   {
@@ -269,13 +266,11 @@
   }
 } static_uniscribe_shaper_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_uniscribe_shaper_funcs ()
 {
   static_uniscribe_shaper_funcs.free_instance ();
 }
-#endif
 
 static hb_uniscribe_shaper_funcs_t *
 hb_uniscribe_shaper_get_funcs ()
@@ -284,44 +279,6 @@
 }
 
 
-struct active_feature_t {
-  OPENTYPE_FEATURE_RECORD rec;
-  unsigned int order;
-
-  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
-    const active_feature_t *a = (const active_feature_t *) pa;
-    const active_feature_t *b = (const active_feature_t *) pb;
-    return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
-	   a->order < b->order ? -1 : a->order > b->order ? 1 :
-	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
-	   0;
-  }
-  bool operator== (const active_feature_t *f)
-  { return cmp (this, f) == 0; }
-};
-
-struct feature_event_t {
-  unsigned int index;
-  bool start;
-  active_feature_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 :
-	   active_feature_t::cmp (&a->feature, &b->feature);
-  }
-};
-
-struct range_record_t {
-  TEXTRANGE_PROPERTIES props;
-  unsigned int index_first; /* == start */
-  unsigned int index_last;  /* == end - 1 */
-};
-
-
 /*
  * shaper face data
  */
@@ -391,7 +348,7 @@
   unsigned int name_table_offset = (length + 3) & ~3;
 
   new_length = name_table_offset + padded_name_table_length;
-  void *new_sfnt_data = calloc (1, new_length);
+  void *new_sfnt_data = hb_calloc (1, new_length);
   if (!new_sfnt_data)
   {
     hb_blob_destroy (blob);
@@ -441,7 +398,7 @@
     }
     else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
     {
-      free (new_sfnt_data);
+      hb_free (new_sfnt_data);
       hb_blob_destroy (blob);
       return nullptr;
     }
@@ -453,20 +410,20 @@
 
   hb_blob_destroy (blob);
   return hb_blob_create ((const char *) new_sfnt_data, new_length,
-			 HB_MEMORY_MODE_WRITABLE, nullptr, free);
+			 HB_MEMORY_MODE_WRITABLE, new_sfnt_data, hb_free);
 }
 
 hb_uniscribe_face_data_t *
 _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
 {
-  hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
+  hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_calloc (1, sizeof (hb_uniscribe_face_data_t));
   if (unlikely (!data))
     return nullptr;
 
   data->funcs = hb_uniscribe_shaper_get_funcs ();
   if (unlikely (!data->funcs))
   {
-    free (data);
+    hb_free (data);
     return nullptr;
   }
 
@@ -477,7 +434,7 @@
   blob = _hb_rename_font (blob, data->face_name);
   if (unlikely (!blob))
   {
-    free (data);
+    hb_free (data);
     return nullptr;
   }
 
@@ -488,7 +445,7 @@
   if (unlikely (!data->fh))
   {
     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
-    free (data);
+    hb_free (data);
     return nullptr;
   }
 
@@ -499,7 +456,7 @@
 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data)
 {
   RemoveFontMemResourceEx (data->fh);
-  free (data);
+  hb_free (data);
 }
 
 
@@ -533,7 +490,7 @@
 hb_uniscribe_font_data_t *
 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
+  hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_calloc (1, sizeof (hb_uniscribe_font_data_t));
   if (unlikely (!data))
     return nullptr;
 
@@ -580,9 +537,19 @@
     DeleteObject (data->hfont);
   if (data->script_cache)
     ScriptFreeCache (&data->script_cache);
-  free (data);
+  hb_free (data);
 }
 
+/**
+ * hb_uniscribe_font_get_logfontw:
+ * @font: The #hb_font_t to work upon
+ *
+ * Fetches the LOGFONTW structure that corresponds to the
+ * specified #hb_font_t font.
+ *
+ * Return value: a pointer to the LOGFONTW retrieved
+ *
+ **/
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
@@ -590,6 +557,16 @@
   return data ? &data->log_font : nullptr;
 }
 
+/**
+ * hb_uniscribe_font_get_hfont:
+ * @font: The #hb_font_t to work upon
+ *
+ * Fetches the HFONT handle that corresponds to the
+ * specified #hb_font_t font.
+ *
+ * Return value: the HFONT retreieved
+ *
+ **/
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
@@ -615,109 +592,6 @@
   const hb_uniscribe_font_data_t *font_data = font->data.uniscribe;
   hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
 
-  /*
-   * Set up features.
-   */
-  hb_vector_t<OPENTYPE_FEATURE_RECORD> feature_records;
-  hb_vector_t<range_record_t> range_records;
-  if (num_features)
-  {
-    /* Sort features by start/end events. */
-    hb_vector_t<feature_event_t> feature_events;
-    for (unsigned int i = 0; i < num_features; i++)
-    {
-      active_feature_t feature;
-      feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
-      feature.rec.lParameter = features[i].value;
-      feature.order = i;
-
-      feature_event_t *event;
-
-      event = feature_events.push ();
-      event->index = features[i].start;
-      event->start = true;
-      event->feature = feature;
-
-      event = feature_events.push ();
-      event->index = features[i].end;
-      event->start = false;
-      event->feature = feature;
-    }
-    feature_events.qsort ();
-    /* Add a strategic final event. */
-    {
-      active_feature_t feature;
-      feature.rec.tagFeature = 0;
-      feature.rec.lParameter = 0;
-      feature.order = num_features + 1;
-
-      feature_event_t *event = feature_events.push ();
-      event->index = 0; /* This value does magic. */
-      event->start = false;
-      event->feature = feature;
-    }
-
-    /* Scan events and save features for each range. */
-    hb_vector_t<active_feature_t> active_features;
-    unsigned int last_index = 0;
-    for (unsigned int i = 0; i < feature_events.length; i++)
-    {
-      feature_event_t *event = &feature_events[i];
-
-      if (event->index != last_index)
-      {
-	/* Save a snapshot of active features and the range. */
-	range_record_t *range = range_records.push ();
-
-	unsigned int offset = feature_records.length;
-
-	active_features.qsort ();
-	for (unsigned int j = 0; j < active_features.length; j++)
-	{
-	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.length - 1].tagFeature)
-	  {
-	    feature_records.push (active_features[j].rec);
-	  }
-	  else
-	  {
-	    /* Overrides value for existing feature. */
-	    feature_records[feature_records.length - 1].lParameter = active_features[j].rec.lParameter;
-	  }
-	}
-
-	/* Will convert to pointer after all is ready, since feature_records.array
-	 * may move as we grow it. */
-	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
-	range->props.cotfRecords = feature_records.length - offset;
-	range->index_first = last_index;
-	range->index_last  = event->index - 1;
-
-	last_index = event->index;
-      }
-
-      if (event->start)
-      {
-	active_features.push (event->feature);
-      }
-      else
-      {
-	active_feature_t *feature = active_features.find (&event->feature);
-	if (feature)
-	  active_features.remove (feature - active_features.arrayZ);
-      }
-    }
-
-    if (!range_records.length) /* No active feature found. */
-      num_features = 0;
-
-    /* Fixup the pointers. */
-    for (unsigned int i = 0; i < range_records.length; i++)
-    {
-      range_record_t *range = &range_records[i];
-      range->props.potfRecords = (OPENTYPE_FEATURE_RECORD *) feature_records + reinterpret_cast<uintptr_t> (range->props.potfRecords);
-    }
-  }
-
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
@@ -836,8 +710,23 @@
 				       nullptr, nullptr,
 				       &lang_count, &lang_tag);
   OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE);
-  hb_vector_t<TEXTRANGE_PROPERTIES*> range_properties;
-  hb_vector_t<int> range_char_counts;
+
+  /*
+   * Set up features.
+   */
+  static_assert ((sizeof (TEXTRANGE_PROPERTIES) == sizeof (hb_ms_features_t)), "");
+  static_assert ((sizeof (OPENTYPE_FEATURE_RECORD) == sizeof (hb_ms_feature_t)), "");
+  hb_vector_t<hb_ms_feature_t> feature_records;
+  hb_vector_t<hb_ms_range_record_t> range_records;
+  bool has_features = false;
+  if (num_features)
+    has_features = hb_ms_setup_features (features,
+					 num_features,
+					 feature_records,
+					 range_records);
+
+  hb_vector_t<hb_ms_features_t*> range_properties;
+  hb_vector_t<uint32_t> range_char_counts;
 
   unsigned int glyphs_offset = 0;
   unsigned int glyphs_len;
@@ -847,42 +736,14 @@
     unsigned int chars_offset = items[i].iCharPos;
     unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
 
-    if (num_features)
-    {
-      range_properties.shrink (0);
-      range_char_counts.shrink (0);
-
-      range_record_t *last_range = &range_records[0];
-
-      for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
-      {
-	range_record_t *range = last_range;
-	while (log_clusters[k] < range->index_first)
-	  range--;
-	while (log_clusters[k] > range->index_last)
-	  range++;
-	if (!range_properties.length ||
-	    &range->props != range_properties[range_properties.length - 1])
-	{
-	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
-	  int *c = range_char_counts.push ();
-	  if (unlikely (!props || !c))
-	  {
-	    range_properties.shrink (0);
-	    range_char_counts.shrink (0);
-	    break;
-	  }
-	  *props = &range->props;
-	  *c = 1;
-	}
-	else
-	{
-	  range_char_counts[range_char_counts.length - 1]++;
-	}
-
-	last_range = range;
-      }
-    }
+    if (has_features)
+      hb_ms_make_feature_ranges (feature_records,
+				 range_records,
+				 item_chars_len,
+				 chars_offset,
+				 log_clusters,
+				 range_properties,
+				 range_char_counts);
 
     /* Asking for glyphs in logical order circumvents at least
      * one bug in Uniscribe. */
@@ -894,8 +755,8 @@
 				     &items[i].a,
 				     script_tags[i],
 				     language_tag,
-				     range_char_counts.arrayZ,
-				     range_properties.arrayZ,
+				     (int *) range_char_counts.arrayZ,
+				     (TEXTRANGE_PROPERTIES**) range_properties.arrayZ,
 				     range_properties.length,
 				     pchars + chars_offset,
 				     item_chars_len,
@@ -935,8 +796,8 @@
 				     &items[i].a,
 				     script_tags[i],
 				     language_tag,
-				     range_char_counts.arrayZ,
-				     range_properties.arrayZ,
+				     (int *) range_char_counts.arrayZ,
+				     (TEXTRANGE_PROPERTIES**) range_properties.arrayZ,
 				     range_properties.length,
 				     pchars + chars_offset,
 				     log_clusters + chars_offset,
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 7b150fb..b0a1e5e 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -38,10 +38,23 @@
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
 
-  hb_vector_t ()  { init (); }
-  hb_vector_t (const hb_vector_t &o)
+  hb_vector_t () = default;
+  hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t ()
   {
-    init ();
+    alloc (lst.size ());
+    for (auto&& item : lst)
+      push (item);
+  }
+  template <typename Iterable,
+	    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);
+  }
+  hb_vector_t (const hb_vector_t &o) : hb_vector_t ()
+  {
     alloc (o.length);
     hb_copy (o, *this);
   }
@@ -55,11 +68,11 @@
   ~hb_vector_t () { fini (); }
 
   private:
-  int allocated; /* == -1 means allocation failed. */
+  int allocated = 0; /* == -1 means allocation failed. */
   public:
-  unsigned int length;
+  unsigned int length = 0;
   public:
-  Type *arrayZ;
+  Type *arrayZ = nullptr;
 
   void init ()
   {
@@ -69,7 +82,7 @@
 
   void fini ()
   {
-    free (arrayZ);
+    hb_free (arrayZ);
     init ();
   }
   void fini_deep ()
@@ -80,7 +93,19 @@
     fini ();
   }
 
-  void reset () { resize (0); }
+  void reset ()
+  {
+    if (unlikely (in_error ()))
+      allocated = length; // Big hack!
+    resize (0);
+  }
+
+  friend void swap (hb_vector_t& a, hb_vector_t& b)
+  {
+    hb_swap (a.allocated, b.allocated);
+    hb_swap (a.length, b.length);
+    hb_swap (a.arrayZ, b.arrayZ);
+  }
 
   hb_vector_t& operator = (const hb_vector_t &o)
   {
@@ -91,11 +116,7 @@
   }
   hb_vector_t& operator = (hb_vector_t &&o)
   {
-    fini ();
-    allocated = o.allocated;
-    length = o.length;
-    arrayZ = o.arrayZ;
-    o.init ();
+    hb_swap (*this, o);
     return *this;
   }
 
@@ -117,7 +138,7 @@
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= length))
-      return Null(Type);
+      return Null (Type);
     return arrayZ[i];
   }
 
@@ -129,7 +150,7 @@
 
   /* Sink interface. */
   template <typename T>
-  hb_vector_t& operator << (T&& v) { push (hb_forward<T> (v)); return *this; }
+  hb_vector_t& operator << (T&& v) { push (std::forward<T> (v)); return *this; }
 
   hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, length); }
   hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); }
@@ -165,14 +186,19 @@
   Type *push ()
   {
     if (unlikely (!resize (length + 1)))
-      return &Crap(Type);
+      return &Crap (Type);
     return &arrayZ[length - 1];
   }
   template <typename T>
   Type *push (T&& v)
   {
     Type *p = push ();
-    *p = hb_forward<T> (v);
+    if (p == &Crap (Type))
+      // 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;
   }
 
@@ -181,7 +207,7 @@
   /* Allocate for size but don't adjust length. */
   bool alloc (unsigned int size)
   {
-    if (unlikely (allocated < 0))
+    if (unlikely (in_error ()))
       return false;
 
     if (likely (size <= (unsigned) allocated))
@@ -195,11 +221,11 @@
 
     Type *new_array = nullptr;
     bool overflows =
-      (int) new_allocated < 0 ||
+      (int) in_error () ||
       (new_allocated < (unsigned) allocated) ||
       hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
     if (likely (!overflows))
-      new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
+      new_array = (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
 
     if (unlikely (!new_array))
     {
@@ -228,8 +254,8 @@
 
   Type pop ()
   {
-    if (!length) return Null(Type);
-    return hb_move (arrayZ[--length]); /* Does this move actually work? */
+    if (!length) return Null (Type);
+    return std::move (arrayZ[--length]); /* Does this move actually work? */
   }
 
   void remove (unsigned int i)
@@ -277,11 +303,27 @@
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   { return as_array ().lsearch (x, not_found); }
+  template <typename T>
+  bool lfind (const T &x, unsigned *pos = nullptr) const
+  { return as_array ().lfind (x, pos); }
 };
 
 template <typename Type>
 struct hb_sorted_vector_t : hb_vector_t<Type>
 {
+  hb_sorted_vector_t () = default;
+  ~hb_sorted_vector_t () = default;
+  hb_sorted_vector_t (hb_sorted_vector_t& o) = default;
+  hb_sorted_vector_t (hb_sorted_vector_t &&o) = default;
+  hb_sorted_vector_t (std::initializer_list<Type> lst) : hb_vector_t<Type> (lst) {}
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  hb_sorted_vector_t (const Iterable &o) : hb_vector_t<Type> (o) {}
+  hb_sorted_vector_t& operator = (const hb_sorted_vector_t &o) = default;
+  hb_sorted_vector_t& operator = (hb_sorted_vector_t &&o) = default;
+  friend void swap (hb_sorted_vector_t& a, hb_sorted_vector_t& b)
+  { hb_swap ((hb_vector_t<Type>&) (a), (hb_vector_t<Type>&) (b)); }
+
   hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->length); }
   hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); }
 
@@ -302,7 +344,7 @@
   { return as_array ().bsearch (x, not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   { return as_array ().bfind (x, i, not_found, to_store); }
 };
diff --git a/src/hb-version.h b/src/hb-version.h
index a564e9f..1a4f0bf 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,12 +36,41 @@
 HB_BEGIN_DECLS
 
 
-#define HB_VERSION_MAJOR 2
-#define HB_VERSION_MINOR 6
-#define HB_VERSION_MICRO 4
+/**
+ * HB_VERSION_MAJOR:
+ *
+ * The major component of the library version available at compile-time.
+ */
+#define HB_VERSION_MAJOR 3
+/**
+ * HB_VERSION_MINOR:
+ *
+ * The minor component of the library version available at compile-time.
+ */
+#define HB_VERSION_MINOR 1
+/**
+ * HB_VERSION_MICRO:
+ *
+ * The micro component of the library version available at compile-time.
+ */
+#define HB_VERSION_MICRO 1
 
-#define HB_VERSION_STRING "2.6.4"
+/**
+ * HB_VERSION_STRING:
+ *
+ * A string literal containing the library version available at compile-time.
+ */
+#define HB_VERSION_STRING "3.1.1"
 
+/**
+ * HB_VERSION_ATLEAST:
+ * @major: the major component of the version number
+ * @minor: the minor component of the version number
+ * @micro: the micro component of the version number
+ *
+ * Tests the library version at compile-time against a minimum value,
+ * as three integer components.
+ */
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
diff --git a/src/hb-version.h.in b/src/hb-version.h.in
index 0ffd889..abcb73f 100644
--- a/src/hb-version.h.in
+++ b/src/hb-version.h.in
@@ -24,7 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
 #error "Include <hb.h> instead."
 #endif
 
@@ -36,12 +36,41 @@
 HB_BEGIN_DECLS
 
 
+/**
+ * HB_VERSION_MAJOR:
+ *
+ * The major component of the library version available at compile-time.
+ */
 #define HB_VERSION_MAJOR @HB_VERSION_MAJOR@
+/**
+ * HB_VERSION_MINOR:
+ *
+ * The minor component of the library version available at compile-time.
+ */
 #define HB_VERSION_MINOR @HB_VERSION_MINOR@
+/**
+ * HB_VERSION_MICRO:
+ *
+ * The micro component of the library version available at compile-time.
+ */
 #define HB_VERSION_MICRO @HB_VERSION_MICRO@
 
+/**
+ * HB_VERSION_STRING:
+ *
+ * A string literal containing the library version available at compile-time.
+ */
 #define HB_VERSION_STRING "@HB_VERSION@"
 
+/**
+ * HB_VERSION_ATLEAST:
+ * @major: the major component of the version number
+ * @minor: the minor component of the version number
+ * @micro: the micro component of the version number
+ *
+ * Tests the library version at compile-time against a minimum value,
+ * as three integer components.
+ */
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
diff --git a/src/hb.h b/src/hb.h
index c5e7072..360686c 100644
--- a/src/hb.h
+++ b/src/hb.h
@@ -32,12 +32,14 @@
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-deprecated.h"
+#include "hb-draw.h"
 #include "hb-face.h"
 #include "hb-font.h"
 #include "hb-map.h"
 #include "hb-set.h"
 #include "hb-shape.h"
 #include "hb-shape-plan.h"
+#include "hb-style.h"
 #include "hb-unicode.h"
 #include "hb-version.h"
 
diff --git a/src/hb.hh b/src/hb.hh
index fcbd330..1f14267 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -62,7 +62,7 @@
 
 /* Error.  Should never happen. */
 #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
-#pragma GCC diagnostic error   "-Wc++11-narrowing"
+#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   "-Wdelete-non-virtual-dtor"
@@ -75,6 +75,7 @@
 #pragma GCC diagnostic error   "-Wmissing-braces"
 #pragma GCC diagnostic error   "-Wmissing-declarations"
 #pragma GCC diagnostic error   "-Wmissing-prototypes"
+#pragma GCC diagnostic error   "-Wnarrowing"
 #pragma GCC diagnostic error   "-Wnested-externs"
 #pragma GCC diagnostic error   "-Wold-style-definition"
 #pragma GCC diagnostic error   "-Wpointer-arith"
@@ -107,6 +108,7 @@
 #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
 #pragma GCC diagnostic warning "-Wmissing-format-attribute"
 #pragma GCC diagnostic warning "-Wundef"
+#pragma GCC diagnostic warning "-Wunused-but-set-variable"
 #endif
 
 /* Ignored currently, but should be fixed at some point. */
@@ -116,6 +118,9 @@
 #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
+#endif
 #endif
 
 /* Ignored intentionally. */
@@ -125,6 +130,7 @@
 #pragma GCC diagnostic ignored "-Wformat-zero-length"
 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
+#pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #pragma GCC diagnostic ignored "-Wtype-limits"
 #pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it
@@ -174,44 +180,62 @@
 #include "hb-aat.h"
 #define HB_AAT_H_IN
 
-#include <limits.h>
-#include <math.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdarg.h>
+#include <cassert>
+#include <cfloat>
+#include <climits>
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+#include <cmath>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 
 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
 #ifdef __MINGW32_VERSION
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
 #endif
-#include <windows.h>
 #else
 #include <intrin.h>
 #endif
 #endif
 
+#ifdef _WIN32
+#include <windows.h>
+#include <winapifamily.h>
+#endif
+
 #define HB_PASTE1(a,b) a##b
 #define HB_PASTE(a,b) HB_PASTE1(a,b)
 
 
 /* Compile-time custom allocator support. */
 
-#if defined(hb_malloc_impl) \
- && defined(hb_calloc_impl) \
- && defined(hb_realloc_impl) \
- && defined(hb_free_impl)
+#if !defined(HB_CUSTOM_MALLOC) \
+  && defined(hb_malloc_impl) \
+  && defined(hb_calloc_impl) \
+  && defined(hb_realloc_impl) \
+  && defined(hb_free_impl)
+#define HB_CUSTOM_MALLOC
+#endif
+
+#ifdef HB_CUSTOM_MALLOC
 extern "C" void* hb_malloc_impl(size_t size);
 extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
 extern "C" void* hb_realloc_impl(void *ptr, size_t size);
 extern "C" void  hb_free_impl(void *ptr);
-#define malloc hb_malloc_impl
-#define calloc hb_calloc_impl
-#define realloc hb_realloc_impl
-#define free hb_free_impl
+#define hb_malloc hb_malloc_impl
+#define hb_calloc hb_calloc_impl
+#define hb_realloc hb_realloc_impl
+#define hb_free hb_free_impl
+#else
+#define hb_malloc malloc
+#define hb_calloc calloc
+#define hb_realloc realloc
+#define hb_free free
 #endif
 
 
@@ -233,12 +257,8 @@
 #endif
 
 #if defined(__GNUC__) && (__GNUC__ >= 3)
-#define HB_PURE_FUNC	__attribute__((pure))
-#define HB_CONST_FUNC	__attribute__((const))
 #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
 #else
-#define HB_PURE_FUNC
-#define HB_CONST_FUNC
 #define HB_PRINTF_FUNC(format_idx, arg_idx)
 #endif
 #if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
@@ -317,6 +337,17 @@
 #  define HB_FALLTHROUGH /* FALLTHROUGH */
 #endif
 
+/* A tag to enforce use of return value for a function */
+#if __cplusplus >= 201703L
+#  define HB_NODISCARD [[nodiscard]]
+#elif defined(__GNUC__) || defined(__clang__)
+#  define HB_NODISCARD __attribute__((warn_unused_result))
+#elif defined(_MSC_VER)
+#  define HB_NODISCARD _Check_return_
+#else
+#  define HB_NODISCARD
+#endif
+
 /* https://github.com/harfbuzz/harfbuzz/issues/1852 */
 #if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__)))
 /* Disable certain sanitizer errors. */
@@ -335,7 +366,7 @@
 #    undef _WIN32_WINNT
 #  endif
 #  ifndef _WIN32_WINNT
-#    if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#    if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #      define _WIN32_WINNT 0x0600
 #    endif
 #  endif
@@ -356,7 +387,7 @@
 #      define HB_NO_SETLOCALE
 #      define HB_NO_ERRNO
 #    endif
-#  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#  elif !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #    ifndef HB_NO_GETENV
 #      define HB_NO_GETENV
 #    endif
@@ -371,13 +402,16 @@
 #endif
 
 #ifndef HB_NO_ERRNO
-#  include <errno.h>
+#  include <cerrno>
 #else
 static int HB_UNUSED _hb_errno = 0;
 #  undef errno
 #  define errno _hb_errno
 #endif
 
+#define HB_STMT_START do
+#define HB_STMT_END   while (0)
+
 #if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT)
 /* atexit() is only safe to be called from shared libraries on certain
  * platforms.  Whitelist.
@@ -406,197 +440,30 @@
  */
 #    define HB_USE_ATEXIT 1
 #  endif
-#endif
+#endif /* defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT) */
 #ifdef HB_NO_ATEXIT
 #  undef HB_USE_ATEXIT
 #endif
 #ifndef HB_USE_ATEXIT
 #  define HB_USE_ATEXIT 0
 #endif
-
-#define HB_STMT_START do
-#define HB_STMT_END   while (0)
-
-/* Static-assert as expression. */
-template <unsigned int cond> class hb_assert_constant_t;
-template <> class hb_assert_constant_t<1> {};
-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
+#if !HB_USE_ATEXIT
+#  define hb_atexit(_) HB_STMT_START { if (0) (_) (); } HB_STMT_END
+#else /* HB_USE_ATEXIT */
+#  ifdef HAVE_ATEXIT
+#    define hb_atexit atexit
+#  else
+     template <void (*function) (void)> struct hb_atexit_t { ~hb_atexit_t () { function (); } };
+#    define hb_atexit(f) static hb_atexit_t<f> _hb_atexit_##__LINE__;
+#  endif
+#endif
 
 /* Lets assert int types.  Saves trouble down the road. */
-static_assert ((sizeof (int8_t) == 1), "");
-static_assert ((sizeof (uint8_t) == 1), "");
-static_assert ((sizeof (int16_t) == 2), "");
-static_assert ((sizeof (uint16_t) == 2), "");
-static_assert ((sizeof (int32_t) == 4), "");
-static_assert ((sizeof (uint32_t) == 4), "");
-static_assert ((sizeof (int64_t) == 8), "");
-static_assert ((sizeof (uint64_t) == 8), "");
 static_assert ((sizeof (hb_codepoint_t) == 4), "");
 static_assert ((sizeof (hb_position_t) == 4), "");
 static_assert ((sizeof (hb_mask_t) == 4), "");
 static_assert ((sizeof (hb_var_int_t) == 4), "");
 
-#define HB_DELETE_COPY_ASSIGN(TypeName) \
-  TypeName(const TypeName&) = delete; \
-  void operator=(const TypeName&) = delete
-#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
-  TypeName() = delete; \
-  TypeName(const TypeName&) = delete; \
-  void operator=(const TypeName&) = delete
-
-
-/* Flags */
-
-/* Enable bitwise ops on enums marked as flags_t */
-/* To my surprise, looks like the function resolver is happy to silently cast
- * one enum to another...  So this doesn't provide the type-checking that I
- * originally had in mind... :(.
- *
- * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
- */
-#ifdef _MSC_VER
-# pragma warning(disable:4200)
-# pragma warning(disable:4800)
-#endif
-#define HB_MARK_AS_FLAG_T(T) \
-	extern "C++" { \
-	  static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
-	  static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
-	  static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
-	  static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
-	  static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
-	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
-	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
-	} \
-	static_assert (true, "")
-
-/* Useful for set-operations on small enums.
- * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
- */
-#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
-#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
-#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
-#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
-#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
-
-
-/* Size signifying variable-sized array */
-#ifndef HB_VAR_ARRAY
-#define HB_VAR_ARRAY 1
-#endif
-
-static inline double
-_hb_roundf (float x)
-{
-  return x >= 0 ? floor ((double) x + .5) : ceil ((double) x - .5);
-}
-#ifndef HAVE_ROUNDF
-#define roundf(x) _hb_roundf(x)
-#endif
-
-/* Endian swap, used in Windows related backends */
-static inline uint16_t hb_uint16_swap (const uint16_t v)
-{ return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
-
-/*
- * Big-endian integers.  Here because fundamental.
- */
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
-  public:
-  BEInt<Type, 1>& operator = (Type V)
-  {
-    v = V;
-    return *this;
-  }
-  operator Type () const { return v; }
-  private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
-  public:
-  BEInt<Type, 2>& operator = (Type V)
-  {
-    v[0] = (V >>  8) & 0xFF;
-    v[1] = (V      ) & 0xFF;
-    return *this;
-  }
-  operator Type () const
-  {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
-    defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
-    /* Spoon-feed the compiler a big-endian integer with alignment 1.
-     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
-    struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
-#endif
-#endif
-    return (v[0] <<  8)
-	 + (v[1]      );
-  }
-  private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
-  public:
-  BEInt<Type, 3>& operator = (Type V)
-  {
-    v[0] = (V >> 16) & 0xFF;
-    v[1] = (V >>  8) & 0xFF;
-    v[2] = (V      ) & 0xFF;
-    return *this;
-  }
-  operator Type () const
-  {
-    return (v[0] << 16)
-	 + (v[1] <<  8)
-	 + (v[2]      );
-  }
-  private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
-  public:
-  BEInt<Type, 4>& operator = (Type V)
-  {
-    v[0] = (V >> 24) & 0xFF;
-    v[1] = (V >> 16) & 0xFF;
-    v[2] = (V >>  8) & 0xFF;
-    v[3] = (V      ) & 0xFF;
-    return *this;
-  }
-  operator Type () const
-  {
-    return (v[0] << 24)
-	 + (v[1] << 16)
-	 + (v[2] <<  8)
-	 + (v[3]      );
-  }
-  private: uint8_t v[4];
-};
-
-
-/*
- * For lack of a better place, put Zawgyi script hack here.
- * https://github.com/harfbuzz/harfbuzz/issues/1162
- */
-
-#define HB_SCRIPT_MYANMAR_ZAWGYI	((hb_script_t) HB_TAG ('Q','a','a','g'))
-
 
 /* Headers we include for everyone.  Keep topologically sorted by dependency.
  * They express dependency amongst themselves, but no other file should include
diff --git a/src/main.cc b/src/main.cc
index 983cb55..1ab013c 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,5 +1,7 @@
 /*
  * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2018,2019,2020  Ebrahim Byagowi
+ * Copyright © 2018  Khaled Hosny
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -24,48 +26,336 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+
+#ifdef HB_NO_OPEN
+#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)
+static void
+svg_dump (hb_face_t *face, unsigned face_index)
+{
+  unsigned glyph_count = hb_face_get_glyph_count (face);
+
+  for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id)
+  {
+    hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id);
+
+    if (hb_blob_get_length (blob) == 0) continue;
+
+    unsigned length;
+    const char *data = hb_blob_get_data (blob, &length);
+
+    char output_path[255];
+    sprintf (output_path, "out/svg-%u-%u.svg%s",
+	     glyph_id,
+	     face_index,
+	     // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
+	     (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : "");
+
+    FILE *f = fopen (output_path, "wb");
+    fwrite (data, 1, length, f);
+    fclose (f);
+
+    hb_blob_destroy (blob);
+  }
+}
+
+/* _png API is so easy to use unlike the below code, don't get confused */
+static void
+png_dump (hb_face_t *face, unsigned face_index)
+{
+  unsigned glyph_count = hb_face_get_glyph_count (face);
+  hb_font_t *font = hb_font_create (face);
+
+  /* scans the font for strikes */
+  unsigned sample_glyph_id;
+  /* we don't care about different strikes for different glyphs at this point */
+  for (sample_glyph_id = 0; sample_glyph_id < glyph_count; ++sample_glyph_id)
+  {
+    hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
+    unsigned blob_length = hb_blob_get_length (blob);
+    hb_blob_destroy (blob);
+    if (blob_length != 0)
+      break;
+  }
+
+  unsigned upem = hb_face_get_upem (face);
+  unsigned blob_length = 0;
+  unsigned strike = 0;
+  for (unsigned ppem = 1; ppem < upem; ++ppem)
+  {
+    hb_font_set_ppem (font, ppem, ppem);
+    hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
+    unsigned new_blob_length = hb_blob_get_length (blob);
+    hb_blob_destroy (blob);
+    if (new_blob_length != blob_length)
+    {
+      for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id)
+      {
+	hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id);
+
+	if (hb_blob_get_length (blob) == 0) continue;
+
+	unsigned length;
+	const char *data = hb_blob_get_data (blob, &length);
+
+	char output_path[255];
+	sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
+
+	FILE *f = fopen (output_path, "wb");
+	fwrite (data, 1, length, f);
+	fclose (f);
+
+	hb_blob_destroy (blob);
+      }
+
+      strike++;
+      blob_length = new_blob_length;
+    }
+  }
+
+  hb_font_destroy (font);
+}
+
+struct user_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)
+{
+  fprintf (user_data.f, "M%d,%d", to_x, user_data.ascender - to_y);
+}
+
+static void
+line_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
+{
+  fprintf (user_data.f, "L%d,%d", to_x, user_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)
+{
+  fprintf (user_data.f, "Q%d,%d %d,%d", control_x, user_data.ascender - control_y,
+					to_x, user_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)
+{
+  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);
+}
+
+static void
+close_path (user_data_t &user_data)
+{
+  fprintf (user_data.f, "Z");
+}
+
+static void
+layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
+{
+  hb_face_t *face = hb_font_get_face (font);
+  unsigned palette_count = hb_ot_color_palette_get_count (face);
+  for (unsigned palette = 0; palette < palette_count; ++palette)
+  {
+    unsigned num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr);
+    if (!num_colors) continue;
+
+    hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t));
+    hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors);
+    if (!num_colors)
+    {
+      free (colors);
+      continue;
+    }
+
+    unsigned num_glyphs = hb_face_get_glyph_count (face);
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; ++gid)
+    {
+      unsigned num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr);
+      if (!num_layers) continue;
+
+      hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t));
+
+      hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers);
+      if (num_layers)
+      {
+	hb_font_extents_t font_extents;
+	hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+	hb_glyph_extents_t extents = {0};
+	if (!hb_font_get_glyph_extents (font, gid, &extents))
+	{
+	  printf ("Skip gid: %d\n", gid);
+	  continue;
+	}
+
+	char output_path[255];
+	sprintf (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;
+
+	for (unsigned layer = 0; layer < num_layers; ++layer)
+	{
+	  hb_color_t color = 0x000000FF;
+	  if (layers[layer].color_index != 0xFFFF)
+	    color = colors[layers[layer].color_index];
+	  fprintf (f, "<path fill=\"#%02X%02X%02X\" ",
+		   hb_color_get_red (color), hb_color_get_green (color), hb_color_get_green (color));
+	  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);
+	  fprintf (f, "\"/>\n");
+	}
+
+	fprintf (f, "</svg>");
+	fclose (f);
+      }
+      free (layers);
+    }
+
+    free (colors);
+  }
+}
+
+static void
+dump_glyphs (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
+{
+  unsigned num_glyphs = hb_face_get_glyph_count (hb_font_get_face (font));
+  for (unsigned gid = 0; gid < num_glyphs; ++gid)
+  {
+    hb_font_extents_t font_extents;
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    hb_glyph_extents_t extents = {0};
+    if (!hb_font_get_glyph_extents (font, gid, &extents))
+    {
+      printf ("Skip gid: %d\n", gid);
+      continue;
+    }
+
+    char output_path[255];
+    sprintf (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);
+    fprintf (f, "\"/></svg>");
+    fclose (f);
+  }
+}
+
+static void
+dump_glyphs (hb_blob_t *blob, const char *font_name)
+{
+  FILE *font_name_file = fopen ("out/.dumped_font_name", "r");
+  if (font_name_file)
+  {
+    fprintf (stderr, "Purge or rename ./out folder if you like to run a glyph dump,\n"
+		     "run it like `rm -rf out && mkdir out && src/main font-file.ttf`\n");
+    return;
+  }
+
+  font_name_file = fopen ("out/.dumped_font_name", "w");
+  if (!font_name_file)
+  {
+    fprintf (stderr, "./out is not accessible as a folder, create it please\n");
+    return;
+  }
+  fwrite (font_name, 1, strlen (font_name), font_name_file);
+  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);
+
+  unsigned num_faces = hb_face_count (blob);
+  for (unsigned face_index = 0; face_index < num_faces; ++face_index)
+  {
+    hb_face_t *face = hb_face_create (blob, face_index);
+    hb_font_t *font = hb_font_create (face);
+
+    if (hb_ot_color_has_png (face))
+      printf ("Dumping png (CBDT/sbix)...\n");
+    png_dump (face, face_index);
+
+    if (hb_ot_color_has_svg (face))
+      printf ("Dumping svg (SVG )...\n");
+    svg_dump (face, face_index);
+
+    if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face))
+      printf ("Dumping layered color glyphs (COLR/CPAL)...\n");
+    layered_glyph_dump (font, funcs, face_index);
+
+    dump_glyphs (font, funcs, face_index);
+
+    hb_font_destroy (font);
+    hb_face_destroy (face);
+  }
+
+  hb_draw_funcs_destroy (funcs);
+}
+#endif
+
+#ifndef MAIN_CC_NO_PRIVATE_API
+/* Only this part of this mini app uses private API */
 #include "hb-static.cc"
 #include "hb-open-file.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsubgpos.hh"
 
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-
-
 using namespace OT;
 
-#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
-#endif
-
-int
-main (int argc, char **argv)
+static void
+print_layout_info_using_private_api (hb_blob_t *blob)
 {
-  if (argc != 2)
-  {
-    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
-    exit (1);
-  }
-
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
-  unsigned int len;
-  const char *font_data = hb_blob_get_data (blob, &len);
-  printf ("Opened font file %s: %d bytes long\n", argv[1], len);
-
-  hb_blob_t *font_blob = hb_sanitize_context_t().sanitize_blob<OpenTypeFontFile> (blob);
+  const char *font_data = hb_blob_get_data (blob, nullptr);
+  hb_blob_t *font_blob = hb_sanitize_context_t ().sanitize_blob<OpenTypeFontFile> (blob);
   const OpenTypeFontFile* sanitized = font_blob->as<OpenTypeFontFile> ();
   if (!font_blob->data)
   {
     printf ("Sanitization of the file wasn't successful. Exit");
-    return 1;
+    exit (1);
   }
   const OpenTypeFontFile& ot = *sanitized;
 
-
   switch (ot.get_tag ())
   {
   case OpenTypeFontFile::TrueTypeTag:
@@ -91,22 +381,22 @@
     break;
   }
 
-  int num_fonts = ot.get_face_count ();
-  printf ("%d font(s) found in file\n", num_fonts);
-  for (int n_font = 0; n_font < num_fonts; n_font++)
+  unsigned num_faces = hb_face_count (blob);
+  printf ("%d 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_fonts);
+    printf ("Font %d of %d:\n", n_font, num_faces);
 
-    int num_tables = font.get_table_count ();
+    unsigned num_tables = font.get_table_count ();
     printf ("  %d table(s) found in font\n", num_tables);
-    for (int n_table = 0; n_table < num_tables; n_table++)
+    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,
 	      (const char *) table.tag,
-	      (unsigned int) table.offset,
-	      (unsigned int) table.length);
+	      (unsigned) table.offset,
+	      (unsigned) table.length);
 
       switch (table.tag)
       {
@@ -115,21 +405,22 @@
       case HB_OT_TAG_GPOS:
 	{
 
-	const GSUBGPOS &g = *CastP<GSUBGPOS> (font_data + table.offset);
+	const GSUBGPOS &g = *reinterpret_cast<const GSUBGPOS *> (font_data + table.offset);
 
-	int num_scripts = g.get_script_count ();
+	unsigned num_scripts = g.get_script_count ();
 	printf ("    %d script(s) found in table\n", num_scripts);
-	for (int n_script = 0; n_script < num_scripts; n_script++)
+	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,
-		  (const char *)g.get_script_tag(n_script));
+		  (const char *) g.get_script_tag (n_script));
 
-	  if (!script.has_default_lang_sys())
+	  if (!script.has_default_lang_sys ())
 	    printf ("      No default language system\n");
 	  int num_langsys = script.get_lang_sys_count ();
 	  printf ("      %d language system(s) found in script\n", num_langsys);
-	  for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) {
+	  for (int n_langsys = script.has_default_lang_sys () ? -1 : 0; n_langsys < num_langsys; ++n_langsys)
+	  {
 	    const LangSys &langsys = n_langsys == -1
 				   ? script.get_default_lang_sys ()
 				   : script.get_lang_sys (n_langsys);
@@ -137,16 +428,16 @@
 	      printf ("      Default Language System\n");
 	    else
 	      printf ("      Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
-		      (const char *)script.get_lang_sys_tag (n_langsys));
+		      (const char *) script.get_lang_sys_tag (n_langsys));
 	    if (!langsys.has_required_feature ())
 	      printf ("        No required feature\n");
 	    else
 	      printf ("        Required feature index: %d\n",
 		      langsys.get_required_feature_index ());
 
-	    int num_features = langsys.get_feature_count ();
+	    unsigned num_features = langsys.get_feature_count ();
 	    printf ("        %d feature(s) found in language system\n", num_features);
-	    for (int n_feature = 0; n_feature < num_features; n_feature++)
+	    for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
 	    {
 	      printf ("        Feature index %2d of %2d: %d\n", n_feature, num_features,
 		      langsys.get_feature_index (n_feature));
@@ -154,29 +445,29 @@
 	  }
 	}
 
-	int num_features = g.get_feature_count ();
+	unsigned num_features = g.get_feature_count ();
 	printf ("    %d feature(s) found in table\n", num_features);
-	for (int n_feature = 0; n_feature < num_features; n_feature++)
+	for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
 	{
 	  const Feature &feature = g.get_feature (n_feature);
-	  int num_lookups = feature.get_lookup_count ();
+	  unsigned num_lookups = feature.get_lookup_count ();
 	  printf ("    Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
-		  HB_UNTAG(g.get_feature_tag(n_feature)));
+		  HB_UNTAG (g.get_feature_tag (n_feature)));
 
 	  printf ("        %d lookup(s) found in feature\n", num_lookups);
-	  for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+	  for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup) {
 	    printf ("        Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
 		    feature.get_lookup_index (n_lookup));
 	  }
 	}
 
-	int num_lookups = g.get_lookup_count ();
+	unsigned num_lookups = g.get_lookup_count ();
 	printf ("    %d lookup(s) found in table\n", num_lookups);
-	for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++)
+	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,
-		  lookup.get_type(), lookup.get_props());
+		  lookup.get_type (), lookup.get_props ());
 	}
 
 	}
@@ -185,7 +476,7 @@
       case GDEF::tableTag:
 	{
 
-	const GDEF &gdef = *CastP<GDEF> (font_data + table.offset);
+	const GDEF &gdef = *reinterpret_cast<const GDEF *> (font_data + table.offset);
 
 	printf ("    Has %sglyph classes\n",
 		  gdef.has_glyph_classes () ? "" : "no ");
@@ -202,6 +493,29 @@
       }
     }
   }
+}
+/* end of private API use */
+#endif
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 2)
+  {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
+  printf ("Opened font file %s: %d 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)
+  dump_glyphs (blob, argv[1]);
+#endif
+  hb_blob_destroy (blob);
 
   return 0;
 }
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..bda44c6
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,731 @@
+hb_version_h = configure_file(
+               command: [find_program('gen-hb-version.py'), meson.project_version(), '@OUTPUT@', '@INPUT@'],
+               input: 'hb-version.h.in',
+               output: 'hb-version.h',
+               install: true,
+               install_dir: join_paths(get_option('includedir'), meson.project_name()))
+
+# Base and default-included sources and headers
+hb_base_sources = files(
+  'hb-aat-layout-ankr-table.hh',
+  'hb-aat-layout-bsln-table.hh',
+  'hb-aat-layout-common.hh',
+  'hb-aat-layout-feat-table.hh',
+  'hb-aat-layout-just-table.hh',
+  'hb-aat-layout-kerx-table.hh',
+  'hb-aat-layout-morx-table.hh',
+  'hb-aat-layout-opbd-table.hh',
+  'hb-aat-layout-trak-table.hh',
+  'hb-aat-layout.cc',
+  'hb-aat-layout.hh',
+  'hb-aat-ltag-table.hh',
+  'hb-aat-map.cc',
+  'hb-aat-map.hh',
+  'hb-algs.hh',
+  'hb-array.hh',
+  'hb-atomic.hh',
+  'hb-bimap.hh',
+  'hb-bit-page.hh',
+  'hb-blob.cc',
+  'hb-blob.hh',
+  'hb-buffer-serialize.cc',
+  'hb-buffer.cc',
+  'hb-buffer.hh',
+  'hb-cache.hh',
+  'hb-cff-interp-common.hh',
+  'hb-cff-interp-cs-common.hh',
+  'hb-cff-interp-dict-common.hh',
+  'hb-cff1-interp-cs.hh',
+  'hb-cff2-interp-cs.hh',
+  'hb-common.cc',
+  'hb-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.cc',
+  '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-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-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',
+  'hb-set-digest.hh',
+  'hb-set.cc',
+  'hb-set.hh',
+  'hb-shape-plan.cc',
+  'hb-shape-plan.hh',
+  'hb-shape.cc',
+  'hb-shaper-impl.hh',
+  'hb-shaper-list.hh',
+  'hb-shaper.cc',
+  'hb-shaper.hh',
+  'hb-static.cc',
+  'hb-string-array.hh',
+  'hb-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.hh',
+)
+
+hb_base_ragel_generated_sources = files(
+  '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_base_ragel_sources = [
+  'hb-buffer-deserialize-json.rl',
+  'hb-buffer-deserialize-text.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_base_headers = files(
+  '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.h',
+)
+hb_base_headers += hb_version_h
+
+# Optional Sources and Headers with external deps
+
+hb_ft_sources = files('hb-ft.cc')
+hb_ft_headers = files('hb-ft.h')
+
+hb_glib_sources = files('hb-glib.cc')
+hb_glib_headers = files('hb-glib.h')
+
+hb_graphite2_sources = files('hb-graphite2.cc')
+hb_graphite2_headers = files('hb-graphite2.h')
+
+# System-dependent sources and headers
+
+hb_coretext_sources = files('hb-coretext.cc')
+hb_coretext_headers = files('hb-coretext.h')
+
+hb_directwrite_sources = files('hb-directwrite.cc')
+hb_directwrite_headers = files('hb-directwrite.h')
+
+hb_gdi_sources = files('hb-gdi.cc')
+hb_gdi_headers = files('hb-gdi.h')
+
+hb_uniscribe_sources = files('hb-uniscribe.cc')
+hb_uniscribe_headers = files('hb-uniscribe.h')
+
+# Sources for libharfbuzz-gobject and libharfbuzz-icu
+hb_icu_sources = files('hb-icu.cc')
+hb_icu_headers = files('hb-icu.h')
+
+# Sources for libharfbuzz-subset
+hb_subset_sources = files(
+  'hb-number.cc',
+  'hb-number.hh',
+  'hb-ot-cff1-table.cc',
+  'hb-ot-cff2-table.cc',
+  '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-plan.cc',
+  'hb-subset-plan.hh',
+  'hb-subset.cc',
+  'hb-subset.hh',
+)
+
+hb_subset_headers = files('hb-subset.h')
+
+hb_gobject_sources = files(
+  'hb-gobject-structs.cc'
+)
+
+hb_gobject_headers = files(
+  'hb-gobject.h',
+  'hb-gobject-structs.h',
+)
+
+ragel = find_program('ragel', version: '6.10', required: false)
+has_ragel = ragel.found()
+if not has_ragel and get_option('ragel_subproject')
+    ragel = subproject('ragel').get_variable('ragel')
+    has_ragel = true
+endif
+if not has_ragel
+  warning('You have to install ragel if you are going to develop HarfBuzz itself')
+else
+  ragel_helper = find_program('gen-ragel-artifacts.py')
+  foreach rl : hb_base_ragel_sources
+    hh = rl.split('.')[0] + '.hh'
+    custom_target('@0@'.format(hh),
+      build_by_default: true,
+      input: rl,
+      output: hh,
+      command: [ragel_helper, ragel, '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
+    )
+  endforeach
+endif
+
+custom_target('harfbuzz.cc',
+  build_by_default: true,
+  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,
+  command: [find_program('gen-harfbuzzcc.py'),
+            '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
+)
+
+incsrc = include_directories('.')
+
+hb_sources = hb_base_sources + hb_base_ragel_generated_sources
+hb_headers = hb_base_headers
+
+harfbuzz_deps = [thread_dep, m_dep] + harfbuzz_extra_deps
+
+libharfbuzz_link_language = 'c'
+
+if conf.get('HAVE_FREETYPE', 0) == 1
+  hb_sources += hb_ft_sources
+  hb_headers += hb_ft_headers
+  harfbuzz_deps += [freetype_dep]
+endif
+
+if conf.get('HAVE_GDI', 0) == 1
+  hb_sources += hb_gdi_sources
+  hb_headers += hb_gdi_headers
+  harfbuzz_deps += gdi_uniscribe_deps
+endif
+
+if conf.get('HAVE_GRAPHITE2', 0) == 1
+  hb_sources += hb_graphite2_sources
+  hb_headers += hb_graphite2_headers
+  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]
+endif
+
+if conf.get('HAVE_UNISCRIBE', 0) == 1
+  hb_sources += hb_uniscribe_sources
+  hb_headers += hb_uniscribe_headers
+endif
+
+if conf.get('HAVE_DIRECTWRITE', 0) == 1
+  hb_sources += hb_directwrite_sources
+  hb_headers += hb_directwrite_headers
+  # hb-directwrite needs a C++ linker
+  libharfbuzz_link_language = 'cpp'
+endif
+
+if conf.get('HAVE_CORETEXT', 0) == 1
+  hb_sources += hb_coretext_sources
+  hb_headers += hb_coretext_headers
+  harfbuzz_deps += coretext_deps
+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')
+
+harfbuzz_def_command_args = [gen_def, '@OUTPUT@', '@INPUT@']
+if get_option('experimental_api')
+  harfbuzz_def_command_args += '--experimental-api'
+endif
+
+harfbuzz_def = custom_target('harfbuzz.def',
+    command: harfbuzz_def_command_args,
+    input: hb_headers,
+    output: 'harfbuzz.def')
+defs_list = [harfbuzz_def]
+
+version = '0.@0@.0'.format(hb_version_int)
+
+extra_hb_cpp_args = []
+if cpp.get_id() == 'msvc'
+  if get_option('default_library') != 'static'
+    extra_hb_cpp_args += '-DHB_DLL_EXPORT'
+  endif
+  hb_so_version = ''
+else
+  hb_so_version = '0'
+endif
+
+if get_option('fuzzer_ldflags') != ''
+  extra_hb_cpp_args += ['-DHB_CUSTOM_MALLOC']
+  hb_sources += 'failing-alloc.c'
+  hb_subset_sources += 'failing-alloc.c'
+  hb_icu_sources += 'failing-alloc.c'
+  hb_gobject_sources += 'failing-alloc.c'
+endif
+
+darwin_versions = [hb_version_int, '@0@.0.0'.format(hb_version_int)]
+
+libharfbuzz = library('harfbuzz', hb_sources,
+  include_directories: incconfig,
+  dependencies: harfbuzz_deps,
+  cpp_args: cpp_args + extra_hb_cpp_args,
+  soversion: hb_so_version,
+  version: version,
+  install: true,
+  darwin_versions: darwin_versions,
+  link_language: libharfbuzz_link_language,
+)
+
+libharfbuzz_dep = declare_dependency(
+  link_with: libharfbuzz,
+  include_directories: incsrc,
+  dependencies: harfbuzz_deps)
+
+# harfbuzz-subset
+harfbuzz_subset_def = custom_target('harfbuzz-subset.def',
+    command: [gen_def, '@OUTPUT@', '@INPUT@'],
+    input: hb_subset_headers,
+    output: 'harfbuzz-subset.def')
+defs_list += [harfbuzz_subset_def]
+
+libharfbuzz_subset = library('harfbuzz-subset', hb_subset_sources,
+  include_directories: incconfig,
+  dependencies: [m_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',
+)
+
+libharfbuzz_subset_dep = declare_dependency(
+  link_with: libharfbuzz_subset,
+  include_directories: incsrc,
+  dependencies: [m_dep])
+
+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'
+    noinst_programs = {
+      'main': 'main.cc',
+      'test-basics': 'test.cc',
+      'test-buffer-serialize': 'test-buffer-serialize.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-would-substitute': 'test-gsub-would-substitute.cc',
+    }
+    foreach name, source : noinst_programs
+      executable(name, source,
+        include_directories: incconfig,
+        cpp_args: cpp_args,
+        dependencies: libharfbuzz_dep,
+        install: false,
+      )
+    endforeach
+  endif
+
+  compiled_tests = {
+    'test-algs': ['test-algs.cc', 'hb-static.cc'],
+    'test-array': ['test-array.cc'],
+    'test-repacker': ['test-repacker.cc', 'hb-static.cc'],
+    'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
+    'test-iter': ['test-iter.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-set': ['test-set.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')
+      # TODO: MSVC doesn't like tests having hb-static.cc, fix them
+      continue
+    endif
+    test(name, executable(name, source,
+      include_directories: incconfig,
+      cpp_args: cpp_args + ['-DMAIN', '-UNDEBUG'],
+      dependencies: libharfbuzz_dep,
+      install: false,
+    ), suite: ['src'])
+  endforeach
+endif
+
+pkgmod.generate(libharfbuzz,
+  description: 'HarfBuzz text shaping library',
+  subdirs: [meson.project_name()],
+  version: meson.project_version(),
+)
+
+pkgmod.generate(libharfbuzz_subset,
+  description: 'HarfBuzz font subsetter',
+  requires: ['harfbuzz = @0@'.format(meson.project_version())],
+  subdirs: [meson.project_name()],
+  version: meson.project_version(),
+)
+
+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@'],
+    input: [hb_icu_headers],
+    output: 'harfbuzz-icu.def')
+  defs_list += [harfbuzz_icu_def]
+
+  libharfbuzz_icu = library('harfbuzz-icu', [hb_icu_sources, hb_icu_headers],
+    include_directories: incconfig,
+    dependencies: icu_dep,
+    link_with: [libharfbuzz],
+    cpp_args: cpp_args + extra_hb_cpp_args,
+    soversion: hb_so_version,
+    version: version,
+    install: true,
+    darwin_versions: darwin_versions,
+    # ICU links to stdc++ anyway so the default linker is good
+    # link_language: 'c',
+  )
+
+  libharfbuzz_icu_dep = declare_dependency(
+    link_with: libharfbuzz_icu,
+    include_directories: incsrc,
+    dependencies: icu_dep)
+
+  pkgmod.generate(libharfbuzz_icu,
+    description: 'HarfBuzz text shaping library ICU integration',
+    requires: ['harfbuzz = @0@'.format(meson.project_version())],
+    subdirs: [meson.project_name()],
+    version: meson.project_version(),
+  )
+
+  install_headers(hb_icu_headers, subdir: meson.project_name())
+endif
+
+have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
+
+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))
+configure_file(input: 'harfbuzz-config.cmake.in',
+  output: 'harfbuzz-config.cmake',
+  configuration: cmake_config,
+  install_dir: join_paths(get_option('libdir'), 'cmake', 'harfbuzz'),
+)
+
+libharfbuzz_gobject_dep = null_dep
+if have_gobject
+  gnome = import('gnome')
+
+  h_templ = configure_file(
+    input: 'hb-gobject-enums.h.tmpl',
+    output: 'hb-gobject-enums-tmp.h.tmpl',
+    configuration: configuration_data(),
+    format: 'cmake')
+
+  cc_templ = configure_file(
+    input: 'hb-gobject-enums.cc.tmpl',
+    output: 'hb-gobject-enums-tmp.cc.tmpl',
+    configuration: configuration_data(),
+    format: 'cmake')
+
+  enums = gnome.mkenums('hb-gobject',
+    sources: hb_headers,
+    h_template: h_templ,
+    c_template: cc_templ,
+    identifier_prefix: 'hb_',
+    symbol_prefix: 'hb_gobject',
+  )
+
+  enum_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',
+    input: enums[1],
+    output: 'hb-gobject-enums.h',
+    command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@'],
+    install: true,
+    install_dir: join_paths(get_option('prefix'), get_option('includedir'), meson.project_name()),
+  )
+
+  hb_gobject_sources += [enum_c]
+
+  harfbuzz_gobject_def = custom_target('harfbuzz-gobject.def',
+    command: [gen_def, '@OUTPUT@', '@INPUT@'],
+    input: [hb_gobject_headers, enum_h],
+    output: 'harfbuzz-gobject.def')
+  defs_list += [harfbuzz_gobject_def]
+
+  libharfbuzz_gobject = library('harfbuzz-gobject', [hb_gobject_sources, enum_c, enum_h],
+    include_directories: incconfig,
+    dependencies: [glib_dep, gobject_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',
+  )
+
+  gir = find_program('g-ir-scanner', required: get_option('introspection'))
+  build_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled())
+
+  build_gir = build_gir and get_option('default_library') != 'static'
+  if not build_gir and get_option('introspection').enabled()
+    error('Introspection support is requested but the default library option should be shared or both')
+  endif
+
+  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],
+      dependencies: libharfbuzz_dep,
+      namespace: 'HarfBuzz',
+      nsversion: '0.0',
+      identifier_prefix: 'hb_',
+      symbol_prefix: ['hb', 'hb_gobject'],
+      includes: ['GObject-2.0'],
+      export_packages: ['harfbuzz-gobject'],
+      header: 'hb-gobject.h',
+      install: true,
+      extra_args:  ['--cflags-begin',
+                    '-DHB_NO_SINGLE_HEADER_ERROR',
+                    '-DHAVE_GOBJECT',
+                    '-DHB_EXTERN=',
+                    '--cflags-end'])
+  endif
+
+  if build_gir
+    libharfbuzz_gobject_sources = hb_gen_files_gir
+  else
+    libharfbuzz_gobject_sources = hb_gobject_sources
+  endif
+
+  libharfbuzz_gobject_dep = declare_dependency(
+    link_with: libharfbuzz_gobject,
+    include_directories: incsrc,
+    sources: libharfbuzz_gobject_sources,
+    dependencies: [glib_dep, gobject_dep])
+
+  pkgmod.generate(libharfbuzz_gobject,
+    description: 'HarfBuzz text shaping library GObject integration',
+    requires: ['harfbuzz = @0@'.format(meson.project_version()), 'glib-2.0', 'gobject-2.0'],
+    subdirs: [meson.project_name()],
+    version: meson.project_version(),
+  )
+
+  install_headers(hb_gobject_headers, subdir: meson.project_name())
+else
+  if get_option('introspection').enabled()
+    error('introspection requires gobject to be enabled')
+  endif
+endif
+
+if get_option('tests').enabled()
+  dist_check_script = [
+    'check-c-linkage-decls',
+    'check-externs',
+    'check-header-guards',
+    'check-includes',
+  ]
+
+  env = environment()
+  env.set('srcdir', meson.current_source_dir())
+  env.set('builddir', meson.current_build_dir())
+  env.set('libs', meson.current_build_dir()) # TODO: Merge this with builddir after autotools removal
+  HBSOURCES = []
+  foreach f : hb_sources
+    HBSOURCES += '@0@'.format(f)
+  endforeach
+  env.set('HBSOURCES', ' '.join(HBSOURCES))
+  HBHEADERS = []
+  foreach f : hb_headers
+    HBHEADERS += '@0@'.format(f)
+  endforeach
+  env.set('HBHEADERS', ' '.join(HBHEADERS))
+
+  if cpp.get_id() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
+    if meson.version().version_compare('>=0.55')
+      dist_check_script += 'check-libstdc++'
+    endif
+    dist_check_script += ['check-static-inits', 'check-symbols']
+  endif
+
+  foreach name : dist_check_script
+    if name == 'check-symbols'
+      test_depends = defs_list
+    else
+      test_depends = []
+    endif
+    test(name, find_program(name + '.py'),
+      env: env,
+      depends: test_depends,
+      suite: ['src'],
+    )
+  endforeach
+endif
+
+install_headers(hb_headers + hb_subset_headers, subdir: meson.project_name())
diff --git a/src/ms-use/COPYING b/src/ms-use/COPYING
new file mode 100644
index 0000000..9e841e7
--- /dev/null
+++ b/src/ms-use/COPYING
@@ -0,0 +1,21 @@
+    MIT License
+
+    Copyright (c) Microsoft Corporation.
+
+    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/src/ms-use/IndicPositionalCategory-Additional.txt b/src/ms-use/IndicPositionalCategory-Additional.txt
new file mode 100644
index 0000000..83a164e
--- /dev/null
+++ b/src/ms-use/IndicPositionalCategory-Additional.txt
@@ -0,0 +1,109 @@
+# 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
+
+# ================================================
+# ================================================
+# OVERRIDES TO ASSIGNED VALUES
+# ================================================
+# ================================================
+
+# Indic_Positional_Category=Bottom
+0F72          ; Bottom  # Mn      TIBETAN VOWEL SIGN I # Not really below, but need to override to fit into Universal model
+0F7A..0F7D    ; Bottom  # Mn  [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO # Not really below, but need to override to fit into Universal model
+0F80          ; Bottom  # Mn      TIBETAN VOWEL SIGN REVERSED I # Not really below, but need to override to fit into Universal model
+A9BF          ; Bottom  # Mc      JAVANESE CONSONANT SIGN CAKRA
+11127..11129  ; Bottom  # Mn  [3] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN II
+1112D         ; Bottom  # Mn      CHAKMA VOWEL SIGN AI
+11130         ; Bottom  # Mn      CHAKMA VOWEL SIGN OI
+
+# ================================================
+
+# Indic_Positional_Category=Left
+1C29          ; Left    # Mc      LEPCHA VOWEL SIGN OO  # Reduced from Top_And_Left
+
+# ================================================
+
+
+# Indic_Positional_Category=Right
+A9BE          ; Right   # Mc      JAVANESE CONSONANT SIGN PENGKAL # Reduced from Bottom_And_Right
+10A0C         ; Right   # Mn      KHAROSHTHI VOWEL LENGTH MARK    # Follows vowels and precedes vowel modifiers
+11942         ; Right   # Mc      DIVES AKURU MEDIAL RA           # Reduced from Bottom_And_Right
+
+# ================================================
+
+# Indic_Positional_Category=Top
+0F74          ; Top     # Mn       TIBETAN VOWEL SIGN U # Not really above, but need to override to fit into Universal model
+1A18          ; Top     # Mn       BUGINESE VOWEL SIGN U # Workaround to allow below to occur before above by treating all below marks as above
+AA35          ; Top     # Mn       CHAM CONSONANT SIGN
+
+# ================================================
+
+# Indic_Positional_Category=Top_And_Right
+0E33          ; Top_And_Right # Lo       THAI CHARACTER SARA AM # IMC has Right, which seems to be a mistake.
+0EB3          ; Top_And_Right # Lo       LAO VOWEL SIGN AM # IMC has Right, which seems to be a mistake.
+
+# ================================================
+# ================================================
+# VALUES NOT ASSIGNED IN Indic_Positional_Category
+# ================================================
+# ================================================
+
+# Indic_Positional_Category=Bottom
+0859..085B    ; Bottom # Mn   [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+18A9          ; Bottom # Mn       MONGOLIAN LETTER ALI GALI DAGALGA
+10AE5         ; Bottom # Mn       MANICHAEAN ABBREVIATION MARK ABOVE  # Overriden, ccc controls order
+10AE6         ; Bottom # Mn       MANICHAEAN ABBREVIATION MARK BELOW
+10F46..10F47  ; Bottom # Mn   [2] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING TWO DOTS BELOW
+10F48..10F4A  ; Bottom # Mn   [3] SOGDIAN COMBINING DOT ABOVE..SOGDIAN COMBINING CURVE ABOVE     # Overriden, ccc controls order
+10F4B         ; Bottom # Mn       SOGDIAN COMBINING CURVE BELOW
+10F4C         ; Bottom # Mn       SOGDIAN COMBINING HOOK ABOVE        # Overriden, ccc controls order
+10F4D..10F50  ; Bottom # Mn   [4] SOGDIAN COMBINING HOOK BELOW..SOGDIAN COMBINING STROKE BELOW
+10F82         ; Bottom # Mn       OLD UYGHUR COMBINING DOT ABOVE      # Overriden, ccc controls order
+10F83         ; Bottom # Mn       OLD UYGHUR COMBINING DOT BELOW
+10F84         ; Bottom # Mn       OLD UYGHUR COMBINING TWO DOTS ABOVE # Overriden, ccc controls order
+10F85         ; Bottom # Mn       OLD UYGHUR COMBINING TWO DOTS BELOW
+16F4F         ; Bottom # Mn       MIAO SIGN CONSONANT MODIFIER BAR
+16F51..16F87  ; Bottom # Mc  [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+16F8F..16F92  ; Bottom # Mn   [4] MIAO TONE RIGHT..MIAO TONE BELOW
+
+# ================================================
+
+# Indic_Positional_Category=Left
+103C          ; Left   # Mc       MYANMAR CONSONANT SIGN MEDIAL RA
+
+# ================================================
+
+# Indic_Positional_Category=Top
+07EB..07F3    ; Top   # Mn   [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07FD          ; Top   # Mn       NKO DANTAYALAN # Not really top, but assigned here to allow ccc to control mark order
+1885..1886    ; Top   # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+10D24..10D27  ; Top   # Mn   [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10EAB..10EAC  ; Top   # Mn   [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+16B30..16B36  ; Top   # Mn   [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+1E130..1E136  ; Top   # Mn   [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+1E2AE         ; Top   # Mn       TOTO SIGN RISING TONE
+1E2EC..1E2EF  ; Top   # Mn   [4] WANCHO TONE TUP..WANCHO TONE KOINI
+1E944..1E94A  ; Top   # Mn   [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+
+# ================================================
+
+# Indic_Positional_Category=Overstruck
+1BC9D..1BC9E  ; Overstruck # Mn  [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+
+# ================================================
+# ================================================
+# Deliberately suppressed
+# ================================================
+# ================================================
+
+# Indic_Positional_Category=NA
+180B..180D   ; NA        # Mn  [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180F         ; NA        # Mn      MONGOLIAN FREE VARIATION SELECTOR FOUR
+2D7F         ; NA        # Mn      TIFINAGH CONSONANT JOINER
diff --git a/src/ms-use/IndicShapingInvalidCluster.txt b/src/ms-use/IndicShapingInvalidCluster.txt
new file mode 100644
index 0000000..c4efe14
--- /dev/null
+++ b/src/ms-use/IndicShapingInvalidCluster.txt
@@ -0,0 +1,105 @@
+# IndicShapingInvalidCluster.txt
+# Date: 2015-03-12, 21:17:00 GMT [AG]
+# Date: 2019-11-08, 23:22:00 GMT [AG]
+#
+# This file defines the following property:
+#
+#    Indic_Shaping_Invalid_Cluster
+#
+# Scope: This file enumerates sequences of characters that should be treated as invalid clusters
+
+  0905 0946       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E
+  0905 093E       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA
+  0930 094D 0907  ; # DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I
+  0909 0941       ; # DEVANAGARI LETTER U, DEVANAGARI VOWEL SIGN U
+  090F 0945       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN CANDRA E
+  090F 0946       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E
+  090F 0947       ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN E
+  0905 0949       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA O
+  0906 0945       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN CANDRA E
+  0905 094A       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT O
+  0906 0946       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN SHORT E
+  0905 094B       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN O
+  0906 0947       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN E
+  0905 094C       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AU
+  0906 0948       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN AI
+  0905 0945       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA E
+  0905 093A       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE
+  0905 093B       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OOE
+  0906 093A       ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN OE
+  0905 094F       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW
+  0905 0956       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UE
+  0905 0957       ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UUE
+  0985 09BE       ; # BENGALI LETTER A, BENGALI VOWEL SIGN AA
+  098B 09C3       ; # BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R
+  098C 09E2       ; # BENGALI LETTER VOCALIC L, BENGALI VOWEL SIGN VOCALIC L
+  0A05 0A3E       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA
+  0A72 0A3F       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN I
+  0A72 0A40       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN II
+  0A73 0A41       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN U
+  0A73 0A42       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN UU
+  0A72 0A47       ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN EE
+  0A05 0A48       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AI
+  0A73 0A4B       ; # GURMUKHI URA, GURMUKHI VOWEL SIGN OO
+  0A05 0A4C       ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU
+  0A85 0ABE       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA
+  0A85 0AC5       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E
+  0A85 0AC7       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN E
+  0A85 0AC8       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AI
+  0A85 0AC9       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA O
+  0A85 0ACB       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN O
+  0A85 0ABE 0AC5  ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E
+  0A85 0ACC       ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AU
+  0A85 0ABE 0AC8  ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI
+  0AC5 0ABE       ; # GUJARATI VOWEL SIGN CANDRA E, GUJARATI VOWEL SIGN AA
+  0B05 0B3E       ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA
+  0B0F 0B57       ; # ORIYA LETTER E, ORIYA AU LENGTH MARK
+  0B13 0B57       ; # ORIYA LETTER O, ORIYA AU LENGTH MARK
+  0B85 0BC2       ; # TAMIL LETTER A, TAMIL VOWEL SIGN UU
+  0C12 0C55       ; # TELUGU LETTER O, TELUGU LENGTH MARK
+  0C12 0C4C       ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU
+  0C3F 0C55       ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK
+  0C46 0C55       ; # TELUGU VOWEL SIGN E, TELUGU LENGTH MARK
+  0C4A 0C55       ; # TELUGU VOWEL SIGN O, TELUGU LENGTH MARK
+  0C89 0CBE       ; # KANNADA LETTER U, KANNADA VOWEL SIGN AA
+  0C92 0CCC       ; # KANNADA LETTER O, KANNADA VOWEL SIGN AU
+  0C8B 0CBE       ; # KANNADA LETTER VOCALIC R, KANNADA VOWEL SIGN AA
+  0D07 0D57       ; # MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK
+  0D09 0D57       ; # MALAYALAM LETTER U, MALAYALAM AU LENGTH MARK
+  0D0E 0D46       ; # MALAYALAM LETTER E, MALAYALAM VOWEL SIGN E
+  0D12 0D3E       ; # MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA
+  0D12 0D57       ; # MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK
+  0D85 0DCF       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN AELA-PILLA
+  0D85 0DD0       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN KETTI AEDA-PILLA
+  0D85 0DD1       ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN DIGA AEDA-PILLA
+  0D8B 0DDF       ; # SINHALA LETTER UYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+  0D8D 0DD8       ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA
+  0D8F 0DDF       ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+  0D91 0DCA       ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA
+  0D91 0DD9       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA  
+  0D91 0DDA       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA
+  0D91 0DDC       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA
+  0D91 0DDD       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
+  0D91 0DDE       ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+  0D94 0DDF       ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA
+  11005 11038     ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA
+  1100B 1103E     ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R
+  1100F 11042     ; # BRAHMI LETTER E, BRAHMI VOWEL SIGN E
+  11680 116AD     ; # TAKRI LETTER A, TAKRI VOWEL SIGN AA
+  11686 116B2     ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
+  11680 116B4     ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
+  11680 116B5     ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
+  112B0 112E0     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
+  112B0 112E5     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
+  112B0 112E6     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
+  112B0 112E7     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN O
+  112B0 112E8     ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AU
+  11481 114B0     ; # TIRHUTA LETTER A, TIRHUTA VOWEL SIGN AA
+  114AA 114B5     ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC R
+  114AA 114B6     ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC RR
+  1148B 114BA     ; # TIRHUTA LETTER E, TIRHUTA VOWEL SIGN SHORT E
+  1148D 114BA     ; # TIRHUTA LETTER O, TIRHUTA VOWEL SIGN SHORT E
+  11600 11639     ; # MODI LETTER A, MODI VOWEL SIGN E
+  11600 1163A     ; # MODI LETTER A, MODI VOWEL SIGN AI
+  11601 11639     ; # MODI LETTER AA, MODI VOWEL SIGN E
+  11601 1163A     ; # MODI LETTER AA, MODI VOWEL SIGN AI
diff --git a/src/ms-use/IndicSyllabicCategory-Additional.txt b/src/ms-use/IndicSyllabicCategory-Additional.txt
new file mode 100644
index 0000000..8bcada3
--- /dev/null
+++ b/src/ms-use/IndicSyllabicCategory-Additional.txt
@@ -0,0 +1,221 @@
+# 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
+
+# ================================================
+# OVERRIDES TO ASSIGNED VALUES
+# ================================================
+
+# Indic_Syllabic_Category=Bindu  
+193A          ; Bindu  # Mn       LIMBU SIGN KEMPHRENG
+AA29          ; Bindu  # Mn       CHAM VOWEL SIGN AA
+10A0D         ; Bindu  # Mn       KHAROSHTHI SIGN DOUBLE RING BELOW
+
+# ================================================
+
+# Indic_Syllabic_Category=Consonant
+0840..0858    ; Consonant # Lo  [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+0F00..0F01    ; Consonant # Lo   [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED
+0F04..0F06    ; Consonant # Po       TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA
+19C1..19C7    ; Consonant # Lo   [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B # Reassigned to avoid clustering with a base consonant
+25CC          ; Consonant # So       DOTTED CIRCLE
+
+# ================================================
+
+# Indic_Syllabic_Category=Consonant_Dead
+0F7F          ; Consonant_Dead    # Mc       TIBETAN SIGN RNAM BCAD # reassigned so that visarga will form an independent cluster
+
+# ================================================
+
+# Indic_Syllabic_Category=Consonant_Final
+0F35          ; Consonant_Final   # Mn       TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37          ; Consonant_Final   # Mn       TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0FC6          ; Consonant_Final   # Mn       TIBETAN SYMBOL PADMA GDAN
+
+# ================================================
+
+# Indic_Syllabic_Category=Consonant_Final_Modifier
+1C36          ; Consonant_Final_Modifier  # Mn   LEPCHA SIGN RAN
+
+# ================================================
+
+# Indic_Syllabic_Category=Gemination_Mark 
+11134         ; Gemination_Mark  # Mc      CHAKMA MAAYYAA
+
+# ================================================
+
+# Indic_Syllabic_Category=Nukta   
+0F71          ; Nukta            # Mn       TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel
+10A38..10A3A  ; Nukta            # Mn   [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+
+# ================================================
+
+# Indic_Syllabic_Category=Tone_Mark
+1A7B..1A7C    ; Tone_Mark         # Mn   [2] TAI THAM SIGN MAI SAM..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F          ; Tone_Mark         # Mn       TAI THAM COMBINING CRYPTOGRAMMIC DOT
+
+# ================================================
+
+# Indic_Syllabic_Category=Vowel_Independent
+AAB1          ; Vowel_Independent # Lo       TAI VIET VOWEL AA
+AABA          ; Vowel_Independent # Lo       TAI VIET VOWEL UA
+AABD          ; Vowel_Independent # Lo       TAI VIET VOWEL AN
+
+# ================================================
+# ================================================
+# VALUES NOT ASSIGNED IN Indic_Syllabic_Category
+# ================================================
+# ================================================
+
+# Indic_Syllabic_Category=Consonant
+0800..0815    ; Consonant # Lo   [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+1800          ; Consonant # Po        MONGOLIAN BIRGA # Reassigned so that legacy Birga + MFVS sequences still work
+1807          ; Consonant # Po        MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER
+180A          ; Consonant # Po        MONGOLIAN NIRUGU
+1820..1878    ; Consonant # Lo   [88] MONGOLIAN LETTER A..MONGOLIAN LETTER CHA WITH TWO DOTS
+1843          ; Consonant # Lm        MONGOLIAN LETTER TODO LONG VOWEL SIGN
+2D30..2D67    ; Consonant # Lo   [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F          ; Consonant # Lm        TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+10570..1057A  ; Consonant # Lo   [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA
+1057C..1058A  ; Consonant # Lo   [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE
+1058C..10592  ; Consonant # Lo    [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE
+10594..10595  ; Consonant # Lo    [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE
+10597..105A1  ; Consonant # Lo   [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA
+105A3..105B1  ; Consonant # Lo   [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE
+105B3..105B9  ; Consonant # Lo    [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE
+105BB..105BC  ; Consonant # Lo    [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE
+10AC0..10AC7  ; Consonant # Lo    [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4  ; Consonant # Lo   [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10D00..10D23  ; Consonant # Lo   [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA
+10E80..10EA9  ; Consonant # Lo   [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+10EB0..10EB1  ; Consonant # Lo    [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
+10F30..10F45  ; Consonant # Lo   [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+111DA         ; Consonant # Lo        SHARADA EKAM
+#HIEROGLYPHS to be moved to new category
+13000..1342E  ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+#For the Begin and End segment to be handled fully correctly, the cluster model needs to be modified.
+13437..13438  ; Consonant # Lo    [2] EGYPTIAN HIEROGLYPH BEGIN SEGMENT..EGYPTIAN HIEROGLYPH END SEGMENT
+16B00..16B2F  ; Consonant # Lo   [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16F00..16F4A  ; Consonant # Lo   [75] MIAO LETTER PA..MIAO LETTER RTE
+16FE4         ; Consonant # Mn        KHITAN SMALL SCRIPT FILLER          # Avoids Mn pushing this into VOWEL class
+18B00..18CD5  ; Consonant # Lo  [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5
+1BC00..1BC6A  ; Consonant # Lo  [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C  ; Consonant # Lo   [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 
+1BC80..1BC88  ; Consonant # Lo    [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99  ; Consonant # Lo   [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1E100..1E12C  ; Consonant # Lo   [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W
+1E137..1E13D  ; Consonant # Lm    [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER
+1E14E         ; Consonant # Lo        NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ
+1E14F         ; Consonant # So        NYIAKENG PUACHUE HMONG CIRCLED CA
+1E290..1E2AD  ; Consonant # Lo   [30] TOTO LETTER PA..TOTO LETTER A
+1E2C0..1E2EB  ; Consonant # Lo   [44] WANCHO LETTER AA..WANCHO LETTER YIH
+1E900..1E921  ; Consonant # Lu   [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
+1E922..1E943  ; Consonant # Ll   [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E94B         ; Consonant # Lm        ADLAM NASALIZATION MARK
+
+# ================================================
+
+# Indic_Syllabic_Category=Consonant_Placeholder
+1880..1884 ; Consonant_Placeholder # Lo   [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+
+# ================================================
+
+# Indic_Syllabic_Category=Gemination_Mark
+10D27         ; Gemination_Mark   # Mn       HANIFI ROHINGYA SIGN TASSI
+
+# ================================================
+
+# Indic_Syllabic_Category=Modifying_Letter
+FE00..FE0F    ; Modifying_Letter  # Mn  [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16# Need to treat them as isolated bases so they don't merge with a cluster in invalid scenarios
+16F50         ; Modifying_Letter  # Lo       MIAO LETTER NASALIZATION
+
+# ================================================
+
+# Indic_Syllabic_Category=Nukta
+0859..085B    ; Nukta            # Mn   [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+0F39          ; Nukta            # Mn       TIBETAN MARK TSA -PHRU # NOW IN UNICODE 10.0
+1885..1886    ; Nukta            # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+18A9          ; Nukta            # Mn       MONGOLIAN LETTER ALI GALI DAGALGA
+1B6B..1B73    ; Nukta            # Mn   [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+10AE5..10AE6  ; Nukta            # Mn   [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+16F4F         ; Nukta            # Mn       MIAO SIGN CONSONANT MODIFIER BAR
+1BC9D..1BC9E  ; Nukta            # Mn   [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1E944..1E94A  ; Nukta            # Mn   [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+10F82..10F85  ; Nukta            # Mn   [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+
+# ================================================
+
+# Indic_Syllabic_Category=Number
+10D30..10D39  ; Number              # Nd  [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
+10F51..10F54  ; Number              # No   [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED
+16AC0..16AC9  ; Number              # Nd  [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
+1E140..1E149  ; Number              # Nd  [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
+1E2F0..1E2F9  ; Number              # Nd  [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+1E950..1E959  ; Number              # Nd  [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+
+# ================================================
+
+# Indic_Syllabic_Category=Tone_Mark
+07EB..07F3    ; Tone_Mark           # Mn   [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07FD          ; Tone_Mark           # Mn       NKO DANTAYALAN
+0F86..0F87    ; Tone_Mark           # Mn   [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+17CF          ; Tone_Mark           # Mn       KHMER SIGN AHSDA
+10D24..10D26  ; Tone_Mark           # Mn   [3] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TANA
+10F46..10F50  ; Tone_Mark           # Mn  [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+16B30..16B36  ; Tone_Mark           # Mn   [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16F8F..16F92  ; Tone_Mark           # Mn   [4] MIAO TONE RIGHT..MIAO TONE BELOW
+1E130..1E136  ; Tone_Mark           # Mn   [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+1E2AE         ; Tone_Mark           # Mn       TOTO SIGN RISING TONE
+1E2EC..1E2EF  ; Tone_Mark           # Mn   [4] WANCHO TONE TUP..WANCHO TONE KOINI
+
+# ================================================
+
+# Indic_Syllabic_Category=Virama
+2D7F          ; Virama              # Mn       TIFINAGH CONSONANT JOINER
+13430..13436  ; Virama              # Cf   [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+
+# ================================================
+
+# Indic_Syllabic_Category=Vowel_Independent
+AAB1          ; Vowel_Independent   # Lo       TAI VIET VOWEL AA
+AABA          ; Vowel_Independent   # Lo       TAI VIET VOWEL UA
+AABD          ; Vowel_Independent   # Lo       TAI VIET VOWEL AN
+
+# ================================================
+
+# Indic_Syllabic_Category=Vowel_Dependent
+0B55          ; Vowel_Dependent     # Mn       ORIYA SIGN OVERLINE
+10EAB..10EAC  ; Vowel_Dependent     # Mn   [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+16F51..16F87  ; Vowel_Dependent     # Mc  [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+
+# ================================================
+# ================================================
+# PROPERTIES NOT ASSIGNED IN Indic_Syllabic_Category
+# ================================================
+# ================================================
+
+# USE_Syllabic_Category=Hieroglyph
+# 13000..1342E ; Hieroglyph          # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+
+# ================================================
+
+# USE_Syllabic_Category=Hieroglyph_Joiner
+# 13430..13436 ; Hieroglyph_Joiner   # Cf        EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+
+# ================================================
+
+# USE_Syllabic_Category= Hieroglyph_Segment_Begin
+# 13437        ; Hieroglyph_Segment_Begin  # Cf  EGYPTIAN HIEROGLYPH BEGIN SEGMENT
+
+# ================================================
+
+# USE_Syllabic_Category= Hieroglyph_Segment_End
+# 13438        ; Hieroglyph_Segment_End    # Cf  EGYPTIAN HIEROGLYPH END SEGMENT 
+
+# ================================================
+
+# eof
diff --git a/src/sample.py b/src/sample.py
index 5d65aa0..fd85048 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -1,27 +1,12 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from __future__ import print_function, division, absolute_import
+#!/usr/bin/env python3
 
 import sys
 import array
 from gi.repository import HarfBuzz as hb
 from gi.repository import GLib
 
-# Python 2/3 compatibility
-try:
-	unicode
-except NameError:
-	unicode = str
-
-def tounicode(s, encoding='utf-8'):
-	if not isinstance(s, unicode):
-		return s.decode(encoding)
-	else:
-		return s
-
 fontdata = open (sys.argv[1], 'rb').read ()
-text = tounicode(sys.argv[2])
+text = sys.argv[2]
 # Need to create GLib.Bytes explicitly until this bug is fixed:
 # https://bugzilla.gnome.org/show_bug.cgi?id=729541
 blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
@@ -35,11 +20,11 @@
 hb.ot_font_set_funcs (font)
 
 buf = hb.buffer_create ()
-class Debugger(object):
+class Debugger (object):
 	def message (self, buf, font, msg, data, _x_what_is_this):
-		print(msg)
+		print (msg)
 		return True
-debugger = Debugger()
+debugger = Debugger ()
 hb.buffer_set_message_func (buf, debugger.message, 1, 0)
 
 ##
@@ -48,17 +33,16 @@
 #
 # See https://github.com/harfbuzz/harfbuzz/pull/271
 #
-if False:
-	# If you do not care about cluster values reflecting Python
-	# string indices, then this is quickest way to add text to
-	# buffer:
-	hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
-	# Otherwise, then following handles both narrow and wide
-	# Python builds (the first item in the array is BOM, so we skip it):
-elif sys.maxunicode == 0x10FFFF:
-	hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32'))[1:], 0, -1)
+# If you do not care about cluster values reflecting Python
+# string indices, then this is quickest way to add text to
+# buffer:
+# hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+# Otherwise, then following handles both narrow and wide
+# Python builds (the first item in the array is BOM, so we skip it):
+if sys.maxunicode == 0x10FFFF:
+	hb.buffer_add_utf32 (buf, array.array ('I', text.encode ('utf-32'))[1:], 0, -1)
 else:
-	hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16'))[1:], 0, -1)
+	hb.buffer_add_utf16 (buf, array.array ('H', text.encode ('utf-16'))[1:], 0, -1)
 
 
 hb.buffer_guess_segment_properties (buf)
@@ -69,11 +53,11 @@
 infos = hb.buffer_get_glyph_infos (buf)
 positions = hb.buffer_get_glyph_positions (buf)
 
-for info,pos in zip(infos, positions):
+for info, pos in zip (infos, positions):
 	gid = info.codepoint
 	cluster = info.cluster
 	x_advance = pos.x_advance
 	x_offset = pos.x_offset
 	y_offset = pos.y_offset
 
-	print("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
+	print ("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
diff --git a/src/test-array.cc b/src/test-array.cc
new file mode 100644
index 0000000..6c88813
--- /dev/null
+++ b/src/test-array.cc
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "hb.hh"
+#include "hb-array.hh"
+
+static void
+test_reverse ()
+{
+  int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  hb_array_t<int> a (values, 9);
+  a.reverse();
+
+  int expected_values[] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
+  hb_array_t<int> expected (expected_values, 9);
+  assert (a == expected);
+}
+
+static void
+test_reverse_range ()
+{
+  int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  hb_array_t<int> a (values, 9);
+  a.reverse(2, 6);
+
+  int expected_values[] = {1, 2, 6, 5, 4, 3, 7, 8, 9};
+  hb_array_t<int> expected (expected_values, 9);
+  assert (a == expected);
+}
+
+static void
+test_reverse_invalid ()
+{
+  int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  hb_array_t<int> a (values, 9);
+
+  a.reverse(4, 3);
+  a.reverse(2, 3);
+  a.reverse(5, 5);
+  a.reverse(12, 15);
+
+  int expected_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  hb_array_t<int> expected (expected_values, 9);
+  assert (a == expected);
+}
+
+int
+main (int argc, char **argv)
+{
+  test_reverse ();
+  test_reverse_range ();
+  test_reverse_invalid ();
+}
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index 6393f0b..8d5a694 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -32,10 +32,8 @@
 #include "hb-ft.h"
 #endif
 
-#include <stdio.h>
-
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -50,7 +48,8 @@
     exit (1);
   }
 
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
   blob = nullptr;
@@ -68,7 +67,7 @@
   buf = hb_buffer_create ();
 
   char line[BUFSIZ], out[BUFSIZ];
-  while (fgets (line, sizeof(line), stdin) != nullptr)
+  while (fgets (line, sizeof(line), stdin))
   {
     hb_buffer_clear_contents (buf);
 
diff --git a/src/test-gpos-size-params.cc b/src/test-gpos-size-params.cc
index ad10ed4..b96381d 100644
--- a/src/test-gpos-size-params.cc
+++ b/src/test-gpos-size-params.cc
@@ -29,10 +29,8 @@
 #include "hb.h"
 #include "hb-ot.h"
 
-#include <stdio.h>
-
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -44,7 +42,8 @@
   }
 
   /* Create the face */
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
   blob = nullptr;
diff --git a/src/test-gsub-would-substitute.cc b/src/test-gsub-would-substitute.cc
index 7ad9e08..8712303 100644
--- a/src/test-gsub-would-substitute.cc
+++ b/src/test-gsub-would-substitute.cc
@@ -29,14 +29,12 @@
 #include "hb.h"
 #include "hb-ot.h"
 
-#include <stdio.h>
-
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -48,7 +46,8 @@
   }
 
   /* Create the face */
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
   blob = nullptr;
diff --git a/src/test-iter.cc b/src/test-iter.cc
index 9c83171..fd201c8 100644
--- a/src/test-iter.cc
+++ b/src/test-iter.cc
@@ -105,7 +105,7 @@
 template <typename Iterable,
 	  hb_requires (hb_is_iterable (Iterable))>
 static void
-test_iterable (const Iterable &lst = Null(Iterable))
+test_iterable (const Iterable &lst = Null (Iterable))
 {
   for (auto _ : lst)
     (void) _;
diff --git a/src/test-map.cc b/src/test-map.cc
new file mode 100644
index 0000000..5761cc8
--- /dev/null
+++ b/src/test-map.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2021  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-map.hh"
+
+
+int
+main (int argc, char **argv)
+{
+
+  /* Test copy constructor. */
+  {
+    hb_map_t v1;
+    v1.set (1, 2);
+    hb_map_t v2 {v1};
+    assert (v1.get_population () == 1);
+    assert (v2.get_population () == 1);
+    assert (v1[1] == 2);
+    assert (v2[1] == 2);
+  }
+
+  /* Test copy assignment. */
+  {
+    hb_map_t v1;
+    v1.set (1, 2);
+    hb_map_t v2 = v1;
+    assert (v1.get_population () == 1);
+    assert (v2.get_population () == 1);
+    assert (v1[1] == 2);
+    assert (v2[1] == 2);
+  }
+
+  /* Test move constructor. */
+  {
+    hb_map_t v {hb_map_t {}};
+  }
+
+  /* Test move assignment. */
+  {
+    hb_map_t v;
+    v = hb_map_t {};
+  }
+
+  /* Test initializing from iterable. */
+  {
+    hb_map_t s;
+
+    s.set (1, 2);
+    s.set (3, 4);
+
+    hb_map_t v (s);
+
+    assert (v.get_population () == 2);
+  }
+
+  /* Test initializing from iterator. */
+  {
+    hb_map_t s;
+
+    s.set (1, 2);
+    s.set (3, 4);
+
+    hb_map_t v (hb_iter (s));
+
+    assert (v.get_population () == 2);
+  }
+
+  /* Test initializing from initializer list and swapping. */
+  {
+    using pair_t = hb_pair_t<hb_codepoint_t, hb_codepoint_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);
+    assert (v1.get_population () == 1);
+    assert (v2.get_population () == 2);
+  }
+
+  return 0;
+}
diff --git a/src/test-meta.cc b/src/test-meta.cc
deleted file mode 100644
index 0b6e02c..0000000
--- a/src/test-meta.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright © 2019  Facebook, 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.
- *
- * Facebook Author(s): Behdad Esfahbod
- */
-
-#include "hb.hh"
-#include "hb-meta.hh"
-
-#include <type_traits>
-
-int
-main (int argc, char **argv)
-{
-  static_assert (hb_is_convertible (void, void), "");
-  static_assert (hb_is_convertible (void, const void), "");
-  static_assert (hb_is_convertible (const void, void), "");
-
-  static_assert (hb_is_convertible (int,  int), "");
-  static_assert (hb_is_convertible (char, int), "");
-  static_assert (hb_is_convertible (long, int), "");
-
-  static_assert (hb_is_convertible (int, int), "");
-
-  static_assert (hb_is_convertible (const int, int), "");
-  static_assert (hb_is_convertible (int, const int), "");
-  static_assert (hb_is_convertible (const int, const int), "");
-
-  static_assert (hb_is_convertible (int&, int), "");
-  static_assert (!hb_is_convertible (int, int&), "");
-
-  static_assert (hb_is_convertible (int, const int&), "");
-  static_assert (!hb_is_convertible (const int, int&), "");
-  static_assert (hb_is_convertible (const int, const int&), "");
-  static_assert (hb_is_convertible (int&, const int), "");
-  static_assert (hb_is_convertible (const int&, int), "");
-  static_assert (hb_is_convertible (const int&, const int), "");
-  static_assert (hb_is_convertible (const int&, const int), "");
-
-  struct X {};
-  struct Y : X {};
-
-  static_assert (hb_is_convertible (const X &, const X), "");
-  static_assert (hb_is_convertible (X &, const X), "");
-  static_assert (hb_is_convertible (X &, const X &), "");
-  static_assert (hb_is_convertible (X, const X &), "");
-  static_assert (hb_is_convertible (const X, const X &), "");
-  static_assert (!hb_is_convertible (const X, X &), "");
-  static_assert (!hb_is_convertible (X, X &), "");
-  static_assert (hb_is_convertible (X &, X &), "");
-
-  static_assert (hb_is_convertible (int&, long), "");
-  static_assert (!hb_is_convertible (int&, long&), "");
-
-  static_assert (hb_is_convertible (int *, int *), "");
-  static_assert (hb_is_convertible (int *, const int *), "");
-  static_assert (!hb_is_convertible (const int *, int *), "");
-  static_assert (!hb_is_convertible (int *, long *), "");
-  static_assert (hb_is_convertible (int *, void *), "");
-  static_assert (!hb_is_convertible (void *, int *), "");
-
-  static_assert (hb_is_base_of (void, void), "");
-  static_assert (hb_is_base_of (void, int), "");
-  static_assert (!hb_is_base_of (int, void), "");
-
-  static_assert (hb_is_base_of (int, int), "");
-  static_assert (hb_is_base_of (const int, int), "");
-  static_assert (hb_is_base_of (int, const int), "");
-
-  static_assert (hb_is_base_of (X, X), "");
-  static_assert (hb_is_base_of (X, Y), "");
-  static_assert (hb_is_base_of (const X, Y), "");
-  static_assert (hb_is_base_of (X, const Y), "");
-  static_assert (!hb_is_base_of (Y, X), "");
-
-  static_assert (hb_is_constructible (int), "");
-  static_assert (hb_is_constructible (int, int), "");
-  static_assert (hb_is_constructible (int, char), "");
-  static_assert (hb_is_constructible (int, long), "");
-  static_assert (!hb_is_constructible (int, X), "");
-  static_assert (!hb_is_constructible (int, int, int), "");
-  static_assert (hb_is_constructible (X), "");
-  static_assert (!hb_is_constructible (X, int), "");
-  static_assert (hb_is_constructible (X, X), "");
-  static_assert (!hb_is_constructible (X, X, X), "");
-  static_assert (hb_is_constructible (X, Y), "");
-  static_assert (!hb_is_constructible (Y, X), "");
-
-  static_assert (hb_is_trivially_default_constructible (X), "");
-  static_assert (hb_is_trivially_default_constructible (Y), "");
-  static_assert (hb_is_trivially_copy_constructible (X), "");
-  static_assert (hb_is_trivially_copy_constructible (Y), "");
-  static_assert (hb_is_trivially_move_constructible (X), "");
-  static_assert (hb_is_trivially_move_constructible (Y), "");
-  static_assert (hb_is_trivially_destructible (Y), "");
-
-  static_assert (hb_is_trivially_copyable (int), "");
-  static_assert (hb_is_trivially_copyable (X), "");
-  static_assert (hb_is_trivially_copyable (Y), "");
-
-  static_assert (hb_is_trivial (int), "");
-  static_assert (hb_is_trivial (X), "");
-  static_assert (hb_is_trivial (Y), "");
-
-  /* TODO Add more meaningful tests. */
-
-  return 0;
-}
diff --git a/src/test-number.cc b/src/test-number.cc
index 3591b13..5783528 100644
--- a/src/test-number.cc
+++ b/src/test-number.cc
@@ -25,7 +25,6 @@
 
 #include "hb.hh"
 #include "hb-number.hh"
-#include "hb-number-parser.hh"
 
 
 int
@@ -146,11 +145,6 @@
     assert ((int) roundf (pv * 1000.) == 123);
     assert (pp - str == 4);
     assert (end - pp == 1);
-
-    /* Test strtod_rl even if libc's strtod_l is used */
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
-    assert (pend - str == 4);
   }
 
   {
@@ -163,10 +157,6 @@
     assert ((int) roundf (pv * 1000.) == 123);
     assert (pp - str == 5);
     assert (end - pp == 0);
-
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
-    assert (pend - str == 5);
   }
 
   {
@@ -179,10 +169,6 @@
     assert ((int) roundf (pv * 1000.) == 123);
     assert (pp - str == 7);
     assert (end - pp == 0);
-
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
-    assert (pend - str == 7);
   }
 
   {
@@ -195,10 +181,6 @@
     assert ((int) roundf (pv * 1000.) == 123);
     assert (pp - str == 6);
     assert (end - pp == 0);
-
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
-    assert (pend - str == 6);
   }
 
   {
@@ -211,10 +193,6 @@
     assert ((int) roundf (pv * 1000.) == 123);
     assert (pp - str == 10);
     assert (end - pp == 0);
-
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
-    assert (pend - str == 10);
   }
 
   {
@@ -228,9 +206,6 @@
     assert (pp - str == 13);
     assert (end - pp == 0);
 
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
-    assert (pend - str == 13);
   }
 
   {
@@ -243,10 +218,6 @@
     assert ((int) roundf (pv * 1000.) == -123);
     assert (pp - str == 8);
     assert (end - pp == 0);
-
-    char *pend;
-    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
-    assert (pend - str == 8);
   }
 
   return 0;
diff --git a/src/test-ot-color.cc b/src/test-ot-color.cc
deleted file mode 100644
index 88924b4..0000000
--- a/src/test-ot-color.cc
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright © 2018  Ebrahim Byagowi
- * Copyright © 2018  Khaled Hosny
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#include "hb.hh"
-
-#include <cairo.h>
-
-#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
-#endif
-
-#if !defined(HB_NO_COLOR) && defined(CAIRO_HAS_SVG_SURFACE)
-
-#include "hb-ot.h"
-
-#include "hb-ft.h"
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-
-#include <cairo-ft.h>
-#include <cairo-svg.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-
-static void
-svg_dump (hb_face_t *face, unsigned int face_index)
-{
-  unsigned glyph_count = hb_face_get_glyph_count (face);
-
-  for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++)
-  {
-    hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id);
-
-    if (hb_blob_get_length (blob) == 0) continue;
-
-    unsigned int length;
-    const char *data = hb_blob_get_data (blob, &length);
-
-    char output_path[255];
-    sprintf (output_path, "out/svg-%u-%u.svg%s",
-	     glyph_id,
-	     face_index,
-	     // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
-	     (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : "");
-
-    FILE *f = fopen (output_path, "wb");
-    fwrite (data, 1, length, f);
-    fclose (f);
-
-    hb_blob_destroy (blob);
-  }
-}
-
-/* _png API is so easy to use unlike the below code, don't get confused */
-static void
-png_dump (hb_face_t *face, unsigned int face_index)
-{
-  unsigned glyph_count = hb_face_get_glyph_count (face);
-  hb_font_t *font = hb_font_create (face);
-
-  /* scans the font for strikes */
-  unsigned int sample_glyph_id;
-  /* we don't care about different strikes for different glyphs at this point */
-  for (sample_glyph_id = 0; sample_glyph_id < glyph_count; sample_glyph_id++)
-  {
-    hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
-    unsigned int blob_length = hb_blob_get_length (blob);
-    hb_blob_destroy (blob);
-    if (blob_length != 0)
-      break;
-  }
-
-  unsigned int upem = hb_face_get_upem (face);
-  unsigned int blob_length = 0;
-  unsigned int strike = 0;
-  for (unsigned int ppem = 1; ppem < upem; ppem++)
-  {
-    hb_font_set_ppem (font, ppem, ppem);
-    hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
-    unsigned int new_blob_length = hb_blob_get_length (blob);
-    hb_blob_destroy (blob);
-    if (new_blob_length != blob_length)
-    {
-      for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++)
-      {
-	hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id);
-
-	if (hb_blob_get_length (blob) == 0) continue;
-
-	unsigned int length;
-	const char *data = hb_blob_get_data (blob, &length);
-
-	char output_path[255];
-	sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
-
-	FILE *f = fopen (output_path, "wb");
-	fwrite (data, 1, length, f);
-	fclose (f);
-
-	hb_blob_destroy (blob);
-      }
-
-      strike++;
-      blob_length = new_blob_length;
-    }
-  }
-
-  hb_font_destroy (font);
-}
-
-static void
-layered_glyph_dump (hb_face_t *face, cairo_font_face_t *cairo_face, unsigned int face_index)
-{
-  unsigned int upem = hb_face_get_upem (face);
-
-  unsigned glyph_count = hb_face_get_glyph_count (face);
-  for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid)
-  {
-    unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr);
-    if (!num_layers)
-      continue;
-
-    hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t));
-
-    hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers);
-    if (num_layers)
-    {
-      // Measure
-      cairo_text_extents_t extents;
-      {
-	cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-	cairo_t *cr = cairo_create (surface);
-	cairo_set_font_face (cr, cairo_face);
-	cairo_set_font_size (cr, upem);
-
-	cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t));
-	for (unsigned int j = 0; j < num_layers; ++j)
-	  glyphs[j].index = layers[j].glyph;
-	cairo_glyph_extents (cr, glyphs, num_layers, &extents);
-	free (glyphs);
-	cairo_surface_destroy (surface);
-	cairo_destroy (cr);
-      }
-
-      // Add a slight margin
-      extents.width += extents.width / 10;
-      extents.height += extents.height / 10;
-      extents.x_bearing -= extents.width / 20;
-      extents.y_bearing -= extents.height / 20;
-
-      // Render
-      unsigned int palette_count = hb_ot_color_palette_get_count (face);
-      for (unsigned int palette = 0; palette < palette_count; palette++)
-      {
-	unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr);
-	if (!num_colors)
-	  continue;
-
-	hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t));
-	hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors);
-	if (num_colors)
-	{
-	  char output_path[255];
-	  sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
-
-	  cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
-	  cairo_t *cr = cairo_create (surface);
-	  cairo_set_font_face (cr, cairo_face);
-	  cairo_set_font_size (cr, upem);
-
-	  for (unsigned int layer = 0; layer < num_layers; ++layer)
-	  {
-	    hb_color_t color = 0x000000FF;
-	    if (layers[layer].color_index != 0xFFFF)
-	      color = colors[layers[layer].color_index];
-	    cairo_set_source_rgba (cr,
-				   hb_color_get_red (color) / 255.,
-				   hb_color_get_green (color) / 255.,
-				   hb_color_get_blue (color) / 255.,
-				   hb_color_get_alpha (color) / 255.);
-
-	    cairo_glyph_t glyph;
-	    glyph.index = layers[layer].glyph;
-	    glyph.x = -extents.x_bearing;
-	    glyph.y = -extents.y_bearing;
-	    cairo_show_glyphs (cr, &glyph, 1);
-	  }
-
-	  cairo_surface_destroy (surface);
-	  cairo_destroy (cr);
-	}
-	free (colors);
-      }
-    }
-
-    free (layers);
-  }
-}
-
-static void
-dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem,
-	     unsigned int num_glyphs, unsigned int face_index)
-{
-  for (unsigned int i = 0; i < num_glyphs; ++i)
-  {
-    cairo_text_extents_t extents;
-    cairo_glyph_t glyph = {0};
-    glyph.index = i;
-
-    // Measure
-    {
-      cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-      cairo_t *cr = cairo_create (surface);
-      cairo_set_font_face (cr, cairo_face);
-      cairo_set_font_size (cr, upem);
-
-      cairo_glyph_extents (cr, &glyph, 1, &extents);
-      cairo_surface_destroy (surface);
-      cairo_destroy (cr);
-    }
-
-    // Add a slight margin
-    extents.width += extents.width / 10;
-    extents.height += extents.height / 10;
-    extents.x_bearing -= extents.width / 20;
-    extents.y_bearing -= extents.height / 20;
-
-    // Render
-    {
-      char output_path[255];
-      sprintf (output_path, "out/%u-%u.svg", face_index, i);
-      cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
-      cairo_t *cr = cairo_create (surface);
-      cairo_set_font_face (cr, cairo_face);
-      cairo_set_font_size (cr, upem);
-      glyph.x = -extents.x_bearing;
-      glyph.y = -extents.y_bearing;
-      cairo_show_glyphs (cr, &glyph, 1);
-      cairo_surface_destroy (surface);
-      cairo_destroy (cr);
-    }
-  }
-}
-
-int
-main (int argc, char **argv)
-{
-  if (argc != 2) {
-    fprintf (stderr, "usage: %s font-file.ttf\n"
-		     "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n",
-		     argv[0], argv[0]);
-    exit (1);
-  }
-
-
-  FILE *font_name_file = fopen ("out/.dumped_font_name", "r");
-  if (font_name_file != nullptr)
-  {
-    fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n");
-    exit (1);
-  }
-
-  font_name_file = fopen ("out/.dumped_font_name", "w");
-  if (font_name_file == nullptr)
-  {
-    fprintf (stderr, "./out is not accessible as a folder, create it please\n");
-    exit (1);
-  }
-  fwrite (argv[1], 1, strlen (argv[1]), font_name_file);
-  fclose (font_name_file);
-
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
-  unsigned int num_faces = hb_face_count (blob);
-  if (num_faces == 0)
-  {
-    fprintf (stderr, "error: The file (%s) was corrupted, empty or not found", argv[1]);
-    exit (1);
-  }
-
-  for (unsigned int face_index = 0; face_index < hb_face_count (blob); face_index++)
-  {
-    hb_face_t *face = hb_face_create (blob, face_index);
-    hb_font_t *font = hb_font_create (face);
-
-    if (hb_ot_color_has_png (face)) printf ("Dumping png (cbdt/sbix)...\n");
-    png_dump (face, face_index);
-
-    if (hb_ot_color_has_svg (face)) printf ("Dumping svg...\n");
-    svg_dump (face, face_index);
-
-    cairo_font_face_t *cairo_face;
-    {
-      FT_Library library;
-      FT_Init_FreeType (&library);
-      FT_Face ft_face;
-      FT_New_Face (library, argv[1], 0, &ft_face);
-      cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
-    }
-    if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face))
-      printf ("Dumping layered color glyphs...\n");
-    layered_glyph_dump (face, cairo_face, face_index);
-
-    unsigned int num_glyphs = hb_face_get_glyph_count (face);
-    unsigned int upem = hb_face_get_upem (face);
-
-    // disabled when color font as cairo rendering of NotoColorEmoji is soooo slow
-    if (!hb_ot_color_has_layers (face) &&
-	!hb_ot_color_has_png (face) &&
-	!hb_ot_color_has_svg (face))
-      dump_glyphs (cairo_face, upem, num_glyphs, face_index);
-
-    hb_font_destroy (font);
-    hb_face_destroy (face);
-    }
-
-  hb_blob_destroy (blob);
-
-  return 0;
-}
-
-#else
-int main (int argc, char **argv) { return 0; }
-#endif
diff --git a/src/test-ot-glyphname.cc b/src/test-ot-glyphname.cc
new file mode 100644
index 0000000..50d0231
--- /dev/null
+++ b/src/test-ot-glyphname.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2019  Adobe, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb.hh"
+#include "hb-ot.h"
+
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
+#endif
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file\n", argv[0]);
+    exit (1);
+  }
+
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_font_t *font = hb_font_create (face);
+  hb_blob_destroy (blob);
+  blob = nullptr;
+  
+
+  const unsigned int num_glyphs = hb_face_get_glyph_count (face);
+  int	result = 1;
+
+  for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+  {
+    char buf[64];
+    unsigned int buf_size = sizeof (buf);
+    if (hb_font_get_glyph_name (font, gid, buf, buf_size))
+    {
+      hb_codepoint_t	gid_inv;
+      if (hb_font_get_glyph_from_name(font, buf, strlen (buf), &gid_inv))
+      {
+	if (gid == gid_inv)
+	{
+	  printf ("%u <-> %s\n", gid, buf);
+	}
+	else
+	{
+	  printf ("%u -> %s -> %u\n", gid, buf, gid_inv);
+	  result = 0;
+	}
+      }
+      else
+      {
+	printf ("%u -> %s -> ?\n", gid, buf);
+	result = 0;
+      }
+    }
+    else
+    {
+      printf ("%u -> ?\n", gid);
+      result = 0;
+    }
+  }
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  return result;
+}
diff --git a/src/test-ot-meta.cc b/src/test-ot-meta.cc
index 1045007..7cf69db 100644
--- a/src/test-ot-meta.cc
+++ b/src/test-ot-meta.cc
@@ -25,11 +25,8 @@
 #include "hb.hh"
 #include "hb-ot.h"
 
-#include <stdlib.h>
-#include <stdio.h>
-
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -40,7 +37,8 @@
     exit (1);
   }
 
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
   blob = nullptr;
diff --git a/src/test-ot-name.cc b/src/test-ot-name.cc
index 4a484c6..bfa654a 100644
--- a/src/test-ot-name.cc
+++ b/src/test-ot-name.cc
@@ -27,11 +27,8 @@
 #include "hb.hh"
 #include "hb-ot.h"
 
-#include <stdlib.h>
-#include <stdio.h>
-
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -42,7 +39,8 @@
     exit (1);
   }
 
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
   blob = nullptr;
diff --git a/src/test-priority-queue.cc b/src/test-priority-queue.cc
new file mode 100644
index 0000000..fab63ac
--- /dev/null
+++ b/src/test-priority-queue.cc
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "hb.hh"
+#include "hb-priority-queue.hh"
+
+static void
+test_insert ()
+{
+  hb_priority_queue_t queue;
+  assert (queue.is_empty ());
+
+  queue.insert (10, 0);
+  assert (!queue.is_empty ());
+  assert (queue.minimum () == hb_pair (10, 0));
+
+  queue.insert (20, 1);
+  assert (queue.minimum () == hb_pair (10, 0));
+
+  queue.insert (5, 2);
+  assert (queue.minimum () == hb_pair (5, 2));
+
+  queue.insert (15, 3);
+  assert (queue.minimum () == hb_pair (5, 2));
+
+  queue.insert (1, 4);
+  assert (queue.minimum () == hb_pair (1, 4));
+}
+
+static void
+test_extract ()
+{
+  hb_priority_queue_t queue;
+  queue.insert (0, 0);
+  queue.insert (60, 6);
+  queue.insert (30, 3);
+  queue.insert (40 ,4);
+  queue.insert (20, 2);
+  queue.insert (50, 5);
+  queue.insert (70, 7);
+  queue.insert (10, 1);
+
+  for (int i = 0; i < 8; i++)
+  {
+    assert (!queue.is_empty ());
+    assert (queue.minimum () == hb_pair (i * 10, i));
+    assert (queue.pop_minimum () == hb_pair (i * 10, i));
+  }
+
+  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 ();
+}
diff --git a/src/test-repacker.cc b/src/test-repacker.cc
new file mode 100644
index 0000000..4df0636
--- /dev/null
+++ b/src/test-repacker.cc
@@ -0,0 +1,1276 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include <string>
+
+#include "hb-repacker.hh"
+#include "hb-open-type.hh"
+
+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);
+}
+
+
+static unsigned add_object(const char* tag,
+                           unsigned len,
+                           hb_serialize_context_t* c)
+{
+  start_object (tag, len, c);
+  return c->pop_pack (false);
+}
+
+
+static void add_offset (unsigned id,
+                        hb_serialize_context_t* c)
+{
+  OT::Offset16* offset = c->start_embed<OT::Offset16> ();
+  c->extend_min (offset);
+  c->add_link (*offset, id);
+}
+
+static void add_wide_offset (unsigned id,
+                             hb_serialize_context_t* c)
+{
+  OT::Offset32* offset = c->start_embed<OT::Offset32> ();
+  c->extend_min (offset);
+  c->add_link (*offset, id);
+}
+
+static void run_resolve_overflow_test (const char* name,
+                                       hb_serialize_context_t& overflowing,
+                                       hb_serialize_context_t& expected,
+                                       unsigned num_iterations = 0)
+{
+  printf (">>> Testing overflowing resolution for %s\n",
+          name);
+
+  graph_t graph (overflowing.object_graph ());
+
+  unsigned buffer_size = overflowing.end - overflowing.start;
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  assert (overflowing.offset_overflow ());
+  hb_resolve_overflows (overflowing.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, num_iterations);
+  assert (!out.offset_overflow ());
+  hb_bytes_t result = out.copy_bytes ();
+
+  assert (!expected.offset_overflow ());
+  hb_bytes_t expected_result = expected.copy_bytes ();
+
+  assert (result.length == expected_result.length);
+  for (unsigned i = 0; i < expected_result.length; i++)
+  {
+    assert (result[i] == expected_result[i]);
+  }
+
+  result.fini ();
+  expected_result.fini ();
+  free (out_buffer);
+}
+
+static void add_virtual_offset (unsigned id,
+                                hb_serialize_context_t* c)
+{
+  c->add_virtual_link (id);
+}
+
+static void
+populate_serializer_simple (hb_serialize_context_t* c)
+{
+  c->start_serialize<char> ();
+
+  unsigned obj_1 = add_object ("ghi", 3, c);
+  unsigned obj_2 = add_object ("def", 3, c);
+
+  start_object ("abc", 3, c);
+  add_offset (obj_2, c);
+  add_offset (obj_1, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_overflow (hb_serialize_context_t* c)
+{
+  std::string large_string(50000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_1 = add_object (large_string.c_str(), 10000, c);
+  unsigned obj_2 = add_object (large_string.c_str(), 20000, c);
+  unsigned obj_3 = add_object (large_string.c_str(), 50000, c);
+
+  start_object ("abc", 3, c);
+  add_offset (obj_3, c);
+  add_offset (obj_2, c);
+  add_offset (obj_1, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_1 = add_object ("def", 3, c);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_1, c);
+  unsigned obj_2 = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 10000, c);
+  add_offset (obj_2, c);
+  add_offset (obj_1, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_isolation_overflow (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_4 = add_object ("4", 1, c);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_4, c);
+  unsigned obj_3 = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 10000, c);
+  add_offset (obj_4, c);
+  unsigned obj_2 = c->pop_pack (false);
+
+  start_object ("1", 1, c);
+  add_wide_offset (obj_3, c);
+  add_offset (obj_2, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_isolation_overflow_complex (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object ("e", 1, c);
+  add_offset (obj_f, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("d", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_d, c);
+  unsigned obj_h = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_c, c);
+  add_offset (obj_h, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 10000, c);
+  add_offset (obj_d, c);
+  unsigned obj_g = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 11000, c);
+  add_offset (obj_d, c);
+  unsigned obj_i = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_offset (obj_g, c);
+  add_offset (obj_i, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_isolation_overflow_complex_expected (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+
+  // space 1
+
+  unsigned obj_f_prime = add_object ("f", 1, c);
+
+  start_object ("e", 1, c);
+  add_offset (obj_f_prime, c);
+  unsigned obj_e_prime = c->pop_pack (false);
+
+  start_object ("d", 1, c);
+  add_offset (obj_e_prime, c);
+  unsigned obj_d_prime = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_d_prime, c);
+  unsigned obj_h = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e_prime, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_c, c);
+  add_offset (obj_h, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  // space 0
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object ("e", 1, c);
+  add_offset (obj_f, c);
+  unsigned obj_e = c->pop_pack (false);
+
+
+  start_object ("d", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 11000, c);
+  add_offset (obj_d, c);
+  unsigned obj_i = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 10000, c);
+  add_offset (obj_d, c);
+  unsigned obj_g = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_offset (obj_g, c);
+  add_offset (obj_i, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_isolation_overflow_spaces (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_d = add_object ("f", 1, c);
+  unsigned obj_e = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack ();
+
+  start_object (large_string.c_str(), 60000, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack ();
+
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  c->pop_pack ();
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_spaces (hb_serialize_context_t* c, bool with_overflow)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_i;
+
+  if (with_overflow)
+    obj_i = add_object ("i", 1, c);
+
+  // Space 2
+  unsigned obj_h = add_object ("h", 1, c);
+
+  start_object (large_string.c_str(), 30000, c);
+  add_offset (obj_h, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  // Space 1
+  if (!with_overflow)
+    obj_i = add_object ("i", 1, c);
+
+  start_object (large_string.c_str(), 30000, c);
+  add_offset (obj_i, c);
+  unsigned obj_g = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 30000, c);
+  add_offset (obj_i, c);
+  unsigned obj_f = c->pop_pack (false);
+
+  start_object ("d", 1, c);
+  add_offset (obj_g, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_f, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  add_wide_offset (obj_d, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_spaces_16bit_connection (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_g = add_object ("g", 1, c);
+  unsigned obj_h = add_object ("h", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_g, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_h, c);
+  unsigned obj_f = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("d", 1, c);
+  add_offset (obj_f, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_e, c);
+  add_offset (obj_h, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  add_wide_offset (obj_d, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_spaces_16bit_connection_expected (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_g_prime = add_object ("g", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_g_prime, c);
+  unsigned obj_e_prime = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e_prime, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  unsigned obj_h_prime = add_object ("h", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_h_prime, c);
+  unsigned obj_f = c->pop_pack (false);
+
+  start_object ("d", 1, c);
+  add_offset (obj_f, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  unsigned obj_g = add_object ("g", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_g, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  unsigned obj_h = add_object ("h", 1, c);
+
+  start_object ("b", 1, c);
+  add_offset (obj_e, c);
+  add_offset (obj_h, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  add_wide_offset (obj_d, c);
+  c->pop_pack (false);
+
+  c->end_serialize ();
+}
+
+static void
+populate_serializer_short_and_wide_subgraph_root (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_e = add_object ("e", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_c, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_c, c);
+  add_offset (obj_e, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  add_wide_offset (obj_d, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_short_and_wide_subgraph_root_expected (hb_serialize_context_t* c)
+{
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_e_prime = add_object ("e", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_e_prime, c);
+  unsigned obj_c_prime = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_c_prime, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  unsigned obj_e = add_object ("e", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+
+  start_object ("b", 1, c);
+  add_offset (obj_c, c);
+  add_offset (obj_e, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_c_prime, c);
+  add_wide_offset (obj_d, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_split_spaces (hb_serialize_context_t* c)
+{
+  // Overflow needs to be resolved by splitting the single space
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_split_spaces_2 (hb_serialize_context_t* c)
+{
+  // Overflow needs to be resolved by splitting the single space
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_split_spaces_expected (hb_serialize_context_t* c)
+{
+  // Overflow needs to be resolved by splitting the single space
+
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_f_prime = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f_prime, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_wide_offset (obj_b, c);
+  add_wide_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c)
+{
+  // Overflow needs to be resolved by splitting the single space
+
+  std::string large_string(70000, 'a');
+  c->start_serialize<char> ();
+
+  // Space 2
+
+  unsigned obj_f_double_prime = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f_double_prime, c);
+  unsigned obj_d_prime = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d_prime, c);
+  unsigned obj_b_prime = c->pop_pack (false);
+
+  // Space 1
+
+  unsigned obj_f_prime = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f_prime, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  // Space 0
+
+  unsigned obj_f = add_object ("f", 1, c);
+
+  start_object (large_string.c_str(), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  // Root
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_wide_offset (obj_b_prime, c);
+  add_wide_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+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> ();
+
+  unsigned obj_5 = add_object ("mn", 2, c);
+
+  unsigned obj_4 = add_object ("jkl", 3, c);
+
+  start_object ("ghi", 3, c);
+  add_offset (obj_4, c);
+  unsigned obj_3 = c->pop_pack (false);
+
+  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);
+  add_offset (obj_5, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_complex_3 (hb_serialize_context_t* c)
+{
+  c->start_serialize<char> ();
+
+  unsigned obj_6 = add_object ("opqrst", 6, c);
+
+  unsigned obj_5 = add_object ("mn", 2, c);
+
+  start_object ("jkl", 3, c);
+  add_offset (obj_6, c);
+  unsigned obj_4 = c->pop_pack (false);
+
+  start_object ("ghi", 3, c);
+  add_offset (obj_4, c);
+  unsigned obj_3 = c->pop_pack (false);
+
+  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);
+  add_offset (obj_5, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_virtual_link (hb_serialize_context_t* c)
+{
+  c->start_serialize<char> ();
+
+  unsigned obj_d = add_object ("d", 1, c);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack ();
+
+  start_object ("e", 1, c);
+  add_virtual_offset (obj_b, c);
+  unsigned obj_e = c->pop_pack();
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack ();
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_offset (obj_c, c);
+  c->pop_pack ();
+
+  c->end_serialize();
+}
+
+static void test_sort_kahn_1 ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_1 (&c);
+
+  graph_t graph (c.object_graph ());
+  graph.sort_kahn ();
+
+  assert(strncmp (graph.object (3).head, "abc", 3) == 0);
+  assert(graph.object (3).links.length == 2);
+  assert(graph.object (3).links[0].objidx == 2);
+  assert(graph.object (3).links[1].objidx == 1);
+
+  assert(strncmp (graph.object (2).head, "def", 3) == 0);
+  assert(graph.object (2).links.length == 1);
+  assert(graph.object (2).links[0].objidx == 0);
+
+  assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
+  assert(graph.object (1).links.length == 0);
+
+  assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
+  assert(graph.object (0).links.length == 0);
+
+  free (buffer);
+}
+
+static void test_sort_kahn_2 ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_2 (&c);
+
+  graph_t graph (c.object_graph ());
+  graph.sort_kahn ();
+
+
+  assert(strncmp (graph.object (4).head, "abc", 3) == 0);
+  assert(graph.object (4).links.length == 3);
+  assert(graph.object (4).links[0].objidx == 3);
+    assert(graph.object (4).links[1].objidx == 0);
+  assert(graph.object (4).links[2].objidx == 2);
+
+  assert(strncmp (graph.object (3).head, "def", 3) == 0);
+  assert(graph.object (3).links.length == 1);
+  assert(graph.object (3).links[0].objidx == 1);
+
+  assert(strncmp (graph.object (2).head, "mn", 2) == 0);
+  assert(graph.object (2).links.length == 0);
+
+  assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
+  assert(graph.object (1).links.length == 1);
+  assert(graph.object (1).links[0].objidx == 0);
+
+  assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
+  assert(graph.object (0).links.length == 0);
+
+  free (buffer);
+}
+
+static void test_sort_shortest ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_2 (&c);
+
+  graph_t graph (c.object_graph ());
+  graph.sort_shortest_distance ();
+
+  assert(strncmp (graph.object (4).head, "abc", 3) == 0);
+  assert(graph.object (4).links.length == 3);
+  assert(graph.object (4).links[0].objidx == 2);
+  assert(graph.object (4).links[1].objidx == 0);
+  assert(graph.object (4).links[2].objidx == 3);
+
+  assert(strncmp (graph.object (3).head, "mn", 2) == 0);
+  assert(graph.object (3).links.length == 0);
+
+  assert(strncmp (graph.object (2).head, "def", 3) == 0);
+  assert(graph.object (2).links.length == 1);
+  assert(graph.object (2).links[0].objidx == 1);
+
+  assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
+  assert(graph.object (1).links.length == 1);
+  assert(graph.object (1).links[0].objidx == 0);
+
+  assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
+  assert(graph.object (0).links.length == 0);
+
+  free (buffer);
+}
+
+static void test_duplicate_leaf ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_2 (&c);
+
+  graph_t graph (c.object_graph ());
+  graph.duplicate (4, 1);
+
+  assert(strncmp (graph.object (5).head, "abc", 3) == 0);
+  assert(graph.object (5).links.length == 3);
+  assert(graph.object (5).links[0].objidx == 3);
+  assert(graph.object (5).links[1].objidx == 4);
+  assert(graph.object (5).links[2].objidx == 0);
+
+  assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
+  assert(graph.object (4).links.length == 0);
+
+  assert(strncmp (graph.object (3).head, "def", 3) == 0);
+  assert(graph.object (3).links.length == 1);
+  assert(graph.object (3).links[0].objidx == 2);
+
+  assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
+  assert(graph.object (2).links.length == 1);
+  assert(graph.object (2).links[0].objidx == 1);
+
+  assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
+  assert(graph.object (1).links.length == 0);
+
+  assert(strncmp (graph.object (0).head, "mn", 2) == 0);
+  assert(graph.object (0).links.length == 0);
+
+  free (buffer);
+}
+
+static void test_duplicate_interior ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_3 (&c);
+
+  graph_t graph (c.object_graph ());
+  graph.duplicate (3, 2);
+
+  assert(strncmp (graph.object (6).head, "abc", 3) == 0);
+  assert(graph.object (6).links.length == 3);
+  assert(graph.object (6).links[0].objidx == 4);
+  assert(graph.object (6).links[1].objidx == 2);
+  assert(graph.object (6).links[2].objidx == 1);
+
+  assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
+  assert(graph.object (5).links.length == 1);
+  assert(graph.object (5).links[0].objidx == 0);
+
+  assert(strncmp (graph.object (4).head, "def", 3) == 0);
+  assert(graph.object (4).links.length == 1);
+  assert(graph.object (4).links[0].objidx == 3);
+
+  assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
+  assert(graph.object (3).links.length == 1);
+  assert(graph.object (3).links[0].objidx == 5);
+
+  assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
+  assert(graph.object (2).links.length == 1);
+  assert(graph.object (2).links[0].objidx == 0);
+
+  assert(strncmp (graph.object (1).head, "mn", 2) == 0);
+  assert(graph.object (1).links.length == 0);
+
+  assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
+  assert(graph.object (0).links.length == 0);
+
+  free (buffer);
+}
+
+static void
+test_serialize ()
+{
+  size_t buffer_size = 100;
+  void* buffer_1 = malloc (buffer_size);
+  hb_serialize_context_t c1 (buffer_1, buffer_size);
+  populate_serializer_simple (&c1);
+  hb_bytes_t expected = c1.copy_bytes ();
+
+  void* buffer_2 = malloc (buffer_size);
+  hb_serialize_context_t c2 (buffer_2, buffer_size);
+
+  graph_t graph (c1.object_graph ());
+  graph.serialize (&c2);
+  hb_bytes_t actual = c2.copy_bytes ();
+
+  assert (actual == expected);
+
+  actual.fini ();
+  expected.fini ();
+  free (buffer_1);
+  free (buffer_2);
+}
+
+static void test_will_overflow_1 ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_complex_2 (&c);
+  graph_t graph (c.object_graph ());
+
+  assert (!graph.will_overflow (nullptr));
+
+  free (buffer);
+}
+
+static void test_will_overflow_2 ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  assert (graph.will_overflow (nullptr));
+
+  free (buffer);
+}
+
+static void test_will_overflow_3 ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_dedup_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  assert (graph.will_overflow (nullptr));
+
+  free (buffer);
+}
+
+static void test_resolve_overflows_via_sort ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
+  assert (!out.offset_overflow ());
+  hb_bytes_t result = out.copy_bytes ();
+  assert (result.length == (80000 + 3 + 3 * 2));
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
+}
+
+static void test_resolve_overflows_via_duplication ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_dedup_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
+  assert (!out.offset_overflow ());
+  hb_bytes_t result = out.copy_bytes ();
+  assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
+}
+
+static void test_resolve_overflows_via_space_assignment ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_spaces (&c, true);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_spaces (&e, false);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_space_assignment",
+                             c,
+                             e);
+
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_overflows_via_isolation ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_isolation_overflow (&c);
+  graph_t graph (c.object_graph ());
+
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  assert (c.offset_overflow ());
+  hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
+  assert (!out.offset_overflow ());
+  hb_bytes_t result = out.copy_bytes ();
+  assert (result.length == (1 + 10000 + 60000 + 1 + 1
+                            + 4 + 3 * 2));
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
+}
+
+static void test_resolve_overflows_via_isolation_with_recursive_duplication ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_isolation_overflow_complex (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_isolation_overflow_complex_expected (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_isolation_with_recursive_duplication",
+                             c,
+                             e);
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_overflows_via_isolating_16bit_space ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_spaces_16bit_connection (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_spaces_16bit_connection_expected (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space",
+                             c,
+                             e);
+
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_overflows_via_isolating_16bit_space_2 ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_short_and_wide_subgraph_root (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_short_and_wide_subgraph_root_expected (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space_2",
+                             c,
+                             e);
+
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_resolve_overflows_via_isolation_spaces ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_isolation_overflow_spaces (&c);
+  graph_t graph (c.object_graph ());
+
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  assert (c.offset_overflow ());
+  hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
+  assert (!out.offset_overflow ());
+  hb_bytes_t result = out.copy_bytes ();
+
+  unsigned expected_length = 3 + 2 * 60000; // objects
+  expected_length += 2 * 4 + 2 * 2; // links
+  assert (result.length == expected_length);
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
+}
+
+static void test_resolve_overflows_via_splitting_spaces ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_split_spaces (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_split_spaces_expected (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces",
+                             c,
+                             e,
+                             1);
+
+  free (buffer);
+  free (expected_buffer);
+
+}
+
+static void test_resolve_overflows_via_splitting_spaces_2 ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_split_spaces_2 (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_split_spaces_expected_2 (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces_2",
+                             c,
+                             e,
+                             1);
+  free (buffer);
+  free (expected_buffer);
+}
+
+static void test_virtual_link ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_virtual_link (&c);
+
+  void* out_buffer = malloc (buffer_size);
+  hb_serialize_context_t out (out_buffer, buffer_size);
+
+  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
+  assert (!out.offset_overflow ());
+
+  hb_bytes_t result = out.copy_bytes ();
+  assert (result.length == 5 + 4 * 2);
+  assert (result[0]  == 'a');
+  assert (result[5]  == 'c');
+  assert (result[8]  == 'e');
+  assert (result[9]  == 'b');
+  assert (result[12] == 'd');
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
+}
+
+// TODO(garretrieger): update will_overflow tests to check the overflows array.
+// TODO(garretrieger): add tests for priority raising.
+
+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 ();
+  test_will_overflow_3 ();
+  test_resolve_overflows_via_sort ();
+  test_resolve_overflows_via_duplication ();
+  test_resolve_overflows_via_space_assignment ();
+  test_resolve_overflows_via_isolation ();
+  test_resolve_overflows_via_isolation_with_recursive_duplication ();
+  test_resolve_overflows_via_isolation_spaces ();
+  test_resolve_overflows_via_isolating_16bit_space ();
+  test_resolve_overflows_via_isolating_16bit_space_2 ();
+  test_resolve_overflows_via_splitting_spaces ();
+  test_resolve_overflows_via_splitting_spaces_2 ();
+  test_duplicate_leaf ();
+  test_duplicate_interior ();
+  test_virtual_link ();
+}
diff --git a/src/test-set.cc b/src/test-set.cc
new file mode 100644
index 0000000..286f1a9
--- /dev/null
+++ b/src/test-set.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2021  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-set.hh"
+
+
+int
+main (int argc, char **argv)
+{
+
+  /* Test copy constructor. */
+  {
+    hb_set_t v1 {1, 2};
+    hb_set_t v2 {v1};
+    assert (v1.get_population () == 2);
+    assert (v2.get_population () == 2);
+  }
+
+  /* Test copy assignment. */
+  {
+    hb_set_t v1 {1, 2};
+    hb_set_t v2 = v1;
+    assert (v1.get_population () == 2);
+    assert (v2.get_population () == 2);
+  }
+
+  /* Test move constructor. */
+  {
+    hb_set_t v {hb_set_t {1, 2}};
+    assert (v.get_population () == 2);
+  }
+
+  /* Test move assignment. */
+  {
+    hb_set_t v;
+    v = hb_set_t {1, 2};
+    assert (v.get_population () == 2);
+  }
+
+  /* Test initializing from iterable. */
+  {
+    hb_set_t s;
+
+    s.add (18);
+    s.add (12);
+
+    hb_set_t v (s);
+
+    assert (v.get_population () == 2);
+  }
+
+  /* Test initializing from iterator. */
+  {
+    hb_set_t s;
+
+    s.add (18);
+    s.add (12);
+
+    hb_set_t v (hb_iter (s));
+
+    assert (v.get_population () == 2);
+  }
+
+  /* Test initializing from initializer list and swapping. */
+  {
+    hb_set_t v1 {1, 2, 3};
+    hb_set_t v2 {4, 5};
+    hb_swap (v1, v2);
+    assert (v1.get_population () == 2);
+    assert (v2.get_population () == 3);
+  }
+
+  return 0;
+}
diff --git a/src/test-vector.cc b/src/test-vector.cc
new file mode 100644
index 0000000..6418a84
--- /dev/null
+++ b/src/test-vector.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 2021  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-vector.hh"
+#include "hb-set.hh"
+
+
+int
+main (int argc, char **argv)
+{
+
+  /* Test copy constructor. */
+  {
+    hb_vector_t<int> v1 {1, 2};
+    hb_vector_t<int> v2 {v1};
+    hb_vector_t<int> V2 {v1};
+    assert (v1.length == 2);
+    assert (v1[0] == 1);
+    assert (v1[1] == 2);
+    assert (v2.length == 2);
+    assert (v2[0] == 1);
+    assert (v2[1] == 2);
+  }
+
+  /* Test copy assignment. */
+  {
+    hb_vector_t<int> v1 {1, 2};
+    hb_vector_t<int> v2 = v1;
+    hb_vector_t<int> V2 = v1;
+    assert (v1.length == 2);
+    assert (v1[0] == 1);
+    assert (v1[1] == 2);
+    assert (v2.length == 2);
+    assert (v2[0] == 1);
+    assert (v2[1] == 2);
+  }
+
+  /* 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}};
+    assert (v.length == 2);
+    assert (v[0] == 1);
+    assert (v[1] == 2);
+  }
+
+  /* Test move assignment. */
+  {
+    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};
+    assert (v.length == 2);
+    assert (v[0] == 1);
+    assert (v[1] == 2);
+  }
+
+  /* Test initializing from iterable. */
+  {
+    hb_set_t s;
+
+    s.add (18);
+    s.add (12);
+
+    hb_vector_t<int> v (s);
+    hb_sorted_vector_t<int> V (s);
+
+    assert (v.length == 2);
+    assert (V.length == 2);
+    assert (v[0] == 12);
+    assert (V[0] == 12);
+    assert (v[1] == 18);
+    assert (V[1] == 18);
+  }
+
+  /* Test initializing from iterator. */
+  {
+    hb_set_t s;
+
+    s.add (18);
+    s.add (12);
+
+    hb_vector_t<int> v (hb_iter (s));
+    hb_vector_t<int> V (hb_iter (s));
+
+    assert (v.length == 2);
+    assert (V.length == 2);
+    assert (v[0] == 12);
+    assert (V[0] == 12);
+    assert (v[1] == 18);
+    assert (V[1] == 18);
+  }
+
+  /* Test initializing from initializer list and swapping. */
+  {
+    hb_vector_t<int> v1 {1, 2, 3};
+    hb_vector_t<int> v2 {4, 5};
+    hb_swap (v1, v2);
+    assert (v1.length == 2);
+    assert (v1[0] == 4);
+    assert (v2.length == 3);
+    assert (v2[2] == 3);
+  }
+
+  /* Test initializing sorted-vector from initializer list and swapping. */
+  {
+    hb_sorted_vector_t<int> v1 {1, 2, 3};
+    hb_sorted_vector_t<int> v2 {4, 5};
+    hb_swap (v1, v2);
+    assert (v1.length == 2);
+    assert (v1[0] == 4);
+    assert (v2.length == 3);
+    assert (v2[2] == 3);
+  }
+
+  return 0;
+}
diff --git a/src/test.cc b/src/test.cc
index 65b469f..d848cf1 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -26,16 +26,12 @@
 
 #include "hb.hh"
 
-#include "hb.h"
-
-#include <stdio.h>
-
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
 #ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x)  hb_blob_get_empty ()
 #endif
 
 int
@@ -46,7 +42,8 @@
     exit (1);
   }
 
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+  assert (blob);
   printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
 
   /* Create the face */
diff --git a/src/update-unicode-tables.make b/src/update-unicode-tables.make
new file mode 100755
index 0000000..8c2eaa4
--- /dev/null
+++ b/src/update-unicode-tables.make
@@ -0,0 +1,49 @@
+#!/usr/bin/env -S make -f
+
+all: packtab \
+	hb-ot-shape-complex-arabic-joining-list.hh \
+	hb-ot-shape-complex-arabic-table.hh hb-unicode-emoji-table.hh \
+	hb-ot-shape-complex-indic-table.cc hb-ot-tag-table.hh \
+	hb-ucd-table.hh hb-ot-shape-complex-use-table.hh \
+	hb-ot-shape-complex-vowel-constraints.cc
+
+.PHONY: all clean packtab
+
+hb-ot-shape-complex-arabic-joining-list.hh: gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt
+	./$^ > $@ || ($(RM) $@; false)
+hb-ot-shape-complex-arabic-table.hh: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
+	./$^ > $@ || ($(RM) $@; false)
+hb-unicode-emoji-table.hh: gen-emoji-table.py emoji-data.txt emoji-test.txt
+	./$^ > $@ || ($(RM) $@; false)
+hb-ot-shape-complex-indic-table.cc: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+	./$^ > $@ || ($(RM) $@; false)
+hb-ot-tag-table.hh: gen-tag-table.py languagetags language-subtag-registry
+	./$^ > $@ || ($(RM) $@; false)
+hb-ucd-table.hh: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
+	./$^ > $@ || ($(RM) $@; false)
+hb-ot-shape-complex-use-table.hh: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt ms-use/IndicSyllabicCategory-Additional.txt ms-use/IndicPositionalCategory-Additional.txt
+	./$^ > $@ || ($(RM) $@; false)
+hb-ot-shape-complex-vowel-constraints.cc: gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
+	./$^ > $@ || ($(RM) $@; false)
+
+packtab:
+	/usr/bin/env python3 -c "import packTab" 2>/dev/null || /usr/bin/env python3 -m pip install git+https://github.com/harfbuzz/packtab
+
+ArabicShaping.txt DerivedCoreProperties.txt IndicPositionalCategory.txt IndicSyllabicCategory.txt Scripts.txt UnicodeData.txt:
+	curl -O https://unicode.org/Public/UCD/latest/ucd/$@
+emoji-data.txt:
+	curl -O https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
+emoji-test.txt:
+	curl -O https://www.unicode.org/Public/emoji/latest/emoji-test.txt
+languagetags:
+	curl -O https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
+language-subtag-registry:
+	curl -O https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
+ucd.nounihan.grouped.zip:
+	curl -O https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip
+
+clean:
+	$(RM) \
+		ArabicShaping.txt UnicodeData.txt Blocks.txt emoji-data.txt \
+		IndicSyllabicCategory.txt IndicPositionalCategory.txt \
+		languagetags language-subtag-registry ucd.nounihan.grouped.zip Scripts.txt
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
new file mode 100644
index 0000000..ea3bb20
--- /dev/null
+++ b/subprojects/.gitignore
@@ -0,0 +1,6 @@
+/freetype2
+/glib
+/packagecache
+/benchmark-1.4.1
+/cairo
+/ragel-6.10
diff --git a/subprojects/cairo.wrap b/subprojects/cairo.wrap
new file mode 100644
index 0000000..afb2695
--- /dev/null
+++ b/subprojects/cairo.wrap
@@ -0,0 +1,5 @@
+[wrap-git]
+directory=cairo
+url=https://gitlab.freedesktop.org/cairo/cairo.git
+depth=1
+revision=1.17.4
diff --git a/subprojects/freetype2.wrap b/subprojects/freetype2.wrap
new file mode 100644
index 0000000..c346deb
--- /dev/null
+++ b/subprojects/freetype2.wrap
@@ -0,0 +1,4 @@
+[wrap-git]
+directory=freetype
+url=https://gitlab.freedesktop.org/freetype/freetype.git
+revision=VER-2-11-0
diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap
new file mode 100644
index 0000000..7a4eae1
--- /dev/null
+++ b/subprojects/glib.wrap
@@ -0,0 +1,6 @@
+[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
diff --git a/subprojects/google-benchmark.wrap b/subprojects/google-benchmark.wrap
new file mode 100644
index 0000000..876927d
--- /dev/null
+++ b/subprojects/google-benchmark.wrap
@@ -0,0 +1,9 @@
+[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
+
diff --git a/subprojects/packagefiles/ragel/meson.build b/subprojects/packagefiles/ragel/meson.build
new file mode 100644
index 0000000..cd317c2
--- /dev/null
+++ b/subprojects/packagefiles/ragel/meson.build
@@ -0,0 +1,58 @@
+project('ragel', 'c', 'cpp',
+  version : '6.10'
+)
+
+conf = configuration_data()
+conf.set_quoted('PACKAGE', meson.project_name())
+conf.set_quoted('VERSION', meson.project_version())
+configure_file(
+  output : 'config.h',
+  configuration : conf
+)
+
+ragel_sources = files(
+  'ragel/buffer.h', 'ragel/cdcodegen.cpp', 'ragel/cdcodegen.h',
+  'ragel/cdfflat.cpp', 'ragel/cdfflat.h', 'ragel/cdfgoto.cpp',
+  'ragel/cdfgoto.h', 'ragel/cdflat.cpp', 'ragel/cdflat.h',
+  'ragel/cdftable.cpp', 'ragel/cdftable.h', 'ragel/cdgoto.cpp',
+  'ragel/cdgoto.h', 'ragel/cdipgoto.cpp', 'ragel/cdipgoto.h',
+  'ragel/cdsplit.cpp', 'ragel/cdsplit.h', 'ragel/cdtable.cpp',
+  'ragel/cdtable.h', 'ragel/common.cpp', 'ragel/common.h',
+  'ragel/cscodegen.cpp', 'ragel/cscodegen.h', 'ragel/csfflat.cpp',
+  'ragel/csfflat.h', 'ragel/csfgoto.cpp', 'ragel/csfgoto.h',
+  'ragel/csflat.cpp', 'ragel/csflat.h', 'ragel/csftable.cpp',
+  'ragel/csftable.h', 'ragel/csgoto.cpp', 'ragel/csgoto.h',
+  'ragel/csipgoto.cpp', 'ragel/csipgoto.h', 'ragel/cssplit.cpp',
+  'ragel/cssplit.h', 'ragel/cstable.cpp', 'ragel/cstable.h',
+  'ragel/dotcodegen.cpp', 'ragel/dotcodegen.h', 'ragel/fsmap.cpp',
+  'ragel/fsmattach.cpp', 'ragel/fsmbase.cpp', 'ragel/fsmgraph.cpp',
+  'ragel/fsmgraph.h', 'ragel/fsmmin.cpp', 'ragel/fsmstate.cpp',
+  'ragel/gendata.cpp', 'ragel/gendata.h', 'ragel/gocodegen.cpp',
+  'ragel/gocodegen.h', 'ragel/gofflat.cpp', 'ragel/gofflat.h',
+  'ragel/gofgoto.cpp', 'ragel/gofgoto.h', 'ragel/goflat.cpp', 'ragel/goflat.h',
+  'ragel/goftable.cpp', 'ragel/goftable.h', 'ragel/gogoto.cpp',
+  'ragel/gogoto.h', 'ragel/goipgoto.cpp', 'ragel/goipgoto.h',
+  'ragel/gotable.cpp', 'ragel/gotable.h', 'ragel/gotablish.cpp',
+  'ragel/gotablish.h', 'ragel/inputdata.cpp', 'ragel/inputdata.h',
+  'ragel/javacodegen.cpp', 'ragel/javacodegen.h', 'ragel/main.cpp',
+  'ragel/mlcodegen.cpp', 'ragel/mlcodegen.h', 'ragel/mlfflat.cpp',
+  'ragel/mlfflat.h', 'ragel/mlfgoto.cpp', 'ragel/mlfgoto.h',
+  'ragel/mlflat.cpp', 'ragel/mlflat.h', 'ragel/mlftable.cpp',
+  'ragel/mlftable.h', 'ragel/mlgoto.cpp', 'ragel/mlgoto.h',
+  'ragel/mltable.cpp', 'ragel/mltable.h', 'ragel/parsedata.cpp',
+  'ragel/parsedata.h', 'ragel/parsetree.cpp', 'ragel/parsetree.h',
+  'ragel/pcheck.h', 'ragel/ragel.h', 'ragel/rbxgoto.cpp', 'ragel/rbxgoto.h',
+  'ragel/redfsm.cpp', 'ragel/redfsm.h', 'ragel/rlparse.cpp', 'ragel/rlparse.h',
+  'ragel/rlscan.cpp', 'ragel/rlscan.h', 'ragel/rubycodegen.cpp',
+  'ragel/rubycodegen.h', 'ragel/rubyfflat.cpp', 'ragel/rubyfflat.h',
+  'ragel/rubyflat.cpp', 'ragel/rubyflat.h', 'ragel/rubyftable.cpp',
+  'ragel/rubyftable.h', 'ragel/rubytable.cpp', 'ragel/rubytable.h',
+  'ragel/version.h', 'ragel/xmlcodegen.cpp', 'ragel/xmlcodegen.h',
+)
+
+ragel = executable(
+  meson.project_name(),
+  ragel_sources,
+  include_directories : ['aapl', 'ragel'],
+  install : true,
+)
diff --git a/subprojects/ragel.wrap b/subprojects/ragel.wrap
new file mode 100644
index 0000000..1dabcbc
--- /dev/null
+++ b/subprojects/ragel.wrap
@@ -0,0 +1,11 @@
+[wrap-file]
+directory = ragel-6.10
+source_url = https://www.colm.net/files/ragel/ragel-6.10.tar.gz
+source_filename = ragel-6.10.tar.gz
+source_hash = 5f156edb65d20b856d638dd9ee2dfb43285914d9aa2b6ec779dac0270cd56c3f
+patch_directory = ragel
+
+[provide]
+ragel = ragel
+
+
diff --git a/subprojects/ttf-parser.wrap b/subprojects/ttf-parser.wrap
new file mode 100644
index 0000000..11cda54
--- /dev/null
+++ b/subprojects/ttf-parser.wrap
@@ -0,0 +1,5 @@
+[wrap-git]
+directory=ttf-parser
+url=https://github.com/RazrFalcon/ttf-parser.git
+depth=1
+revision=master
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
deleted file mode 100644
index d2b1994..0000000
--- a/test/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-add_subdirectory(api)
-add_subdirectory(shaping)
-add_subdirectory(subset)
-add_subdirectory(fuzzing)
diff --git a/test/Makefile.am b/test/Makefile.am
index 66b3e6e..01d542a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,10 +2,10 @@
 
 NULL =
 EXTRA_DIST =
-SUBDIRS = api shaping fuzzing subset
+SUBDIRS = api shape subset fuzzing
 
 EXTRA_DIST += \
-	CMakeLists.txt \
+	meson.build \
 	$(NULL)
 
 # Convenience targets:
diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt
deleted file mode 100644
index 0c7337c..0000000
--- a/test/api/CMakeLists.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-if (HB_HAVE_GLIB)
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM)
-  extract_make_variable (TEST_PROGS ${MAKEFILEAM})
-
-  list (APPEND TEST_PROGS
-    test-ot-color
-    test-ot-name
-    test-ot-tag
-    test-c
-    test-cplusplus
-  )
-
-  if (HB_HAVE_FREETYPE)
-    list (APPEND TEST_PROGS test-ot-math)
-  endif ()
-
-  foreach (test_name IN ITEMS ${TEST_PROGS})
-    if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.c)
-      add_executable (${test_name} ${test_name}.c)
-    elseif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.cc)
-      add_executable (${test_name} ${test_name}.cc)
-    else ()
-      message (FATAL_ERROR "No source file found for test ${test_name}")
-    endif ()
-    target_link_libraries (${test_name} harfbuzz harfbuzz-subset)
-    if (WIN32)
-      set_property (TARGET ${test_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-      add_test (NAME ${test_name} COMMAND ${test_name})
-    else (WIN32)
-      add_test (${test_name} ${test_name})
-    endif (WIN32)
-  endforeach ()
-  set_tests_properties (${TEST_PROGS} PROPERTIES ENVIRONMENT
-    "G_TEST_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};G_TEST_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}"
-  )
-endif ()
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 9d4084b..883464c 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -12,7 +12,7 @@
 libs:
 	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
 
-EXTRA_DIST += CMakeLists.txt
+EXTRA_DIST += meson.build
 
 EXTRA_DIST += fonts
 
@@ -32,28 +32,53 @@
 	test-baseline \
 	test-blob \
 	test-buffer \
+	test-c \
 	test-collect-unicodes \
+	test-cplusplus \
 	test-common \
+	test-draw \
 	test-font \
+	test-font-scale \
 	test-map \
 	test-object \
+	test-ot-alternates \
+	test-ot-color \
+	test-ot-collect-glyphs \
 	test-ot-face \
+	test-ot-glyphname \
+	test-ot-ligature-carets \
+	test-ot-layout \
+	test-ot-name \
+	test-ot-meta \
+	test-ot-metrics \
+	test-ot-tag \
+	test-ot-extents-cff \
+	test-ot-metrics-tt-var \
 	test-set \
 	test-shape \
+	test-style \
 	test-subset \
 	test-subset-cmap \
 	test-subset-drop-tables \
 	test-subset-glyf \
 	test-subset-hdmx \
 	test-subset-hmtx \
+	test-subset-nameids \
 	test-subset-os2 \
 	test-subset-post \
 	test-subset-vmtx \
 	test-subset-cff1 \
 	test-subset-cff2 \
+	test-subset-gvar \
+	test-subset-hvar \
+	test-subset-vvar \
+	test-subset-sbix \
+	test-subset-gpos \
+	test-subset-colr \
+	test-subset-cbdt \
 	test-unicode \
+	test-var-coords \
 	test-version \
-	test-subset-nameids \
 	$(NULL)
 
 test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@@ -67,7 +92,14 @@
 test_subset_vmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cff1_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_gvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_hvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_vvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_sbix_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+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_unicode_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -79,19 +111,6 @@
 test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS)
 endif
 
-
-TEST_PROGS += \
-	test-ot-color \
-	test-ot-ligature-carets \
-	test-ot-name \
-	test-ot-meta \
-	test-ot-metrics \
-	test-ot-tag \
-	test-ot-extents-cff \
-	test-ot-metrics-tt-var \
-	$(NULL)
-
-
 if HAVE_PTHREAD
 if HAVE_FREETYPE
 TEST_PROGS += test-multithread
@@ -111,12 +130,7 @@
 test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
 endif # HAVE_FREETYPE
 
-
 # Tests for header compilation
-TEST_PROGS += \
-	test-c \
-	test-cplusplus \
-	$(NULL)
 test_cplusplus_SOURCES = test-cplusplus.cc
 test_c_CPPFLAGS = $(AM_CPPFLAGS)
 test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/test/shaping/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf b/test/api/fonts/AdobeVFPrototype-Subset.otf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf
copy to test/api/fonts/AdobeVFPrototype-Subset.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.WA.gpos.otf b/test/api/fonts/AdobeVFPrototype.WA.gpos.otf
new file mode 100644
index 0000000..7dd6fb5
--- /dev/null
+++ b/test/api/fonts/AdobeVFPrototype.WA.gpos.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf b/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf
new file mode 100644
index 0000000..c9da07b
--- /dev/null
+++ b/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.abc.otf b/test/api/fonts/AdobeVFPrototype.abc.otf
index cc47708..0e403a6 100644
--- a/test/api/fonts/AdobeVFPrototype.abc.otf
+++ b/test/api/fonts/AdobeVFPrototype.abc.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
index 935bdbf..55ab495 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf
index 85f6cf6..5533baa 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
index ad4d53b..d90f3ef 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.otf b/test/api/fonts/AdobeVFPrototype.ac.otf
index beab7d5..96eb2eb 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.otf
Binary files differ
diff --git a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
index 8cb3005..8ff99c6 100644
--- a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
+++ b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/Cantarell.A.otf b/test/api/fonts/Cantarell.A.otf
new file mode 100644
index 0000000..da06ff7
--- /dev/null
+++ b/test/api/fonts/Cantarell.A.otf
Binary files differ
diff --git a/test/api/fonts/Estedad-VF.ttf b/test/api/fonts/Estedad-VF.ttf
new file mode 100644
index 0000000..f6c22b7
--- /dev/null
+++ b/test/api/fonts/Estedad-VF.ttf
Binary files differ
diff --git a/test/api/fonts/Mada-VF.ttf b/test/api/fonts/Mada-VF.ttf
new file mode 100644
index 0000000..e6f4404
--- /dev/null
+++ b/test/api/fonts/Mada-VF.ttf
Binary files differ
diff --git a/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf b/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf
new file mode 100644
index 0000000..00a4b0a
--- /dev/null
+++ b/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf
Binary files differ
diff --git a/test/api/fonts/Mplus1p-Regular.ttf b/test/api/fonts/Mplus1p-Regular.ttf
new file mode 100644
index 0000000..f89a28e
--- /dev/null
+++ b/test/api/fonts/Mplus1p-Regular.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf
new file mode 100644
index 0000000..94efc6a
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.cmap.ttf b/test/api/fonts/NotoColorEmoji.cmap.ttf
new file mode 100644
index 0000000..c1dd869
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.cmap.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf b/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf
new file mode 100644
index 0000000..b577752
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.default.39.ttf b/test/api/fonts/NotoColorEmoji.subset.default.39.ttf
new file mode 100644
index 0000000..34e878e
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.default.39.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf
new file mode 100644
index 0000000..e7f361a
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf
new file mode 100644
index 0000000..df1ff9b
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf
new file mode 100644
index 0000000..8d2fb18
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
new file mode 100644
index 0000000..cdccded
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
Binary files differ
diff --git a/test/api/fonts/NotoColorEmoji.subset.ttf b/test/api/fonts/NotoColorEmoji.subset.ttf
new file mode 100644
index 0000000..14a544a
--- /dev/null
+++ b/test/api/fonts/NotoColorEmoji.subset.ttf
Binary files differ
diff --git a/test/api/fonts/NotoNastaliqUrdu-Regular.ttf b/test/api/fonts/NotoNastaliqUrdu-Regular.ttf
new file mode 100644
index 0000000..891f633
--- /dev/null
+++ b/test/api/fonts/NotoNastaliqUrdu-Regular.ttf
Binary files differ
diff --git a/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf b/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf
new file mode 100644
index 0000000..42bb608
--- /dev/null
+++ b/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf
Binary files differ
diff --git a/test/api/fonts/OpenSans-Regular.ttf b/test/api/fonts/OpenSans-Regular.ttf
new file mode 100644
index 0000000..db43334
--- /dev/null
+++ b/test/api/fonts/OpenSans-Regular.ttf
Binary files differ
diff --git a/test/api/fonts/Qahiri-Regular.ttf b/test/api/fonts/Qahiri-Regular.ttf
new file mode 100644
index 0000000..d97cbcb
--- /dev/null
+++ b/test/api/fonts/Qahiri-Regular.ttf
Binary files differ
diff --git a/test/api/fonts/README b/test/api/fonts/README
index 4830c47..29038b5 100644
--- a/test/api/fonts/README
+++ b/test/api/fonts/README
@@ -3,3 +3,9 @@
 Inconsolata-Regular.abc.widerc.ttf has the hmtx width of "c" set to 600; everything else is 500. Subsetting out c should reduce numberOfHMetrics to 1.
 
 chromacheck-* fonts are from https://github.com/RoelN/ChromaCheck/tree/master/fonts and licensed under MIT by Roel Nieskens and Google.
+
+RanaKufi-Regular.subset.otf is from https://github.com/alif-type/rana-kufi/ but the subset is licensed for us in MIT for the project use.
+
+glyphs.ttf is from https://github.com/RazrFalcon/ttf-parser/blob/337e7d1/tests/fonts/glyphs.ttf
+
+Estedad-VF.ttf, licensed under OFL 1.1, is from https://github.com/aminabedi68/Estedad
diff --git a/test/api/fonts/RanaKufi-Regular.subset.otf b/test/api/fonts/RanaKufi-Regular.subset.otf
new file mode 100644
index 0000000..a327a2c
--- /dev/null
+++ b/test/api/fonts/RanaKufi-Regular.subset.otf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular-gpos-.aw.ttf b/test/api/fonts/Roboto-Regular-gpos-.aw.ttf
new file mode 100644
index 0000000..74ab2bd
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular-gpos-.aw.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular-gpos-aw.ttf b/test/api/fonts/Roboto-Regular-gpos-aw.ttf
new file mode 100644
index 0000000..2d03cc3
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular-gpos-aw.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
index 7860f2f..073d461 100644
--- a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
+++ b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.abc.ttf b/test/api/fonts/Roboto-Regular.abc.ttf
index 705ec69..3d481e7 100644
--- a/test/api/fonts/Roboto-Regular.abc.ttf
+++ b/test/api/fonts/Roboto-Regular.abc.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.abcAE.ttf b/test/api/fonts/Roboto-Regular.abcAE.ttf
new file mode 100644
index 0000000..b3aae5b
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.abcAE.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.ac.ttf b/test/api/fonts/Roboto-Regular.ac.ttf
index 5a5e68e..b735a46 100644
--- a/test/api/fonts/Roboto-Regular.ac.ttf
+++ b/test/api/fonts/Roboto-Regular.ac.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.bAE.ttf b/test/api/fonts/Roboto-Regular.bAE.ttf
new file mode 100644
index 0000000..c7d1b3a
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.bAE.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.empty.ttf b/test/api/fonts/Roboto-Regular.empty.ttf
new file mode 100644
index 0000000..fbd4fba
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.empty.ttf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
index fa2a0e4..1e5cc96 100644
--- a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.otf b/test/api/fonts/SourceSansPro-Regular.otf
new file mode 100644
index 0000000..279e691
--- /dev/null
+++ b/test/api/fonts/SourceSansPro-Regular.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf b/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf
new file mode 100644
index 0000000..09b13c5
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf b/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf
new file mode 100644
index 0000000..7065045
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman.abc.ttf b/test/api/fonts/SourceSansVariable-Roman.abc.ttf
new file mode 100644
index 0000000..dbbc388
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman.abc.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf b/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf
new file mode 100644
index 0000000..9f9ecd6
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman.ac.ttf b/test/api/fonts/SourceSansVariable-Roman.ac.ttf
new file mode 100644
index 0000000..c12daf2
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman.ac.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf
index 7d94abc..7ad8a8c 100644
--- a/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf
+++ b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf
new file mode 100644
index 0000000..a535734
--- /dev/null
+++ b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf
new file mode 100644
index 0000000..8326bec
--- /dev/null
+++ b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf
Binary files differ
diff --git a/test/api/fonts/Stroking.otf b/test/api/fonts/Stroking.otf
new file mode 100644
index 0000000..a14c361
--- /dev/null
+++ b/test/api/fonts/Stroking.otf
Binary files differ
diff --git a/test/api/fonts/Stroking.ttf b/test/api/fonts/Stroking.ttf
new file mode 100644
index 0000000..b88c6fa
--- /dev/null
+++ b/test/api/fonts/Stroking.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAREight.ttf b/test/api/fonts/TestGVAREight.ttf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/TestGVAREight.ttf
copy to test/api/fonts/TestGVAREight.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARFour.ttf b/test/api/fonts/TestGVARFour.ttf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/TestGVARFour.ttf
copy to test/api/fonts/TestGVARFour.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAROne.ttf b/test/api/fonts/TestGVAROne.ttf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/TestGVAROne.ttf
copy to test/api/fonts/TestGVAROne.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARThree.ttf b/test/api/fonts/TestGVARThree.ttf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/TestGVARThree.ttf
copy to test/api/fonts/TestGVARThree.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARTwo.ttf b/test/api/fonts/TestGVARTwo.ttf
similarity index 100%
copy from test/shaping/data/text-rendering-tests/fonts/TestGVARTwo.ttf
copy to test/api/fonts/TestGVARTwo.ttf
Binary files differ
diff --git a/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf b/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf
new file mode 100644
index 0000000..ea7411a
--- /dev/null
+++ b/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf
Binary files differ
diff --git a/test/api/fonts/TwemojiMozilla.subset.default.32.ttf b/test/api/fonts/TwemojiMozilla.subset.default.32.ttf
new file mode 100644
index 0000000..9ac8407
--- /dev/null
+++ b/test/api/fonts/TwemojiMozilla.subset.default.32.ttf
Binary files differ
diff --git a/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf b/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf
new file mode 100644
index 0000000..7119a37
--- /dev/null
+++ b/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf
Binary files differ
diff --git a/test/api/fonts/TwemojiMozilla.subset.ttf b/test/api/fonts/TwemojiMozilla.subset.ttf
new file mode 100644
index 0000000..5045cb3
--- /dev/null
+++ b/test/api/fonts/TwemojiMozilla.subset.ttf
Binary files differ
diff --git a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
index 8c198b7..dc79b69 100644
--- a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
+++ b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160
new file mode 100644
index 0000000..b36f5b1
--- /dev/null
+++ b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160
Binary files differ
diff --git a/test/api/fonts/glyphs.ttf b/test/api/fonts/glyphs.ttf
new file mode 100644
index 0000000..64ff55e
--- /dev/null
+++ b/test/api/fonts/glyphs.ttf
Binary files differ
diff --git a/test/api/fonts/lcar.ttf b/test/api/fonts/lcar.ttf
deleted file mode 100644
index 4d17663..0000000
--- a/test/api/fonts/lcar.ttf
+++ /dev/null
Binary files differ
diff --git a/test/api/fonts/sbix.ttf b/test/api/fonts/sbix.ttf
new file mode 100644
index 0000000..575af90
--- /dev/null
+++ b/test/api/fonts/sbix.ttf
Binary files differ
diff --git a/test/api/fonts/sbix_X.ttf b/test/api/fonts/sbix_X.ttf
new file mode 100644
index 0000000..6960f8f
--- /dev/null
+++ b/test/api/fonts/sbix_X.ttf
Binary files differ
diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h
index 99f567a..61a9260 100644
--- a/test/api/hb-subset-test.h
+++ b/test/api/hb-subset-test.h
@@ -69,8 +69,14 @@
 hb_subset_test_create_input_from_nameids (const hb_set_t *name_ids)
 {
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
-  hb_set_t * input_name_ids  = hb_subset_input_nameid_set (input);
+  hb_set_t * input_name_ids  = hb_subset_input_set (input, HB_SUBSET_SETS_NAME_ID);
   hb_set_set (input_name_ids, name_ids);
+
+  hb_set_t *name_langids = hb_subset_input_set (input, HB_SUBSET_SETS_NAME_LANG_ID);
+  hb_set_add_range (name_langids, 0, 0x5FFF);
+
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_NAME_LEGACY);
   return input;
 }
 
@@ -78,7 +84,7 @@
 hb_subset_test_create_subset (hb_face_t *source,
 			      hb_subset_input_t *input)
 {
-  hb_face_t *subset = hb_subset (source, input);
+  hb_face_t *subset = hb_subset_or_fail (source, input);
   g_assert (subset);
 
   hb_subset_input_destroy (input);
@@ -94,7 +100,10 @@
   expected_blob = hb_face_reference_table (expected, table);
   actual_blob = hb_face_reference_table (actual, table);
   fprintf(stderr, "comparing %c%c%c%c, expected %d bytes, actual %d bytes\n", HB_UNTAG(table), hb_blob_get_length(expected_blob), hb_blob_get_length (actual_blob));
-  hb_test_assert_blobs_equal (expected_blob, actual_blob);
+
+  if (hb_blob_get_length (expected_blob) != 0 ||
+      hb_blob_get_length (actual_blob) != 0)
+    hb_test_assert_blobs_equal (expected_blob, actual_blob);
   hb_blob_destroy (expected_blob);
   hb_blob_destroy (actual_blob);
 }
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index b866e44..7390e57 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -104,25 +104,25 @@
 static inline void
 hb_test_bug_freedesktop (unsigned int number)
 {
-  hb_test_bug ("http://bugs.freedesktop.org/", number);
+  hb_test_bug ("https://bugs.freedesktop.org/", number);
 }
 
 static inline void
 hb_test_bug_gnome (unsigned int number)
 {
-  hb_test_bug ("http://bugzilla.gnome.org/", number);
+  hb_test_bug ("https://bugzilla.gnome.org/", number);
 }
 
 static inline void
 hb_test_bug_mozilla (unsigned int number)
 {
-  hb_test_bug ("http://bugzilla.mozilla.org/", number);
+  hb_test_bug ("https://bugzilla.mozilla.org/", number);
 }
 
 static inline void
 hb_test_bug_redhat (unsigned int number)
 {
-  hb_test_bug ("http://bugzilla.redhat.com/", number);
+  hb_test_bug ("https://bugzilla.redhat.com/", number);
 }
 
 
@@ -296,9 +296,9 @@
   char *path = g_strdup (font_path);
 #endif
 
-  hb_blob_t *blob = hb_blob_create_from_file (path);
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (path);
   hb_face_t *face;
-  if (hb_blob_get_length (blob) == 0)
+  if (!blob)
     g_error ("Font %s not found.", path);
 
   face = hb_face_create (blob, 0);
diff --git a/test/api/meson.build b/test/api/meson.build
new file mode 100644
index 0000000..7ea2954
--- /dev/null
+++ b/test/api/meson.build
@@ -0,0 +1,91 @@
+if conf.get('HAVE_GLIB', 0) == 0
+  message('You need to have glib support enabled to run test/api tests')
+  subdir_done()
+endif
+
+tests = [
+  'test-aat-layout.c',
+  'test-baseline.c',
+  'test-blob.c',
+  'test-buffer.c',
+  'test-c.c',
+  'test-collect-unicodes.c',
+  'test-cplusplus.cc',
+  'test-common.c',
+  'test-draw.c',
+  'test-font.c',
+  'test-font-scale.c',
+  'test-map.c',
+  'test-object.c',
+  'test-ot-alternates.c',
+  'test-ot-collect-glyphs.c',
+  'test-ot-color.c',
+  'test-ot-face.c',
+  'test-ot-glyphname.c',
+  'test-ot-layout.c',
+  'test-ot-ligature-carets.c',
+  'test-ot-name.c',
+  'test-ot-meta.c',
+  'test-ot-metrics.c',
+  'test-ot-tag.c',
+  'test-ot-extents-cff.c',
+  'test-ot-metrics-tt-var.c',
+  'test-set.c',
+  'test-shape.c',
+  'test-style.c',
+  'test-subset.c',
+  'test-subset-cmap.c',
+  'test-subset-drop-tables.c',
+  'test-subset-glyf.c',
+  'test-subset-hdmx.c',
+  'test-subset-hmtx.c',
+  'test-subset-nameids.c',
+  'test-subset-os2.c',
+  'test-subset-post.c',
+  'test-subset-vmtx.c',
+  'test-subset-cff1.c',
+  'test-subset-cff2.c',
+  'test-subset-gvar.c',
+  'test-subset-hvar.c',
+  'test-subset-vvar.c',
+  'test-subset-sbix.c',
+  'test-subset-gpos.c',
+  'test-subset-colr.c',
+  'test-subset-cbdt.c',
+  'test-unicode.c',
+  'test-var-coords.c',
+  'test-version.c',
+]
+
+if conf.get('HAVE_FREETYPE', 0) == 1
+  tests += 'test-ot-math.c'
+endif
+
+if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_PTHREAD', 0) == 1
+  tests += 'test-multithread.c'
+endif
+
+# Default test running environment
+env = environment()
+env.set('MALLOC_CHECK_', '2')
+env.set('G_DEBUG', 'gc-friendly')
+env.set('G_SLICE', 'always-malloc')
+env.set('G_TEST_SRCDIR', meson.current_source_dir())
+env.set('G_TEST_BUILDDIR', meson.current_build_dir())
+
+foreach source : tests
+  test_name = source.split('.')[0]
+
+  deps = [glib_dep, freetype_dep, thread_dep, libharfbuzz_dep, libharfbuzz_icu_dep]
+  suite = ['api']
+  if test_name.contains('-subset')
+    deps += libharfbuzz_subset_dep
+    suite += 'subset'
+  endif
+
+  test(test_name, executable(test_name, source,
+    include_directories: [incconfig],
+    dependencies: deps,
+    install: false,
+  ), env: env, suite: suite)
+endforeach
diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c
index 228f0f3..4b48d5c 100644
--- a/test/api/test-buffer.c
+++ b/test/api/test-buffer.c
@@ -71,7 +71,7 @@
 
     case BUFFER_ONE_BY_ONE:
       for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++)
-	hb_buffer_add (b, utf32[i], i);
+      hb_buffer_add (b, utf32[i], i);
       break;
 
     case BUFFER_UTF32:
@@ -856,6 +856,74 @@
   g_assert (!hb_buffer_allocation_successful (b));
 }
 
+typedef struct {
+  const char *contents;
+  hb_buffer_serialize_format_t format;
+  unsigned int num_items;
+  hb_bool_t success;
+} serialization_test_t;
+
+static const serialization_test_t serialization_tests[] = {
+  { "<U+0640=0|U+0635=1>", HB_BUFFER_SERIALIZE_FORMAT_TEXT, 2, 1 },
+  { "[{\"u\":1600,\"cl\":0},{\"u\":1589,\"cl\":1}]", HB_BUFFER_SERIALIZE_FORMAT_JSON, 2, 1 },
+
+  /* Mixed glyphs/Unicodes -> parse fail */
+  { "[{\"u\":1600,\"cl\":0},{\"g\":1589,\"cl\":1}]", HB_BUFFER_SERIALIZE_FORMAT_JSON, 0, 0 },
+  { "<U+0640=0|uni0635=1>", HB_BUFFER_SERIALIZE_FORMAT_TEXT, 0, 0 },
+};
+
+static void
+test_buffer_serialize_deserialize (void)
+{
+  hb_buffer_t *b;
+  unsigned int i;
+
+  for (i = 0; i < G_N_ELEMENTS (serialization_tests); i++)
+  {
+    unsigned int consumed;
+    char round_trip[1024];
+
+    b = hb_buffer_create ();
+    hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -1);
+
+    const serialization_test_t *test = &serialization_tests[i];
+    g_test_message ("serialize test #%d", i);
+
+    (void) hb_buffer_deserialize_unicode (b, test->contents, -1, NULL, test->format);
+
+    // Expected parse failure, got one, don't round-trip
+    if (test->success != 0)
+    {
+      unsigned int num_glyphs = hb_buffer_get_length (b);
+      g_assert_cmpint (num_glyphs, ==, test->num_items);
+
+      hb_buffer_serialize_unicode (b, 0, num_glyphs, round_trip,
+				   sizeof(round_trip), &consumed, test->format,
+				   HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+      g_assert_cmpstr (round_trip, ==, test->contents);
+    }
+
+    hb_buffer_destroy (b);
+
+  }
+
+  char test[1024];
+  unsigned int consumed;
+  hb_buffer_t *indeterminate = hb_buffer_get_empty ();
+  hb_buffer_serialize (indeterminate, 0, (unsigned) -1,
+		       test, sizeof(test), &consumed, NULL,
+		       HB_BUFFER_SERIALIZE_FORMAT_JSON,
+		       HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+  g_assert_cmpstr ( test, ==, "[]");
+
+  hb_buffer_serialize (indeterminate, 0, (unsigned) - 1,
+		       test, sizeof(test), &consumed, NULL,
+		       HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+		       HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+  g_assert_cmpstr ( test, ==, "!!");
+
+}
+
 int
 main (int argc, char **argv)
 {
@@ -880,6 +948,7 @@
   hb_test_add (test_buffer_utf16_conversion);
   hb_test_add (test_buffer_utf32_conversion);
   hb_test_add (test_buffer_empty);
+  hb_test_add (test_buffer_serialize_deserialize);
 
   return hb_test_run();
 }
diff --git a/test/api/test-draw.c b/test/api/test-draw.c
new file mode 100644
index 0000000..c502f7d
--- /dev/null
+++ b/test/api/test-draw.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright © 2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+#ifdef HB_EXPERIMENTAL_API
+typedef struct user_data_t
+{
+  char *str;
+  unsigned size;
+  unsigned consumed;
+} user_data_t;
+
+/* Our modified itoa, why not using libc's? it is going to be used
+   in harfbuzzjs where libc isn't available */
+static void _hb_reverse (char *buf, unsigned int len)
+{
+  unsigned start = 0, end = len - 1;
+  while (start < end)
+  {
+    char c = buf[end];
+    buf[end] = buf[start];
+    buf[start] = c;
+    start++; end--;
+  }
+}
+static unsigned _hb_itoa (int32_t num, char *buf)
+{
+  unsigned int i = 0;
+  hb_bool_t is_negative = num < 0;
+  if (is_negative) num = -num;
+  do
+  {
+    buf[i++] = '0' + num % 10;
+    num /= 10;
+  } while (num);
+  if (is_negative) buf[i++] = '-';
+  _hb_reverse (buf, i);
+  buf[i] = '\0';
+  return i;
+}
+
+#define ITOA_BUF_SIZE 12 // 10 digits in int32, 1 for negative sign, 1 for \0
+
+static void
+test_itoa (void)
+{
+  char s[] = "12345";
+  _hb_reverse (s, 5);
+  g_assert_cmpmem (s, 5, "54321", 5);
+
+  {
+    unsigned num = 12345;
+    char buf[ITOA_BUF_SIZE];
+    unsigned len = _hb_itoa (num, buf);
+    g_assert_cmpmem (buf, len, "12345", 5);
+  }
+
+  {
+    unsigned num = 3152;
+    char buf[ITOA_BUF_SIZE];
+    unsigned len = _hb_itoa (num, buf);
+    g_assert_cmpmem (buf, len, "3152", 4);
+  }
+
+  {
+    int num = -6457;
+    char buf[ITOA_BUF_SIZE];
+    unsigned len = _hb_itoa (num, buf);
+    g_assert_cmpmem (buf, len, "-6457", 5);
+  }
+}
+
+static void
+move_to (hb_position_t to_x, hb_position_t to_y, user_data_t *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);
+}
+
+static void
+line_to (hb_position_t to_x, hb_position_t to_y, user_data_t *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);
+}
+
+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)
+{
+
+  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);
+}
+
+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)
+{
+  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);
+}
+
+static void
+close_path (user_data_t *user_data)
+{
+  if (user_data->consumed + 2 > user_data->size) return;
+  user_data->str[user_data->consumed++] = 'Z';
+}
+
+static hb_draw_funcs_t *funcs;
+static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic ones */
+
+static void
+test_hb_draw_empty (void)
+{
+  g_assert (!hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL));
+}
+
+static void
+test_hb_draw_glyf (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  char str[1024];
+  user_data_t user_data = {
+    .str = str,
+    .size = sizeof (str),
+    .consumed = 0
+  };
+
+  user_data.consumed = 0;
+  g_assert (!hb_font_draw_glyph (font, 4, funcs, &user_data));
+
+  user_data.consumed = 0;
+  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_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"
+		    "Q198,-13 148,18Q97,48 70,104Q43,160 43,236Q43,314 76,371"
+		    "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);
+
+  /* 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));
+  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"
+		     "L451,116C438,75 415,43 384,21C352,-2 313,-13 266,-13C221,-13 181,-3 148,18"
+		     "C114,38 88,67 70,104C52,141 43,185 43,236C43,288 54,333 76,371"
+		     "C97,408 125,437 160,457C195,477 232,487 272,487C301,487 329,481 354,470"
+		     "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);
+
+  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));
+  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"
+		     "Q211,-16 153,13Q95,41 60,98Q25,156 25,241Q25,323 62,382"
+		     "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);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_hb_draw_cff1 (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf");
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  char str[1024];
+  user_data_t user_data = {
+    .str = str,
+    .size = sizeof (str),
+    .consumed = 0
+  };
+  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_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);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_hb_draw_cff1_rline (void)
+{
+  /* https://github.com/harfbuzz/harfbuzz/pull/2053 */
+  hb_face_t *face = hb_test_open_font_file ("fonts/RanaKufi-Regular.subset.otf");
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  char str[1024];
+  user_data_t user_data = {
+    .str = str,
+    .size = sizeof (str),
+    .consumed = 0
+  };
+  g_assert (hb_font_draw_glyph (font, 1, funcs, &user_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);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_hb_draw_cff2 (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  char str[1024];
+  user_data_t user_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+
+  user_data.consumed = 0;
+  g_assert (hb_font_draw_glyph (font, 3, funcs, &user_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);
+
+  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));
+  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);
+
+  hb_font_destroy (font);
+}
+
+static void
+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 = {
+    .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_face_destroy (face);
+    {
+      user_data.consumed = 0;
+      g_assert (hb_font_draw_glyph (font, 0, funcs, &user_data));
+      char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
+      g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
+    }
+    {
+      user_data.consumed = 0;
+      g_assert (hb_font_draw_glyph (font, 1, funcs, &user_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);
+    }
+    {
+      user_data.consumed = 0;
+      g_assert (hb_font_draw_glyph (font, 4, funcs, &user_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"
+			"Q240,693 219,664Q197,634 197,571L197,536L332,536L332,468Z"
+			"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);
+    }
+    {
+      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);
+    }
+    {
+      user_data.consumed = 0;
+      g_assert (hb_font_draw_glyph (font, 6, funcs, &user_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);
+    }
+
+    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_face_destroy (face);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 1, funcs, &user_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);
+
+    hb_font_destroy (font);
+  }
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/cff1_dotsect.nohints.otf");
+    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));
+    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);
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+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 = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  /* truetype glyphs */
+  {
+    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);
+
+    /* should get a path for the glyph */
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 37, funcs, &user_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);
+
+    /* should get a path for the glyph */
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 171, funcs, &user_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);
+
+    hb_font_destroy (font);
+  }
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_buffer_t *buffer = hb_buffer_create ();
+    hb_codepoint_t codepoint = 1610; /* ي */
+    hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+    hb_buffer_set_direction (buffer, HB_DIRECTION_RTL);
+    hb_shape (font, buffer, NULL, 0);
+    codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint;
+    hb_buffer_destroy (buffer);
+
+    /* should resolve composite glyphs recursively */
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_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"
+		      "Q88,-44 118,-64Q147,-85 181,-94Q214,-104 243,-104L473,-104"
+		      "Q501,-104 525,-91Q549,-78 564,-56Q578,-34 578,-8Q578,18 557,43"
+		      "L442,182Q439,179 437,176Q435,173 432,170L581,170L581,274ZM184,-194"
+		      "Q184,-216 199,-231Q214,-246 236,-246Q258,-246 273,-231Q288,-216 288,-194"
+		      "Q288,-172 273,-157Q258,-142 236,-142Q214,-142 199,-157Q184,-172 184,-194Z"
+		      "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);
+
+    /* 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 */
+    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);
+
+    hb_font_destroy (font);
+  }
+  /* CFF glyphs, should get a path for the glyph */
+  {
+    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);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 5, funcs, &user_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);
+
+    hb_font_destroy (font);
+  }
+  /* CFF glyphs (CID font) */
+  {
+    /* replaced with a subset as the original one was 15MB */
+    hb_face_t *face = hb_test_open_font_file ("fonts/NotoSansCJKkr-Regular-subset-colon.ttf");
+    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));
+    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);
+
+    hb_font_destroy (font);
+  }
+  /* Skip SBIX glyphs (empty path), COLR glyphs (empty path), WOFF ttf glyphs, WOFF2 ttf glyph */
+}
+
+static void
+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 = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  /* Skia */
+  {
+    /* Skipping Skia tests for now even the fact we can actually do platform specific tests using our CIs */
+  }
+  /* truetype variations */
+  /* should support sharing all points */
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/TestGVAROne.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_variation_t var;
+    var.tag = HB_TAG ('w','g','h','t');
+    var.value = 300;
+    hb_font_set_variations (font, &var, 1);
+
+    hb_buffer_t *buffer = hb_buffer_create ();
+    hb_codepoint_t codepoint = 24396; /* 彌 */
+    hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+    hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+    hb_shape (font, buffer, NULL, 0);
+    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));
+    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"
+		      "Q137,-59 188,-59Q211,-59 222,-46Q233,-34 236,12Q238,58 240,135"
+		      "Q242,211 242,262L74,262L94,527L242,527L242,719L63,719L63,754"
+		      "L285,754L285,492L133,492L117,297L285,297Q285,241 284,185"
+		      "Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94Z"
+		      "M461,12L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147"
+		      "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20"
+		      "Q544,64 528,86Q500,44 461,12ZM465,258L438,285Q474,316 501,351"
+		      "Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453L598,434"
+		      "Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322Q491,280 465,258Z"
+		      "M707,12L680,43Q717,68 753,115Q731,147 691,188L719,211Q739,190 754,172"
+		      "Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117Q828,82 852,43"
+		      "L820,20Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730L664,-94"
+		      "L621,-94ZM348,570L324,605Q425,629 527,688L555,656Q491,621 439,601"
+		      "Q386,581 348,570ZM715,258L688,285Q727,318 753,351Q733,378 695,418L723,441"
+		      "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);
+
+    hb_font_destroy (font);
+  }
+  /* should support sharing enumerated points */
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/TestGVARTwo.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_variation_t var;
+    var.tag = HB_TAG ('w','g','h','t');
+    var.value = 300;
+    hb_font_set_variations (font, &var, 1);
+
+    hb_buffer_t *buffer = hb_buffer_create ();
+    hb_codepoint_t codepoint = 24396; /* 彌 */
+    hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+    hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+    hb_shape (font, buffer, NULL, 0);
+    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));
+    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"
+		      "Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527"
+		      "L242,719L63,719L63,754L285,754L285,492L133,492L117,297L285,297"
+		      "Q285,241 284,185Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94Z"
+		      "M461,12L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147"
+		      "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20"
+		      "Q544,64 528,86Q500,44 461,12ZM465,258L438,285Q474,316 501,351"
+		      "Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453L598,434"
+		      "Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322Q491,280 465,258Z"
+		      "M707,12L680,43Q717,68 753,115Q731,147 691,188L719,211Q739,190 754,172"
+		      "Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117Q828,82 852,43L820,20"
+		      "Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730L664,-94L621,-94ZM348,570"
+		      "L324,605Q425,629 527,688L555,656Q491,621 439,601Q386,581 348,570ZM715,258L688,285"
+		      "Q727,318 753,351Q733,378 695,418L723,441Q754,410 775,381Q794,407 813,453"
+		      "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);
+
+    hb_font_destroy (font);
+  }
+  /* should support sharing no points */
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/TestGVARThree.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_variation_t var;
+    var.tag = HB_TAG ('w','g','h','t');
+    var.value = 300;
+    hb_font_set_variations (font, &var, 1);
+
+    hb_buffer_t *buffer = hb_buffer_create ();
+    hb_codepoint_t codepoint = 24396; /* 彌 */
+    hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+    hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+    hb_shape (font, buffer, NULL, 0);
+    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));
+    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"
+		      "Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527L242,719"
+		      "L63,719L63,754L285,754L285,492L133,492L117,297L285,297Q285,241 284,185"
+		      "Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94ZM461,12"
+		      "L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147"
+		      "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20Q544,64 528,86"
+		      "Q500,44 461,12ZM465,258L438,285Q474,316 501,351Q474,388 445,418L473,441"
+		      "Q500,414 523,381Q546,413 563,453L598,434Q571,382 549,352Q576,320 598,285"
+		      "L563,262Q546,294 525,322Q491,280 465,258ZM707,12L680,43Q717,68 753,115"
+		      "Q731,147 691,188L719,211Q739,190 754,172Q769,154 774,147Q793,185 809,230"
+		      "L844,211Q822,155 801,117Q828,82 852,43L820,20Q798,58 778,87Q747,43 707,12Z"
+		      "M621,-94L621,730L664,730L664,-94L621,-94ZM348,570L324,605Q425,629 527,688"
+		      "L555,656Q491,621 439,601Q386,581 348,570ZM715,258L688,285Q727,318 753,351"
+		      "Q733,378 695,418L723,441Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352"
+		      "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);
+
+    hb_font_destroy (font);
+  }
+
+  /* CFF2 variations */
+  {
+    hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype-Subset.otf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_variation_t var;
+    var.tag = HB_TAG ('w','g','h','t');
+    /* applies variations to CFF2 glyphs */
+    {
+      var.value = 100;
+      hb_font_set_variations (font, &var, 1);
+
+      hb_buffer_t *buffer = hb_buffer_create ();
+      hb_codepoint_t codepoint = '$';
+      hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+      hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+      hb_shape (font, buffer, NULL, 0);
+      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));
+      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"
+		        "C119,592 178,637 262,637C311,637 346,626 390,585L348,629L373,535"
+		        "C380,510 394,503 408,503C424,503 434,510 437,526C418,614 348,665 259,665"
+		        "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);
+    }
+    {
+      var.value = 500;
+      hb_font_set_variations (font, &var, 1);
+
+      hb_buffer_t *buffer = hb_buffer_create ();
+      hb_codepoint_t codepoint = '$';
+      hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+      hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+      hb_shape (font, buffer, NULL, 0);
+      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));
+      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"
+			"C150,571 204,606 276,606C308,606 342,601 386,582L327,621"
+			"L343,546C355,490 382,476 408,476C428,476 448,487 455,512"
+			"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);
+    }
+    /* substitutes GSUB features depending on variations */
+    {
+      var.value = 900;
+      hb_font_set_variations (font, &var, 1);
+
+      hb_buffer_t *buffer = hb_buffer_create ();
+      hb_codepoint_t codepoint = '$';
+      hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1);
+      hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+      hb_shape (font, buffer, NULL, 0);
+      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));
+      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"
+			"C342,589 370,585 420,562L341,607L352,539C363,468 398,454 434,454C459,454 486,468 492,506"
+			"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);
+    }
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+test_hb_draw_estedad_vf (void)
+{
+  /* https://github.com/harfbuzz/harfbuzz/issues/2215 */
+  char str[2048];
+  user_data_t user_data = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  {
+    /* See https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L115-L124 */
+    hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf");
+    hb_font_t *font = hb_font_create (face);
+    hb_face_destroy (face);
+
+    hb_variation_t var;
+    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));
+    /* 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);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 180, funcs, &user_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"
+		       "Q1590,545 1590,693Q1590,842 1534,973Q1477,1104 1377,1205"
+		       "Q1277,1305 1144,1362Q1010,1419 856,1419Q701,1419 567,1362"
+		       "Q433,1305 333,1205Q233,1104 177,973Q120,842 120,693Z"
+		       "M220,693Q220,828 270,945Q320,1061 409,1148Q497,1235 612,1284"
+		       "Q726,1333 855,1333Q984,1333 1099,1284Q1213,1235 1302,1148"
+		       "Q1390,1061 1440,945Q1490,828 1490,693Q1490,558 1440,442"
+		       "Q1390,325 1302,237Q1213,149 1099,100Q984,51 855,51"
+		       "Q726,51 611,100Q497,149 408,237Q320,325 270,442"
+		       "Q220,558 220,693ZM690,643L690,997L886,997Q970,997 1029,949"
+		       "Q1087,901 1087,819Q1087,737 1028,690Q969,643 886,643L690,643Z"
+		       "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);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 262, funcs, &user_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);
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+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 = {
+    .str = str,
+    .size = sizeof (str)
+  };
+  {
+    /* See https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L115-L124 */
+    hb_face_t *face = hb_test_open_font_file ("fonts/Stroking.ttf");
+    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));
+    /* 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"
+		      "Q2816,1764 2722,1985Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712"
+		      "Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985Q436,1764 436,1522ZM256,1528"
+		      "Q256,1714 306,1892Q355,2069 443,2220Q531,2370 658,2497Q784,2623 935,2711"
+		      "Q1085,2799 1263,2849Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711"
+		      "Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892Q2996,1714 2996,1528"
+		      "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);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 7, funcs, &user_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"
+		       "Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712"
+		       "Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985"
+		       "Q436,1764 436,1522ZM256,1528Q256,1714 306,1892Q355,2069 443,2220"
+		       "Q531,2370 658,2497Q784,2623 935,2711Q1085,2799 1263,2849"
+		       "Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711"
+		       "Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892"
+		       "Q2996,1714 2996,1528Q2996,1342 2947,1165Q2897,987 2809,837"
+		       "Q2721,686 2595,560Q2468,433 2318,345Q2167,257 1990,208"
+		       "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);
+
+    hb_font_destroy (font);
+  }
+  {
+    /* https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L131-L138 */
+    hb_face_t *face = hb_test_open_font_file ("fonts/Stroking.otf");
+    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));
+    /* 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);
+
+    user_data.consumed = 0;
+    g_assert (hb_font_draw_glyph (font, 5, funcs, &user_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);
+
+    hb_font_destroy (font);
+  }
+}
+
+static void
+test_hb_draw_immutable (void)
+{
+  hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
+  g_assert (!hb_draw_funcs_is_immutable (draw_funcs));
+  hb_draw_funcs_make_immutable (draw_funcs);
+  g_assert (hb_draw_funcs_is_immutable (draw_funcs));
+  hb_draw_funcs_destroy (draw_funcs);
+}
+
+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_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_make_immutable (funcs2);
+
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_itoa);
+  hb_test_add (test_hb_draw_empty);
+  hb_test_add (test_hb_draw_glyf);
+  hb_test_add (test_hb_draw_cff1);
+  hb_test_add (test_hb_draw_cff1_rline);
+  hb_test_add (test_hb_draw_cff2);
+  hb_test_add (test_hb_draw_ttf_parser_tests);
+  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);
+  hb_test_add (test_hb_draw_immutable);
+  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-font-scale.c b/test/api/test-font-scale.c
new file mode 100644
index 0000000..6949e70
--- /dev/null
+++ b/test/api/test-font-scale.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 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"
+
+#include <hb.h>
+
+/* test for https://github.com/harfbuzz/harfbuzz/issues/3274 */
+
+static void
+test_hb_scale (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Cantarell.A.otf");
+  hb_font_t *font1 = hb_font_create (face);
+  hb_font_t *font2 = hb_font_create (face);
+
+  double scale = 64 * 1024 * 96./72.;
+  hb_font_set_scale (font1, scale, scale);
+  hb_font_set_scale (font2, - scale, - scale);
+
+  g_assert_cmpint (hb_font_get_glyph_h_advance (font1, 1), ==, - hb_font_get_glyph_h_advance (font2, 1));
+
+  hb_font_destroy (font1);
+  hb_font_destroy (font2);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_hb_scale);
+  return hb_test_run ();
+}
diff --git a/test/api/test-map.c b/test/api/test-map.c
index 0911991..02df8b9 100644
--- a/test/api/test-map.c
+++ b/test/api/test-map.c
@@ -104,6 +104,33 @@
   /* Now you can't access them anymore */
 }
 
+static void
+test_map_get_population (void)
+{
+  hb_map_t *m = hb_map_create ();
+
+  hb_map_set (m, 12, 21);
+  g_assert_cmpint (hb_map_get_population (m), ==, 1);
+  hb_map_set (m, 78, 87);
+  g_assert_cmpint (hb_map_get_population (m), ==, 2);
+
+  hb_map_set (m, 78, 87);
+  g_assert_cmpint (hb_map_get_population (m), ==, 2);
+  hb_map_set (m, 78, 13);
+  g_assert_cmpint (hb_map_get_population (m), ==, 2);
+
+  hb_map_set (m, 95, 56);
+  g_assert_cmpint (hb_map_get_population (m), ==, 3);
+
+  hb_map_del (m, 78);
+  g_assert_cmpint (hb_map_get_population (m), ==, 2);
+
+  hb_map_del (m, 103);
+  g_assert_cmpint (hb_map_get_population (m), ==, 2);
+
+  hb_map_destroy (m);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -112,6 +139,7 @@
   hb_test_add (test_map_basic);
   hb_test_add (test_map_userdata);
   hb_test_add (test_map_refcount);
+  hb_test_add (test_map_get_population);
 
   return hb_test_run();
 }
diff --git a/test/api/test-ot-alternates.c b/test/api/test-ot-alternates.c
new file mode 100644
index 0000000..4db6b15
--- /dev/null
+++ b/test/api/test-ot-alternates.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+#include <hb-ot.h>
+
+static void
+test_ot_layout_lookup_get_glyph_alternates (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+
+  hb_codepoint_t alternates[3];
+  unsigned alternates_count = 3;
+  g_assert_cmpuint (7, ==, hb_ot_layout_lookup_get_glyph_alternates (face, 1, 1091, 2, &alternates_count, alternates));
+
+  g_assert_cmpuint (3, ==, alternates_count);
+  g_assert_cmpuint (1606, ==, alternates[0]);
+  g_assert_cmpuint (1578, ==, alternates[1]);
+  g_assert_cmpuint (1592, ==, alternates[2]);
+
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_ot_layout_lookup_get_glyph_alternates);
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-collect-glyphs.c b/test/api/test-ot-collect-glyphs.c
new file mode 100644
index 0000000..3b3b643
--- /dev/null
+++ b/test/api/test-ot-collect-glyphs.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+#include <hb-ot.h>
+
+#define BEGIN(tag, idx) \
+  hb_ot_layout_lookup_collect_glyphs (face, tag, idx, before, input, after, output) \
+
+#define END() \
+  hb_set_clear (before); \
+  hb_set_clear (input); \
+  hb_set_clear (after); \
+  hb_set_clear (output)
+
+static void
+test_ot_layout_lookup_collect_glyphs_source_sans (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf");
+
+  hb_set_t *before = hb_set_create();
+  hb_set_t *input = hb_set_create();
+  hb_set_t *after = hb_set_create();
+  hb_set_t *output = hb_set_create();
+  hb_codepoint_t g = HB_SET_VALUE_INVALID;
+
+  /* SingleSubst */
+  BEGIN(HB_OT_TAG_GSUB, 0);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+  g_assert_cmpuint (684, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (54, ==, g);
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (372, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (574, ==, g);
+  END();
+
+  /* AlternateSubst */
+  BEGIN(HB_OT_TAG_GSUB, 1);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (143, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (2, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (319, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (519, ==, g);
+  END();
+
+  /* MultipleSubst */
+  BEGIN(HB_OT_TAG_GSUB, 7);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (10, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (92, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (9, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (6, ==, g);
+  END();
+
+  /* LigatureSubst */
+  BEGIN(HB_OT_TAG_GSUB, 10);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (14, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (1823, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (22, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (1897, ==, g);
+  END();
+
+  /* ChainContextSubstFormat3 */
+  BEGIN(HB_OT_TAG_GSUB, 8);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (10, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (92, ==, g);
+
+  g_assert_cmpuint (2, ==, hb_set_get_population (after));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (after, &g));
+  g_assert_cmpuint (1826, ==, g);
+  g_assert (hb_set_next (after, &g));
+  g_assert_cmpuint (1837, ==, g);
+
+  g_assert_cmpuint (9, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (6, ==, g);
+  END();
+
+  /* ChainContextSubstFormat3 */
+  BEGIN(HB_OT_TAG_GSUB, 13);
+  g_assert_cmpuint (771, ==, hb_set_get_population (before));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (before, &g));
+  g_assert_cmpuint (2, ==, g);
+
+  g_assert_cmpuint (28, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (1823, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (48, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (325, ==, g);
+  END();
+
+  /* MarkBasePos */
+  BEGIN(HB_OT_TAG_GPOS, 0);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (179, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (28, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  /* MarkMarkPos */
+  BEGIN(HB_OT_TAG_GPOS, 9);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (48, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (1823, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  /* PairPos */
+  BEGIN(HB_OT_TAG_GPOS, 10);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (1426, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (2, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  hb_face_destroy (face);
+  face = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
+
+  /* SinglePosFormat2 */
+  BEGIN(HB_OT_TAG_GPOS, 1);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (1, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (4, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  hb_face_destroy (face);
+  hb_set_destroy (before);
+  hb_set_destroy (input);
+  hb_set_destroy (after);
+  hb_set_destroy (output);
+}
+
+static void
+test_ot_layout_lookup_collect_glyphs_noto_nastaliq (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf");
+
+  hb_set_t *before = hb_set_create();
+  hb_set_t *input = hb_set_create();
+  hb_set_t *after = hb_set_create();
+  hb_set_t *output = hb_set_create();
+  hb_codepoint_t g = HB_SET_VALUE_INVALID;
+
+  /* ExtensionSubst -> ContextSubstFormat1 */
+  BEGIN(HB_OT_TAG_GSUB, 9);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (3, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (228, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (416, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (441, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (3, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (267, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (268, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (279, ==, g);
+  END();
+
+  /* ExtensionSubst -> SingleSubst */
+  BEGIN(HB_OT_TAG_GSUB, 10);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (3, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (228, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (416, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (441, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (3, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (267, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (268, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (279, ==, g);
+  END();
+
+  /* ExtensionSubst -> ChainContextSubstFormat2 */
+  BEGIN(HB_OT_TAG_GSUB, 16);
+  g_assert_cmpuint (16, ==, hb_set_get_population (before));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (before, &g));
+  g_assert_cmpuint (74, ==, g);
+
+  g_assert_cmpuint (27, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (276, ==, g);
+
+  g_assert_cmpuint (14, ==, hb_set_get_population (after));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (after, &g));
+  g_assert_cmpuint (252, ==, g);
+
+  g_assert_cmpuint (43, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (74, ==, g);
+  END();
+
+  /* ExtensionSubst -> ContextSubstFormat2 */
+  BEGIN(HB_OT_TAG_GSUB, 39);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (246, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (252, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (258, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (74, ==, g);
+  END();
+
+
+  /* CursivePos */
+  BEGIN(HB_OT_TAG_GPOS, 0);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (616, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (228, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  /* ExtensionSubst -> MarkLigPos */
+  BEGIN(HB_OT_TAG_GPOS, 13);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (46, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (1004, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  /* ExtensionSubst -> SinglePosFormat1 */
+  BEGIN(HB_OT_TAG_GPOS, 17);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (242, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (257, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+  g_assert_cmpuint (0, ==, hb_set_get_population (output));
+  END();
+
+  hb_face_destroy (face);
+  hb_set_destroy (before);
+  hb_set_destroy (input);
+  hb_set_destroy (after);
+  hb_set_destroy (output);
+}
+
+static void
+test_ot_layout_lookup_collect_glyphs_qahiri (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Qahiri-Regular.ttf");
+
+  hb_set_t *before = hb_set_create();
+  hb_set_t *input = hb_set_create();
+  hb_set_t *after = hb_set_create();
+  hb_set_t *output = hb_set_create();
+  hb_codepoint_t g = HB_SET_VALUE_INVALID;
+
+  /* SingleSubstFormat1 */
+  BEGIN(HB_OT_TAG_GSUB, 0);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (4, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (52, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (60, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (62, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (159, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (4, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (53, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (61, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (63, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (160, ==, g);
+  END();
+
+  /* ChainContextSubstFormat1 */
+  BEGIN(HB_OT_TAG_GSUB, 11);
+  g_assert_cmpuint (1, ==, hb_set_get_population (before));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (before, &g));
+  g_assert_cmpuint (39, ==, g);
+
+  g_assert_cmpuint (2, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (154, ==, g);
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (159, ==, g);
+
+  g_assert_cmpuint (1, ==, hb_set_get_population (after));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (after, &g));
+  g_assert_cmpuint (179, ==, g);
+
+  g_assert_cmpuint (2, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (155, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (162, ==, g);
+  END();
+
+  /* ContextSubstFormat3 */
+  BEGIN(HB_OT_TAG_GSUB, 31);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (4, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (53, ==, g);
+
+  g_assert_cmpuint (0, ==, hb_set_get_population (after));
+
+  g_assert_cmpuint (4, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (52, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (60, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (62, ==, g);
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (159, ==, g);
+  END();
+
+  /* ReverseChainSingleSubst */
+  BEGIN(HB_OT_TAG_GSUB, 32);
+  g_assert_cmpuint (0, ==, hb_set_get_population (before));
+
+  g_assert_cmpuint (42, ==, hb_set_get_population (input));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (input, &g));
+  g_assert_cmpuint (47, ==, g);
+
+  g_assert_cmpuint (46, ==, hb_set_get_population (after));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (after, &g));
+  g_assert_cmpuint (61, ==, g);
+
+  g_assert_cmpuint (42, ==, hb_set_get_population (output));
+  g = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (output, &g));
+  g_assert_cmpuint (463, ==, g);
+  END();
+
+  hb_face_destroy (face);
+  hb_set_destroy (before);
+  hb_set_destroy (input);
+  hb_set_destroy (after);
+  hb_set_destroy (output);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_ot_layout_lookup_collect_glyphs_source_sans);
+  hb_test_add (test_ot_layout_lookup_collect_glyphs_noto_nastaliq);
+  hb_test_add (test_ot_layout_lookup_collect_glyphs_qahiri);
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c
index 7109e30..e6aeb0d 100644
--- a/test/api/test-ot-extents-cff.c
+++ b/test/api/test-ot-extents-cff.c
@@ -170,7 +170,7 @@
 
   g_assert_cmpint (extents.x_bearing, ==, 12);
   g_assert_cmpint (extents.y_bearing, ==, 655);
-  g_assert_cmpint (extents.width, ==, 652);
+  g_assert_cmpint (extents.width, ==, 651);
   g_assert_cmpint (extents.height, ==, -655);
 
   result = hb_font_get_glyph_extents (font, 2, &extents);
@@ -178,7 +178,7 @@
 
   g_assert_cmpint (extents.x_bearing, ==, 8);
   g_assert_cmpint (extents.y_bearing, ==, 669);
-  g_assert_cmpint (extents.width, ==, 649);
+  g_assert_cmpint (extents.width, ==, 648);
   g_assert_cmpint (extents.height, ==, -669);
 
   hb_font_destroy (font);
@@ -201,7 +201,7 @@
 
   g_assert_cmpint (extents.x_bearing, ==, 13);
   g_assert_cmpint (extents.y_bearing, ==, 652);
-  g_assert_cmpint (extents.width, ==, 653);
+  g_assert_cmpint (extents.width, ==, 652);
   g_assert_cmpint (extents.height, ==, -652);
 
   result = hb_font_get_glyph_extents (font, 2, &extents);
diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c
index 44a9116..6a8ebcd 100644
--- a/test/api/test-ot-face.c
+++ b/test/api/test-ot-face.c
@@ -27,22 +27,24 @@
 #ifndef TEST_OT_FACE_NO_MAIN
 #include "hb-test.h"
 #endif
+#include <hb-aat.h>
 #include <hb-ot.h>
 
 /* Unit tests for hb-ot-*.h */
 
-
-static void
-test_face (hb_face_t *face,
-	   hb_codepoint_t cp)
+/* Return some dummy result so that compiler won't just optimize things */
+static long long
+test_font (hb_font_t *font, hb_codepoint_t cp)
 {
-  hb_font_t *font = hb_font_create (face);
+  long long result = 0;
+
+  hb_face_t *face = hb_font_get_face (font);
   hb_set_t *set;
-  hb_codepoint_t g;
-  hb_position_t x, y;
+  hb_codepoint_t g = 0;
+  hb_position_t x = 0, y = 0;
   char buf[5] = {0};
-  unsigned int len;
-  hb_glyph_extents_t extents;
+  unsigned int len = 0;
+  hb_glyph_extents_t extents = {0};
   hb_ot_font_set_funcs (font);
 
   set = hb_set_create ();
@@ -74,12 +76,55 @@
   hb_ot_color_has_png (face);
   hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp));
 
+  {
+    hb_aat_layout_feature_type_t feature = HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC;
+    unsigned count = 1;
+    hb_aat_layout_get_feature_types (face, 0, &count, &feature);
+    hb_aat_layout_feature_type_get_name_id (face, HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE);
+    hb_aat_layout_feature_selector_info_t setting = {0};
+    unsigned default_index;
+    count = 1;
+    hb_aat_layout_feature_type_get_selector_infos (face, HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE, 0, &count, &setting, &default_index);
+    result += count + feature + setting.disable + setting.disable + setting.name_id + setting.reserved + default_index;
+  }
+
+  hb_set_t *lookup_indexes = hb_set_create ();
+  hb_set_add (lookup_indexes, 0);
+
+  hb_map_t *lookup_mapping = hb_map_create ();
+  hb_map_set (lookup_mapping, 0, 0);
+  hb_set_t *feature_indices = hb_set_create ();
+  hb_set_destroy (lookup_indexes);
+  hb_set_destroy (feature_indices);
+  hb_map_destroy (lookup_mapping);
+
   hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL);
 
   hb_ot_layout_has_glyph_classes (face);
   hb_ot_layout_has_substitution (face);
   hb_ot_layout_has_positioning (face);
 
+  hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, cp, 0, NULL, NULL);
+
+  {
+    unsigned temp = 0, temp2 = 0;
+    hb_ot_name_id_t name = HB_OT_NAME_ID_FULL_NAME;
+    hb_ot_layout_get_size_params (face, &temp, &temp, &name, &temp, &temp);
+    hb_tag_t cv01 = HB_TAG ('c','v','0','1');
+    unsigned feature_index = 0;
+    hb_ot_layout_language_find_feature (face, HB_OT_TAG_GSUB, 0,
+					HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+					cv01, &feature_index);
+    hb_ot_layout_feature_get_name_ids (face, HB_OT_TAG_GSUB, feature_index,
+				       &name, &name, &name, &temp, &name);
+    temp = 1;
+    hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index, 0, &temp, &g);
+    temp = 1;
+    hb_ot_layout_language_get_feature_indexes (face, HB_OT_TAG_GSUB, 0, 0, 0, &temp, &temp2);
+
+    result += temp + name + feature_index + temp2;
+  }
+
   hb_ot_math_has_data (face);
   hb_ot_math_get_constant (font, HB_OT_MATH_CONSTANT_MATH_LEADING);
   hb_ot_math_get_glyph_italics_correction (font, cp);
@@ -104,20 +149,36 @@
   hb_ot_name_get_utf16 (face, cp, NULL, NULL, NULL);
   hb_ot_name_get_utf32 (face, cp, NULL, NULL, NULL);
 
+#if 0
+  hb_style_get_value (font, HB_STYLE_TAG_ITALIC);
+  hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE);
+  hb_style_get_value (font, HB_STYLE_TAG_SLANT);
+  hb_style_get_value (font, HB_STYLE_TAG_WIDTH);
+  hb_style_get_value (font, HB_STYLE_TAG_WEIGHT);
+#endif
+
   hb_ot_var_get_axis_count (face);
   hb_ot_var_get_axis_infos (face, 0, NULL, NULL);
   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);
-  hb_font_destroy (font);
+
+  return result + g + x + y + buf[0] + buf[1] + buf[2] + buf[3] + buf[4] + len +
+	 extents.height + extents.width + extents.x_bearing + extents.y_bearing;
 }
 
 #ifndef TEST_OT_FACE_NO_MAIN
 static void
 test_ot_face_empty (void)
 {
-  test_face (hb_face_get_empty (), 0);
+  test_font (hb_font_get_empty (), 0);
 }
 
 static void
diff --git a/test/api/test-ot-glyphname.c b/test/api/test-ot-glyphname.c
new file mode 100644
index 0000000..635da9f
--- /dev/null
+++ b/test/api/test-ot-glyphname.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2019  Adobe, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include "hb-ot.h"
+
+static void
+test_one_glyph (hb_font_t *font,  hb_codepoint_t gid, const char *name)
+{
+  char			buf[64];
+  hb_codepoint_t	glyph;
+
+  g_assert(hb_font_get_glyph_name (font, gid, buf, sizeof (buf)));
+  g_assert_cmpstr(buf, ==, name);
+  g_assert(hb_font_get_glyph_from_name (font, name, -1, &glyph));
+  g_assert_cmpint(glyph, ==, gid);
+}
+
+/* Unit tests for CFF glyph names  */
+
+static void
+test_standard_names (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/MathTestFontFull.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  test_one_glyph (font, 0,   ".notdef");
+  test_one_glyph (font, 27,  "Z");
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_non_standard_names (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/MathTestFontFull.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  test_one_glyph (font, 46,  "arrowdblright");
+  test_one_glyph (font, 138, "uni21E7_size5");
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_predef_charset_names (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/cff1_expert.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  test_one_glyph (font, 0,   ".notdef");
+  test_one_glyph (font, 29,  "centsuperior");
+  test_one_glyph (font, 86,  "commainferior");
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_standard_names);
+  hb_test_add (test_non_standard_names);
+  hb_test_add (test_predef_charset_names);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-ot-layout.c b/test/api/test-ot-layout.c
new file mode 100644
index 0000000..5c6ccce
--- /dev/null
+++ b/test/api/test-ot-layout.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+#include <hb-ot.h>
+
+#define STATIC_ARRAY_SIZE 255
+
+static void
+test_ot_layout_table_get_script_tags (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf");
+
+  unsigned int total = 0;
+  unsigned int count = STATIC_ARRAY_SIZE;
+  unsigned int offset = 0;
+  hb_tag_t tags[STATIC_ARRAY_SIZE];
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_table_get_script_tags (face, HB_OT_TAG_GSUB, offset, &count, tags);
+    g_assert_cmpuint (3, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (3, ==, count);
+      g_assert_cmpuint (HB_TAG ('a','r','a','b'), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('d','f','l','t'), ==, tags[1]);
+      g_assert_cmpuint (HB_TAG ('l','a','t','n'), ==, tags[2]);
+    }
+  }
+  count = STATIC_ARRAY_SIZE;
+  offset = 0;
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_table_get_script_tags (face, HB_OT_TAG_GPOS, offset, &count, tags);
+    g_assert_cmpuint (1, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (1, ==, count);
+      g_assert_cmpuint (HB_TAG ('a','r','a','b'), ==, tags[0]);
+    }
+  }
+
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_table_find_script (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf");
+  unsigned int index;
+
+  g_assert (hb_ot_layout_table_find_script (face, HB_OT_TAG_GSUB, HB_TAG ('a','r','a','b'), &index));
+  g_assert_cmpuint (0, ==, index);
+  g_assert (hb_ot_layout_table_find_script (face, HB_OT_TAG_GSUB, HB_TAG ('d','f','l','t'), &index));
+  g_assert_cmpuint (1, ==, index);
+  g_assert (hb_ot_layout_table_find_script (face, HB_OT_TAG_GSUB, HB_TAG ('l','a','t','n'), &index));
+  g_assert_cmpuint (2, ==, index);
+
+  g_assert (hb_ot_layout_table_find_script (face, HB_OT_TAG_GPOS, HB_TAG ('a','r','a','b'), &index));
+  g_assert_cmpuint (0, ==, index);
+  g_assert (!hb_ot_layout_table_find_script (face, HB_OT_TAG_GPOS, HB_TAG ('d','f','l','t'), &index));
+  g_assert_cmpuint (0xFFFF, ==, index);
+  g_assert (!hb_ot_layout_table_find_script (face, HB_OT_TAG_GPOS, HB_TAG ('l','a','t','n'), &index));
+  g_assert_cmpuint (0xFFFF, ==, index);
+
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_table_get_feature_tags (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf");
+
+  unsigned int total = 0;
+  unsigned int count = STATIC_ARRAY_SIZE;
+  unsigned int offset = 0;
+  hb_tag_t tags[STATIC_ARRAY_SIZE];
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_table_get_feature_tags (face, HB_OT_TAG_GSUB, offset, &count, tags);
+    g_assert_cmpuint (14, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (14, ==, count);
+      g_assert_cmpuint (HB_TAG ('c','c','m','p'), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('i','s','o','l'), ==, tags[10]);
+      g_assert_cmpuint (HB_TAG ('r','l','i','g'), ==, tags[13]);
+    }
+  }
+  count = STATIC_ARRAY_SIZE;
+  offset = 0;
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_table_get_feature_tags (face, HB_OT_TAG_GPOS, offset, &count, tags);
+    g_assert_cmpuint (3, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (3, ==, count);
+      g_assert_cmpuint (HB_TAG ('c','u','r','s'), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('m','a','r','k'), ==, tags[1]);
+      g_assert_cmpuint (HB_TAG ('m','k','m','k'), ==, tags[2]);
+    }
+  }
+
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_script_get_language_tags (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf");
+
+  unsigned int total = 0;
+  unsigned int count = STATIC_ARRAY_SIZE;
+  unsigned int offset = 0;
+  hb_tag_t tags[STATIC_ARRAY_SIZE];
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GSUB, 0, offset, &count, tags);
+    g_assert_cmpuint (2, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (2, ==, count);
+      g_assert_cmpuint (HB_TAG ('F','A','R',' '), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('K','U','R',' '), ==, tags[1]);
+    }
+  }
+  count = STATIC_ARRAY_SIZE;
+  offset = 0;
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GPOS, 1, offset, &count, tags);
+    g_assert_cmpuint (2, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (2, ==, count);
+      g_assert_cmpuint (HB_TAG ('F','A','R',' '), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('K','U','R',' '), ==, tags[1]);
+    }
+  }
+
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_language_get_feature_tags (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf");
+
+  unsigned int total = 0;
+  unsigned int count = STATIC_ARRAY_SIZE;
+  unsigned int offset = 0;
+  hb_tag_t tags[STATIC_ARRAY_SIZE];
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_language_get_feature_tags (face, HB_OT_TAG_GSUB, 0, 0, offset, &count, tags);
+    g_assert_cmpuint (6, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (6, ==, count);
+      g_assert_cmpuint (HB_TAG ('c','a','l','t'), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('f','i','n','a'), ==, tags[1]);
+      g_assert_cmpuint (HB_TAG ('i','n','i','t'), ==, tags[2]);
+      g_assert_cmpuint (HB_TAG ('l','i','g','a'), ==, tags[3]);
+      g_assert_cmpuint (HB_TAG ('m','e','d','i'), ==, tags[4]);
+      g_assert_cmpuint (HB_TAG ('r','l','i','g'), ==, tags[5]);
+    }
+  }
+  count = STATIC_ARRAY_SIZE;
+  offset = 0;
+  while (count == STATIC_ARRAY_SIZE)
+  {
+    total = hb_ot_layout_language_get_feature_tags (face, HB_OT_TAG_GPOS, 1, 0, offset, &count, tags);
+    g_assert_cmpuint (3, ==, total);
+    offset += count;
+    if (count)
+    {
+      g_assert_cmpuint (3, ==, count);
+      g_assert_cmpuint (HB_TAG ('k','e','r','n'), ==, tags[0]);
+      g_assert_cmpuint (HB_TAG ('m','a','r','k'), ==, tags[1]);
+      g_assert_cmpuint (HB_TAG ('m','k','m','k'), ==, tags[2]);
+    }
+  }
+
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_ot_layout_table_get_script_tags);
+  hb_test_add (test_ot_layout_table_find_script);
+  hb_test_add (test_ot_layout_script_get_language_tags);
+  hb_test_add (test_ot_layout_table_get_feature_tags);
+  hb_test_add (test_ot_layout_language_get_feature_tags);
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-ligature-carets.c b/test/api/test-ot-ligature-carets.c
index d842785..7e2d91b 100644
--- a/test/api/test-ot-ligature-carets.c
+++ b/test/api/test-ot-ligature-carets.c
@@ -28,29 +28,135 @@
 #include <hb-ot.h>
 
 static void
-test_ot_layout_feature_get_name_ids_and_characters (void)
+test_ot_layout_get_ligature_carets_ot_gdef (void)
 {
-  hb_face_t *face = hb_test_open_font_file ("fonts/lcar.ttf");
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf");
   hb_font_t *font = hb_font_create (face);
   hb_font_set_scale (font, hb_face_get_upem (face) * 2, hb_face_get_upem (face) * 4);
 
-  hb_position_t caret_array[2];
-  unsigned int caret_count = 2;
-  g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_RTL,
-							     98, 0, &caret_count,
+  hb_position_t caret_array[16];
+
+  /* call with no result */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       188, 0, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (0, ==, caret_count);
+  }
+
+  /* call with no result and some offset */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       188, 10, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (0, ==, caret_count);
+  }
+
+  /* a glyph with 3 ligature carets */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1020, 0, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (3, ==, caret_count);
+    g_assert_cmpuint (2718, ==, caret_array[0]);
+    g_assert_cmpuint (5438, ==, caret_array[1]);
+    g_assert_cmpuint (8156, ==, caret_array[2]);
+  }
+
+  /* the same glyph as above but with offset */
+  {
+    caret_array[2] = 123;
+
+    unsigned caret_count = 16;
+    g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1020, 1, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (2, ==, caret_count);
+    g_assert_cmpuint (5438, ==, caret_array[0]);
+    g_assert_cmpuint (8156, ==, caret_array[1]);
+
+    g_assert_cmpuint (123, ==, caret_array[2]);
+  }
+
+  /* the same glyph as above but with another offset */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1020, 2, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (1, ==, caret_count);
+    g_assert_cmpuint (8156, ==, caret_array[0]);
+  }
+
+  /* call with no result */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1021, 0, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (0, ==, caret_count);
+  }
+
+  /* a glyph with 1 ligature caret */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (1, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1022, 0, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (1, ==, caret_count);
+    g_assert_cmpuint (3530, ==, caret_array[0]);
+  }
+
+  /* the same glyph as above but with offset */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (1, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1022, 1, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (0, ==, caret_count);
+  }
+
+  /* a glyph with 2 ligature carets */
+  {
+    unsigned caret_count = 16;
+    g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR,
+							       1023, 0, &caret_count,
+							       caret_array));
+
+    g_assert_cmpuint (2, ==, caret_count);
+    g_assert_cmpuint (2352, ==, caret_array[0]);
+    g_assert_cmpuint (4706, ==, caret_array[1]);
+  }
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_layout_get_ligature_carets_empty (void)
+{
+  hb_face_t *face = hb_face_get_empty ();
+  hb_font_t *font = hb_font_create (face);
+  hb_font_set_scale (font, hb_face_get_upem (face) * 2, hb_face_get_upem (face) * 4);
+
+  hb_position_t caret_array[3];
+  unsigned int caret_count = 3;
+  g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_RTL,
+							     1024, 0, &caret_count,
 							     caret_array));
 
-  g_assert_cmpuint (2, ==, caret_count);
-  g_assert_cmpuint (1130, ==, caret_array[0]);
-  g_assert_cmpuint (2344, ==, caret_array[1]);
-
-  g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_BTT,
-							     98, 0, &caret_count,
-							     caret_array));
-
-  g_assert_cmpuint (2, ==, caret_count);
-  g_assert_cmpuint (2260, ==, caret_array[0]);
-  g_assert_cmpuint (4688, ==, caret_array[1]);
+  g_assert_cmpuint (0, ==, caret_count);
 
   hb_font_destroy (font);
   hb_face_destroy (face);
@@ -61,7 +167,8 @@
 {
   g_test_init (&argc, &argv, NULL);
 
-  hb_test_add (test_ot_layout_feature_get_name_ids_and_characters);
+  hb_test_add (test_ot_layout_get_ligature_carets_ot_gdef);
+  hb_test_add (test_ot_layout_get_ligature_carets_empty);
 
   return hb_test_run ();
 }
diff --git a/test/api/test-ot-metrics-tt-var.c b/test/api/test-ot-metrics-tt-var.c
index 2305a95..9871c08 100644
--- a/test/api/test-ot-metrics-tt-var.c
+++ b/test/api/test-ot-metrics-tt-var.c
@@ -159,7 +159,7 @@
 
   g_assert_cmpint (extents.x_bearing, ==, 50);
   g_assert_cmpint (extents.y_bearing, ==, 667);
-  g_assert_cmpint (extents.width, ==, 593);
+  g_assert_cmpint (extents.width, ==, 592);
   g_assert_cmpint (extents.height, ==, -679);
 
   hb_font_destroy (font);
@@ -234,6 +234,23 @@
   hb_font_destroy (font);
 }
 
+static void
+test_advance_tt_var_gvar_infer (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TestGVAREight.ttf");
+  hb_font_t *font = hb_font_create (face);
+  hb_ot_font_set_funcs (font);
+  hb_face_destroy (face);
+
+  int coords[6] = {100};
+  hb_font_set_var_coords_normalized (font, coords, 6);
+
+  hb_glyph_extents_t extents = {0};
+  g_assert (hb_font_get_glyph_extents (font, 4, &extents));
+
+  hb_font_destroy (font);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -245,6 +262,7 @@
   hb_test_add (test_advance_tt_var_anchor);
   hb_test_add (test_extents_tt_var_comp);
   hb_test_add (test_advance_tt_var_comp_v);
+  hb_test_add (test_advance_tt_var_gvar_infer);
 
   return hb_test_run ();
 }
diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c
index c2ae4fd..d688eb3 100644
--- a/test/api/test-ot-name.c
+++ b/test/api/test-ot-name.c
@@ -68,6 +68,15 @@
   g_assert_cmpint (char_count, ==, 2);
   g_assert_cmpint (characters[0], ==, 10);
   g_assert_cmpint (characters[1], ==, 24030);
+
+  char_count = 100;
+  characters[1] = 1234;
+  all_chars = hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index,
+						   1, &char_count, characters);
+  g_assert_cmpint (all_chars, ==, 2);
+  g_assert_cmpint (char_count, ==, 1);
+  g_assert_cmpint (characters[0], ==, 24030);
+  g_assert_cmpint (characters[1], ==, 1234);
 }
 
 static void
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index 958fd6b..75131ab 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -164,10 +164,16 @@
   test_script_tags_from_language ("copt", "en", HB_SCRIPT_COPTIC);
   test_script_tags_from_language (NULL, "x-hbsc", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("copt", "x-hbsc", HB_SCRIPT_COPTIC);
+  test_script_tags_from_language (NULL, "x-hbsc-", HB_SCRIPT_INVALID);
+  test_script_tags_from_language (NULL, "x-hbsc-1", HB_SCRIPT_INVALID);
+  test_script_tags_from_language (NULL, "x-hbsc-1a", HB_SCRIPT_INVALID);
+  test_script_tags_from_language (NULL, "x-hbsc-1a2b3c4x", HB_SCRIPT_INVALID);
+  test_script_tags_from_language ("2lon", "x-hbsc-326c6f6e67", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("abc ", "x-hbscabc", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("deva", "x-hbscdeva", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("dev2", "x-hbscdev2", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("dev3", "x-hbscdev3", HB_SCRIPT_INVALID);
+  test_script_tags_from_language ("dev3", "x-hbsc-64657633", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("copt", "x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
   test_script_tags_from_language (NULL, "en-x-hbsc", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("copt", "en-x-hbsc", HB_SCRIPT_COPTIC);
@@ -175,6 +181,7 @@
   test_script_tags_from_language ("deva", "en-x-hbscdeva", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("dev2", "en-x-hbscdev2", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("dev3", "en-x-hbscdev3", HB_SCRIPT_INVALID);
+  test_script_tags_from_language ("dev3", "en-x-hbsc-64657633", HB_SCRIPT_INVALID);
   test_script_tags_from_language ("copt", "en-x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
 }
 
@@ -266,12 +273,12 @@
 static void
 test_ot_tags_to_script_and_language (void)
 {
-  test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbscdflt");
+  test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbsc-44464c54");
   test_tags_to_script_and_language ("latn", "ENG", "Latn", "en");
-  test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbscdeva");
-  test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbscdev2");
+  test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbsc-64657661");
+  test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbsc-64657632");
   test_tags_to_script_and_language ("dev3", "MAR", "Deva", "mr");
-  test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbotqtz0-hbscqaa");
+  test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbot-51545a30-hbsc-71616120");
 }
 
 static void
@@ -291,13 +298,17 @@
   test_language_two_way ("ENG", "en");
   test_tag_from_language ("ENG", "en_US");
 
-  test_language_two_way ("CJA", "cja"); /* Western Cham */
-  test_language_two_way ("CJM", "cjm"); /* Eastern Cham */
+  test_language_two_way ("CJA", "cja-x-hbot-434a4120"); /* Western Cham */
+  test_language_two_way ("CJM", "cjm-x-hbot-434a4d20"); /* Eastern Cham */
+  test_tag_from_language ("CJM", "cjm");
   test_language_two_way ("EVN", "eve");
 
   test_language_two_way ("HAL", "cfm"); /* BCP47 and current ISO639-3 code for Halam/Falam Chin */
   test_tag_from_language ("HAL", "flm"); /* Retired ISO639-3 code for Halam/Falam Chin */
 
+  test_language_two_way ("HYE0", "hy");
+  test_language_two_way ("HYE", "hyw");
+
   test_tag_from_language ("QIN", "bgr"); /* Bawm Chin */
   test_tag_from_language ("QIN", "cbl"); /* Bualkhaw Chin */
   test_tag_from_language ("QIN", "cka"); /* Khumi Awa Chin */
@@ -324,6 +335,8 @@
   test_language_two_way ("FAR", "fa");
   test_tag_from_language ("FAR", "fa_IR");
 
+  test_language_two_way ("MNK", "man"); /* Mandingo [macrolanguage] */
+
   test_language_two_way ("SWA", "aii"); /* Swadaya Aramaic */
 
   test_language_two_way ("SYR", "syr"); /* Syriac [macrolanguage] */
@@ -336,10 +349,12 @@
   test_tag_from_language ("ZHS", "zh"); /* Chinese */
   test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */
   test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */
-  test_tag_from_language ("ZHH", "zh-mo"); /* Chinese (Macao) */
-  test_tag_from_language ("ZHH", "zh-hant-mo"); /* Chinese (Macao) */
+  test_tag_from_language ("ZHTM", "zh-mo"); /* Chinese (Macao) */
+  test_tag_from_language ("ZHTM", "zh-hant-mo"); /* Chinese (Macao) */
+  test_tag_from_language ("ZHS", "zh-hans-mo"); /* Chinese (Simplified, Macao) */
   test_language_two_way ("ZHH", "zh-HK"); /* Chinese (Hong Kong) */
   test_tag_from_language ("ZHH", "zH-HanT-hK"); /* Chinese (Hong Kong) */
+  test_tag_from_language ("ZHS", "zH-HanS-hK"); /* Chinese (Simplified, Hong Kong) */
   test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */
   test_language_two_way ("ZHS", "zh-Hans"); /* Chinese (Simplified) */
   test_language_two_way ("ZHT", "zh-Hant"); /* Chinese (Traditional) */
@@ -351,13 +366,20 @@
   test_tag_from_language ("ZHH", "yue-Hant");
   test_tag_from_language ("ZHS", "yue-Hans");
 
-  test_language_two_way ("ABC", "abc");
-  test_language_two_way ("ABCD", "x-hbotabcd");
+  test_language_two_way ("ABC", "abc-x-hbot-41424320");
+  test_language_two_way ("ABCD", "x-hbot-41424344");
   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc");
   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc");
   test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbotabcd");
+  test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320-zxc");
+  test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320");
+  test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbot-41424344");
 
+  test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot");
   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc");
+  test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc-414243");
+  test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-414243");
+  test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-4142432");
 
   test_tag_from_language ("dflt", "xy");
   test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */
@@ -423,12 +445,27 @@
   test_language_two_way ("SYRN", "und-Syrn");
 
   /* Test that x-hbot overrides the base language */
-  test_tag_from_language ("ABC", "fa-x-hbotabc-zxc");
-  test_tag_from_language ("ABC", "fa-ir-x-hbotabc-zxc");
-  test_tag_from_language ("ABC", "zh-x-hbotabc-zxc");
-  test_tag_from_language ("ABC", "zh-cn-x-hbotabc-zxc");
-  test_tag_from_language ("ABC", "zh-xy-x-hbotabc-zxc");
-  test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-zxc");
+  test_tag_from_language ("ABC", "fa-x-hbotabc-hbot-41686121-zxc");
+  test_tag_from_language ("ABC", "fa-ir-x-hbotabc-hbot-41686121-zxc");
+  test_tag_from_language ("ABC", "zh-x-hbotabc-hbot-41686121-zxc");
+  test_tag_from_language ("ABC", "zh-cn-x-hbotabc-hbot-41686121-zxc");
+  test_tag_from_language ("ABC", "zh-xy-x-hbotabc-hbot-41686121-zxc");
+  test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-hbot-41686121-zxc");
+
+  test_tag_from_language ("Aha!", "fa-x-hbot-41686121-hbotabc-zxc");
+  test_tag_from_language ("Aha!", "fa-ir-x-hbot-41686121-hbotabc-zxc");
+  test_tag_from_language ("Aha!", "zh-x-hbot-41686121-hbotabc-zxc");
+  test_tag_from_language ("Aha!", "zh-cn-x-hbot-41686121-hbotabc-zxc");
+  test_tag_from_language ("Aha!", "zh-xy-x-hbot-41686121-hbotabc-zxc");
+  test_tag_from_language ("Aha!", "xyz-xy-x-hbot-41686121-hbotabc-zxc");
+
+  /* Invalid x-hbot */
+  test_tag_from_language ("dflt", "x-hbot");
+  test_tag_from_language ("dflt", "x-hbot-");
+  test_tag_from_language ("dflt", "x-hbot-1");
+  test_tag_from_language ("dflt", "x-hbot-1a");
+  test_tag_from_language ("dflt", "x-hbot-1a2b3c4x");
+  test_tag_from_language ("2lon", "x-hbot-326c6f6e67");
 
   /* Unnormalized BCP 47 tags */
   test_tag_from_language ("ARA", "ar-aao");
@@ -446,6 +483,10 @@
   test_tag_from_language ("ZHS", "zh-min-nan");
   test_tag_from_language ("ZHS", "zh-xiang");
 
+  /* BCP 47 tags that look similar to unrelated language system tags */
+  test_tag_from_language ("SQI", "als");
+  test_tag_from_language ("dflt", "far");
+
   /* A UN M.49 region code, not an extended language subtag */
   test_tag_from_language ("ARA", "ar-001");
 
diff --git a/test/api/test-set.c b/test/api/test-set.c
index aa2b388..f2f9419 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -121,6 +121,11 @@
   hb_set_del (s, 800);
   g_assert (!hb_set_has (s, 800));
 
+  g_assert_cmpint (hb_set_get_max (s), ==, 799);
+
+  hb_set_del_range (s, 0, 799);
+  g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID);
+
   hb_set_destroy (s);
 }
 
@@ -135,6 +140,133 @@
 //   printf ("}\n");
 // }
 
+static void test_set_intersect_empty (void)
+{
+  hb_set_t* a = hb_set_create ();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 21483);
+  hb_set_add (b, 24064);
+
+  hb_set_intersect (a, b);
+  g_assert (hb_set_is_empty (a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+
+
+  a = hb_set_create ();
+  hb_set_add (a, 16777216);
+
+  b = hb_set_create();
+  hb_set_add (b, 0);
+
+  hb_set_intersect (a, b);
+  g_assert (hb_set_is_empty (a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+static void test_set_intersect_page_reduction (void)
+{
+  hb_set_t* a = hb_set_create ();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 3585);
+  hb_set_add (b, 24405);
+
+  hb_set_intersect(a, b);
+  g_assert (hb_set_is_equal (a, b));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+static void test_set_union (void)
+{
+  hb_set_t* a = hb_set_create();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 21483);
+  hb_set_add (b, 24064);
+
+  hb_set_t* u = hb_set_create ();
+  hb_set_add (u, 3585);
+  hb_set_add (u, 21333);
+  hb_set_add (u, 21483);
+  hb_set_add (u, 24064);
+  hb_set_add (u, 24405);
+
+  hb_set_union(b, a);
+  g_assert (hb_set_is_equal (u, b));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+  hb_set_destroy (u);
+}
+
+static void
+test_set_subsets (void)
+{
+  hb_set_t *s = hb_set_create ();
+  hb_set_t *l = hb_set_create ();
+
+  hb_set_add (l, 0x0FFFF);
+  hb_set_add (s, 0x1FFFF);
+  g_assert (!hb_set_is_subset (s, l));
+  hb_set_clear (s);
+
+  hb_set_add (s, 0x0FFF0);
+  g_assert (!hb_set_is_subset (s, l));
+  hb_set_clear (s);
+
+  hb_set_add (s, 0x0AFFF);
+  g_assert (!hb_set_is_subset (s, l));
+
+  hb_set_clear (s);
+  g_assert (hb_set_is_subset (s, l));
+
+  hb_set_clear (l);
+  g_assert (hb_set_is_subset (s, l));
+
+  hb_set_add (s, 0x1FFFF);
+  g_assert (!hb_set_is_subset (s, l));
+  hb_set_clear (s);
+
+  hb_set_add (s, 0xFF);
+  hb_set_add (s, 0x1FFFF);
+  hb_set_add (s, 0x2FFFF);
+
+  hb_set_add (l, 0xFF);
+  hb_set_add (l, 0x1FFFF);
+  hb_set_add (l, 0x2FFFF);
+
+  g_assert (hb_set_is_subset (s, l));
+  hb_set_del (l, 0xFF);
+  g_assert (!hb_set_is_subset (s, l));
+  hb_set_add (l, 0xFF);
+
+  hb_set_del (l, 0x2FFFF);
+  g_assert (!hb_set_is_subset (s, l));
+  hb_set_add (l, 0x2FFFF);
+
+  hb_set_del (l, 0x1FFFF);
+  g_assert (!hb_set_is_subset (s, l));
+
+  hb_set_destroy (s);
+  hb_set_destroy (l);
+}
+
 static void
 test_set_algebra (void)
 {
@@ -395,15 +527,568 @@
   hb_set_destroy (b);
 }
 
+static void
+test_set_delrange (void)
+{
+  const unsigned P = 512;	/* Page size. */
+  struct { unsigned b, e; } ranges[] = {
+    { 35, P-15 },		/* From page middle thru middle. */
+    { P, P+100 },		/* From page start thru middle. */
+    { P+300, P*2-1 },		/* From page middle thru end. */
+    { P*3, P*4+100 },		/* From page start thru next page middle. */
+    { P*4+300, P*6-1 },		/* From page middle thru next page end. */
+    { P*6+200,P*8+100 },	/* From page middle covering one page thru page middle. */
+    { P*9, P*10+105 },		/* From page start covering one page thru page middle. */
+    { P*10+305, P*12-1 },	/* From page middle covering one page thru page end. */
+    { P*13, P*15-1 },		/* From page start covering two pages thru page end. */
+    { P*15+100, P*18+100 }	/* From page middle covering two pages thru page middle. */
+  };
+  unsigned n = sizeof (ranges) / sizeof(ranges[0]);
+
+  hb_set_t *s = hb_set_create ();
+
+  test_empty (s);
+  for (unsigned int g = 0; g < ranges[n - 1].e + P; g += 2)
+    hb_set_add (s, g);
+
+  hb_set_add (s, P*2-1);
+  hb_set_add (s, P*6-1);
+  hb_set_add (s, P*12-1);
+  hb_set_add (s, P*15-1);
+
+  for (unsigned i = 0; i < n; i++)
+    hb_set_del_range (s, ranges[i].b, ranges[i].e);
+
+  hb_set_del_range (s, P*13+5, P*15-10);	/* Deletion from deleted pages. */
+
+  for (unsigned i = 0; i < n; i++)
+  {
+    unsigned b = ranges[i].b;
+    unsigned e = ranges[i].e;
+    g_assert (hb_set_has (s, (b-2)&~1));
+    while (b <= e)
+      g_assert (!hb_set_has (s, b++));
+    g_assert (hb_set_has (s, (e+2)&~1));
+  }
+
+  hb_set_destroy (s);
+}
+
+static const unsigned max_set_elements = -1;
+
+static void
+test_set_inverted_basics (void)
+{
+  // Tests:
+  // add, del, has, get_population, is_empty, get_min, get_max
+  // for inverted sets.
+  hb_set_t *s = hb_set_create ();
+  hb_set_invert (s);
+
+  g_assert_cmpint (hb_set_get_population (s), ==, max_set_elements);
+  g_assert (hb_set_has (s, 0));
+  g_assert (hb_set_has (s, 13));
+  g_assert (hb_set_has (s, max_set_elements - 1));
+  g_assert (!hb_set_is_empty (s));
+  g_assert_cmpint (hb_set_get_min (s), ==, 0);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 1);
+
+  hb_set_del (s, 13);
+  g_assert (!hb_set_has (s, 13));
+  g_assert_cmpint (hb_set_get_population (s), ==, max_set_elements - 1);
+  g_assert_cmpint (hb_set_get_min (s), ==, 0);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 1);
+
+  hb_set_add (s, 13);
+  g_assert (hb_set_has (s, 13));
+  g_assert_cmpint (hb_set_get_population (s), ==, max_set_elements);
+
+  hb_set_del (s, 0);
+  hb_set_del (s, max_set_elements - 1);
+  g_assert (!hb_set_has (s, 0));
+  g_assert (hb_set_has (s, 13));
+  g_assert (!hb_set_has (s, max_set_elements - 1));
+  g_assert (!hb_set_is_empty (s));
+  g_assert_cmpint (hb_set_get_population (s), ==, max_set_elements - 2);
+  g_assert_cmpint (hb_set_get_min (s), ==, 1);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 2);
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_inverted_ranges (void)
+{
+  // Tests:
+  // add_range, del_range, has, get_population, is_empty, get_min, get_max
+  // for inverted sets.
+  hb_set_t *s = hb_set_create ();
+  hb_set_invert (s);
+
+  hb_set_del_range (s, 41, 4000);
+  hb_set_add_range (s, 78, 601);
+
+  g_assert (hb_set_has (s, 40));
+  g_assert (!hb_set_has (s, 41));
+  g_assert (!hb_set_has (s, 64));
+  g_assert (!hb_set_has (s, 77));
+  g_assert (hb_set_has (s, 78));
+  g_assert (hb_set_has (s, 300));
+  g_assert (hb_set_has (s, 601));
+  g_assert (!hb_set_has (s, 602));
+  g_assert (!hb_set_has (s, 3000));
+  g_assert (!hb_set_has (s, 4000));
+  g_assert (hb_set_has (s, 4001));
+
+  g_assert (!hb_set_is_empty (s));
+  g_assert_cmpint (hb_set_get_population (s), ==, max_set_elements - 3436);
+  g_assert_cmpint (hb_set_get_min (s), ==, 0);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 1);
+
+  hb_set_del_range (s, 0, 37);
+  g_assert (!hb_set_has (s, 0));
+  g_assert (!hb_set_has (s, 37));
+  g_assert (hb_set_has (s, 38));
+  g_assert (!hb_set_is_empty (s));
+  g_assert_cmpint (hb_set_get_population (s), ==,
+                   max_set_elements - 3436 - 38);
+  g_assert_cmpint (hb_set_get_min (s), ==, 38);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 1);
+
+  hb_set_del_range (s, max_set_elements - 13, max_set_elements - 1);
+  g_assert (!hb_set_has (s, max_set_elements - 1));
+  g_assert (!hb_set_has (s, max_set_elements - 13));
+  g_assert (hb_set_has (s, max_set_elements - 14));
+
+  g_assert (!hb_set_is_empty (s));
+  g_assert_cmpint (hb_set_get_population (s), ==,
+                   max_set_elements - 3436 - 38 - 13);
+  g_assert_cmpint (hb_set_get_min (s), ==, 38);
+  g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 14);
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_inverted_iteration_next (void)
+{
+  // Tests:
+  // next, next_range
+  hb_set_t *s = hb_set_create ();
+  hb_set_invert (s);
+
+  hb_set_del_range (s, 41, 4000);
+  hb_set_add_range (s, 78, 601);
+
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  hb_codepoint_t start = 0;
+  hb_codepoint_t end = 0;
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 0);
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 1);
+
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 1);
+  g_assert_cmpint (end, ==, 40);
+
+  start = 40;
+  end = 40;
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 78);
+  g_assert_cmpint (end, ==, 601);
+
+  start = 40;
+  end = 57;
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 78);
+  g_assert_cmpint (end, ==, 601);
+
+  cp = 39;
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 40);
+
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 78);
+
+  cp = 56;
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 78);
+
+  cp = 78;
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 79);
+
+  cp = 601;
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 4001);
+
+  cp = HB_SET_VALUE_INVALID;
+  hb_set_del (s, 0);
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, 1);
+
+  start = 0;
+  end = 0;
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 1);
+  g_assert_cmpint (end, ==, 40);
+
+  cp = max_set_elements - 1;
+  g_assert (!hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, HB_SET_VALUE_INVALID);
+
+  start = 4000;
+  end = 4000;
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 4001);
+  g_assert_cmpint (end, ==, max_set_elements - 1);
+
+  start = max_set_elements - 1;
+  end = max_set_elements - 1;
+  g_assert (!hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (end, ==, HB_SET_VALUE_INVALID);
+
+  cp = max_set_elements - 3;
+  hb_set_del (s, max_set_elements - 1);
+  g_assert (hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, max_set_elements - 2);
+  g_assert (!hb_set_next (s, &cp));
+  g_assert_cmpint (cp, ==, HB_SET_VALUE_INVALID);
+
+
+  start = max_set_elements - 2;
+  end = max_set_elements - 2;
+  g_assert (!hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (end, ==, HB_SET_VALUE_INVALID);
+
+  start = max_set_elements - 3;
+  end = max_set_elements - 3;
+  g_assert (hb_set_next_range (s, &start, &end));
+  g_assert_cmpint (start, ==, max_set_elements - 2);
+  g_assert_cmpint (end, ==, max_set_elements - 2);
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_inverted_iteration_prev (void)
+{
+  // Tests:
+  // previous, previous_range
+  hb_set_t *s = hb_set_create ();
+  hb_set_invert (s);
+
+  hb_set_del_range (s, 41, 4000);
+  hb_set_add_range (s, 78, 601);
+
+  hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+  hb_codepoint_t start = max_set_elements - 1;
+  hb_codepoint_t end = max_set_elements - 1;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, max_set_elements - 1);
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, max_set_elements - 2);
+
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 4001);
+  g_assert_cmpint (end, ==, max_set_elements - 2);
+
+  start = 4001;
+  end = 4001;
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 78);
+  g_assert_cmpint (end, ==, 601);
+
+  start = 2500;
+  end = 3000;
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 78);
+  g_assert_cmpint (end, ==, 601);
+
+  cp = 4002;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 4001);
+
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 601);
+
+  cp = 3500;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 601);
+
+  cp = 601;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 600);
+
+  cp = 78;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 40);
+
+  cp = HB_SET_VALUE_INVALID;
+  hb_set_del (s, max_set_elements - 1);
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, max_set_elements - 2);
+
+  start = max_set_elements - 1;
+  end = max_set_elements - 1;
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 4001);
+  g_assert_cmpint (end, ==, max_set_elements - 2);
+
+  cp = 0;
+  g_assert (!hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, HB_SET_VALUE_INVALID);
+
+  cp = 40;
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 39);
+
+  start = 40;
+  end = 40;
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 0);
+  g_assert_cmpint (end, ==, 39);
+
+  start = 0;
+  end = 0;
+  g_assert (!hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (end, ==, HB_SET_VALUE_INVALID);
+
+
+  cp = 2;
+  hb_set_del (s, 0);
+  g_assert (hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, 1);
+  g_assert (!hb_set_previous (s, &cp));
+  g_assert_cmpint (cp, ==, HB_SET_VALUE_INVALID);
+
+  start = 1;
+  end = 1;
+  g_assert (!hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (end, ==, HB_SET_VALUE_INVALID);
+
+  start = 2;
+  end = 2;
+  g_assert (hb_set_previous_range (s, &start, &end));
+  g_assert_cmpint (start, ==, 1);
+  g_assert_cmpint (end, ==, 1);
+
+  hb_set_destroy (s);
+}
+
+
+static void
+test_set_inverted_equality (void)
+{
+  hb_set_t *a = hb_set_create ();
+  hb_set_t *b = hb_set_create ();
+  hb_set_invert (a);
+  hb_set_invert (b);
+
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_add (a, 10);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_del (a, 42);
+  g_assert (!hb_set_is_equal (a, b));
+  g_assert (!hb_set_is_equal (b, a));
+
+  hb_set_del (b, 42);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_del_range (a, 43, 50);
+  hb_set_del_range (a, 51, 76);
+  hb_set_del_range (b, 43, 76);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_del (a, 0);
+  g_assert (!hb_set_is_equal (a, b));
+  g_assert (!hb_set_is_equal (b, a));
+
+  hb_set_del (b, 0);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_del (a, max_set_elements - 1);
+  g_assert (!hb_set_is_equal (a, b));
+  g_assert (!hb_set_is_equal (b, a));
+
+  hb_set_del (b, max_set_elements - 1);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_invert (a);
+  g_assert (!hb_set_is_equal (a, b));
+  g_assert (!hb_set_is_equal (b, a));
+
+  hb_set_invert (b);
+  g_assert (hb_set_is_equal (a, b));
+  g_assert (hb_set_is_equal (b, a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+typedef enum {
+  UNION = 0,
+  INTERSECT,
+  SUBTRACT,
+  SYM_DIFF,
+  LAST,
+} set_operation;
+
+static hb_set_t* prepare_set(hb_bool_t has_x,
+                             hb_bool_t inverted,
+                             hb_bool_t has_page,
+                             hb_bool_t is_null)
+{
+  static const hb_codepoint_t x = 13;
+  if (is_null)
+    return hb_set_get_empty ();
+
+  hb_set_t* s = hb_set_create ();
+  if (inverted) hb_set_invert (s);
+  if (has_page)
+  {
+    // Ensure a page exists for x.
+    inverted ? hb_set_del (s, x) : hb_set_add (s, x);
+  }
+  if (has_x)
+    hb_set_add (s, x);
+  else
+    hb_set_del (s, x);
+
+  return s;
+}
+
+static hb_bool_t
+check_set_operations(hb_bool_t a_has_x,
+                     hb_bool_t a_inverted,
+                     hb_bool_t a_has_page,
+                     hb_bool_t a_is_null,
+                     hb_bool_t b_has_x,
+                     hb_bool_t b_inverted,
+                     hb_bool_t b_has_page,
+                     hb_bool_t b_is_null,
+                     set_operation op)
+{
+  hb_codepoint_t x = 13;
+  hb_set_t* a = prepare_set (a_has_x, a_inverted, a_has_page, a_is_null);
+  hb_set_t* b = prepare_set (b_has_x, b_inverted, b_has_page, b_is_null);
+
+  const char* op_name;
+  hb_bool_t has_expected;
+  hb_bool_t should_have_x;
+  switch (op) {
+  default:
+  case LAST:
+  case UNION:
+    op_name = "union";
+    should_have_x = (a_has_x || b_has_x) && !a_is_null;
+    hb_set_union (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case INTERSECT:
+    op_name = "intersect";
+    should_have_x = (a_has_x && b_has_x) && !a_is_null;
+    hb_set_intersect (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case SUBTRACT:
+    op_name = "subtract";
+    should_have_x = (a_has_x && !b_has_x) && !a_is_null;
+    hb_set_subtract (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case SYM_DIFF:
+    op_name = "sym_diff";
+    should_have_x = (a_has_x ^ b_has_x) && !a_is_null;
+    hb_set_symmetric_difference (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  }
+
+  printf ("%s%s%s%s %-9s %s%s%s%s == %s  [%s]\n",
+          a_inverted ? "i" : " ",
+          a_has_page ? "p" : " ",
+          a_is_null ? "n" : " ",
+          a_has_x ? "{13}" : "{}  ",
+          op_name,
+          b_inverted ? "i" : " ",
+          b_has_page ? "p" : " ",
+          b_is_null ? "n" : " ",
+          b_has_x ? "{13}" : "{}  ",
+          should_have_x ? "{13}" : "{}  ",
+          has_expected ? "succeeded" : "failed");
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+
+  return has_expected;
+}
+
+static void
+test_set_inverted_operations (void)
+{
+  hb_bool_t all_succeeded = 1;
+  for (hb_bool_t a_has_x = 0; a_has_x <= 1; a_has_x++) {
+    for (hb_bool_t a_inverted = 0; a_inverted <= 1; a_inverted++) {
+      for (hb_bool_t b_has_x = 0; b_has_x <= 1; b_has_x++) {
+        for (hb_bool_t b_inverted = 0; b_inverted <= 1; b_inverted++) {
+          for (hb_bool_t a_has_page = 0; a_has_page <= !(a_has_x ^ a_inverted); a_has_page++) {
+            for (hb_bool_t b_has_page = 0; b_has_page <= !(b_has_x ^ b_inverted); b_has_page++) {
+              for (hb_bool_t a_is_null = 0; a_is_null <= (!a_has_x && !a_has_page && !a_inverted); a_is_null++) {
+                for (hb_bool_t b_is_null = 0; b_is_null <= (!b_has_x && !b_has_page && !b_inverted); b_is_null++) {
+                  for (set_operation op = UNION; op < LAST; op++) {
+                    all_succeeded = check_set_operations (a_has_x, a_inverted, a_has_page, a_is_null,
+                                                          b_has_x, b_inverted, b_has_page, b_is_null,
+                                                          op)
+                                    && all_succeeded;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  g_assert (all_succeeded);
+}
+
 int
 main (int argc, char **argv)
 {
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_set_basic);
+  hb_test_add (test_set_subsets);
   hb_test_add (test_set_algebra);
   hb_test_add (test_set_iter);
   hb_test_add (test_set_empty);
+  hb_test_add (test_set_delrange);
+
+  hb_test_add (test_set_intersect_empty);
+  hb_test_add (test_set_intersect_page_reduction);
+  hb_test_add (test_set_union);
+
+  hb_test_add (test_set_inverted_basics);
+  hb_test_add (test_set_inverted_ranges);
+  hb_test_add (test_set_inverted_iteration_next);
+  hb_test_add (test_set_inverted_iteration_prev);
+  hb_test_add (test_set_inverted_equality);
+  hb_test_add (test_set_inverted_operations);
 
   return hb_test_run();
 }
diff --git a/test/api/test-style.c b/test/api/test-style.c
new file mode 100644
index 0000000..73accfb
--- /dev/null
+++ b/test/api/test-style.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+/* Unit tests for hb-style.h */
+
+#define assert_cmpfloat(n1, n2) g_assert_cmpint ((int) (n1 * 100.f), ==, (int) (n2 * 100.f))
+
+static void
+test_empty_face (void)
+{
+  hb_font_t *empty = hb_font_get_empty ();
+
+  assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_WEIGHT), 400);
+}
+
+static void
+test_regular_face (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_font_t *font = hb_font_create (face);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 400);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_face_user_setting (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_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 389.34f); /* its default weight */
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 0);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 200);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 1);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 300);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 2);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 400);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 3);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT),600);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 4);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 700);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 5);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0);
+
+  hb_font_set_var_named_instance (font, 6);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 50);
+
+  hb_font_set_var_named_instance (font, 7);
+
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE), 0);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100);
+  assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900);
+  assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 100);
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_empty_face);
+  hb_test_add (test_regular_face);
+  hb_test_add (test_face_user_setting);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-subset-cbdt.c b/test/api/test-subset-cbdt.c
new file mode 100644
index 0000000..dcc06e1
--- /dev/null
+++ b/test/api/test-subset-cbdt.c
@@ -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.
+ *
+ * Google Author(s): Calder Kitagawa
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for CBDT/CBLC subsetting */
+
+static void
+test_subset_cbdt_noop (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x38);
+  hb_set_add (codepoints, 0x39);
+  hb_set_add (codepoints, 0xAE);
+  hb_set_add (codepoints, 0x2049);
+  hb_set_add (codepoints, 0x20E3);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face, face_subset, HB_TAG ('C','B','L','C'));
+  hb_subset_test_check (face, face_subset, HB_TAG ('C','B','D','T'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_cbdt_keep_one (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.default.39.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x39);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C'));
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_cbdt_keep_one_last_subtable (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.default.2049.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x2049);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C'));
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_cbdt_keep_multiple_subtables (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.multiple_size_tables.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x38);
+  hb_set_add (codepoints, 0xAE);
+  hb_set_add (codepoints, 0x2049);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C'));
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_cbdt_index_format_3 (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.index_format3.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x38);
+  hb_set_add (codepoints, 0xAE);
+  hb_set_add (codepoints, 0x2049);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C'));
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+// TODO: add support/tests for index formats 2,4,5 (image formats are treated as
+// opaque blobs when subsetting so don't need to be tested separately).
+// TODO: add a test that keeps no codepoints.
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_cbdt_noop);
+  hb_test_add (test_subset_cbdt_keep_one);
+  hb_test_add (test_subset_cbdt_keep_one_last_subtable);
+  // The following use manually crafted expectation files as they are not
+  // binary compatible with FontTools.
+  hb_test_add (test_subset_cbdt_keep_multiple_subtables);
+  // Can use FontTools after https://github.com/fonttools/fonttools/issues/1817
+  // is resolved.
+  hb_test_add (test_subset_cbdt_index_format_3);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-subset-cff1.c b/test/api/test-subset-cff1.c
index 8b4025d..7c68a49 100644
--- a/test/api/test-subset-cff1.c
+++ b/test/api/test-subset-cff1.c
@@ -80,7 +80,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -103,7 +103,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_desubroutinize (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_DESUBROUTINIZE);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -126,8 +126,8 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
-  hb_subset_input_set_desubroutinize (input, true);
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_NO_HINTING | HB_SUBSET_FLAGS_DESUBROUTINIZE);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -170,7 +170,7 @@
   hb_set_add (codepoints, 0x41);
   hb_set_add (codepoints, 0x4C2E);
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
   hb_set_destroy (codepoints);
 
@@ -193,7 +193,7 @@
   hb_set_add (codepoints, 0x41);
   hb_set_add (codepoints, 0x4C2E);
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_desubroutinize (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_DESUBROUTINIZE);
   face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
   hb_set_destroy (codepoints);
 
@@ -216,8 +216,8 @@
   hb_set_add (codepoints, 0x41);
   hb_set_add (codepoints, 0x4C2E);
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
-  hb_subset_input_set_desubroutinize (input, true);
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_NO_HINTING | HB_SUBSET_FLAGS_DESUBROUTINIZE);
   face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
   hb_set_destroy (codepoints);
 
@@ -279,7 +279,7 @@
   hb_face_t *face_test;
   hb_set_add (codepoints, 0x69);  /* i */
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   face_test = hb_subset_test_create_subset (face, input);
   hb_set_destroy (codepoints);
 
@@ -302,7 +302,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_retain_gids (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -325,7 +325,7 @@
   hb_set_add (codepoints, 0x41);
   hb_set_add (codepoints, 0x4C2E);
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_retain_gids (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
   face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
   hb_set_destroy (codepoints);
 
diff --git a/test/api/test-subset-cff2.c b/test/api/test-subset-cff2.c
index 7ffcf5e..a5dde42 100644
--- a/test/api/test-subset-cff2.c
+++ b/test/api/test-subset-cff2.c
@@ -80,7 +80,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -103,7 +103,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_desubroutinize (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_DESUBROUTINIZE);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -126,8 +126,8 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_desubroutinize (input, true);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_DESUBROUTINIZE | HB_SUBSET_FLAGS_NO_HINTING);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -150,7 +150,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_retain_gids (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
diff --git a/test/api/test-subset-cmap.c b/test/api/test-subset-cmap.c
index 74e91ca..e16400e 100644
--- a/test/api/test-subset-cmap.c
+++ b/test/api/test-subset-cmap.c
@@ -90,6 +90,91 @@
   hb_face_destroy (face_abc);
 }
 
+static void
+test_subset_cmap4_no_exceeding_maximum_codepoint (void)
+{
+  hb_face_t *face_origin = hb_test_open_font_file ("fonts/Mplus1p-Regular.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/Mplus1p-Regular-cmap4-testing.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x20);
+  hb_set_add (codepoints, 0x21);
+  hb_set_add (codepoints, 0x1d542);
+  hb_set_add (codepoints, 0x201a2);
+
+  face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('c','m','a','p'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face_origin);
+}
+
+static void
+test_subset_cmap_empty_tables (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_empty = hb_test_open_font_file ("fonts/Roboto-Regular.empty.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 100);
+  hb_set_add (codepoints, 101);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_empty, face_abc_subset, HB_TAG ('c','m','a','p'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_empty);
+}
+
+static void
+test_subset_cmap_noto_color_emoji_noop (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x38);
+  hb_set_add (codepoints, 0x39);
+  hb_set_add (codepoints, 0xAE);
+  hb_set_add (codepoints, 0x2049);
+  hb_set_add (codepoints, 0x20E3);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face, face_subset, HB_TAG ('c','m','a','p'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_cmap_noto_color_emoji_non_consecutive_glyphs (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.38,AE,2049.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x38);
+  hb_set_add (codepoints, 0xAE);
+  hb_set_add (codepoints, 0x2049);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('c','m','a','p'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
 // TODO(rsheeter) test cmap to no codepoints
 
 int
@@ -100,6 +185,10 @@
   hb_test_add (test_subset_cmap);
   hb_test_add (test_subset_cmap_noop);
   hb_test_add (test_subset_cmap_non_consecutive_glyphs);
+  hb_test_add (test_subset_cmap4_no_exceeding_maximum_codepoint);
+  hb_test_add (test_subset_cmap_empty_tables);
+  hb_test_add (test_subset_cmap_noto_color_emoji_noop);
+  hb_test_add (test_subset_cmap_noto_color_emoji_non_consecutive_glyphs);
 
   return hb_test_run();
 }
diff --git a/test/api/test-subset-colr.c b/test/api/test-subset-colr.c
new file mode 100644
index 0000000..4035092
--- /dev/null
+++ b/test/api/test-subset-colr.c
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Calder Kitagawa
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for COLR subsetting */
+
+static void
+test_subset_colr_noop (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, '2');
+  hb_set_add (codepoints, 0x3297);
+  hb_set_add (codepoints, 0x3299);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face, face_subset, HB_TAG ('C','O','L','R'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_colr_keep_one_colr_glyph (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.3297.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, 0x3297);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_colr_keep_mixed_glyph (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.32,3299.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, '2');
+  hb_set_add (codepoints, 0x3299);
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+static void
+test_subset_colr_keep_no_colr_glyph (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.32.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_subset;
+  hb_set_add (codepoints, '2');
+  face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_expected);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_colr_noop);
+  hb_test_add (test_subset_colr_keep_one_colr_glyph);
+  hb_test_add (test_subset_colr_keep_mixed_glyph);
+  hb_test_add (test_subset_colr_keep_no_colr_glyph);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-subset-drop-tables.c b/test/api/test-subset-drop-tables.c
index e234080..327b17b 100644
--- a/test/api/test-subset-drop-tables.c
+++ b/test/api/test-subset-drop-tables.c
@@ -38,11 +38,12 @@
   hb_set_add (codepoints, 97);
   hb_set_add (codepoints, 99);
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
-  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'd', 'm', 'x'));
-  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'm', 't', 'x'));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG ('h', 'd', 'm', 'x'));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG ('h', 'm', 't', 'x'));
   hb_set_destroy (codepoints);
 
-  hb_face_t* subset = hb_subset (face, input);
+  hb_face_t* subset = hb_subset_or_fail (face, input);
+  g_assert (subset);
 
   hb_blob_t *hdmx = hb_face_reference_table (subset, HB_TAG ('h', 'd', 'm', 'x'));
   hb_blob_t *hmtx = hb_face_reference_table (subset, HB_TAG ('h', 'm', 't', 'x'));
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 2b330ce..94670be 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -80,6 +80,31 @@
 }
 
 static void
+test_subset_glyf_set_overlaps_flag (void)
+{
+  hb_face_t *face_abcAE = hb_test_open_font_file ("fonts/Roboto-Regular.abcAE.ttf");
+  hb_face_t *face_bAE = hb_test_open_font_file ("fonts/Roboto-Regular.bAE.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abcAE_subset;
+  hb_set_add (codepoints, 32);
+  hb_set_add (codepoints, 98);
+  hb_set_add (codepoints, 508);
+
+  hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG);
+  face_abcAE_subset = hb_subset_test_create_subset (face_abcAE, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_bAE, face_abcAE_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_bAE, face_abcAE_subset, HB_TAG ('g','l','y','f'));
+
+  hb_face_destroy (face_abcAE_subset);
+  hb_face_destroy (face_abcAE);
+  hb_face_destroy (face_bAE);
+}
+
+static void
 test_subset_glyf_with_input_glyphs (void)
 {
   hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
@@ -137,9 +162,9 @@
 
   input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
-  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
-  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
+  hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'S', 'U', 'B'));
+  hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'P', 'O', 'S'));
+  hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'D', 'E', 'F'));
 
   face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -166,9 +191,9 @@
 
   input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
-  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
-  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'S', 'U', 'B'));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'P', 'O', 'S'));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'D', 'E', 'F'));
 
   face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -214,7 +239,7 @@
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -238,7 +263,7 @@
   hb_face_t *face_generated_subset;
   hb_set_add (codepoints, 0x1fc);
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
 
   face_generated_subset = hb_subset_test_create_subset (face_components, input);
   hb_set_destroy (codepoints);
@@ -273,14 +298,13 @@
   }
 
   input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_drop_hints (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
   hb_set_destroy (codepoints);
 
-  face_subset = hb_subset_test_create_subset (face, input);
-  g_assert (face_subset);
-  g_assert (face_subset == hb_face_get_empty ());
+  face_subset = hb_subset_or_fail (face, input);
+  g_assert (!face_subset);
 
-  hb_face_destroy (face_subset);
+  hb_subset_input_destroy (input);
   hb_face_destroy (face);
 }
 
@@ -296,7 +320,7 @@
   hb_set_add (codepoints, 99);
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_retain_gids (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -320,7 +344,7 @@
   hb_set_add (codepoints, 97);
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
-  hb_subset_input_set_retain_gids (input, true);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -342,6 +366,7 @@
 
   hb_test_add (test_subset_glyf_noop);
   hb_test_add (test_subset_glyf);
+  hb_test_add (test_subset_glyf_set_overlaps_flag);
   hb_test_add (test_subset_glyf_with_input_glyphs);
   hb_test_add (test_subset_glyf_strip_hints_simple);
   hb_test_add (test_subset_glyf_strip_hints_composite);
diff --git a/test/api/test-subset-gpos.c b/test/api/test-subset-gpos.c
new file mode 100644
index 0000000..ff7defb
--- /dev/null
+++ b/test/api/test-subset-gpos.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2020 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for GPOS subsetting */
+
+static void
+test_subset_gpos_lookup_subtable (void)
+{
+  hb_face_t *face_pwa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-.aw.ttf");
+  hb_face_t *face_wa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-aw.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_pwa_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'w');
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+
+  hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG),
+              HB_TAG ('G', 'P', 'O', 'S'));
+
+  face_pwa_subset = hb_subset_test_create_subset (face_pwa, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_wa, face_pwa_subset, HB_TAG ('G','P','O','S'));
+
+  hb_face_destroy (face_pwa_subset);
+  hb_face_destroy (face_pwa);
+  hb_face_destroy (face_wa);
+}
+
+static void
+test_subset_gpos_pairpos1_vf (void)
+{
+  hb_face_t *face_wav = hb_test_open_font_file ("fonts/AdobeVFPrototype.WAV.gpos.otf");
+  hb_face_t *face_wa = hb_test_open_font_file ("fonts/AdobeVFPrototype.WA.gpos.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_wav_subset;
+  hb_set_add (codepoints, 'W');
+  hb_set_add (codepoints, 'A');
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+
+  hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG),
+              HB_TAG ('G', 'P', 'O', 'S'));
+
+  face_wav_subset = hb_subset_test_create_subset (face_wav, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_wa, face_wav_subset, HB_TAG ('G','P','O','S'));
+
+  hb_face_destroy (face_wav_subset);
+  hb_face_destroy (face_wav);
+  hb_face_destroy (face_wa);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_gpos_lookup_subtable);
+  hb_test_add (test_subset_gpos_pairpos1_vf);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-subset-gvar.c b/test/api/test-subset-gvar.c
new file mode 100644
index 0000000..5ffc02d
--- /dev/null
+++ b/test/api/test-subset-gvar.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for gvar subsetting */
+
+static void
+test_subset_gvar_noop (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','v','a','r'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+}
+
+static void
+test_subset_gvar (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','v','a','r'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_gvar_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.retaingids.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','v','a','r'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_gvar_noop);
+  hb_test_add (test_subset_gvar);
+  hb_test_add (test_subset_gvar_retaingids);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index 7178833..c41a121 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -82,9 +82,8 @@
   hb_set_add (codepoints, 'b');
   hb_set_add (codepoints, 'c');
 
-  subset = hb_subset (face, input);
-  g_assert (subset);
-  g_assert (subset == hb_face_get_empty ());
+  subset = hb_subset_or_fail (face, input);
+  g_assert (!subset);
 
   hb_subset_input_destroy (input);
   hb_face_destroy (subset);
diff --git a/test/api/test-subset-hmtx.c b/test/api/test-subset-hmtx.c
index 1b51dc2..28cca00 100644
--- a/test/api/test-subset-hmtx.c
+++ b/test/api/test-subset-hmtx.c
@@ -162,9 +162,8 @@
   hb_set_add (codepoints, 'b');
   hb_set_add (codepoints, 'c');
 
-  subset = hb_subset (face, input);
-  g_assert (subset);
-  g_assert (subset == hb_face_get_empty ());
+  subset = hb_subset_or_fail (face, input);
+  g_assert (!subset);
 
   hb_subset_input_destroy (input);
   hb_face_destroy (subset);
diff --git a/test/api/test-subset-hvar.c b/test/api/test-subset-hvar.c
new file mode 100644
index 0000000..925b743
--- /dev/null
+++ b/test/api/test-subset-hvar.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for HVAR subsetting */
+
+static void
+test_subset_map_HVAR_noop (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file("fonts/AdobeVFPrototype.abc.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+}
+
+static void
+test_subset_map_HVAR (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_map_HVAR_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.retaingids.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_map_modHVAR (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-modHVAR.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-modHVAR.ac.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_identity_HVAR_noop (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+}
+
+static void
+test_subset_identity_HVAR (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_identity_HVAR_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.retaingids.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_map_HVAR_noop);
+  hb_test_add (test_subset_map_HVAR);
+  hb_test_add (test_subset_map_HVAR_retaingids);
+  hb_test_add (test_subset_map_modHVAR);
+  hb_test_add (test_subset_identity_HVAR_noop);
+  hb_test_add (test_subset_identity_HVAR);
+  hb_test_add (test_subset_identity_HVAR_retaingids);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-subset-sbix.c b/test/api/test-subset-sbix.c
new file mode 100644
index 0000000..16ac666
--- /dev/null
+++ b/test/api/test-subset-sbix.c
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Calder Kitagawa
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for sbix subsetting */
+
+static void
+test_subset_sbix_noop (void)
+{
+  hb_face_t *face_XY = hb_test_open_font_file ("fonts/sbix.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_XY_subset;
+  hb_set_add (codepoints, 88);
+  hb_set_add (codepoints, 89);
+  face_XY_subset = hb_subset_test_create_subset (face_XY, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_XY, face_XY_subset, HB_TAG ('s','b','i','x'));
+
+  hb_face_destroy (face_XY_subset);
+  hb_face_destroy (face_XY);
+}
+
+static void
+test_subset_sbix_keep_one (void)
+{
+  hb_face_t *face_XY = hb_test_open_font_file ("fonts/sbix.ttf");
+  hb_face_t *face_X = hb_test_open_font_file ("fonts/sbix_X.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_X_subset;
+  hb_set_add (codepoints, 88);
+  face_X_subset = hb_subset_test_create_subset (face_XY, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_X, face_X_subset, HB_TAG ('s','b','i','x'));
+
+  hb_face_destroy (face_X_subset);
+  hb_face_destroy (face_XY);
+  hb_face_destroy (face_X);
+}
+
+// TODO: add a test that doesn't use contiguous codepoints.
+// TODO: add a test that keeps no codepoints.
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_sbix_noop);
+  hb_test_add (test_subset_sbix_keep_one);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-subset-vvar.c b/test/api/test-subset-vvar.c
new file mode 100644
index 0000000..7b526d9
--- /dev/null
+++ b/test/api/test-subset-vvar.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for VVAR subsetting */
+
+static void
+test_subset_VVAR_noop (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('V','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+}
+
+static void
+test_subset_VVAR (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.ac.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('V','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_VVAR_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('V','V','A','R'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_VVAR_noop);
+  hb_test_add (test_subset_VVAR);
+  hb_test_add (test_subset_VVAR_retaingids);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-subset.c b/test/api/test-subset.c
index 85e4fdf..27bf73c 100644
--- a/test/api/test-subset.c
+++ b/test/api/test-subset.c
@@ -42,7 +42,7 @@
   hb_set_add (codepoints, 'b');
   hb_set_add (codepoints, 'c');
 
-  subset = hb_subset (face, input);
+  subset = hb_subset_or_fail (face, input);
   g_assert (subset);
   g_assert (subset != hb_face_get_empty ());
 
@@ -64,9 +64,8 @@
   hb_set_add (codepoints, 'b');
   hb_set_add (codepoints, 'c');
 
-  subset = hb_subset (face, input);
-  g_assert (subset);
-  g_assert (subset == hb_face_get_empty ());
+  subset = hb_subset_or_fail (face, input);
+  g_assert (!subset);
 
   hb_subset_input_destroy (input);
   hb_face_destroy (subset);
@@ -86,15 +85,76 @@
   hb_set_add (codepoints, 'b');
   hb_set_add (codepoints, 'c');
 
-  subset = hb_subset (face, input);
-  g_assert (subset);
-  g_assert (subset == hb_face_get_empty ());
+  subset = hb_subset_or_fail (face, input);
+  g_assert (!subset);
 
   hb_subset_input_destroy (input);
   hb_face_destroy (subset);
   hb_face_destroy (face);
 }
 
+static void
+test_subset_set_flags (void)
+{
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+
+  g_assert (hb_subset_input_get_flags (input) == HB_SUBSET_FLAGS_DEFAULT);
+
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_NAME_LEGACY |
+                             HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+                             HB_SUBSET_FLAGS_GLYPH_NAMES);
+
+  g_assert (hb_subset_input_get_flags (input) ==
+            (hb_subset_flags_t) (
+            HB_SUBSET_FLAGS_NAME_LEGACY |
+            HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+            HB_SUBSET_FLAGS_GLYPH_NAMES));
+
+  hb_subset_input_set_flags (input,
+                             HB_SUBSET_FLAGS_NAME_LEGACY |
+                             HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+                             HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES);
+
+  g_assert (hb_subset_input_get_flags (input) ==
+            (hb_subset_flags_t) (
+            HB_SUBSET_FLAGS_NAME_LEGACY |
+            HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+            HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES));
+
+
+  hb_subset_input_destroy (input);
+}
+
+
+static void
+test_subset_sets (void)
+{
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  hb_set_t* set = hb_set_create ();
+
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_GLYPH_INDEX), 83);
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_UNICODE), 85);
+
+  hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+  hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG), 87);
+
+  hb_set_add (set, 83);
+  g_assert (hb_set_is_equal (hb_subset_input_glyph_set (input), set));
+  hb_set_clear (set);
+
+  hb_set_add (set, 85);
+  g_assert (hb_set_is_equal (hb_subset_input_unicode_set (input), set));
+  hb_set_clear (set);
+
+  hb_set_add (set, 87);
+  g_assert (hb_set_is_equal (hb_subset_input_set (input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG), set));
+  hb_set_clear (set);
+
+  hb_set_destroy (set);
+  hb_subset_input_destroy (input);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -103,6 +163,8 @@
   hb_test_add (test_subset_32_tables);
   hb_test_add (test_subset_no_inf_loop);
   hb_test_add (test_subset_crash);
+  hb_test_add (test_subset_set_flags);
+  hb_test_add (test_subset_sets);
 
   return hb_test_run();
 }
diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c
index 71a471d..dd1e3d0 100644
--- a/test/api/test-unicode.c
+++ b/test/api/test-unicode.c
@@ -178,6 +178,12 @@
   /* Unicode-12.0 character additions */
   {   0x0EBA,   9 },
 
+  /* Unicode-13.0 character additions */
+  {   0x1ABF, 220 },
+
+  /* Unicode-14.0 character additions */
+  {   0x1DFA, 218 },
+
   { 0x111111, 0 }
 };
 
@@ -255,6 +261,12 @@
   /* Unicode-12.1 character additions */
   {   0x32FF, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
 
+  /* Unicode-13.0 character additions */
+  {   0x08BE, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
+
+  /* Unicode-14.0 character additions */
+  {   0x20C0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
+
   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
 };
 
@@ -499,6 +511,19 @@
   /* Unicode-12.1 additions */
   {   0x32FF, HB_SCRIPT_COMMON },
 
+  /* Unicode-13.0 additions */
+  {   0x10E80, HB_SCRIPT_YEZIDI },
+  {   0x10FB0, HB_SCRIPT_CHORASMIAN },
+  {   0x11900, HB_SCRIPT_DIVES_AKURU },
+  {   0x18B00, HB_SCRIPT_KHITAN_SMALL_SCRIPT },
+
+  /* Unicode-14.0 additions */
+  {  0x10570, HB_SCRIPT_VITHKUQI },
+  {  0x10F70, HB_SCRIPT_OLD_UYGHUR },
+  {  0x12F90, HB_SCRIPT_CYPRO_MINOAN },
+  {  0x16A70, HB_SCRIPT_TANGSA },
+  {  0x1E290, HB_SCRIPT_TOTO },
+
   { 0x111111, HB_SCRIPT_UNKNOWN }
 };
 
@@ -537,6 +562,8 @@
     G_N_ELEMENTS (name##_tests_more), \
     DEFAULT \
   }
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
 static const property_t properties[] =
 {
   PROPERTY (combining_class, 0),
@@ -544,6 +571,7 @@
   PROPERTY (mirroring, RETURNS_UNICODE_ITSELF),
   PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN)
 };
+#pragma GCC diagnostic pop
 #undef PROPERTY
 
 static void
diff --git a/test/api/test-var-coords.c b/test/api/test-var-coords.c
new file mode 100644
index 0000000..aa152e3
--- /dev/null
+++ b/test/api/test-var-coords.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb-ot.h>
+
+/* Unit tests for hb_font_[gs]et_var_coords_ */
+
+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))
+#endif
+
+#define EPSILON 0.05f
+	
+  hb_face_t *face = hb_test_open_font_file ("fonts/TestCFF2VF.otf");
+  hb_font_t *font = hb_font_create (face);
+
+  /* Normalized coords as input */
+  int normalized_coords[] = {100, 0};
+  hb_font_set_var_coords_normalized (font, normalized_coords, 2);
+  g_assert_cmpint ((int) hb_font_get_var_coords_design (font, NULL)[0], ==, 403);
+  g_assert_cmpint ((int) hb_font_get_var_coords_normalized (font, NULL)[0], ==, 100);
+
+  /* Design coords as input */
+  float design_coords[] = {206.f, 0};
+  hb_font_set_var_coords_design (font, design_coords, 2);
+  g_assert_cmpint ((int) hb_font_get_var_coords_normalized (font, NULL)[0], ==, -16117);
+  g_assert_cmpint ((int) hb_font_get_var_coords_design (font, NULL)[0], ==, 206);
+
+  for (float weight = 200; weight < 901; ++weight)
+  {
+    int normalized;
+    hb_ot_var_normalize_coords (face, 1, &weight, &normalized);
+    hb_font_set_var_coords_normalized (font, &normalized, 1);
+    float converted_back = hb_font_get_var_coords_design (font, NULL)[0];
+    // fprintf (stderr, "%f: %d => %f\n", weight, normalized, converted_back);
+    g_assert_true (G_APPROX_VALUE (converted_back, weight, EPSILON));
+  }
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+#endif
+}
+
+static void
+test_get_var_get_axis_infos (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf");
+
+  g_assert_cmpint (hb_ot_var_get_axis_count (face), ==, 2);
+
+  hb_ot_var_axis_info_t info;
+  unsigned c = 1;
+
+  g_assert_cmpint (hb_ot_var_get_axis_infos (face, 0, &c, &info), ==, 2);
+  g_assert (info.tag == HB_TAG ('w','g','h','t'));
+  g_assert_cmpint (c, ==, 1);
+
+  hb_ot_var_get_axis_infos (face, 1, &c, &info);
+  g_assert (info.tag == HB_TAG ('w','d','t','h'));
+  g_assert_cmpint (c, ==, 1);
+
+  hb_ot_var_get_axis_infos (face, 2, &c, &info);
+  g_assert_cmpint (c, ==, 0);
+
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_get_var_coords);
+  hb_test_add (test_get_var_get_axis_infos);
+  return hb_test_run ();
+}
diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt
deleted file mode 100644
index 577d13c..0000000
--- a/test/fuzzing/CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-if (HB_CHECK)
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM)
-  extract_make_variable (hb_shape_fuzzer_SOURCES ${MAKEFILEAM})
-  extract_make_variable (hb_subset_fuzzer_SOURCES ${MAKEFILEAM})
-
-  # TODO: enable these two
-  #extract_make_variable (FUZZING_CPPFLAGS ${MAKEFILEAM}) # extracting regex fail
-  #add_executable (hb-shape-fuzzer # it should be run only after ragel execution
-  #  ${project_sources} ${project_extra_sources} ${project_headers}
-  #  ${hb_shape_fuzzer_SOURCES})
-
-  add_executable (hb-shape-fuzzer ${hb_shape_fuzzer_SOURCES})
-  target_link_libraries (hb-shape-fuzzer harfbuzz)
-
-  add_executable (hb-subset-fuzzer ${hb_subset_fuzzer_SOURCES})
-  target_link_libraries (hb-subset-fuzzer harfbuzz-subset)
-
-  target_compile_definitions(hb-shape-fuzzer PUBLIC ${FUZZING_CPPFLAGS})
-  target_compile_definitions(hb-subset-fuzzer PUBLIC ${FUZZING_CPPFLAGS})
-
-  add_test (NAME hb-shape-fuzzer
-    COMMAND "${PYTHON_EXECUTABLE}" run-shape-fuzzer-tests.py $<TARGET_FILE:hb-shape-fuzzer>
-    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-  add_test (NAME hb-subset-fuzzer
-    COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $<TARGET_FILE:hb-subset-fuzzer>
-    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-endif ()
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index 5bd2d7e..2e2b2c9 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -19,13 +19,16 @@
 	README \
 	run-shape-fuzzer-tests.py \
 	run-subset-fuzzer-tests.py \
-	CMakeLists.txt \
+	run-draw-fuzzer-tests.py \
+	meson.build \
 	fonts \
 	$(NULL)
 
 check_PROGRAMS = \
 	hb-shape-fuzzer \
 	hb-subset-fuzzer \
+	hb-set-fuzzer \
+	hb-draw-fuzzer \
 	$(NULL)
 
 AM_CPPFLAGS = \
@@ -54,9 +57,29 @@
 hb_subset_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
 hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la
 
+hb_set_fuzzer_SOURCES = \
+	hb-fuzzer.hh \
+	hb-set-fuzzer.cc \
+	main.cc \
+	$(NULL)
+hb_set_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
+hb_set_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
+hb_set_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
+
+hb_draw_fuzzer_SOURCES = \
+	hb-fuzzer.hh \
+	hb-draw-fuzzer.cc \
+	main.cc \
+	$(NULL)
+hb_draw_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
+hb_draw_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
+hb_draw_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
+
+
 check:
 	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-shape-fuzzer-tests.py
 	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-subset-fuzzer-tests.py
+	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-draw-fuzzer-tests.py
 check-valgrind:
 	$(AM_V_at)RUN_VALGRIND=1 $(MAKE) $(AM_MAKEFLGS) check
 
diff --git a/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376 b/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376
new file mode 100644
index 0000000..8e58f0d
--- /dev/null
+++ b/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376
Binary files differ
diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf
new file mode 100644
index 0000000..df1ff9b
--- /dev/null
+++ b/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf
Binary files differ
diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
new file mode 100644
index 0000000..cdccded
--- /dev/null
+++ b/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
Binary files differ
diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.ttf
new file mode 100644
index 0000000..14a544a
--- /dev/null
+++ b/test/fuzzing/fonts/NotoColorEmoji.subset.ttf
Binary files differ
diff --git a/test/fuzzing/fonts/TwemojiMozilla.subset.ttf b/test/fuzzing/fonts/TwemojiMozilla.subset.ttf
new file mode 100644
index 0000000..357dda3
--- /dev/null
+++ b/test/fuzzing/fonts/TwemojiMozilla.subset.ttf
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328
new file mode 100644
index 0000000..d13a838
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512
new file mode 100644
index 0000000..2b3143d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296
new file mode 100644
index 0000000..f476997
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648
new file mode 100644
index 0000000..29ea912
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696
new file mode 100644
index 0000000..0aaed32
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888
new file mode 100644
index 0000000..d18e3b5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176
new file mode 100644
index 0000000..5e0fe47
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640
new file mode 100644
index 0000000..897e4bc
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104
new file mode 100644
index 0000000..51828e8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008
new file mode 100644
index 0000000..4121e5a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056
new file mode 100644
index 0000000..760167f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352
new file mode 100644
index 0000000..c6e33d2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032
new file mode 100644
index 0000000..99af4b9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640
new file mode 100644
index 0000000..922d2d5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112
new file mode 100644
index 0000000..dd9ce36
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120
new file mode 100644
index 0000000..655cda5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816
new file mode 100644
index 0000000..458478e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032
new file mode 100644
index 0000000..7f8275a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144
new file mode 100644
index 0000000..9fea686
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432
new file mode 100644
index 0000000..c1fb1d1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712
new file mode 100644
index 0000000..f40b66b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776
new file mode 100644
index 0000000..f1fd18a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176
new file mode 100644
index 0000000..54fbd3b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920
new file mode 100644
index 0000000..b0adc5d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872
new file mode 100644
index 0000000..33fda47
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560
new file mode 100644
index 0000000..f6ce7c0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168
new file mode 100644
index 0000000..cffd8ac
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504
new file mode 100644
index 0000000..3ae21cd
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088
new file mode 100644
index 0000000..7ee1efa
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928
new file mode 100644
index 0000000..ecb527e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384
new file mode 100644
index 0000000..490e843
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304
new file mode 100644
index 0000000..951bc6c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120
new file mode 100644
index 0000000..bc9a1c4
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5952939792531456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5952939792531456
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5952939792531456
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144
new file mode 100644
index 0000000..4c81a86
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200
new file mode 100644
index 0000000..f002d27
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440
new file mode 100644
index 0000000..a27a9c1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944
new file mode 100644
index 0000000..3ab6230
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440
new file mode 100644
index 0000000..c243a78
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088
new file mode 100644
index 0000000..0e72493
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360
new file mode 100644
index 0000000..33603bb
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768
new file mode 100644
index 0000000..78a2709
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856
new file mode 100644
index 0000000..12b91a0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416
new file mode 100644
index 0000000..37e5368
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032
new file mode 100644
index 0000000..f5c27ee
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048
new file mode 100644
index 0000000..5c23559
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568
new file mode 100644
index 0000000..dc419f0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416
new file mode 100644
index 0000000..094f7d3
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008
new file mode 100644
index 0000000..cf9814a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128
new file mode 100644
index 0000000..cc6708a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072
new file mode 100644
index 0000000..f6e1461
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632
new file mode 100644
index 0000000..baff79f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752
new file mode 100644
index 0000000..319a56c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752
new file mode 100644
index 0000000..1ba504d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480
new file mode 100644
index 0000000..f27e995
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816
new file mode 100644
index 0000000..d8a3989
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816
@@ -0,0 +1 @@
+       
\ No newline at end of file
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5061207689134080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5061207689134080
new file mode 100644
index 0000000..85ed043
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5061207689134080
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032
new file mode 100644
index 0000000..2f2f7b8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936
new file mode 100644
index 0000000..3dbf5a5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240
new file mode 100644
index 0000000..9add16d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368
new file mode 100644
index 0000000..cc37c6e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496
new file mode 100644
index 0000000..6b0a192
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552
new file mode 100644
index 0000000..a9d66af
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880
new file mode 100644
index 0000000..ad45129
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072
new file mode 100644
index 0000000..bf1cd32
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912
new file mode 100644
index 0000000..1650649
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744
similarity index 100%
rename from test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744
rename to test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760
new file mode 100644
index 0000000..fb27d42
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408
new file mode 100644
index 0000000..310fabb
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864
new file mode 100644
index 0000000..7264709
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392
new file mode 100644
index 0000000..9b31fed
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032
new file mode 100644
index 0000000..d989234
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216
new file mode 100644
index 0000000..360938a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800
new file mode 100644
index 0000000..f6368c6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080
new file mode 100644
index 0000000..95f02d7
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4681956043390976 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4681956043390976
new file mode 100644
index 0000000..56bc941
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4681956043390976
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984
new file mode 100644
index 0000000..0a0f649
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880
new file mode 100644
index 0000000..d6624f3
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664
new file mode 100644
index 0000000..013a859
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5001604901240832 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5001604901240832
new file mode 100644
index 0000000..198be09
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5001604901240832
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5041767803125760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5041767803125760
new file mode 100644
index 0000000..d23fa57
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5041767803125760
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5072358514753536 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5072358514753536
new file mode 100644
index 0000000..d3cf859
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5072358514753536
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280
new file mode 100644
index 0000000..d94f5a7
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5127321313476608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5127321313476608
new file mode 100644
index 0000000..476e251
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5127321313476608
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688
new file mode 100644
index 0000000..7b049ba
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5141317848530944.fuzz b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5141317848530944.fuzz
new file mode 100644
index 0000000..df578c7
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5141317848530944.fuzz
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680
new file mode 100644
index 0000000..16213e4
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168
new file mode 100644
index 0000000..50db8d4
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024
new file mode 100644
index 0000000..fe83d24
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376
new file mode 100644
index 0000000..74958bf
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536
new file mode 100644
index 0000000..61e7fa1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472
new file mode 100644
index 0000000..250710b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744
new file mode 100644
index 0000000..e82995e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048
new file mode 100644
index 0000000..d04f7d8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5241922561114112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5241922561114112
new file mode 100644
index 0000000..122a968
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5241922561114112
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352
new file mode 100644
index 0000000..1c1919f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5269686781607936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5269686781607936
new file mode 100644
index 0000000..5c0ad79
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5269686781607936
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808
new file mode 100644
index 0000000..193cf89
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5362189182566400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5362189182566400
new file mode 100644
index 0000000..fb1b226
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5362189182566400
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904
new file mode 100644
index 0000000..1ad7971
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072
new file mode 100644
index 0000000..6b245f3
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417934246772736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417934246772736
new file mode 100644
index 0000000..03ba8eb
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5417934246772736
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5443213648330752 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5443213648330752
new file mode 100644
index 0000000..0d38d6d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5443213648330752
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5522792714993664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5522792714993664
new file mode 100644
index 0000000..4f714f3
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5522792714993664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544
new file mode 100644
index 0000000..0a9ce89
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400
new file mode 100644
index 0000000..d58d3f6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760
new file mode 100644
index 0000000..590e6fc
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552
new file mode 100644
index 0000000..f9cf239
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632
new file mode 100644
index 0000000..a83df52
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056
new file mode 100644
index 0000000..f639f17
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152
new file mode 100644
index 0000000..22827d6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984
new file mode 100644
index 0000000..dbf5f8c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248
new file mode 100644
index 0000000..8631cd6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112
new file mode 100644
index 0000000..24da16e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936
new file mode 100644
index 0000000..fbc3f52
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784
new file mode 100644
index 0000000..d283d14
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656
new file mode 100644
index 0000000..323f5c5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776
index 3881fbe..11a2367 100644
--- a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072
new file mode 100644
index 0000000..f1af962
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392
new file mode 100644
index 0000000..f7d3c0d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296
new file mode 100644
index 0000000..fc238c2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872
new file mode 100644
index 0000000..cc9e421
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400
new file mode 100644
index 0000000..9df6922
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032
new file mode 100644
index 0000000..ac1571c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296
new file mode 100644
index 0000000..42296e5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232
new file mode 100644
index 0000000..c72812e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976
new file mode 100644
index 0000000..f2f0ec9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344
new file mode 100644
index 0000000..fba50e5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664
new file mode 100644
index 0000000..01973d5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392
new file mode 100644
index 0000000..4356547
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128
new file mode 100644
index 0000000..96cfb00
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008
new file mode 100644
index 0000000..c464afa
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624
new file mode 100644
index 0000000..51cf483
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048
new file mode 100644
index 0000000..b7a3721
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715464591376384 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715464591376384
new file mode 100644
index 0000000..63faabe
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715464591376384
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072
new file mode 100644
index 0000000..383e61a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192
new file mode 100644
index 0000000..1e39613
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456
new file mode 100644
index 0000000..83314a1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688
new file mode 100644
index 0000000..31ea527
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688
new file mode 100644
index 0000000..b69d811
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280
new file mode 100644
index 0000000..557c823
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168
new file mode 100644
index 0000000..5761151
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512
new file mode 100644
index 0000000..46ec929
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880
new file mode 100644
index 0000000..8717442
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432
new file mode 100644
index 0000000..b93e1b1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856
new file mode 100644
index 0000000..b23c11a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456
new file mode 100644
index 0000000..96775e9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840
new file mode 100644
index 0000000..af2a62a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624
new file mode 100644
index 0000000..90a743b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032
new file mode 100644
index 0000000..028e4b2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128
new file mode 100644
index 0000000..a5f5af8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5965777994907648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5965777994907648
new file mode 100644
index 0000000..a302c10
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5965777994907648
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5991762219892736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5991762219892736
new file mode 100644
index 0000000..de5d90e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5991762219892736
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064
new file mode 100644
index 0000000..035dd72
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256
new file mode 100644
index 0000000..3f0f045
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136
new file mode 100644
index 0000000..6419459
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312
new file mode 100644
index 0000000..750700f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6254792024915968 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6254792024915968
new file mode 100644
index 0000000..9debc1d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6254792024915968
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848
new file mode 100644
index 0000000..5465069
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6315334756335616 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6315334756335616
new file mode 100644
index 0000000..a7d8dda
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6315334756335616
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800
new file mode 100644
index 0000000..b01eb8d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664
new file mode 100644
index 0000000..696bd6e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360
new file mode 100644
index 0000000..b6aab7b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856
new file mode 100644
index 0000000..3d883bd
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6616166961905664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6616166961905664
new file mode 100644
index 0000000..35b6479
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6616166961905664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424
new file mode 100644
index 0000000..0bbeb5c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424
Binary files differ
diff --git a/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer
new file mode 100644
index 0000000..0f6503d
--- /dev/null
+++ b/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer
Binary files differ
diff --git a/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer b/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer
new file mode 100644
index 0000000..8b1c293
--- /dev/null
+++ b/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer
Binary files differ
diff --git a/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer
new file mode 100644
index 0000000..eac0b7d
--- /dev/null
+++ b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer\0501\051" "b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer\0501\051"
new file mode 100644
index 0000000..d508980
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer\0501\051"
Binary files differ
diff --git a/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer
new file mode 100644
index 0000000..a358833
--- /dev/null
+++ b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer\0501\051" "b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer\0501\051"
new file mode 100644
index 0000000..a358833
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer\0501\051"
Binary files differ
diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer
new file mode 100644
index 0000000..f467471
--- /dev/null
+++ b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0501\051" "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0501\051"
new file mode 100644
index 0000000..d53fcff
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0501\051"
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0502\051" "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0502\051"
new file mode 100644
index 0000000..bab475e
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0502\051"
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0503\051" "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0503\051"
new file mode 100644
index 0000000..81045cf
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0503\051"
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0504\051" "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0504\051"
new file mode 100644
index 0000000..ee58436
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0504\051"
Binary files differ
diff --git "a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0505\051" "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0505\051"
new file mode 100644
index 0000000..f467471
--- /dev/null
+++ "b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer\0505\051"
Binary files differ
diff --git a/test/fuzzing/fonts/kanit.ttf b/test/fuzzing/fonts/kanit.ttf
new file mode 100644
index 0000000..03dc644
--- /dev/null
+++ b/test/fuzzing/fonts/kanit.ttf
Binary files differ
diff --git a/test/fuzzing/fonts/leak-34f1798a142fd0dfdd71a96fb6aa7de19a62865e b/test/fuzzing/fonts/leak-34f1798a142fd0dfdd71a96fb6aa7de19a62865e
new file mode 100644
index 0000000..0726b93
--- /dev/null
+++ b/test/fuzzing/fonts/leak-34f1798a142fd0dfdd71a96fb6aa7de19a62865e
Binary files differ
diff --git a/test/fuzzing/fonts/sbix.ttf b/test/fuzzing/fonts/sbix.ttf
new file mode 100644
index 0000000..e3da30a
--- /dev/null
+++ b/test/fuzzing/fonts/sbix.ttf
Binary files differ
diff --git a/test/fuzzing/hb-draw-fuzzer.cc b/test/fuzzing/hb-draw-fuzzer.cc
new file mode 100644
index 0000000..772a358
--- /dev/null
+++ b/test/fuzzing/hb-draw-fuzzer.cc
@@ -0,0 +1,177 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include <hb-ot.h>
+
+#include "hb-fuzzer.hh"
+
+#ifdef HB_EXPERIMENTAL_API
+struct _user_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;
+};
+
+static void
+_move_to (hb_position_t to_x, hb_position_t 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;
+}
+
+static void
+_line_to (hb_position_t to_x, hb_position_t 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;
+}
+
+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_)
+{
+  _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;
+}
+
+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_)
+{
+  _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;
+}
+
+static void
+_close_path (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);
+}
+#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)
+{
+  /* Other gid specific misc calls */
+  hb_face_collect_variation_unicodes (face, cp, set);
+
+  hb_codepoint_t g;
+  hb_font_get_nominal_glyph (font, cp, &g);
+  hb_font_get_variation_glyph (font, cp, cp, &g);
+  hb_font_get_glyph_h_advance (font, cp);
+  hb_font_get_glyph_v_advance (font, cp);
+  hb_position_t x, y;
+  hb_font_get_glyph_h_origin (font, cp, &x, &y);
+  hb_font_get_glyph_v_origin (font, cp, &x, &y);
+  hb_font_get_glyph_contour_point (font, cp, 0, &x, &y);
+  char buf[64];
+  hb_font_get_glyph_name (font, cp, buf, sizeof (buf));
+
+  hb_ot_color_palette_get_name_id (face, cp);
+  hb_ot_color_palette_color_get_name_id (face, cp);
+  hb_ot_color_palette_get_flags (face, cp);
+  hb_ot_color_palette_get_colors (face, cp, 0, nullptr, nullptr);
+  hb_ot_color_glyph_get_layers (face, cp, 0, nullptr, nullptr);
+  hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, cp));
+  hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp));
+
+  hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, cp, 0, nullptr, nullptr);
+
+  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_variants (font, cp, HB_DIRECTION_TTB, 0, nullptr, nullptr);
+  hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, nullptr, nullptr, nullptr);
+}
+
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
+{
+  alloc_state = size; /* see src/failing-alloc.c */
+
+  hb_blob_t *blob = hb_blob_create ((const char *) data, size,
+				    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+  hb_face_t *face = hb_face_create (blob, 0);
+  hb_font_t *font = hb_font_create (face);
+
+  unsigned num_coords = 0;
+  if (size) num_coords = data[size - 1];
+  num_coords = hb_ot_var_get_axis_count (face) > num_coords ? num_coords : hb_ot_var_get_axis_count (face);
+  int *coords = (int *) calloc (num_coords, sizeof (int));
+  if (size > num_coords + 1)
+    for (unsigned i = 0; i < num_coords; ++i)
+      coords[i] = ((int) data[size - num_coords + i - 1] - 128) * 10;
+  hb_font_set_var_coords_normalized (font, coords, num_coords);
+  free (coords);
+
+  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};
+
+  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
+  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
+
+    /* Glyph extents also may practices the similar path, call it now that is related */
+    hb_glyph_extents_t extents;
+    if (hb_font_get_glyph_extents (font, gid, &extents))
+      counter += !!extents.width + !!extents.height + !!extents.x_bearing + !!extents.y_bearing;
+
+    if (!counter) counter += 1;
+
+    /* other misc calls */
+    misc_calls_for_gid (face, font, set, gid);
+  }
+  hb_set_destroy (set);
+  assert (counter);
+#ifdef HB_EXPERIMENTAL_API
+  hb_draw_funcs_destroy (funcs);
+#endif
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+  hb_blob_destroy (blob);
+  return 0;
+}
diff --git a/test/fuzzing/hb-fuzzer.hh b/test/fuzzing/hb-fuzzer.hh
index d0c617e..52e00dd 100644
--- a/test/fuzzing/hb-fuzzer.hh
+++ b/test/fuzzing/hb-fuzzer.hh
@@ -1,4 +1,18 @@
 #include <hb.h>
 #include <stddef.h>
 
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size);
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
+#define HB_UNUSED	__attribute__((unused))
+#else
+#define HB_UNUSED
+#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
diff --git a/test/fuzzing/hb-set-fuzzer.cc b/test/fuzzing/hb-set-fuzzer.cc
new file mode 100644
index 0000000..0a547f3
--- /dev/null
+++ b/test/fuzzing/hb-set-fuzzer.cc
@@ -0,0 +1,90 @@
+#include "hb-fuzzer.hh"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hb.h"
+
+// Only allow ~5,000 set values between the two input sets.
+// Arbitarily long input sets do not trigger any meaningful
+// differences in behaviour so there's no benefit from allowing
+// the fuzzer to create super large sets.
+#define MAX_INPUT_SIZE 20000
+
+enum set_operation_t : uint8_t
+{
+  INTERSECT = 0,
+  UNION = 1,
+  SUBTRACT = 2,
+  SYMMETRIC_DIFFERENCE = 3
+};
+
+struct instructions_t
+{
+  set_operation_t operation;
+  uint32_t first_set_size;
+};
+
+static hb_set_t *create_set (const uint32_t *value_array, int count)
+{
+  hb_set_t *set = hb_set_create ();
+  for (int i = 0; i < count; i++)
+    hb_set_add (set, value_array[i]);
+  return set;
+}
+
+
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
+{
+  alloc_state = size; /* see src/failing-alloc.c */
+
+  if (size < sizeof (instructions_t))
+    return 0;
+
+  if (size > MAX_INPUT_SIZE)
+    return 0;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+  const instructions_t &instructions = reinterpret_cast<const instructions_t &> (data);
+#pragma GCC diagnostic pop
+  data += sizeof (instructions_t);
+  size -= sizeof (instructions_t);
+
+  const uint32_t *values = reinterpret_cast<const uint32_t *> (data);
+  size = size / sizeof (uint32_t);
+
+  if (size < instructions.first_set_size)
+    return 0;
+
+  hb_set_t *set_a = create_set (values, instructions.first_set_size);
+
+  values += instructions.first_set_size;
+  size -= instructions.first_set_size;
+  hb_set_t *set_b = create_set (values, size);
+
+  switch (instructions.operation)
+  {
+  case INTERSECT:
+    hb_set_intersect (set_a, set_b);
+    break;
+  case UNION:
+    hb_set_union (set_a, set_b);
+    break;
+  case SUBTRACT:
+    hb_set_subtract (set_a, set_b);
+    break;
+  case SYMMETRIC_DIFFERENCE:
+    hb_set_symmetric_difference (set_a, set_b);
+    break;
+  default:
+    break;
+  }
+
+  hb_set_destroy (set_a);
+  hb_set_destroy (set_b);
+
+  return 0;
+}
diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc
index 64a6b12..661ea9f 100644
--- a/test/fuzzing/hb-shape-fuzzer.cc
+++ b/test/fuzzing/hb-shape-fuzzer.cc
@@ -3,12 +3,16 @@
 #include <hb-ot.h>
 #include <string.h>
 
+#include <stdlib.h>
+
 #define TEST_OT_FACE_NO_MAIN 1
 #include "../api/test-ot-face.c"
 #undef TEST_OT_FACE_NO_MAIN
 
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
+  alloc_state = size; /* see src/failing-alloc.c */
+
   hb_blob_t *blob = hb_blob_create ((const char *)data, size,
 				    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
   hb_face_t *face = hb_face_create (blob, 0);
@@ -16,6 +20,16 @@
   hb_ot_font_set_funcs (font);
   hb_font_set_scale (font, 12, 12);
 
+  unsigned num_coords = 0;
+  if (size) num_coords = data[size - 1];
+  num_coords = hb_ot_var_get_axis_count (face) > num_coords ? num_coords : hb_ot_var_get_axis_count (face);
+  int *coords = (int *) calloc (num_coords, sizeof (int));
+  if (size > num_coords + 1)
+    for (unsigned i = 0; i < num_coords; ++i)
+      coords[i] = ((int) data[size - num_coords + i - 1] - 128) * 10;
+  hb_font_set_var_coords_normalized (font, coords, num_coords);
+  free (coords);
+
   {
     const char text[] = "ABCDEXYZ123@_%&)*$!";
     hb_buffer_t *buffer = hb_buffer_create ();
@@ -29,7 +43,11 @@
   unsigned int len = sizeof (text32);
   if (size < len)
     len = size;
-  memcpy(text32, data + size - len, len);
+  if (len)
+    memcpy (text32, data + size - len, len);
+
+  /* Misc calls on font. */
+  text32[10] = test_font (font, text32[15]) % 256;
 
   hb_buffer_t *buffer = hb_buffer_create ();
   hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
@@ -37,9 +55,6 @@
   hb_shape (font, buffer, nullptr, 0);
   hb_buffer_destroy (buffer);
 
-  /* Misc calls on face. */
-  test_face (face, text32[15]);
-
   hb_font_destroy (font);
   hb_face_destroy (face);
   hb_blob_destroy (blob);
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index 428765e..fa95c87 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -11,28 +11,20 @@
 trySubset (hb_face_t *face,
 	   const hb_codepoint_t text[],
 	   int text_length,
-	   bool drop_hints,
-	   bool drop_layout,
-	   bool retain_gids)
+           unsigned flag_bits)
 {
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
-  hb_subset_input_set_drop_hints (input, drop_hints);
-  hb_subset_input_set_retain_gids (input, retain_gids);
+  if (!input) return;
+
+  hb_subset_input_set_flags (input, (hb_subset_flags_t) flag_bits);
+
   hb_set_t *codepoints = hb_subset_input_unicode_set (input);
 
-  if (!drop_layout)
-  {
-    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'S', 'U', 'B'));
-    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'P', 'O', 'S'));
-    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'D', 'E', 'F'));
-  }
-
   for (int i = 0; i < text_length; i++)
-  {
     hb_set_add (codepoints, text[i]);
-  }
 
-  hb_face_t *result = hb_subset (face, input);
+  hb_face_t *result = hb_subset_or_fail (face, input);
+  if (result)
   {
     hb_blob_t *blob = hb_face_reference_blob (result);
     unsigned int length;
@@ -51,31 +43,20 @@
   hb_subset_input_destroy (input);
 }
 
-static void
-trySubset (hb_face_t *face,
-	   const hb_codepoint_t text[],
-	   int text_length,
-	   const uint8_t flags[1])
+extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
 {
-  bool drop_hints =  flags[0] & (1 << 0);
-  bool drop_layout = flags[0] & (1 << 1);
-  bool retain_gids = flags[0] & (1 << 2);
-  trySubset (face, text, text_length,
-	     drop_hints, drop_layout, retain_gids);
-}
+  alloc_state = size; /* see src/failing-alloc.c */
 
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
-  hb_blob_t *blob = hb_blob_create ((const char *)data, size,
+  hb_blob_t *blob = hb_blob_create ((const char *) data, size,
 				    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
   hb_face_t *face = hb_face_create (blob, 0);
 
   /* Just test this API here quickly. */
-  hb_set_t *output = hb_set_create();
+  hb_set_t *output = hb_set_create ();
   hb_face_collect_unicodes (face, output);
   hb_set_destroy (output);
 
-  uint8_t flags[1] = {0};
+  unsigned flags = HB_SUBSET_FLAGS_DEFAULT;
   const hb_codepoint_t text[] =
       {
 	'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
@@ -85,14 +66,14 @@
   trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags);
 
   hb_codepoint_t text_from_data[16];
-  if (size > sizeof(text_from_data) + sizeof(flags)) {
+  if (size > sizeof (text_from_data) + sizeof (flags)) {
     memcpy (text_from_data,
-	    data + size - sizeof(text_from_data),
-	    sizeof(text_from_data));
+	    data + size - sizeof (text_from_data),
+	    sizeof (text_from_data));
 
-    memcpy (flags,
-	    data + size - sizeof(text_from_data) - sizeof(flags),
-	    sizeof(flags));
+    memcpy (&flags,
+	    data + size - sizeof (text_from_data) - sizeof (flags),
+	    sizeof (flags));
     unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
 
     trySubset (face, text_from_data, text_size, flags);
diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc
index 5318f64..3024eb5 100644
--- a/test/fuzzing/main.cc
+++ b/test/fuzzing/main.cc
@@ -1,28 +1,22 @@
 #include "hb-fuzzer.hh"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
+#include <cassert>
+#include <cstdio>
 
 int main (int argc, char **argv)
 {
-  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
-
-  unsigned int len;
-  const char *font_data = hb_blob_get_data (blob, &len);
-  if (len == 0)
-  {
-    printf ("Font not found.\n");
-    exit (1);
-  }
-
   for (int i = 1; i < argc; i++)
   {
-    printf ("%s\n", argv[i]);
+    hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[i]);
+    assert (blob);
+
+    unsigned len = 0;
+    const char *font_data = hb_blob_get_data (blob, &len);
+    printf ("%s (%u bytes)\n", argv[i], len);
+
     LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len);
+
+    hb_blob_destroy (blob);
   }
-
-  hb_blob_destroy (blob);
-
   return 0;
 }
diff --git a/test/fuzzing/meson.build b/test/fuzzing/meson.build
new file mode 100644
index 0000000..9ddb4b2
--- /dev/null
+++ b/test/fuzzing/meson.build
@@ -0,0 +1,65 @@
+tests = [
+  'hb-shape-fuzzer.cc',
+  'hb-subset-fuzzer.cc',
+  'hb-set-fuzzer.cc',
+  'hb-draw-fuzzer.cc',
+]
+
+foreach file_name : tests
+  test_name = file_name.split('.')[0]
+
+  sources = [file_name]
+  fuzzer_ldflags = []
+  extra_cpp_args = []
+
+  if get_option('fuzzer_ldflags') == ''
+    sources += 'main.cc'
+  else
+    fuzzer_ldflags += get_option('fuzzer_ldflags').split()
+    extra_cpp_args += '-DHB_IS_IN_FUZZER'
+  endif
+
+  exe = executable(test_name, sources,
+    cpp_args: cpp_args + extra_cpp_args,
+    include_directories: [incconfig, incsrc],
+    link_args: fuzzer_ldflags,
+    link_with: [libharfbuzz, libharfbuzz_subset],
+    install: false,
+  )
+  set_variable('@0@_exe'.format(test_name.underscorify()), exe)
+endforeach
+
+env = environment()
+env.set('srcdir', meson.current_source_dir())
+
+test('shape_fuzzer', find_program('run-shape-fuzzer-tests.py'),
+  args: [
+    hb_shape_fuzzer_exe,
+  ],
+  timeout: 300,
+  depends: [hb_shape_fuzzer_exe, libharfbuzz, libharfbuzz_subset],
+  workdir: join_paths(meson.current_build_dir(), '..', '..'),
+  env: env,
+  suite: ['fuzzing', 'slow'],
+)
+
+test('subset_fuzzer', find_program('run-subset-fuzzer-tests.py'),
+  args: [
+    hb_subset_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: join_paths(meson.current_build_dir(), '..', '..'),
+  env: env,
+  suite: ['fuzzing', 'slow'],
+)
+
+test('draw_fuzzer', find_program('run-draw-fuzzer-tests.py'),
+  args: [
+    hb_draw_fuzzer_exe,
+  ],
+  workdir: join_paths(meson.current_build_dir(), '..', '..'),
+  env: env,
+  suite: ['fuzzing'],
+)
diff --git a/test/fuzzing/run-draw-fuzzer-tests.py b/test/fuzzing/run-draw-fuzzer-tests.py
new file mode 100755
index 0000000..8b5a2e8
--- /dev/null
+++ b/test/fuzzing/run-draw-fuzzer-tests.py
@@ -0,0 +1,66 @@
+#!/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_draw_fuzzer = os.path.join (top_builddir, "hb-draw-fuzzer" + EXEEXT)
+
+if not os.path.exists (hb_draw_fuzzer):
+	if len (sys.argv) == 1 or not os.path.exists (sys.argv[1]):
+		sys.exit ("""Failed to find hb-draw-fuzzer binary automatically,
+please provide it as the first argument to the tool""")
+
+	hb_draw_fuzzer = sys.argv[1]
+
+print ('hb_draw_fuzzer:', hb_draw_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.""")
+
+parent_path = os.path.join (srcdir, "fonts")
+for file in os.listdir (parent_path):
+	if "draw" not in file: continue
+	path = os.path.join (parent_path, file)
+
+	if valgrind:
+		text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_draw_fuzzer, path])
+	else:
+		text, returncode = cmd ([hb_draw_fuzzer, path])
+		if 'error' in text:
+			returncode = 1
+
+	if (not valgrind or returncode) and text.strip ():
+		print (text)
+
+	if returncode != 0:
+		print ('failure on %s' % file)
+		fails = fails + 1
+
+
+if fails:
+	sys.exit ("%d draw fuzzer related tests failed." % fails)
diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py
index 94fc877..382f609 100755
--- a/test/fuzzing/run-shape-fuzzer-tests.py
+++ b/test/fuzzing/run-shape-fuzzer-tests.py
@@ -1,43 +1,14 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
-
-import sys, os, subprocess, tempfile, threading
-
-
-def which (program):
-	# https://stackoverflow.com/a/377028
-	def is_exe (fpath):
-		return os.path.isfile (fpath) and os.access (fpath, os.X_OK)
-
-	fpath, _ = os.path.split (program)
-	if fpath:
-		if is_exe (program):
-			return program
-	else:
-		for path in os.environ["PATH"].split (os.pathsep):
-			exe_file = os.path.join (path, program)
-			if is_exe (exe_file):
-				return exe_file
-
-	return None
+import sys, os, subprocess, tempfile, shutil
 
 
 def cmd (command):
-	# https://stackoverflow.com/a/4408409
-	# https://stackoverflow.com/a/10012262
+	# https://stackoverflow.com/a/4408409 as we might have huge output sometimes
 	with tempfile.TemporaryFile () as tempf:
 		p = subprocess.Popen (command, stderr=tempf)
-		is_killed = {'value': False}
-
-		def timeout (p, is_killed):
-			is_killed['value'] = True
-			p.kill ()
-		timeout_seconds = int (os.environ.get ("HB_TEST_SHAPE_FUZZER_TIMEOUT", "2"))
-		timer = threading.Timer (timeout_seconds, timeout, [p, is_killed])
 
 		try:
-			timer.start()
 			p.wait ()
 			tempf.seek (0)
 			text = tempf.read ()
@@ -45,51 +16,38 @@
 			#TODO: Detect debug mode with a better way
 			is_debug_mode = b"SANITIZE" in text
 
-			text = "" if is_debug_mode else text.decode ("utf-8").strip ()
-			returncode = p.returncode
-		finally:
-			timer.cancel()
-
-		if is_killed['value']:
-			text = 'error: timeout, ' + text
-			returncode = 1
-
-		return text, returncode
+			return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode
+		except subprocess.TimeoutExpired:
+			return 'error: timeout, ' + ' '.join (command), 1
 
 
-srcdir = os.environ.get ("srcdir", ".")
-EXEEXT = os.environ.get ("EXEEXT", "")
-top_builddir = os.environ.get ("top_builddir", ".")
+srcdir = os.getenv ("srcdir", ".")
+EXEEXT = os.getenv ("EXEEXT", "")
+top_builddir = os.getenv ("top_builddir", ".")
 hb_shape_fuzzer = os.path.join (top_builddir, "hb-shape-fuzzer" + EXEEXT)
 
 if not os.path.exists (hb_shape_fuzzer):
 	if len (sys.argv) == 1 or not os.path.exists (sys.argv[1]):
-		print ("""Failed to find hb-shape-fuzzer binary automatically,
+		sys.exit ("""Failed to find hb-shape-fuzzer binary automatically,
 please provide it as the first argument to the tool""")
-		sys.exit (1)
 
 	hb_shape_fuzzer = sys.argv[1]
 
 print ('hb_shape_fuzzer:', hb_shape_fuzzer)
 fails = 0
 
-libtool = os.environ.get ('LIBTOOL')
 valgrind = None
-if os.environ.get ('RUN_VALGRIND', ''):
-	valgrind = which ('valgrind')
+if os.getenv ('RUN_VALGRIND', ''):
+	valgrind = shutil.which ('valgrind')
 	if valgrind is None:
-		print ("""Valgrind requested but not found.""")
-		sys.exit (1)
-	if libtool is None:
-		print ("""Valgrind support is currently autotools only and needs libtool but not found.""")
-
+		sys.exit ("""Valgrind requested but not found.""")
 
 parent_path = os.path.join (srcdir, "fonts")
 for file in os.listdir (parent_path):
 	path = os.path.join (parent_path, file)
 
 	if valgrind:
-		text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --error-exitcode=1', '--', hb_shape_fuzzer, path])
+		text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_shape_fuzzer, path])
 	else:
 		text, returncode = cmd ([hb_shape_fuzzer, path])
 		if 'error' in text:
@@ -104,5 +62,4 @@
 
 
 if fails:
-	print ("%i shape fuzzer related tests failed." % fails)
-	sys.exit (1)
+	sys.exit ("%d shape fuzzer related tests failed." % fails)
diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py
index f290e6e..da7d1e5 100755
--- a/test/fuzzing/run-subset-fuzzer-tests.py
+++ b/test/fuzzing/run-subset-fuzzer-tests.py
@@ -1,43 +1,14 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-from __future__ import print_function, division, absolute_import
-
-import sys, os, subprocess, tempfile, threading
+import sys, os, subprocess, tempfile, shutil
 
 
-def which(program):
-	# https://stackoverflow.com/a/377028
-	def is_exe(fpath):
-		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
-
-	fpath, _ = os.path.split(program)
-	if fpath:
-		if is_exe(program):
-			return program
-	else:
-		for path in os.environ["PATH"].split(os.pathsep):
-			exe_file = os.path.join(path, program)
-			if is_exe(exe_file):
-				return exe_file
-
-	return None
-
-
-def cmd(command):
-	# https://stackoverflow.com/a/4408409
-	# https://stackoverflow.com/a/10012262
-	with tempfile.TemporaryFile() as tempf:
+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)
-		is_killed = {'value': False}
-
-		def timeout(p, is_killed):
-			is_killed['value'] = True
-			p.kill()
-		timeout_seconds = int (os.environ.get ("HB_TEST_SUBSET_FUZZER_TIMEOUT", "8"))
-		timer = threading.Timer (timeout_seconds, timeout, [p, is_killed])
 
 		try:
-			timer.start()
 			p.wait ()
 			tempf.seek (0)
 			text = tempf.read ()
@@ -45,44 +16,31 @@
 			#TODO: Detect debug mode with a better way
 			is_debug_mode = b"SANITIZE" in text
 
-			text = "" if is_debug_mode else text.decode ("utf-8").strip ()
-			returncode = p.returncode
-		finally:
-			timer.cancel()
-
-		if is_killed['value']:
-			text = 'error: timeout, ' + text
-			returncode = 1
-
-		return text, returncode
+			return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode
+		except subprocess.TimeoutExpired:
+			return 'error: timeout, ' + ' '.join (command), 1
 
 
-srcdir = os.environ.get ("srcdir", ".")
-EXEEXT = os.environ.get ("EXEEXT", "")
-top_builddir = os.environ.get ("top_builddir", ".")
+srcdir = os.getenv ("srcdir", ".")
+EXEEXT = os.getenv ("EXEEXT", "")
+top_builddir = os.getenv ("top_builddir", ".")
 hb_subset_fuzzer = os.path.join (top_builddir, "hb-subset-fuzzer" + EXEEXT)
 
 if not os.path.exists (hb_subset_fuzzer):
         if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]):
-                print ("""Failed to find hb-subset-fuzzer binary automatically,
+                sys.exit ("""Failed to find hb-subset-fuzzer binary automatically,
 please provide it as the first argument to the tool""")
-                sys.exit (1)
 
         hb_subset_fuzzer = sys.argv[1]
 
 print ('hb_subset_fuzzer:', hb_subset_fuzzer)
 fails = 0
 
-libtool = os.environ.get('LIBTOOL')
 valgrind = None
-if os.environ.get('RUN_VALGRIND', ''):
-	valgrind = which ('valgrind')
+if os.getenv ('RUN_VALGRIND', ''):
+	valgrind = shutil.which ('valgrind')
 	if valgrind is None:
-		print ("""Valgrind requested but not found.""")
-		sys.exit (1)
-	if libtool is None:
-		print ("""Valgrind support is currently autotools only and needs libtool but not found.""")
-
+		sys.exit ("""Valgrind requested but not found.""")
 
 def run_dir (parent_path):
 	global fails
@@ -93,7 +51,7 @@
 
 		print ("running subset fuzzer against %s" % path)
 		if valgrind:
-			text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --show-leak-kinds=all --error-exitcode=1', '--', hb_subset_fuzzer, path])
+			text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_subset_fuzzer, path])
 		else:
 			text, returncode = cmd ([hb_subset_fuzzer, path])
 			if 'error' in text:
@@ -111,5 +69,4 @@
 run_dir (os.path.join (srcdir, "fonts"))
 
 if fails:
-        print ("%i subset fuzzer related tests failed." % fails)
-        sys.exit (1)
+	sys.exit ("%d subset 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
index 0000000..d8a3989
--- /dev/null
+++ b/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816
@@ -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
index 0000000..5b1e7e3
--- /dev/null
+++ b/test/fuzzing/sets/intersect_01
Binary files differ
diff --git a/test/fuzzing/sets/subtract_01 b/test/fuzzing/sets/subtract_01
new file mode 100644
index 0000000..1c60ac6
--- /dev/null
+++ b/test/fuzzing/sets/subtract_01
Binary files differ
diff --git a/test/fuzzing/sets/symmetric_diff_01 b/test/fuzzing/sets/symmetric_diff_01
new file mode 100644
index 0000000..70801a7
--- /dev/null
+++ b/test/fuzzing/sets/symmetric_diff_01
Binary files differ
diff --git a/test/fuzzing/sets/union_01 b/test/fuzzing/sets/union_01
new file mode 100644
index 0000000..5a13eb0
--- /dev/null
+++ b/test/fuzzing/sets/union_01
Binary files differ
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 0000000..8b4b83f
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,4 @@
+subdir('api')
+subdir('shape')
+subdir('subset')
+subdir('fuzzing')
diff --git a/test/shape/Makefile.am b/test/shape/Makefile.am
new file mode 100644
index 0000000..316b173
--- /dev/null
+++ b/test/shape/Makefile.am
@@ -0,0 +1,39 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+SUBDIRS = data
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+libs:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
+
+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)
+
+# TODO Figure out Python stuff
+EXTRA_DIST += \
+	hb_test_tools.py \
+	$(NULL)
+CLEANFILES += \
+	hb_test_tools.py[co] \
+	$(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/test/shaping/README.md b/test/shape/README.md
similarity index 100%
rename from test/shaping/README.md
rename to test/shape/README.md
diff --git a/test/shaping/data/Makefile.am b/test/shape/data/Makefile.am
similarity index 100%
rename from test/shaping/data/Makefile.am
rename to test/shape/data/Makefile.am
diff --git a/test/shaping/data/aots/COPYING b/test/shape/data/aots/COPYING
similarity index 100%
rename from test/shaping/data/aots/COPYING
rename to test/shape/data/aots/COPYING
diff --git a/test/shape/data/aots/Makefile.am b/test/shape/data/aots/Makefile.am
new file mode 100644
index 0000000..6b71d89
--- /dev/null
+++ b/test/shape/data/aots/Makefile.am
@@ -0,0 +1,27 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+EXTRA_DIST = \
+	COPYING \
+	fonts \
+	update.py \
+	meson.build \
+	$(TESTS) \
+	$(NULL)
+
+TEST_EXTENSIONS = .tests
+if HAVE_FREETYPE
+TESTS_ENVIRONMENT = HAVE_FREETYPE=1
+else
+TESTS_ENVIRONMENT = HAVE_FREETYPE=0
+endif
+TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
+
+include Makefile.sources
+
+-include $(top_srcdir)/git.mk
diff --git a/test/shape/data/aots/Makefile.sources b/test/shape/data/aots/Makefile.sources
new file mode 100644
index 0000000..ffa311b
--- /dev/null
+++ b/test/shape/data/aots/Makefile.sources
@@ -0,0 +1,133 @@
+TESTS = \
+	tests/classdef1_empty.tests \
+	tests/classdef1_multiple.tests \
+	tests/classdef1_single.tests \
+	tests/classdef1.tests \
+	tests/classdef2_empty.tests \
+	tests/classdef2_multiple.tests \
+	tests/classdef2_single.tests \
+	tests/classdef2.tests \
+	tests/cmap0.tests \
+	tests/cmap10.tests \
+	tests/cmap12.tests \
+	tests/cmap2.tests \
+	tests/cmap4.tests \
+	tests/cmap6.tests \
+	tests/cmap8.tests \
+	tests/gpos_chaining1_boundary.tests \
+	tests/gpos_chaining1_lookupflag.tests \
+	tests/gpos_chaining1_multiple_subrules.tests \
+	tests/gpos_chaining1_next_glyph.tests \
+	tests/gpos_chaining1_simple.tests \
+	tests/gpos_chaining1_successive.tests \
+	tests/gpos_chaining2_boundary.tests \
+	tests/gpos_chaining2_lookupflag.tests \
+	tests/gpos_chaining2_multiple_subrules.tests \
+	tests/gpos_chaining2_next_glyph.tests \
+	tests/gpos_chaining2_simple.tests \
+	tests/gpos_chaining2_successive.tests \
+	tests/gpos_chaining3_boundary.tests \
+	tests/gpos_chaining3_lookupflag.tests \
+	tests/gpos_chaining3_next_glyph.tests \
+	tests/gpos_chaining3_simple.tests \
+	tests/gpos_chaining3_successive.tests \
+	tests/gpos_context1_boundary.tests \
+	tests/gpos_context1_expansion.tests \
+	tests/gpos_context1_lookupflag.tests \
+	tests/gpos_context1_multiple_subrules.tests \
+	tests/gpos_context1_next_glyph.tests \
+	tests/gpos_context1_simple.tests \
+	tests/gpos_context1_successive.tests \
+	tests/gpos_context2_boundary.tests \
+	tests/gpos_context2_classes.tests \
+	tests/gpos_context2_expansion.tests \
+	tests/gpos_context2_lookupflag.tests \
+	tests/gpos_context2_multiple_subrules.tests \
+	tests/gpos_context2_next_glyph.tests \
+	tests/gpos_context2_simple.tests \
+	tests/gpos_context2_successive.tests \
+	tests/gpos_context3_boundary.tests \
+	tests/gpos_context3_lookupflag.tests \
+	tests/gpos_context3_next_glyph.tests \
+	tests/gpos_context3_simple.tests \
+	tests/gpos_context3_successive.tests \
+	tests/gpos1_1_lookupflag.tests \
+	tests/gpos1_1_simple.tests \
+	tests/gpos1_2_lookupflag.tests \
+	tests/gpos1_2.tests \
+	tests/gpos2_1_lookupflag.tests \
+	tests/gpos2_1_next_glyph.tests \
+	tests/gpos2_1_simple.tests \
+	tests/gpos2_1.tests \
+	tests/gpos2_2.tests \
+	tests/gpos3_lookupflag.tests \
+	tests/gpos3.tests \
+	tests/gpos4_lookupflag.tests \
+	tests/gpos4_multiple_anchors.tests \
+	tests/gpos4_simple.tests \
+	tests/gpos5.tests \
+	tests/gpos6.tests \
+	tests/gpos7_1.tests \
+	tests/gpos9.tests \
+	tests/gsub_chaining1_boundary.tests \
+	tests/gsub_chaining1_lookupflag.tests \
+	tests/gsub_chaining1_multiple_subrules.tests \
+	tests/gsub_chaining1_next_glyph.tests \
+	tests/gsub_chaining1_simple.tests \
+	tests/gsub_chaining1_successive.tests \
+	tests/gsub_chaining2_boundary.tests \
+	tests/gsub_chaining2_lookupflag.tests \
+	tests/gsub_chaining2_multiple_subrules.tests \
+	tests/gsub_chaining2_next_glyph.tests \
+	tests/gsub_chaining2_simple.tests \
+	tests/gsub_chaining2_successive.tests \
+	tests/gsub_chaining3_boundary.tests \
+	tests/gsub_chaining3_lookupflag.tests \
+	tests/gsub_chaining3_next_glyph.tests \
+	tests/gsub_chaining3_simple.tests \
+	tests/gsub_chaining3_successive.tests \
+	tests/gsub_context1_boundary.tests \
+	tests/gsub_context1_expansion.tests \
+	tests/gsub_context1_lookupflag.tests \
+	tests/gsub_context1_multiple_subrules.tests \
+	tests/gsub_context1_next_glyph.tests \
+	tests/gsub_context1_simple.tests \
+	tests/gsub_context1_successive.tests \
+	tests/gsub_context2_boundary.tests \
+	tests/gsub_context2_classes.tests \
+	tests/gsub_context2_expansion.tests \
+	tests/gsub_context2_lookupflag.tests \
+	tests/gsub_context2_multiple_subrules.tests \
+	tests/gsub_context2_next_glyph.tests \
+	tests/gsub_context2_simple.tests \
+	tests/gsub_context2_successive.tests \
+	tests/gsub_context3_boundary.tests \
+	tests/gsub_context3_lookupflag.tests \
+	tests/gsub_context3_next_glyph.tests \
+	tests/gsub_context3_simple.tests \
+	tests/gsub_context3_successive.tests \
+	tests/gsub1_1_lookupflag.tests \
+	tests/gsub1_1_modulo.tests \
+	tests/gsub1_1_simple.tests \
+	tests/gsub1_2_lookupflag.tests \
+	tests/gsub1_2_simple.tests \
+	tests/gsub2_1_lookupflag.tests \
+	tests/gsub2_1_multiple_sequences.tests \
+	tests/gsub2_1_simple.tests \
+	tests/gsub3_1_lookupflag.tests \
+	tests/gsub3_1_multiple.tests \
+	tests/gsub3_1_simple.tests \
+	tests/gsub4_1_lookupflag.tests \
+	tests/gsub4_1_multiple_ligatures.tests \
+	tests/gsub4_1_multiple_ligsets.tests \
+	tests/gsub4_1_simple.tests \
+	tests/gsub7.tests \
+	tests/lookupflag_ignore_attach.tests \
+	tests/lookupflag_ignore_base.tests \
+	tests/lookupflag_ignore_combination.tests \
+	tests/lookupflag_ignore_ligatures.tests \
+	tests/lookupflag_ignore_marks.tests \
+	$(NULL)
+
+DISABLED_TESTS = \
+	$(NULL)
diff --git a/test/shaping/data/aots/fonts/classdef1_font1.otf b/test/shape/data/aots/fonts/classdef1_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef1_font1.otf
rename to test/shape/data/aots/fonts/classdef1_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef1_font2.otf b/test/shape/data/aots/fonts/classdef1_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef1_font2.otf
rename to test/shape/data/aots/fonts/classdef1_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef1_font3.otf b/test/shape/data/aots/fonts/classdef1_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef1_font3.otf
rename to test/shape/data/aots/fonts/classdef1_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef1_font4.otf b/test/shape/data/aots/fonts/classdef1_font4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef1_font4.otf
rename to test/shape/data/aots/fonts/classdef1_font4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef2_font1.otf b/test/shape/data/aots/fonts/classdef2_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef2_font1.otf
rename to test/shape/data/aots/fonts/classdef2_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef2_font2.otf b/test/shape/data/aots/fonts/classdef2_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef2_font2.otf
rename to test/shape/data/aots/fonts/classdef2_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef2_font3.otf b/test/shape/data/aots/fonts/classdef2_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef2_font3.otf
rename to test/shape/data/aots/fonts/classdef2_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/classdef2_font4.otf b/test/shape/data/aots/fonts/classdef2_font4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/classdef2_font4.otf
rename to test/shape/data/aots/fonts/classdef2_font4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap0_font1.otf b/test/shape/data/aots/fonts/cmap0_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap0_font1.otf
rename to test/shape/data/aots/fonts/cmap0_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap10_font1.otf b/test/shape/data/aots/fonts/cmap10_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap10_font1.otf
rename to test/shape/data/aots/fonts/cmap10_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap10_font2.otf b/test/shape/data/aots/fonts/cmap10_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap10_font2.otf
rename to test/shape/data/aots/fonts/cmap10_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap12_font1.otf b/test/shape/data/aots/fonts/cmap12_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap12_font1.otf
rename to test/shape/data/aots/fonts/cmap12_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap14_font1.otf b/test/shape/data/aots/fonts/cmap14_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap14_font1.otf
rename to test/shape/data/aots/fonts/cmap14_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap2_font1.otf b/test/shape/data/aots/fonts/cmap2_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap2_font1.otf
rename to test/shape/data/aots/fonts/cmap2_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap4_font1.otf b/test/shape/data/aots/fonts/cmap4_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap4_font1.otf
rename to test/shape/data/aots/fonts/cmap4_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap4_font2.otf b/test/shape/data/aots/fonts/cmap4_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap4_font2.otf
rename to test/shape/data/aots/fonts/cmap4_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap4_font3.otf b/test/shape/data/aots/fonts/cmap4_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap4_font3.otf
rename to test/shape/data/aots/fonts/cmap4_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap4_font4.otf b/test/shape/data/aots/fonts/cmap4_font4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap4_font4.otf
rename to test/shape/data/aots/fonts/cmap4_font4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap6_font1.otf b/test/shape/data/aots/fonts/cmap6_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap6_font1.otf
rename to test/shape/data/aots/fonts/cmap6_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap6_font2.otf b/test/shape/data/aots/fonts/cmap6_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap6_font2.otf
rename to test/shape/data/aots/fonts/cmap6_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap8_font1.otf b/test/shape/data/aots/fonts/cmap8_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap8_font1.otf
rename to test/shape/data/aots/fonts/cmap8_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_composition_font1.otf b/test/shape/data/aots/fonts/cmap_composition_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_composition_font1.otf
rename to test/shape/data/aots/fonts/cmap_composition_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_subtableselection_font1.otf b/test/shape/data/aots/fonts/cmap_subtableselection_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_subtableselection_font1.otf
rename to test/shape/data/aots/fonts/cmap_subtableselection_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_subtableselection_font2.otf b/test/shape/data/aots/fonts/cmap_subtableselection_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_subtableselection_font2.otf
rename to test/shape/data/aots/fonts/cmap_subtableselection_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_subtableselection_font3.otf b/test/shape/data/aots/fonts/cmap_subtableselection_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_subtableselection_font3.otf
rename to test/shape/data/aots/fonts/cmap_subtableselection_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_subtableselection_font4.otf b/test/shape/data/aots/fonts/cmap_subtableselection_font4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_subtableselection_font4.otf
rename to test/shape/data/aots/fonts/cmap_subtableselection_font4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/cmap_subtableselection_font5.otf b/test/shape/data/aots/fonts/cmap_subtableselection_font5.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/cmap_subtableselection_font5.otf
rename to test/shape/data/aots/fonts/cmap_subtableselection_font5.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos1_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos1_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_1_simple_f1.otf b/test/shape/data/aots/fonts/gpos1_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos1_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_1_simple_f2.otf b/test/shape/data/aots/fonts/gpos1_1_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_1_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos1_1_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_1_simple_f3.otf b/test/shape/data/aots/fonts/gpos1_1_simple_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_1_simple_f3.otf
rename to test/shape/data/aots/fonts/gpos1_1_simple_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_1_simple_f4.otf b/test/shape/data/aots/fonts/gpos1_1_simple_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_1_simple_f4.otf
rename to test/shape/data/aots/fonts/gpos1_1_simple_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_2_font1.otf b/test/shape/data/aots/fonts/gpos1_2_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_2_font1.otf
rename to test/shape/data/aots/fonts/gpos1_2_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos1_2_font2.otf b/test/shape/data/aots/fonts/gpos1_2_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos1_2_font2.otf
rename to test/shape/data/aots/fonts/gpos1_2_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_font6.otf b/test/shape/data/aots/fonts/gpos2_1_font6.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_font6.otf
rename to test/shape/data/aots/fonts/gpos2_1_font6.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_font7.otf b/test/shape/data/aots/fonts/gpos2_1_font7.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_font7.otf
rename to test/shape/data/aots/fonts/gpos2_1_font7.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos2_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos2_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_lookupflag_f2.otf b/test/shape/data/aots/fonts/gpos2_1_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gpos2_1_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos2_1_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos2_1_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_next_glyph_f2.otf b/test/shape/data/aots/fonts/gpos2_1_next_glyph_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_next_glyph_f2.otf
rename to test/shape/data/aots/fonts/gpos2_1_next_glyph_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_1_simple_f1.otf b/test/shape/data/aots/fonts/gpos2_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos2_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_2_font1.otf b/test/shape/data/aots/fonts/gpos2_2_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_2_font1.otf
rename to test/shape/data/aots/fonts/gpos2_2_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_2_font2.otf b/test/shape/data/aots/fonts/gpos2_2_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_2_font2.otf
rename to test/shape/data/aots/fonts/gpos2_2_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_2_font3.otf b/test/shape/data/aots/fonts/gpos2_2_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_2_font3.otf
rename to test/shape/data/aots/fonts/gpos2_2_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_2_font4.otf b/test/shape/data/aots/fonts/gpos2_2_font4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_2_font4.otf
rename to test/shape/data/aots/fonts/gpos2_2_font4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos2_2_font5.otf b/test/shape/data/aots/fonts/gpos2_2_font5.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos2_2_font5.otf
rename to test/shape/data/aots/fonts/gpos2_2_font5.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos3_font1.otf b/test/shape/data/aots/fonts/gpos3_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos3_font1.otf
rename to test/shape/data/aots/fonts/gpos3_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos3_font2.otf b/test/shape/data/aots/fonts/gpos3_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos3_font2.otf
rename to test/shape/data/aots/fonts/gpos3_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos3_font3.otf b/test/shape/data/aots/fonts/gpos3_font3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos3_font3.otf
rename to test/shape/data/aots/fonts/gpos3_font3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos4_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos4_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos4_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos4_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos4_lookupflag_f2.otf b/test/shape/data/aots/fonts/gpos4_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos4_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gpos4_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos4_multiple_anchors_1.otf b/test/shape/data/aots/fonts/gpos4_multiple_anchors_1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos4_multiple_anchors_1.otf
rename to test/shape/data/aots/fonts/gpos4_multiple_anchors_1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos4_simple_1.otf b/test/shape/data/aots/fonts/gpos4_simple_1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos4_simple_1.otf
rename to test/shape/data/aots/fonts/gpos4_simple_1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos5_font1.otf b/test/shape/data/aots/fonts/gpos5_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos5_font1.otf
rename to test/shape/data/aots/fonts/gpos5_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos6_font1.otf b/test/shape/data/aots/fonts/gpos6_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos6_font1.otf
rename to test/shape/data/aots/fonts/gpos6_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos7_1_font1.otf b/test/shape/data/aots/fonts/gpos7_1_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos7_1_font1.otf
rename to test/shape/data/aots/fonts/gpos7_1_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos9_font1.otf b/test/shape/data/aots/fonts/gpos9_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos9_font1.otf
rename to test/shape/data/aots/fonts/gpos9_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos9_font2.otf b/test/shape/data/aots/fonts/gpos9_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos9_font2.otf
rename to test/shape/data/aots/fonts/gpos9_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_chaining1_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_boundary_f3.otf b/test/shape/data/aots/fonts/gpos_chaining1_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_boundary_f3.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_boundary_f4.otf b/test/shape/data/aots/fonts/gpos_chaining1_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_boundary_f4.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gpos_chaining1_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_simple_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_simple_f2.otf b/test/shape/data/aots/fonts/gpos_chaining1_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining1_successive_f1.otf b/test/shape/data/aots/fonts/gpos_chaining1_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining1_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining1_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_chaining2_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_boundary_f3.otf b/test/shape/data/aots/fonts/gpos_chaining2_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_boundary_f3.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_boundary_f4.otf b/test/shape/data/aots/fonts/gpos_chaining2_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_boundary_f4.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gpos_chaining2_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_simple_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_simple_f2.otf b/test/shape/data/aots/fonts/gpos_chaining2_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining2_successive_f1.otf b/test/shape/data/aots/fonts/gpos_chaining2_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining2_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining2_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_chaining3_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_chaining3_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_boundary_f3.otf b/test/shape/data/aots/fonts/gpos_chaining3_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_boundary_f3.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_boundary_f4.otf b/test/shape/data/aots/fonts/gpos_chaining3_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_boundary_f4.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_chaining3_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_chaining3_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_simple_f1.otf b/test/shape/data/aots/fonts/gpos_chaining3_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_simple_f2.otf b/test/shape/data/aots/fonts/gpos_chaining3_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_chaining3_successive_f1.otf b/test/shape/data/aots/fonts/gpos_chaining3_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_chaining3_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_chaining3_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_context1_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_context1_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_context1_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_expansion_f1.otf b/test/shape/data/aots/fonts/gpos_context1_expansion_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_expansion_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_expansion_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_context1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_lookupflag_f2.otf b/test/shape/data/aots/fonts/gpos_context1_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gpos_context1_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gpos_context1_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gpos_context1_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gpos_context1_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_context1_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_simple_f1.otf b/test/shape/data/aots/fonts/gpos_context1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_simple_f2.otf b/test/shape/data/aots/fonts/gpos_context1_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos_context1_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context1_successive_f1.otf b/test/shape/data/aots/fonts/gpos_context1_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context1_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_context1_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_context2_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_context2_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_context2_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_classes_f1.otf b/test/shape/data/aots/fonts/gpos_context2_classes_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_classes_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_classes_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_classes_f2.otf b/test/shape/data/aots/fonts/gpos_context2_classes_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_classes_f2.otf
rename to test/shape/data/aots/fonts/gpos_context2_classes_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_expansion_f1.otf b/test/shape/data/aots/fonts/gpos_context2_expansion_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_expansion_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_expansion_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_context2_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_lookupflag_f2.otf b/test/shape/data/aots/fonts/gpos_context2_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gpos_context2_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gpos_context2_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gpos_context2_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gpos_context2_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_context2_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_simple_f1.otf b/test/shape/data/aots/fonts/gpos_context2_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_simple_f2.otf b/test/shape/data/aots/fonts/gpos_context2_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_simple_f2.otf
rename to test/shape/data/aots/fonts/gpos_context2_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context2_successive_f1.otf b/test/shape/data/aots/fonts/gpos_context2_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context2_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_context2_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_boundary_f1.otf b/test/shape/data/aots/fonts/gpos_context3_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_boundary_f1.otf
rename to test/shape/data/aots/fonts/gpos_context3_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_boundary_f2.otf b/test/shape/data/aots/fonts/gpos_context3_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_boundary_f2.otf
rename to test/shape/data/aots/fonts/gpos_context3_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_lookupflag_f1.otf b/test/shape/data/aots/fonts/gpos_context3_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gpos_context3_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_lookupflag_f2.otf b/test/shape/data/aots/fonts/gpos_context3_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gpos_context3_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_next_glyph_f1.otf b/test/shape/data/aots/fonts/gpos_context3_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gpos_context3_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_simple_f1.otf b/test/shape/data/aots/fonts/gpos_context3_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_simple_f1.otf
rename to test/shape/data/aots/fonts/gpos_context3_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gpos_context3_successive_f1.otf b/test/shape/data/aots/fonts/gpos_context3_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gpos_context3_successive_f1.otf
rename to test/shape/data/aots/fonts/gpos_context3_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub1_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub1_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub1_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub1_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub1_1_modulo_f1.otf b/test/shape/data/aots/fonts/gsub1_1_modulo_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub1_1_modulo_f1.otf
rename to test/shape/data/aots/fonts/gsub1_1_modulo_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub1_1_simple_f1.otf b/test/shape/data/aots/fonts/gsub1_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub1_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub1_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub1_2_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub1_2_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub1_2_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub1_2_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub1_2_simple_f1.otf b/test/shape/data/aots/fonts/gsub1_2_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub1_2_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub1_2_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub2_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub2_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub2_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub2_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub2_1_multiple_sequences_f1.otf b/test/shape/data/aots/fonts/gsub2_1_multiple_sequences_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub2_1_multiple_sequences_f1.otf
rename to test/shape/data/aots/fonts/gsub2_1_multiple_sequences_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub2_1_simple_f1.otf b/test/shape/data/aots/fonts/gsub2_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub2_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub2_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub3_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub3_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub3_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub3_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub3_1_multiple_f1.otf b/test/shape/data/aots/fonts/gsub3_1_multiple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub3_1_multiple_f1.otf
rename to test/shape/data/aots/fonts/gsub3_1_multiple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub3_1_simple_f1.otf b/test/shape/data/aots/fonts/gsub3_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub3_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub3_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub4_1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub4_1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub4_1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub4_1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub4_1_multiple_ligatures_f1.otf b/test/shape/data/aots/fonts/gsub4_1_multiple_ligatures_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub4_1_multiple_ligatures_f1.otf
rename to test/shape/data/aots/fonts/gsub4_1_multiple_ligatures_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub4_1_multiple_ligatures_f2.otf b/test/shape/data/aots/fonts/gsub4_1_multiple_ligatures_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub4_1_multiple_ligatures_f2.otf
rename to test/shape/data/aots/fonts/gsub4_1_multiple_ligatures_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub4_1_multiple_ligsets_f1.otf b/test/shape/data/aots/fonts/gsub4_1_multiple_ligsets_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub4_1_multiple_ligsets_f1.otf
rename to test/shape/data/aots/fonts/gsub4_1_multiple_ligsets_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub4_1_simple_f1.otf b/test/shape/data/aots/fonts/gsub4_1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub4_1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub4_1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub7_font1.otf b/test/shape/data/aots/fonts/gsub7_font1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub7_font1.otf
rename to test/shape/data/aots/fonts/gsub7_font1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub7_font2.otf b/test/shape/data/aots/fonts/gsub7_font2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub7_font2.otf
rename to test/shape/data/aots/fonts/gsub7_font2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_chaining1_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_boundary_f3.otf b/test/shape/data/aots/fonts/gsub_chaining1_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_boundary_f3.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_boundary_f4.otf b/test/shape/data/aots/fonts/gsub_chaining1_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_boundary_f4.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gsub_chaining1_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_simple_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_simple_f2.otf b/test/shape/data/aots/fonts/gsub_chaining1_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_simple_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining1_successive_f1.otf b/test/shape/data/aots/fonts/gsub_chaining1_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining1_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining1_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_chaining2_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_boundary_f3.otf b/test/shape/data/aots/fonts/gsub_chaining2_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_boundary_f3.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_boundary_f4.otf b/test/shape/data/aots/fonts/gsub_chaining2_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_boundary_f4.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gsub_chaining2_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_simple_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_simple_f2.otf b/test/shape/data/aots/fonts/gsub_chaining2_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_simple_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining2_successive_f1.otf b/test/shape/data/aots/fonts/gsub_chaining2_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining2_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining2_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_chaining3_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_chaining3_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_boundary_f3.otf b/test/shape/data/aots/fonts/gsub_chaining3_boundary_f3.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_boundary_f3.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_boundary_f3.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_boundary_f4.otf b/test/shape/data/aots/fonts/gsub_chaining3_boundary_f4.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_boundary_f4.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_boundary_f4.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_chaining3_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_chaining3_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_simple_f1.otf b/test/shape/data/aots/fonts/gsub_chaining3_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_simple_f2.otf b/test/shape/data/aots/fonts/gsub_chaining3_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_simple_f2.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_chaining3_successive_f1.otf b/test/shape/data/aots/fonts/gsub_chaining3_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_chaining3_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_chaining3_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_context1_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_context1_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_context1_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_expansion_f1.otf b/test/shape/data/aots/fonts/gsub_context1_expansion_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_expansion_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_expansion_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_context1_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_lookupflag_f2.otf b/test/shape/data/aots/fonts/gsub_context1_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gsub_context1_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gsub_context1_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gsub_context1_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gsub_context1_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_context1_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_simple_f1.otf b/test/shape/data/aots/fonts/gsub_context1_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_simple_f2.otf b/test/shape/data/aots/fonts/gsub_context1_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_simple_f2.otf
rename to test/shape/data/aots/fonts/gsub_context1_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context1_successive_f1.otf b/test/shape/data/aots/fonts/gsub_context1_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context1_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_context1_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_context2_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_context2_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_context2_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_classes_f1.otf b/test/shape/data/aots/fonts/gsub_context2_classes_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_classes_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_classes_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_classes_f2.otf b/test/shape/data/aots/fonts/gsub_context2_classes_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_classes_f2.otf
rename to test/shape/data/aots/fonts/gsub_context2_classes_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_expansion_f1.otf b/test/shape/data/aots/fonts/gsub_context2_expansion_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_expansion_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_expansion_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_context2_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_lookupflag_f2.otf b/test/shape/data/aots/fonts/gsub_context2_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gsub_context2_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_multiple_subrules_f1.otf b/test/shape/data/aots/fonts/gsub_context2_multiple_subrules_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_multiple_subrules_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_multiple_subrules_f2.otf b/test/shape/data/aots/fonts/gsub_context2_multiple_subrules_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_multiple_subrules_f2.otf
rename to test/shape/data/aots/fonts/gsub_context2_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_context2_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_simple_f1.otf b/test/shape/data/aots/fonts/gsub_context2_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_simple_f2.otf b/test/shape/data/aots/fonts/gsub_context2_simple_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_simple_f2.otf
rename to test/shape/data/aots/fonts/gsub_context2_simple_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context2_successive_f1.otf b/test/shape/data/aots/fonts/gsub_context2_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context2_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_context2_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_boundary_f1.otf b/test/shape/data/aots/fonts/gsub_context3_boundary_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_boundary_f1.otf
rename to test/shape/data/aots/fonts/gsub_context3_boundary_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_boundary_f2.otf b/test/shape/data/aots/fonts/gsub_context3_boundary_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_boundary_f2.otf
rename to test/shape/data/aots/fonts/gsub_context3_boundary_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_lookupflag_f1.otf b/test/shape/data/aots/fonts/gsub_context3_lookupflag_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_lookupflag_f1.otf
rename to test/shape/data/aots/fonts/gsub_context3_lookupflag_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_lookupflag_f2.otf b/test/shape/data/aots/fonts/gsub_context3_lookupflag_f2.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_lookupflag_f2.otf
rename to test/shape/data/aots/fonts/gsub_context3_lookupflag_f2.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_next_glyph_f1.otf b/test/shape/data/aots/fonts/gsub_context3_next_glyph_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_next_glyph_f1.otf
rename to test/shape/data/aots/fonts/gsub_context3_next_glyph_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_simple_f1.otf b/test/shape/data/aots/fonts/gsub_context3_simple_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_simple_f1.otf
rename to test/shape/data/aots/fonts/gsub_context3_simple_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/gsub_context3_successive_f1.otf b/test/shape/data/aots/fonts/gsub_context3_successive_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/gsub_context3_successive_f1.otf
rename to test/shape/data/aots/fonts/gsub_context3_successive_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/lookupflag_ignore_attach_f1.otf b/test/shape/data/aots/fonts/lookupflag_ignore_attach_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/lookupflag_ignore_attach_f1.otf
rename to test/shape/data/aots/fonts/lookupflag_ignore_attach_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/lookupflag_ignore_base_f1.otf b/test/shape/data/aots/fonts/lookupflag_ignore_base_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/lookupflag_ignore_base_f1.otf
rename to test/shape/data/aots/fonts/lookupflag_ignore_base_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/lookupflag_ignore_combination_f1.otf b/test/shape/data/aots/fonts/lookupflag_ignore_combination_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/lookupflag_ignore_combination_f1.otf
rename to test/shape/data/aots/fonts/lookupflag_ignore_combination_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/lookupflag_ignore_ligatures_f1.otf b/test/shape/data/aots/fonts/lookupflag_ignore_ligatures_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/lookupflag_ignore_ligatures_f1.otf
rename to test/shape/data/aots/fonts/lookupflag_ignore_ligatures_f1.otf
Binary files differ
diff --git a/test/shaping/data/aots/fonts/lookupflag_ignore_marks_f1.otf b/test/shape/data/aots/fonts/lookupflag_ignore_marks_f1.otf
similarity index 100%
rename from test/shaping/data/aots/fonts/lookupflag_ignore_marks_f1.otf
rename to test/shape/data/aots/fonts/lookupflag_ignore_marks_f1.otf
Binary files differ
diff --git a/test/shape/data/aots/hb-aots-tester.cpp b/test/shape/data/aots/hb-aots-tester.cpp
new file mode 100644
index 0000000..1528584
--- /dev/null
+++ b/test/shape/data/aots/hb-aots-tester.cpp
@@ -0,0 +1,437 @@
+/*____________________________________________________________________________
+
+    Copyright 2000-2016 Adobe Systems Incorporated. All Rights Reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use these files except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+____________________________________________________________________________*/
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+#include "hb.h"
+#include "hb-ot.h"
+
+static const bool verbose = true;
+
+struct TestData
+{
+    TestData(hb_buffer_t  *buffer_,
+             hb_face_t    *face_,
+             hb_font_t    *font_,
+             hb_feature_t *features_,
+             int           num_features_)
+        : buffer(buffer_), face(face_), font(font_),
+          features(features_), num_features(num_features_)
+    { }
+    ~TestData()
+    {
+        free (features);
+        hb_face_destroy (face);
+        hb_font_destroy (font);
+        hb_buffer_destroy (buffer);
+    }
+
+    hb_buffer_t  *buffer;
+    hb_face_t    *face;
+    hb_font_t    *font;
+    hb_feature_t *features;
+    int           num_features;
+};
+
+TestData
+runTest(const char *testName,
+        const char *fontfileName,
+        unsigned int *in, int nbIn,
+        unsigned int *select, int nbSelect)
+{
+    FILE *f = fopen (fontfileName, "rb");
+    fseek(f, 0, SEEK_END);
+    long fontsize = ftell(f);
+    fseek(f, 0, SEEK_SET);
+    char *fontdata = (char *)malloc (fontsize);
+    fread(fontdata, fontsize, 1, f);
+    fclose(f);
+
+    if (verbose) {
+        printf ("------------------------------- %s\n", testName);
+    }
+
+    // setup font
+    hb_blob_t *blob = hb_blob_create(fontdata, fontsize,
+                                     HB_MEMORY_MODE_WRITABLE,
+                                     0, 0);
+    hb_face_t *face = hb_face_create(blob, 0);
+    hb_font_t *font = hb_font_create(face);
+    unsigned int upem = hb_face_get_upem (face);
+
+    hb_font_set_scale(font, upem, upem);
+    hb_ot_font_set_funcs (font);
+
+    // setup buffer
+    hb_buffer_t *buffer = hb_buffer_create();
+    hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
+    hb_buffer_set_script(buffer, HB_SCRIPT_LATIN);
+    hb_buffer_set_language(buffer, hb_language_from_string("en", 2));
+
+    hb_buffer_add_utf32(buffer, in, nbIn, 0, nbIn);
+
+    // setup features
+    hb_feature_t *features;
+    int nbFeatures;
+
+    if (nbSelect == 0)
+    {
+        nbFeatures = 1;
+
+        features = (hb_feature_t *) malloc (sizeof (*features));
+        features[0].tag = HB_TAG('t', 'e', 's', 't');
+        features[0].value = 1;
+        features[0].start = HB_FEATURE_GLOBAL_START;
+        features[0].end = HB_FEATURE_GLOBAL_END;
+    }
+    else
+    {
+        nbFeatures = 0;
+
+        features = (hb_feature_t *) malloc (sizeof (*features) * nbSelect);
+        for (int i = 0; i < nbSelect; i++) {
+            if (select[i] != -1) {
+                features[nbFeatures].tag = HB_TAG('t', 'e', 's', 't');
+                features[nbFeatures].value = select[i];
+                features[nbFeatures].start = i;
+                features[nbFeatures].end = i + 1;
+                nbFeatures++;
+            }
+        }
+    }
+
+    // shape
+    hb_shape(font, buffer, features, nbFeatures);
+
+    hb_blob_destroy(blob);
+
+    return TestData(buffer, face, font, features, nbFeatures);
+}
+
+
+void printArray (const char* s, int *a, int n)
+{
+    printf ("%s  %d : ", s, n);
+    for (int i = 0; i < n; i++) {
+        printf (" %d", a[i]);
+    }
+    printf ("\n");
+}
+
+void printUArray (const char* s, unsigned int *a, int n)
+{
+    printArray (s, (int *) a, n);
+}
+
+bool gsub_test(const char *testName,
+               const char *fontfileName,
+               int nbIn, unsigned int *in,
+               int nbSelect, unsigned int *select,
+               int nbExpected, unsigned int *expected)
+{
+    TestData data = runTest(testName,
+                            fontfileName,
+                            in, nbIn,
+                            select, nbSelect);
+
+    // verify
+    hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
+    unsigned int nbActual = hb_buffer_get_length(data.buffer);
+
+    bool ok = true;
+
+    if (nbActual != nbExpected)
+        ok = false;
+    else {
+        for (int i = 0; i < nbActual; i++) {
+            if (actual[i].codepoint != expected [i]) {
+                ok = false;
+                break;
+            }
+        }
+    }
+
+
+    char test_name[255];
+    sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
+    FILE *tests_file = fopen (test_name, "a+");
+    if (!ok) fprintf (tests_file, "#");
+    fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
+    for (unsigned int i = 0; i < data.num_features; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        char buf[255];
+        hb_feature_to_string (&data.features[i], buf, sizeof (buf));
+        fprintf (tests_file, "%s", buf);
+    }
+    fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions;");
+
+    for (unsigned int i = 0; i < nbIn; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        fprintf (tests_file, "U+%04X", in[i]);
+    }
+
+    fprintf (tests_file, ";[");
+    for (unsigned int i = 0; i < nbActual; i++)
+    {
+        if (i != 0) fprintf (tests_file, "|");
+        fprintf (tests_file, "%d", expected[i]);
+    }
+    fprintf (tests_file, "]");
+
+    fprintf (tests_file, "\n");
+    fclose (tests_file);
+
+
+    if (! ok) {
+        printf ("******* GSUB %s\n", testName);
+
+        printf ("expected %d:", nbExpected);
+        for (int i = 0; i < nbExpected; i++) {
+            printf (" %d", expected[i]); }
+        printf ("\n");
+
+        printf ("  actual %d:", nbActual);
+        for (int i = 0; i < nbActual; i++) {
+            printf (" %d", actual[i].codepoint); }
+        printf ("\n");
+
+    }
+
+    return ok;
+}
+
+bool cmap_test(const char *testName,
+               const char *fontfileName,
+               int nbIn, unsigned int *in,
+               int nbSelect, unsigned int *select,
+               int nbExpected, unsigned int *expected)
+{
+    TestData data = runTest(testName,
+                            fontfileName,
+                            in, nbIn,
+                            select, nbSelect);
+
+    // verify
+    hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
+    unsigned int nbActual = hb_buffer_get_length(data.buffer);
+
+    bool ok = true;
+
+    if (nbActual != nbExpected)
+        ok = false;
+    else {
+        for (int i = 0; i < nbActual; i++) {
+            if (actual[i].codepoint != expected [i]) {
+                ok = false;
+                break;
+            }
+        }
+    }
+
+
+    char test_name[255];
+    sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
+    FILE *tests_file = fopen (test_name, "a+");
+    if (!ok) fprintf (tests_file, "#");
+    fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
+    for (unsigned int i = 0; i < data.num_features; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        char buf[255];
+        hb_feature_to_string (&data.features[i], buf, sizeof (buf));
+        fprintf (tests_file, "%s", buf);
+    }
+    fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;");
+
+    for (unsigned int i = 0; i < nbIn; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        fprintf (tests_file, "U+%04X", in[i]);
+    }
+
+    fprintf (tests_file, ";[");
+    for (unsigned int i = 0; i < nbActual; i++)
+    {
+        if (i != 0) fprintf (tests_file, "|");
+        fprintf (tests_file, "%d", expected[i]);
+    }
+    fprintf (tests_file, "]");
+
+    fprintf (tests_file, "\n");
+    fclose (tests_file);
+
+
+    if (! ok) {
+        printf ("******* cmap %s\n", testName);
+
+        printf ("expected %d:", nbExpected);
+        for (int i = 0; i < nbExpected; i++) {
+            printf (" %d", expected[i]); }
+        printf ("\n");
+
+        printf ("  actual %d:", nbActual);
+        for (int i = 0; i < nbActual; i++) {
+            printf (" %d", actual[i].codepoint); }
+        printf ("\n");
+
+    }
+
+    return ok;
+}
+
+bool gpos_test(const char *testName,
+               const char *fontfileName,
+               int nbIn,
+               unsigned int *in,
+               int nbOut,
+               unsigned int *out,
+               int *x,
+               int *y)
+{
+    TestData data = runTest(testName,
+                            fontfileName,
+                            in, nbIn,
+                            0, 0);
+
+    // verify
+    unsigned int nbActual;
+    hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, &nbActual);
+    hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (data.buffer, NULL);
+
+    unsigned int *actualG = (unsigned int *) malloc(sizeof(*actualG) * nbActual);
+    int *actualX = (int *) malloc(sizeof(*actualX) * nbActual);
+    int *actualY = (int *) malloc(sizeof(*actualY) * nbActual);
+    int curX = 0;
+    int curY = 0;
+    for (int i = 0; i < nbActual; i++) {
+        actualG[i] = actual[i].codepoint;
+        actualX[i] = curX + pos[i].x_offset;
+        actualY[i] = curY + pos[i].y_offset;
+
+        curX += pos[i].x_advance;
+        if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+            curX -= 1500;
+        curY += pos[i].y_advance;
+    }
+
+    bool nbOk = true;
+    bool xOk = true;
+    bool yOk = true;
+
+    if (nbActual != nbOut)
+        nbOk = false;
+    else {
+        for (int i = 0; i < nbActual; i++) {
+            if (actualX[i] != x[i]) {
+                xOk = false;
+            }
+            if (actualY[i] != y[i]) {
+                yOk = false;
+            }
+        }
+    }
+
+    bool ok = (nbOk && xOk && yOk);
+    if (! ok) {
+        printf ("******* GPOS %s\n", testName);
+
+        if (! (nbOk && xOk)) {
+            printArray ("expectedX", x, nbOut);
+            printArray ("actualX  ", actualX, nbActual);
+
+            printf ("xadv/pos:");
+            for (int i = 0; i < nbOut; i++) {
+                printf (" %d/%d", pos[i].x_advance, pos[i].x_offset);
+            }
+            printf ("\n");
+        }
+
+        if (! (nbOk && yOk)) {
+            printArray ("expectedY", y, nbOut);
+            printArray ("actualY  ", actualY, nbActual);
+
+            printf ("yadv/pos:");
+            for (int i = 0; i < nbOut; i++) {
+                printf (" %d/%d", pos[i].y_advance, pos[i].y_offset);
+            }
+            printf ("\n");
+        }
+    }
+
+
+    char test_name[255];
+    sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
+    FILE *tests_file = fopen (test_name, "a+");
+    if (!ok) fprintf (tests_file, "#");
+    fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
+    for (unsigned int i = 0; i < data.num_features; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        char buf[255];
+        hb_feature_to_string (&data.features[i], buf, sizeof (buf));
+        fprintf (tests_file, "%s", buf);
+    }
+    fprintf (tests_file, "\" --no-clusters --no-glyph-names --ned;");
+
+    for (unsigned int i = 0; i < nbIn; i++)
+    {
+        if (i != 0) fprintf (tests_file, ",");
+        fprintf (tests_file, "U+%04X", in[i]);
+    }
+
+    fprintf (tests_file, ";[");
+    int accumlatedAdvance = 0;
+    for (unsigned int i = 0; i < nbActual; i++)
+    {
+        if (i != 0) fprintf (tests_file, "|");
+        fprintf (tests_file, "%d", /*it should be "out[i]"*/ actualG[i]);
+
+        int expected_x = x[i] + accumlatedAdvance;
+        int expected_y = y[i];
+        if (expected_x || expected_y) fprintf (tests_file, "@%d,%d", expected_x, expected_y);
+        if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+            accumlatedAdvance += 1500;
+    }
+    fprintf (tests_file, "]");
+
+    fprintf (tests_file, "\n");
+    fclose (tests_file);
+
+
+    free(actualG);
+    free(actualX);
+    free(actualY);
+
+    return ok;
+}
+
+
+int main(int argc, char **argv)
+{
+    int failures = 0;
+    int pass = 0;
+
+#include "hb-aots-tester.h"
+
+    printf ("%d failures, %d pass\n", failures, pass);
+}
+
+
+
diff --git a/test/shape/data/aots/meson.build b/test/shape/data/aots/meson.build
new file mode 100644
index 0000000..bda2711
--- /dev/null
+++ b/test/shape/data/aots/meson.build
@@ -0,0 +1,130 @@
+aots_tests = [
+  'classdef1_empty.tests',
+  'classdef1_multiple.tests',
+  'classdef1_single.tests',
+  'classdef1.tests',
+  'classdef2_empty.tests',
+  'classdef2_multiple.tests',
+  'classdef2_single.tests',
+  'classdef2.tests',
+  'cmap0.tests',
+  'cmap10.tests',
+  'cmap12.tests',
+  'cmap2.tests',
+  'cmap4.tests',
+  'cmap6.tests',
+  'cmap8.tests',
+  'gpos_chaining1_boundary.tests',
+  'gpos_chaining1_lookupflag.tests',
+  'gpos_chaining1_multiple_subrules.tests',
+  'gpos_chaining1_next_glyph.tests',
+  'gpos_chaining1_simple.tests',
+  'gpos_chaining1_successive.tests',
+  'gpos_chaining2_boundary.tests',
+  'gpos_chaining2_lookupflag.tests',
+  'gpos_chaining2_multiple_subrules.tests',
+  'gpos_chaining2_next_glyph.tests',
+  'gpos_chaining2_simple.tests',
+  'gpos_chaining2_successive.tests',
+  'gpos_chaining3_boundary.tests',
+  'gpos_chaining3_lookupflag.tests',
+  'gpos_chaining3_next_glyph.tests',
+  'gpos_chaining3_simple.tests',
+  'gpos_chaining3_successive.tests',
+  'gpos_context1_boundary.tests',
+  'gpos_context1_expansion.tests',
+  'gpos_context1_lookupflag.tests',
+  'gpos_context1_multiple_subrules.tests',
+  'gpos_context1_next_glyph.tests',
+  'gpos_context1_simple.tests',
+  'gpos_context1_successive.tests',
+  'gpos_context2_boundary.tests',
+  'gpos_context2_classes.tests',
+  'gpos_context2_expansion.tests',
+  'gpos_context2_lookupflag.tests',
+  'gpos_context2_multiple_subrules.tests',
+  'gpos_context2_next_glyph.tests',
+  'gpos_context2_simple.tests',
+  'gpos_context2_successive.tests',
+  'gpos_context3_boundary.tests',
+  'gpos_context3_lookupflag.tests',
+  'gpos_context3_next_glyph.tests',
+  'gpos_context3_simple.tests',
+  'gpos_context3_successive.tests',
+  'gpos1_1_lookupflag.tests',
+  'gpos1_1_simple.tests',
+  'gpos1_2_lookupflag.tests',
+  'gpos1_2.tests',
+  'gpos2_1_lookupflag.tests',
+  'gpos2_1_next_glyph.tests',
+  'gpos2_1_simple.tests',
+  'gpos2_1.tests',
+  'gpos2_2.tests',
+  'gpos3_lookupflag.tests',
+  'gpos3.tests',
+  'gpos4_lookupflag.tests',
+  'gpos4_multiple_anchors.tests',
+  'gpos4_simple.tests',
+  'gpos5.tests',
+  'gpos6.tests',
+  'gpos7_1.tests',
+  'gpos9.tests',
+  'gsub_chaining1_boundary.tests',
+  'gsub_chaining1_lookupflag.tests',
+  'gsub_chaining1_multiple_subrules.tests',
+  'gsub_chaining1_next_glyph.tests',
+  'gsub_chaining1_simple.tests',
+  'gsub_chaining1_successive.tests',
+  'gsub_chaining2_boundary.tests',
+  'gsub_chaining2_lookupflag.tests',
+  'gsub_chaining2_multiple_subrules.tests',
+  'gsub_chaining2_next_glyph.tests',
+  'gsub_chaining2_simple.tests',
+  'gsub_chaining2_successive.tests',
+  'gsub_chaining3_boundary.tests',
+  'gsub_chaining3_lookupflag.tests',
+  'gsub_chaining3_next_glyph.tests',
+  'gsub_chaining3_simple.tests',
+  'gsub_chaining3_successive.tests',
+  'gsub_context1_boundary.tests',
+  'gsub_context1_expansion.tests',
+  'gsub_context1_lookupflag.tests',
+  'gsub_context1_multiple_subrules.tests',
+  'gsub_context1_next_glyph.tests',
+  'gsub_context1_simple.tests',
+  'gsub_context1_successive.tests',
+  'gsub_context2_boundary.tests',
+  'gsub_context2_classes.tests',
+  'gsub_context2_expansion.tests',
+  'gsub_context2_lookupflag.tests',
+  'gsub_context2_multiple_subrules.tests',
+  'gsub_context2_next_glyph.tests',
+  'gsub_context2_simple.tests',
+  'gsub_context2_successive.tests',
+  'gsub_context3_boundary.tests',
+  'gsub_context3_lookupflag.tests',
+  'gsub_context3_next_glyph.tests',
+  'gsub_context3_simple.tests',
+  'gsub_context3_successive.tests',
+  'gsub1_1_lookupflag.tests',
+  'gsub1_1_modulo.tests',
+  'gsub1_1_simple.tests',
+  'gsub1_2_lookupflag.tests',
+  'gsub1_2_simple.tests',
+  'gsub2_1_lookupflag.tests',
+  'gsub2_1_multiple_sequences.tests',
+  'gsub2_1_simple.tests',
+  'gsub3_1_lookupflag.tests',
+  'gsub3_1_multiple.tests',
+  'gsub3_1_simple.tests',
+  'gsub4_1_lookupflag.tests',
+  'gsub4_1_multiple_ligatures.tests',
+  'gsub4_1_multiple_ligsets.tests',
+  'gsub4_1_simple.tests',
+  'gsub7.tests',
+  'lookupflag_ignore_attach.tests',
+  'lookupflag_ignore_base.tests',
+  'lookupflag_ignore_combination.tests',
+  'lookupflag_ignore_ligatures.tests',
+  'lookupflag_ignore_marks.tests',
+]
diff --git a/test/shape/data/aots/tests/classdef1.tests b/test/shape/data/aots/tests/classdef1.tests
new file mode 100644
index 0000000..b19f358
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef1.tests
@@ -0,0 +1 @@
+../fonts/classdef1_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
diff --git a/test/shape/data/aots/tests/classdef1_empty.tests b/test/shape/data/aots/tests/classdef1_empty.tests
new file mode 100644
index 0000000..28d0237
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef1_empty.tests
@@ -0,0 +1 @@
+../fonts/classdef1_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef1_multiple.tests b/test/shape/data/aots/tests/classdef1_multiple.tests
new file mode 100644
index 0000000..b5bebc4
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef1_multiple.tests
@@ -0,0 +1 @@
+../fonts/classdef1_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shape/data/aots/tests/classdef1_single.tests b/test/shape/data/aots/tests/classdef1_single.tests
new file mode 100644
index 0000000..0390af5
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef1_single.tests
@@ -0,0 +1 @@
+../fonts/classdef2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef2.tests b/test/shape/data/aots/tests/classdef2.tests
new file mode 100644
index 0000000..bf22d4e
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef2.tests
@@ -0,0 +1 @@
+../fonts/classdef2_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|20|21]
diff --git a/test/shape/data/aots/tests/classdef2_empty.tests b/test/shape/data/aots/tests/classdef2_empty.tests
new file mode 100644
index 0000000..652dc11
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef2_empty.tests
@@ -0,0 +1 @@
+../fonts/classdef2_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/classdef2_multiple.tests b/test/shape/data/aots/tests/classdef2_multiple.tests
new file mode 100644
index 0000000..25af349
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef2_multiple.tests
@@ -0,0 +1 @@
+../fonts/classdef2_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024;[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shape/data/aots/tests/classdef2_single.tests b/test/shape/data/aots/tests/classdef2_single.tests
new file mode 100644
index 0000000..0390af5
--- /dev/null
+++ b/test/shape/data/aots/tests/classdef2_single.tests
@@ -0,0 +1 @@
+../fonts/classdef2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|25|21]
diff --git a/test/shape/data/aots/tests/cmap0.tests b/test/shape/data/aots/tests/cmap0.tests
new file mode 100644
index 0000000..200527e
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap0.tests
@@ -0,0 +1 @@
+../fonts/cmap0_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+FFFF;[0|0|0|17|56|12|0|0]
diff --git a/test/shape/data/aots/tests/cmap10.tests b/test/shape/data/aots/tests/cmap10.tests
new file mode 100644
index 0000000..4d20384
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap10.tests
@@ -0,0 +1,2 @@
+../fonts/cmap10_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|0|26|27|32|0]
+../fonts/cmap10_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
diff --git a/test/shape/data/aots/tests/cmap12.tests b/test/shape/data/aots/tests/cmap12.tests
new file mode 100644
index 0000000..9354a68
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap12.tests
@@ -0,0 +1 @@
+../fonts/cmap12_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+101723,U+101724,U+101727,U+101728,U+102522,U+102523,U+102527,U+102528,U+FFFF;[0|0|0|23|24|27|0|0|53|57|0|0]
diff --git a/test/shape/data/aots/tests/cmap2.tests b/test/shape/data/aots/tests/cmap2.tests
new file mode 100644
index 0000000..d8a992f
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap2.tests
@@ -0,0 +1 @@
+#../fonts/cmap2_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0]
diff --git a/test/shape/data/aots/tests/cmap4.tests b/test/shape/data/aots/tests/cmap4.tests
new file mode 100644
index 0000000..a0d17ab
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap4.tests
@@ -0,0 +1,6 @@
+../fonts/cmap4_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|40|41|53|0|0|256|261|266|0|0]
+../fonts/cmap4_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|0]
+../fonts/cmap4_font3.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0010,U+0011,U+0012,U+001E,U+001F,U+00C7,U+00C8,U+00CD,U+00D2,U+00D3,U+FFFF;[0|0|0|0|0|0|0|0|0|0|0|0|65534]
+../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+AFC7,U+AFC8,U+AFC9,U+B02B,U+B02C,U+B02D;[0|0|44500|44501|44599|44600|0]
+#../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+FDE7,U+FDE8,U+FDE9,U+FE0B,U+FE0C,U+FE0D,U+FE4C,U+FE4D;[0|0|65500|65501|65535|0]
+../fonts/cmap4_font4.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0063,U+0064,U+01F3,U+01F4,U+01F5,U+03E8,U+03E9;[0|0|65136|65535|0|1|500|0]
diff --git a/test/shape/data/aots/tests/cmap6.tests b/test/shape/data/aots/tests/cmap6.tests
new file mode 100644
index 0000000..bb5af86
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap6.tests
@@ -0,0 +1,2 @@
+../fonts/cmap6_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|17|56|12|0|0]
+../fonts/cmap6_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0021,U+0022,U+0023,U+0024,U+0025,U+FFFF;[0|0|0|0|0|0|0|0]
diff --git a/test/shape/data/aots/tests/cmap8.tests b/test/shape/data/aots/tests/cmap8.tests
new file mode 100644
index 0000000..f65e015
--- /dev/null
+++ b/test/shape/data/aots/tests/cmap8.tests
@@ -0,0 +1 @@
+#../fonts/cmap8_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;U+0000,U+0001,U+0033,U+0034,U+0035,U+0036,U+0037,U+8431,U+8432,U+8434,U+9232,U+109422,U+109423,U+109424,U+109425,U+FFFF;[0|0|0|17|56|12|0|0|20|22|23|0|26|27|32|0]
diff --git a/test/shape/data/aots/tests/gpos1_1_lookupflag.tests b/test/shape/data/aots/tests/gpos1_1_lookupflag.tests
new file mode 100644
index 0000000..d59ed62
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos1_1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gpos1_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos1_1_simple.tests b/test/shape/data/aots/tests/gpos1_1_simple.tests
new file mode 100644
index 0000000..6fd49fa
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos1_1_simple.tests
@@ -0,0 +1,4 @@
+../fonts/gpos1_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
+../fonts/gpos1_1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,-200|19@3000,0|20@4500,-200|21@6000,0]
+../fonts/gpos1_1_simple_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@2800,0|20@4300,0|21@5600,0]
+#../fonts/gpos1_1_simple_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,-200|20@4500,-200|21@6000,-400]
diff --git a/test/shape/data/aots/tests/gpos1_2.tests b/test/shape/data/aots/tests/gpos1_2.tests
new file mode 100644
index 0000000..c8d949d
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos1_2.tests
@@ -0,0 +1 @@
+../fonts/gpos1_2_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos1_2_lookupflag.tests b/test/shape/data/aots/tests/gpos1_2_lookupflag.tests
new file mode 100644
index 0000000..e2c694f
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos1_2_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gpos1_2_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos2_1.tests b/test/shape/data/aots/tests/gpos2_1.tests
new file mode 100644
index 0000000..ca94605
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos2_1.tests
@@ -0,0 +1,2 @@
+../fonts/gpos2_1_font6.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0]
+../fonts/gpos2_1_font7.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011,U+0015,U+0016,U+0011;[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0|21@10000,0|22@12000,-600|17@13500,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_lookupflag.tests b/test/shape/data/aots/tests/gpos2_1_lookupflag.tests
new file mode 100644
index 0000000..0aacce0
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos2_1_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gpos2_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
+../fonts/gpos2_1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_next_glyph.tests b/test/shape/data/aots/tests/gpos2_1_next_glyph.tests
new file mode 100644
index 0000000..990314d
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos2_1_next_glyph.tests
@@ -0,0 +1,2 @@
+../fonts/gpos2_1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
+../fonts/gpos2_1_next_glyph_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shape/data/aots/tests/gpos2_1_simple.tests b/test/shape/data/aots/tests/gpos2_1_simple.tests
new file mode 100644
index 0000000..86c1b9a
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos2_1_simple.tests
@@ -0,0 +1,2 @@
+../fonts/gpos2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
+../fonts/gpos2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
diff --git a/test/shape/data/aots/tests/gpos2_2.tests b/test/shape/data/aots/tests/gpos2_2.tests
new file mode 100644
index 0000000..afcd661
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos2_2.tests
@@ -0,0 +1,5 @@
+../fonts/gpos2_2_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011,U+0012,U+0014;[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
+../fonts/gpos2_2_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
+../fonts/gpos2_2_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
+../fonts/gpos2_2_font4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
+../fonts/gpos2_2_font5.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shape/data/aots/tests/gpos3.tests b/test/shape/data/aots/tests/gpos3.tests
new file mode 100644
index 0000000..6981ec5
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos3.tests
@@ -0,0 +1,11 @@
+#../fonts/gpos3_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
+../fonts/gpos3_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@6000,0]
+#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0012,U+0011;[17|18@1500,0|18@1600,100|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1599,99|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0012,U+0011;[17|20@1500,0|18@1602,102|17@4500,0]
+#../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0014,U+0013,U+0011;[17|20@1500,0|19@1601,101|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0011;[17|18@1500,0|20@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0012,U+0011;[17|19@1500,0|18@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011;[17|19@1500,0|20@3000,0|17@4500,0]
+../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012;[17|18@1500,0]
+../fonts/gpos3_font3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0]
diff --git a/test/shape/data/aots/tests/gpos3_lookupflag.tests b/test/shape/data/aots/tests/gpos3_lookupflag.tests
new file mode 100644
index 0000000..c615f4e
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos3_lookupflag.tests
@@ -0,0 +1,2 @@
+#../fonts/gpos3_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|19@1599,99|17@6000,0]
+#../fonts/gpos3_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0015,U+0015,U+0015,U+0013,U+0011;[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0|19@1599,99|17@9000,0]
diff --git a/test/shape/data/aots/tests/gpos4_lookupflag.tests b/test/shape/data/aots/tests/gpos4_lookupflag.tests
new file mode 100644
index 0000000..e75ba84
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos4_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gpos4_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0013,U+0011;[17|18@1500,0|17@3000,0|19@4500,0|17@4500,0]
+../fonts/gpos4_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@3000,0|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos4_multiple_anchors.tests b/test/shape/data/aots/tests/gpos4_multiple_anchors.tests
new file mode 100644
index 0000000..793041f
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos4_multiple_anchors.tests
@@ -0,0 +1 @@
+#../fonts/gpos4_multiple_anchors_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0015,U+0016,U+0012,U+0013,U+0014,U+0015,U+0016;[17|19@-100,-80|20@-1591,-71|21@-3102,-82|22@-4593,-73|18@1500,0|19@1420,-60|20@-71,-51|21@-1582,-62|22@-3073,-53]
diff --git a/test/shape/data/aots/tests/gpos4_simple.tests b/test/shape/data/aots/tests/gpos4_simple.tests
new file mode 100644
index 0000000..a25361c
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos4_simple.tests
@@ -0,0 +1,5 @@
+#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
+../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
+../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0019,U+0019,U+0013,U+0011;[25|25@1500,0|19@3000,0|17@3000,0]
+#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0013,U+0011;[17|18@1500,0|19@1400,-80|19@-100,-80|17@3000,0]
+#../fonts/gpos4_simple_1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0014,U+0013,U+0011;[17|18@1500,0|20@3000,0|19@-100,-80|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos5.tests b/test/shape/data/aots/tests/gpos5.tests
new file mode 100644
index 0000000..d1462f4
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos5.tests
@@ -0,0 +1,2 @@
+../fonts/gpos5_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+0013,U+001F,U+0011;[17|18@1500,0|19@1400,-80|17@3000,0]
+#../fonts/gpos5_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+001E,U+001F,U+0013,U+0011;[17|18@1500,0|19@1401,-79|17@3000,0]
diff --git a/test/shape/data/aots/tests/gpos6.tests b/test/shape/data/aots/tests/gpos6.tests
new file mode 100644
index 0000000..b65c941
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos6.tests
@@ -0,0 +1,3 @@
+#../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|19@-100,-80|17@1500,0]
+../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0011,U+0013,U+0011;[17|17@1500,0|19@3000,0|17@3000,0]
+../fonts/gpos6_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0014,U+0014,U+0013,U+0011;[20|20|19|17]
diff --git a/test/shape/data/aots/tests/gpos7_1.tests b/test/shape/data/aots/tests/gpos7_1.tests
new file mode 100644
index 0000000..ba773ba
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos7_1.tests
@@ -0,0 +1,2 @@
+../fonts/gpos7_1_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1600,0|19@3200,0|20@4800,0|21@6000,0]
+../fonts/gpos7_1_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0011,U+0012,U+0013,U+0011;[17|18@1500,0|17@3000,0|18@4500,0|19@6000,0|17@7500,0]
diff --git a/test/shape/data/aots/tests/gpos9.tests b/test/shape/data/aots/tests/gpos9.tests
new file mode 100644
index 0000000..5a2bc90
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos9.tests
@@ -0,0 +1,2 @@
+../fonts/gpos9_font1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
+../fonts/gpos9_font2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0011,U+0012,U+0013,U+0014,U+0015,U+0011;[17|18@1300,0|19@2700,0|20@4300,0|21@5700,0|17@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_boundary.tests b/test/shape/data/aots/tests/gpos_chaining1_boundary.tests
new file mode 100644
index 0000000..ab7e264
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gpos_chaining1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests
new file mode 100644
index 0000000..dd10344
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests
new file mode 100644
index 0000000..e4e37f7
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_chaining1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests
new file mode 100644
index 0000000..4431e52
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_simple.tests b/test/shape/data/aots/tests/gpos_chaining1_simple.tests
new file mode 100644
index 0000000..bdb61a9
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gpos_chaining1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining1_successive.tests b/test/shape/data/aots/tests/gpos_chaining1_successive.tests
new file mode 100644
index 0000000..dba4fc3
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining1_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_boundary.tests b/test/shape/data/aots/tests/gpos_chaining2_boundary.tests
new file mode 100644
index 0000000..e731ad9
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gpos_chaining2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests
new file mode 100644
index 0000000..432dd9e
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests
new file mode 100644
index 0000000..d7374ad
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_chaining2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
+../fonts/gpos_chaining2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests
new file mode 100644
index 0000000..30e9b7c
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_simple.tests b/test/shape/data/aots/tests/gpos_chaining2_simple.tests
new file mode 100644
index 0000000..2d10871
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gpos_chaining2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining2_successive.tests b/test/shape/data/aots/tests/gpos_chaining2_successive.tests
new file mode 100644
index 0000000..069e856
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining2_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_boundary.tests b/test/shape/data/aots/tests/gpos_chaining3_boundary.tests
new file mode 100644
index 0000000..aa846d0
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining3_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gpos_chaining3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests b/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests
new file mode 100644
index 0000000..53b61b1
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining3_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20@1500,0|90@3000,0|21@3000,0|91@4500,0|22@4500,0|92@6000,0|23@6020,0|93@7500,0|94@7500,0|24@7500,0|90@9000,0|25@9000,0|91@10500,0|26@10500,0|0@12000,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests b/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests
new file mode 100644
index 0000000..29eb1ab
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining3_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22@1500,0|21@3020,0|22@4500,0|21@6020,0|22@7500,0|21@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_simple.tests b/test/shape/data/aots/tests/gpos_chaining3_simple.tests
new file mode 100644
index 0000000..3a96de7
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining3_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gpos_chaining3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
+../fonts/gpos_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016;[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shape/data/aots/tests/gpos_chaining3_successive.tests b/test/shape/data/aots/tests/gpos_chaining3_successive.tests
new file mode 100644
index 0000000..ddddf47
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_chaining3_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_chaining3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_boundary.tests b/test/shape/data/aots/tests/gpos_context1_boundary.tests
new file mode 100644
index 0000000..39e2749
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_expansion.tests b/test/shape/data/aots/tests/gpos_context1_expansion.tests
new file mode 100644
index 0000000..e8105d3
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_expansion.tests
@@ -0,0 +1 @@
+../fonts/gpos_context1_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_lookupflag.tests b/test/shape/data/aots/tests/gpos_context1_lookupflag.tests
new file mode 100644
index 0000000..2120eb3
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests
new file mode 100644
index 0000000..78e7a3b
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_next_glyph.tests b/test/shape/data/aots/tests/gpos_context1_next_glyph.tests
new file mode 100644
index 0000000..4bcd327
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_context1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_simple.tests b/test/shape/data/aots/tests/gpos_context1_simple.tests
new file mode 100644
index 0000000..5353a54
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_simple.tests
@@ -0,0 +1,3 @@
+../fonts/gpos_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
+../fonts/gpos_context1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context1_successive.tests b/test/shape/data/aots/tests/gpos_context1_successive.tests
new file mode 100644
index 0000000..285e143
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context1_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_context1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_boundary.tests b/test/shape/data/aots/tests/gpos_context2_boundary.tests
new file mode 100644
index 0000000..e93aa74
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_classes.tests b/test/shape/data/aots/tests/gpos_context2_classes.tests
new file mode 100644
index 0000000..d0fbc0d
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_classes.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context2_classes_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20@1500,0|26@3020,0|28@4500,0|24@6000,0|0@7500,0|21@9000,0|27@10520,0|26@12000,0|24@13500,0|0@15000,0|22@16500,0|27@18000,0|26@19500,0|24@21000,0]
+../fonts/gpos_context2_classes_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22@1500,0|27@3020,0|26@4500,0|24@6000,0|0@7500,0|24@9000,0|24@10500,0|29@12020,0|22@13500,0|0@15000,0|22@16500,0|27@18020,0|26@19500,0|24@21000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_expansion.tests b/test/shape/data/aots/tests/gpos_context2_expansion.tests
new file mode 100644
index 0000000..74eb5ef
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_expansion.tests
@@ -0,0 +1 @@
+../fonts/gpos_context2_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_lookupflag.tests b/test/shape/data/aots/tests/gpos_context2_lookupflag.tests
new file mode 100644
index 0000000..a9432a3
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context2_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests b/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests
new file mode 100644
index 0000000..d02cdde
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
+../fonts/gpos_context2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_next_glyph.tests b/test/shape/data/aots/tests/gpos_context2_next_glyph.tests
new file mode 100644
index 0000000..57855bd
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_context2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_simple.tests b/test/shape/data/aots/tests/gpos_context2_simple.tests
new file mode 100644
index 0000000..15c65c2
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_simple.tests
@@ -0,0 +1,3 @@
+../fonts/gpos_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
+../fonts/gpos_context2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context2_successive.tests b/test/shape/data/aots/tests/gpos_context2_successive.tests
new file mode 100644
index 0000000..9aba57f
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context2_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_context2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_boundary.tests b/test/shape/data/aots/tests/gpos_context3_boundary.tests
new file mode 100644
index 0000000..29f0ec5
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context3_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
+../fonts/gpos_context3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_lookupflag.tests b/test/shape/data/aots/tests/gpos_context3_lookupflag.tests
new file mode 100644
index 0000000..e1cb329
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context3_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1520,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4520,0|0@6000,0]
+../fonts/gpos_context3_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20@1500,0|90@3000,0|21@3020,0|91@4500,0|92@4500,0|22@4500,0|0@6000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_next_glyph.tests b/test/shape/data/aots/tests/gpos_context3_next_glyph.tests
new file mode 100644
index 0000000..b5e70ba
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context3_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gpos_context3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_simple.tests b/test/shape/data/aots/tests/gpos_context3_simple.tests
new file mode 100644
index 0000000..228afc1
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context3_simple.tests
@@ -0,0 +1,2 @@
+../fonts/gpos_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
+../fonts/gpos_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0|20@9020,0|21@10520,0|22@12020,0|0@13500,0]
diff --git a/test/shape/data/aots/tests/gpos_context3_successive.tests b/test/shape/data/aots/tests/gpos_context3_successive.tests
new file mode 100644
index 0000000..658222d
--- /dev/null
+++ b/test/shape/data/aots/tests/gpos_context3_successive.tests
@@ -0,0 +1 @@
+../fonts/gpos_context3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --ned;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shape/data/aots/tests/gsub1_1_lookupflag.tests b/test/shape/data/aots/tests/gsub1_1_lookupflag.tests
new file mode 100644
index 0000000..3f5722b
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub1_1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub1_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|24|20|21]
diff --git a/test/shape/data/aots/tests/gsub1_1_modulo.tests b/test/shape/data/aots/tests/gsub1_1_modulo.tests
new file mode 100644
index 0000000..d716f18
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub1_1_modulo.tests
@@ -0,0 +1 @@
+../fonts/gsub1_1_modulo_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018;[17|18|17|24|23|18|23|24]
diff --git a/test/shape/data/aots/tests/gsub1_1_simple.tests b/test/shape/data/aots/tests/gsub1_1_simple.tests
new file mode 100644
index 0000000..11649be
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub1_1_simple.tests
@@ -0,0 +1 @@
+../fonts/gsub1_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
diff --git a/test/shape/data/aots/tests/gsub1_2_lookupflag.tests b/test/shape/data/aots/tests/gsub1_2_lookupflag.tests
new file mode 100644
index 0000000..13e523d
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub1_2_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub1_2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|18|19|25|21]
diff --git a/test/shape/data/aots/tests/gsub1_2_simple.tests b/test/shape/data/aots/tests/gsub1_2_simple.tests
new file mode 100644
index 0000000..372c3e6
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub1_2_simple.tests
@@ -0,0 +1 @@
+../fonts/gsub1_2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|22|19|25|21]
diff --git a/test/shape/data/aots/tests/gsub2_1_lookupflag.tests b/test/shape/data/aots/tests/gsub2_1_lookupflag.tests
new file mode 100644
index 0000000..178d5d6
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub2_1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub2_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|18|22|23|17]
diff --git a/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests b/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests
new file mode 100644
index 0000000..394a9a7
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub2_1_multiple_sequences.tests
@@ -0,0 +1 @@
+../fonts/gsub2_1_multiple_sequences_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0011;[17|20|21|22|23|17]
diff --git a/test/shape/data/aots/tests/gsub2_1_simple.tests b/test/shape/data/aots/tests/gsub2_1_simple.tests
new file mode 100644
index 0000000..817d92e
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub2_1_simple.tests
@@ -0,0 +1,2 @@
+../fonts/gsub2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013;[17|20|21|22|19]
+../fonts/gsub2_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0012;[17|20|21|22|19|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub3_1_lookupflag.tests b/test/shape/data/aots/tests/gsub3_1_lookupflag.tests
new file mode 100644
index 0000000..8233f0e
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub3_1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub3_1_lookupflag_f1.otf;--features="-test[4],test[5],test[6]=2,-test[7]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|18|18|19|22|23|19|17]
diff --git a/test/shape/data/aots/tests/gsub3_1_multiple.tests b/test/shape/data/aots/tests/gsub3_1_multiple.tests
new file mode 100644
index 0000000..47311aa
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub3_1_multiple.tests
@@ -0,0 +1 @@
+../fonts/gsub3_1_multiple_f1.otf;--features="-test[1],test[2],test[3]=2,-test[4],-test[5],test[6],test[7]=2,-test[8]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011;[17|18|20|21|18|19|22|23|19|17]
diff --git a/test/shape/data/aots/tests/gsub3_1_simple.tests b/test/shape/data/aots/tests/gsub3_1_simple.tests
new file mode 100644
index 0000000..2b9d7d1
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub3_1_simple.tests
@@ -0,0 +1 @@
+../fonts/gsub3_1_simple_f1.otf;--features="-test[1],test[3],test[5]=2,test[7]=3,-test[9],test[11]" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011;[17|18|17|20|17|21|17|22|17|18|17|20|17]
diff --git a/test/shape/data/aots/tests/gsub4_1_lookupflag.tests b/test/shape/data/aots/tests/gsub4_1_lookupflag.tests
new file mode 100644
index 0000000..d65a59a
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub4_1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub4_1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0018,U+0012,U+0018,U+0013,U+0018,U+0018,U+0014,U+0018,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|23|24|24|24|24|17|18|19|22|20]
diff --git a/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests b/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests
new file mode 100644
index 0000000..c96d722
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub4_1_multiple_ligatures.tests
@@ -0,0 +1,2 @@
+../fonts/gsub4_1_multiple_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|24|22|20]
+../fonts/gsub4_1_multiple_ligatures_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|24|20|17|24|22|20]
diff --git a/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests b/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests
new file mode 100644
index 0000000..e3f2437
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub4_1_multiple_ligsets.tests
@@ -0,0 +1 @@
+../fonts/gsub4_1_multiple_ligsets_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0015,U+0014,U+0013,U+0016;[17|23|21|24|22]
diff --git a/test/shape/data/aots/tests/gsub4_1_simple.tests b/test/shape/data/aots/tests/gsub4_1_simple.tests
new file mode 100644
index 0000000..0e56383
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub4_1_simple.tests
@@ -0,0 +1 @@
+../fonts/gsub4_1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014;[17|23|17|18|19|22|20]
diff --git a/test/shape/data/aots/tests/gsub7.tests b/test/shape/data/aots/tests/gsub7.tests
new file mode 100644
index 0000000..46bba7f
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub7.tests
@@ -0,0 +1,2 @@
+../fonts/gsub7_font1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|24|20|21]
+../fonts/gsub7_font2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|29|20|21]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_boundary.tests b/test/shape/data/aots/tests/gsub_chaining1_boundary.tests
new file mode 100644
index 0000000..43f37be
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gsub_chaining1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining1_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining1_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests
new file mode 100644
index 0000000..685cf19
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests
new file mode 100644
index 0000000..6a0993a
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_chaining1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests
new file mode 100644
index 0000000..f66f5e2
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_simple.tests b/test/shape/data/aots/tests/gsub_chaining1_simple.tests
new file mode 100644
index 0000000..f812b55
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gsub_chaining1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining1_successive.tests b/test/shape/data/aots/tests/gsub_chaining1_successive.tests
new file mode 100644
index 0000000..1dce9a1
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining1_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_boundary.tests b/test/shape/data/aots/tests/gsub_chaining2_boundary.tests
new file mode 100644
index 0000000..eacd1d5
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gsub_chaining2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining2_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining2_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests
new file mode 100644
index 0000000..a368e23
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests
new file mode 100644
index 0000000..7e54033
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_chaining2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|24|0|20|21|62|23|0]
+../fonts/gsub_chaining2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests
new file mode 100644
index 0000000..350902b
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|63|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_simple.tests b/test/shape/data/aots/tests/gsub_chaining2_simple.tests
new file mode 100644
index 0000000..1cdb9f8
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gsub_chaining2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining2_successive.tests b/test/shape/data/aots/tests/gsub_chaining2_successive.tests
new file mode 100644
index 0000000..ab872a4
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining2_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_boundary.tests b/test/shape/data/aots/tests/gsub_chaining3_boundary.tests
new file mode 100644
index 0000000..a9ce264
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining3_boundary.tests
@@ -0,0 +1,4 @@
+../fonts/gsub_chaining3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|22|23|0]
+../fonts/gsub_chaining3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining3_boundary_f3.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|22|23|0]
+../fonts/gsub_chaining3_boundary_f4.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|21|62|23|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests b/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests
new file mode 100644
index 0000000..ef6682e
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining3_lookupflag.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000;[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests b/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests
new file mode 100644
index 0000000..6245fa9
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining3_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000;[0|22|61|22|61|22|21|0]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_simple.tests b/test/shape/data/aots/tests/gsub_chaining3_simple.tests
new file mode 100644
index 0000000..b930260
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining3_simple.tests
@@ -0,0 +1,11 @@
+../fonts/gsub_chaining3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|62|23|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|20|21|62|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000;[0|20|21|22|23|24|25|0|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019;[0|20|21|22|23|24|25]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0018;[0|20|21|22|23|24]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[0|0|21|22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[21|22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0016,U+0017,U+0018,U+0019,U+001A,U+0000;[22|23|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000;[0|20|21|22|0|24|25|26|0]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017;[0|20|21|22|23]
+../fonts/gsub_chaining3_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016;[0|20|21|22]
diff --git a/test/shape/data/aots/tests/gsub_chaining3_successive.tests b/test/shape/data/aots/tests/gsub_chaining3_successive.tests
new file mode 100644
index 0000000..d8d34df
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_chaining3_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_chaining3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000;[0|25|20|61|63|24|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_boundary.tests b/test/shape/data/aots/tests/gsub_context1_boundary.tests
new file mode 100644
index 0000000..22de4e0
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context1_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context1_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_expansion.tests b/test/shape/data/aots/tests/gsub_context1_expansion.tests
new file mode 100644
index 0000000..c31f515
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_expansion.tests
@@ -0,0 +1 @@
+../fonts/gsub_context1_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_lookupflag.tests b/test/shape/data/aots/tests/gsub_context1_lookupflag.tests
new file mode 100644
index 0000000..57cd900
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context1_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context1_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests
new file mode 100644
index 0000000..6ade722
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context1_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
+../fonts/gsub_context1_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_next_glyph.tests b/test/shape/data/aots/tests/gsub_context1_next_glyph.tests
new file mode 100644
index 0000000..824f068
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_context1_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_simple.tests b/test/shape/data/aots/tests/gsub_context1_simple.tests
new file mode 100644
index 0000000..496eee6
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_simple.tests
@@ -0,0 +1,3 @@
+../fonts/gsub_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context1_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
+../fonts/gsub_context1_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context1_successive.tests b/test/shape/data/aots/tests/gsub_context1_successive.tests
new file mode 100644
index 0000000..a04b437
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context1_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_context1_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_boundary.tests b/test/shape/data/aots/tests/gsub_context2_boundary.tests
new file mode 100644
index 0000000..65963af
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context2_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context2_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_classes.tests b/test/shape/data/aots/tests/gsub_context2_classes.tests
new file mode 100644
index 0000000..eac17b1
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_classes.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context2_classes_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018;[0|20|66|28|24|0|21|67|26|24|0|22|27|26|24]
+../fonts/gsub_context2_classes_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018;[0|22|67|26|24|0|24|24|69|22|0|22|67|26|24]
diff --git a/test/shape/data/aots/tests/gsub_context2_expansion.tests b/test/shape/data/aots/tests/gsub_context2_expansion.tests
new file mode 100644
index 0000000..4c37118
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_expansion.tests
@@ -0,0 +1 @@
+../fonts/gsub_context2_expansion_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|61|62|63|22|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_lookupflag.tests b/test/shape/data/aots/tests/gsub_context2_lookupflag.tests
new file mode 100644
index 0000000..a4d229d
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context2_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context2_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests b/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests
new file mode 100644
index 0000000..22495b8
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_multiple_subrules.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context2_multiple_subrules_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|60|21|22|0|20|61|0]
+../fonts/gsub_context2_multiple_subrules_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000;[0|20|61|22|0|20|61|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_next_glyph.tests b/test/shape/data/aots/tests/gsub_context2_next_glyph.tests
new file mode 100644
index 0000000..ea2fad2
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_context2_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_simple.tests b/test/shape/data/aots/tests/gsub_context2_simple.tests
new file mode 100644
index 0000000..c58947b
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_simple.tests
@@ -0,0 +1,3 @@
+../fonts/gsub_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context2_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000;[0|20|0|20|21|0]
+../fonts/gsub_context2_simple_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|60|20|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context2_successive.tests b/test/shape/data/aots/tests/gsub_context2_successive.tests
new file mode 100644
index 0000000..7ccdecf
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context2_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_context2_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_boundary.tests b/test/shape/data/aots/tests/gsub_context3_boundary.tests
new file mode 100644
index 0000000..7ad6fcb
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context3_boundary.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context3_boundary_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|20|20|20|20|20|0]
+../fonts/gsub_context3_boundary_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|60|60|60|60|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_lookupflag.tests b/test/shape/data/aots/tests/gsub_context3_lookupflag.tests
new file mode 100644
index 0000000..3cdc87e
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context3_lookupflag.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context3_lookupflag_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|60|90|61|91|92|62|0]
+../fonts/gsub_context3_lookupflag_f2.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000;[0|20|90|61|91|92|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_next_glyph.tests b/test/shape/data/aots/tests/gsub_context3_next_glyph.tests
new file mode 100644
index 0000000..462019a
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context3_next_glyph.tests
@@ -0,0 +1 @@
+../fonts/gsub_context3_next_glyph_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000;[0|60|20|60|20|20|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_simple.tests b/test/shape/data/aots/tests/gsub_context3_simple.tests
new file mode 100644
index 0000000..d1b628a
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context3_simple.tests
@@ -0,0 +1,2 @@
+../fonts/gsub_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0000;[0|60|61|62|0]
+../fonts/gsub_context3_simple_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000;[0|20|0|20|21|0|60|61|62|0]
diff --git a/test/shape/data/aots/tests/gsub_context3_successive.tests b/test/shape/data/aots/tests/gsub_context3_successive.tests
new file mode 100644
index 0000000..99ec256
--- /dev/null
+++ b/test/shape/data/aots/tests/gsub_context3_successive.tests
@@ -0,0 +1 @@
+../fonts/gsub_context3_successive_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0000,U+0014,U+0015,U+0016,U+0017,U+0000;[0|20|61|63|0]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_attach.tests b/test/shape/data/aots/tests/lookupflag_ignore_attach.tests
new file mode 100644
index 0000000..16a22e0
--- /dev/null
+++ b/test/shape/data/aots/tests/lookupflag_ignore_attach.tests
@@ -0,0 +1,5 @@
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+000D,U+001A,U+000A;[10|15|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+0017,U+001D,U+001A,U+000A;[10|15|21|22|23|29|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+0015,U+000D,U+0016,U+001B,U+001A,U+000A;[10|11|21|13|22|27|26|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+0016,U+0017,U+001A,U+000A;[10|11|27|13|22|23|26|10]
+../fonts/lookupflag_ignore_attach_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+000A,U+000B,U+001B,U+000D,U+000E,U+0017,U+001A,U+000A;[10|11|27|13|14|23|26|10]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_base.tests b/test/shape/data/aots/tests/lookupflag_ignore_base.tests
new file mode 100644
index 0000000..ba4f730
--- /dev/null
+++ b/test/shape/data/aots/tests/lookupflag_ignore_base.tests
@@ -0,0 +1,2 @@
+../fonts/lookupflag_ignore_base_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0013,U+0014,U+0015;[17|23|21]
+../fonts/lookupflag_ignore_base_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+0018,U+0018,U+0013,U+0019,U+0014,U+0015;[17|23|24|24|25|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_combination.tests b/test/shape/data/aots/tests/lookupflag_ignore_combination.tests
new file mode 100644
index 0000000..08b5b48
--- /dev/null
+++ b/test/shape/data/aots/tests/lookupflag_ignore_combination.tests
@@ -0,0 +1,3 @@
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0014,U+0015;[17|23|26|21]
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+001F,U+0014,U+0015;[17|23|26|24|30|31|21]
+../fonts/lookupflag_ignore_combination_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+0020,U+0014,U+0015;[17|18|26|19|24|30|32|20|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests b/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests
new file mode 100644
index 0000000..b523815
--- /dev/null
+++ b/test/shape/data/aots/tests/lookupflag_ignore_ligatures.tests
@@ -0,0 +1,3 @@
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+001B,U+0013,U+001B,U+0014,U+0015;[17|23|26|27|27|21]
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+0018,U+0013,U+001B,U+0014,U+0015;[17|18|26|24|19|27|20|21]
+../fonts/lookupflag_ignore_ligatures_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001A,U+002A,U+0013,U+001B,U+0014,U+0015;[17|18|26|42|19|27|20|21]
diff --git a/test/shape/data/aots/tests/lookupflag_ignore_marks.tests b/test/shape/data/aots/tests/lookupflag_ignore_marks.tests
new file mode 100644
index 0000000..de1ccf2
--- /dev/null
+++ b/test/shape/data/aots/tests/lookupflag_ignore_marks.tests
@@ -0,0 +1 @@
+../fonts/lookupflag_ignore_marks_f1.otf;--features="test" --no-clusters --no-glyph-names --no-positions;U+0011,U+0012,U+001C,U+001D,U+0013,U+001D,U+0014,U+0015;[17|23|28|29|29|21]
diff --git a/test/shape/data/aots/update.py b/test/shape/data/aots/update.py
new file mode 100755
index 0000000..d3b5455
--- /dev/null
+++ b/test/shape/data/aots/update.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+
+import sys, os, subprocess, shutil
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+git = shutil.which ('git'); assert git
+make = shutil.which ('make'); assert make
+java = shutil.which ('java'); assert java
+cxx = shutil.which ('c++'); assert cxx
+
+pull = False
+if not os.path.exists ('aots'):
+	subprocess.run ([git, 'clone', 'https://github.com/adobe-type-tools/aots'], check=True)
+	pull = True
+
+if pull or 'pull' in sys.argv:
+	subprocess.run ([git, 'pull'], cwd='aots', check=True)
+	subprocess.run ([make, '-C', 'aots'], check=True)
+	subprocess.run ([make, '-C', 'aots/harfbuzz'], check=True)
+
+shutil.copy ('hb-aots-tester.cpp', 'aots/harfbuzz')
+# TODO: remove *nix assumptions
+subprocess.run ([cxx, '-std=c++11', '-Wno-narrowing', 'aots/harfbuzz/hb-aots-tester.cpp',
+	'../../../../src/harfbuzz.cc', '-DHB_NO_MT', '-fno-exceptions', '-lm',
+	'-I../../../../src', '-o', 'aots/harfbuzz/aots'], check=True)
+shutil.rmtree ('tests')
+os.mkdir ('tests')
+subprocess.run (['./aots'], cwd='aots/harfbuzz', check=True)
diff --git a/test/shaping/data/in-house/COPYING b/test/shape/data/in-house/COPYING
similarity index 100%
rename from test/shaping/data/in-house/COPYING
rename to test/shape/data/in-house/COPYING
diff --git a/test/shape/data/in-house/Makefile.am b/test/shape/data/in-house/Makefile.am
new file mode 100644
index 0000000..a284578
--- /dev/null
+++ b/test/shape/data/in-house/Makefile.am
@@ -0,0 +1,26 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+EXTRA_DIST = \
+	COPYING \
+	fonts \
+	meson.build \
+	$(TESTS) \
+	$(NULL)
+
+TEST_EXTENSIONS = .tests
+if HAVE_FREETYPE
+TESTS_ENVIRONMENT = HAVE_FREETYPE=1
+else
+TESTS_ENVIRONMENT = HAVE_FREETYPE=0
+endif
+TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
+
+include Makefile.sources
+
+-include $(top_srcdir)/git.mk
diff --git a/test/shape/data/in-house/Makefile.sources b/test/shape/data/in-house/Makefile.sources
new file mode 100644
index 0000000..2432d89
--- /dev/null
+++ b/test/shape/data/in-house/Makefile.sources
@@ -0,0 +1,72 @@
+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-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/emoji-clusters.tests \
+	tests/fallback-positioning.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/indic-old-spec.tests \
+	tests/indic-pref-blocking.tests \
+	tests/indic-script-extensions.tests \
+	tests/indic-special-cases.tests \
+	tests/indic-syllable.tests \
+	tests/indic-vowel-letter-spoofing.tests \
+	tests/item-context.tests \
+	tests/kern-format2.tests \
+	tests/khmer-mark-order.tests \
+	tests/khmer-misc.tests \
+	tests/language-tags.tests \
+	tests/ligature-id.tests \
+	tests/macos.tests \
+	tests/mark-attachment.tests \
+	tests/mark-filtering-sets.tests \
+	tests/mongolian-variation-selector.tests \
+	tests/myanmar-misc.tests \
+	tests/myanmar-syllable.tests \
+	tests/myanmar-zawgyi.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/tibetan-contractions-2.tests \
+	tests/tibetan-vowels.tests \
+	tests/tt-kern-gpos.tests \
+	tests/use-indic3.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 \
+	tests/zero-width-marks.tests \
+	$(NULL)
+
+DISABLED_TESTS = \
+	$(NULL)
diff --git a/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf b/test/shape/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf
rename to test/shape/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf b/test/shape/data/in-house/fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf
rename to test/shape/data/in-house/fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf b/test/shape/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf
new file mode 100644
index 0000000..46ebee8
--- /dev/null
+++ b/test/shape/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf b/test/shape/data/in-house/fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf
rename to test/shape/data/in-house/fonts/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf b/test/shape/data/in-house/fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf
rename to test/shape/data/in-house/fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf b/test/shape/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf
new file mode 100644
index 0000000..4d0f52a
--- /dev/null
+++ b/test/shape/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf b/test/shape/data/in-house/fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
rename to test/shape/data/in-house/fonts/15dfc433a135a658b9f4b1a861b5cdd9658ccbb9.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf b/test/shape/data/in-house/fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf
rename to test/shape/data/in-house/fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf b/test/shape/data/in-house/fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf
rename to test/shape/data/in-house/fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf b/test/shape/data/in-house/fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf
rename to test/shape/data/in-house/fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf b/test/shape/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf
rename to test/shape/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/1b66a1f4b076b734caa6397b3e57231af1feaafb.ttf b/test/shape/data/in-house/fonts/1b66a1f4b076b734caa6397b3e57231af1feaafb.ttf
new file mode 100644
index 0000000..906f5bf
--- /dev/null
+++ b/test/shape/data/in-house/fonts/1b66a1f4b076b734caa6397b3e57231af1feaafb.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf b/test/shape/data/in-house/fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf
rename to test/shape/data/in-house/fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf b/test/shape/data/in-house/fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf
rename to test/shape/data/in-house/fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf b/test/shape/data/in-house/fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf
rename to test/shape/data/in-house/fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf b/test/shape/data/in-house/fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf
rename to test/shape/data/in-house/fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf b/test/shape/data/in-house/fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf
rename to test/shape/data/in-house/fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf b/test/shape/data/in-house/fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf
rename to test/shape/data/in-house/fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf b/test/shape/data/in-house/fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf
rename to test/shape/data/in-house/fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf b/test/shape/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf
new file mode 100644
index 0000000..952d40a
--- /dev/null
+++ b/test/shape/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf b/test/shape/data/in-house/fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
rename to test/shape/data/in-house/fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf b/test/shape/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf
rename to test/shape/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf b/test/shape/data/in-house/fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
rename to test/shape/data/in-house/fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf b/test/shape/data/in-house/fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf
rename to test/shape/data/in-house/fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf b/test/shape/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf
rename to test/shape/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf b/test/shape/data/in-house/fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf
rename to test/shape/data/in-house/fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf b/test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf
new file mode 100644
index 0000000..de14336
--- /dev/null
+++ b/test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/341421e629668b1a1242245d39238ca48432d35d.ttf b/test/shape/data/in-house/fonts/341421e629668b1a1242245d39238ca48432d35d.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/341421e629668b1a1242245d39238ca48432d35d.ttf
rename to test/shape/data/in-house/fonts/341421e629668b1a1242245d39238ca48432d35d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf b/test/shape/data/in-house/fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf
rename to test/shape/data/in-house/fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf b/test/shape/data/in-house/fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf
rename to test/shape/data/in-house/fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf b/test/shape/data/in-house/fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf
rename to test/shape/data/in-house/fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf b/test/shape/data/in-house/fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf
rename to test/shape/data/in-house/fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/3b791518a9ba89675df02f1eefbc9026a50648a6.ttf b/test/shape/data/in-house/fonts/3b791518a9ba89675df02f1eefbc9026a50648a6.ttf
new file mode 100644
index 0000000..76855be
--- /dev/null
+++ b/test/shape/data/in-house/fonts/3b791518a9ba89675df02f1eefbc9026a50648a6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf b/test/shape/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf
rename to test/shape/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf b/test/shape/data/in-house/fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf
rename to test/shape/data/in-house/fonts/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf b/test/shape/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf
rename to test/shape/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf b/test/shape/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf
rename to test/shape/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf b/test/shape/data/in-house/fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf
rename to test/shape/data/in-house/fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf b/test/shape/data/in-house/fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf
new file mode 100644
index 0000000..7312779
--- /dev/null
+++ b/test/shape/data/in-house/fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/3f24aff8b768e586162e9b9d03b15c36508dd2ae.ttf b/test/shape/data/in-house/fonts/3f24aff8b768e586162e9b9d03b15c36508dd2ae.ttf
new file mode 100644
index 0000000..7449e48
--- /dev/null
+++ b/test/shape/data/in-house/fonts/3f24aff8b768e586162e9b9d03b15c36508dd2ae.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf b/test/shape/data/in-house/fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf
rename to test/shape/data/in-house/fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf b/test/shape/data/in-house/fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf
rename to test/shape/data/in-house/fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf b/test/shape/data/in-house/fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf
rename to test/shape/data/in-house/fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf b/test/shape/data/in-house/fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf
rename to test/shape/data/in-house/fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf b/test/shape/data/in-house/fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf
rename to test/shape/data/in-house/fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf b/test/shape/data/in-house/fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf
rename to test/shape/data/in-house/fonts/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf b/test/shape/data/in-house/fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
rename to test/shape/data/in-house/fonts/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf b/test/shape/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf
rename to test/shape/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf b/test/shape/data/in-house/fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf
rename to test/shape/data/in-house/fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf b/test/shape/data/in-house/fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf
rename to test/shape/data/in-house/fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf b/test/shape/data/in-house/fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf
rename to test/shape/data/in-house/fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf b/test/shape/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf
rename to test/shape/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf b/test/shape/data/in-house/fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf
rename to test/shape/data/in-house/fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf b/test/shape/data/in-house/fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
rename to test/shape/data/in-house/fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf b/test/shape/data/in-house/fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf
rename to test/shape/data/in-house/fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf b/test/shape/data/in-house/fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf
rename to test/shape/data/in-house/fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf b/test/shape/data/in-house/fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
rename to test/shape/data/in-house/fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf b/test/shape/data/in-house/fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf
rename to test/shape/data/in-house/fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf b/test/shape/data/in-house/fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf
rename to test/shape/data/in-house/fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf b/test/shape/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
rename to test/shape/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf b/test/shape/data/in-house/fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
rename to test/shape/data/in-house/fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf b/test/shape/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf
rename to test/shape/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf b/test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
rename to test/shape/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf b/test/shape/data/in-house/fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf
new file mode 100644
index 0000000..64ab1c6
--- /dev/null
+++ b/test/shape/data/in-house/fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf b/test/shape/data/in-house/fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
rename to test/shape/data/in-house/fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf b/test/shape/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf
new file mode 100644
index 0000000..f1e07f2
--- /dev/null
+++ b/test/shape/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf b/test/shape/data/in-house/fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf
rename to test/shape/data/in-house/fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf b/test/shape/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf
new file mode 100644
index 0000000..395f423
--- /dev/null
+++ b/test/shape/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf b/test/shape/data/in-house/fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf
rename to test/shape/data/in-house/fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf b/test/shape/data/in-house/fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf
rename to test/shape/data/in-house/fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf b/test/shape/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf
rename to test/shape/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf b/test/shape/data/in-house/fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf
rename to test/shape/data/in-house/fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf b/test/shape/data/in-house/fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
rename to test/shape/data/in-house/fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf b/test/shape/data/in-house/fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf
rename to test/shape/data/in-house/fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf b/test/shape/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf
rename to test/shape/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf b/test/shape/data/in-house/fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf
rename to test/shape/data/in-house/fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf b/test/shape/data/in-house/fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf
rename to test/shape/data/in-house/fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf b/test/shape/data/in-house/fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf
rename to test/shape/data/in-house/fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf b/test/shape/data/in-house/fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
rename to test/shape/data/in-house/fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf b/test/shape/data/in-house/fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf
rename to test/shape/data/in-house/fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf b/test/shape/data/in-house/fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf
rename to test/shape/data/in-house/fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf b/test/shape/data/in-house/fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf
rename to test/shape/data/in-house/fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8454d22037f892e76614e1645d066689a0200e61.ttf b/test/shape/data/in-house/fonts/8454d22037f892e76614e1645d066689a0200e61.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8454d22037f892e76614e1645d066689a0200e61.ttf
rename to test/shape/data/in-house/fonts/8454d22037f892e76614e1645d066689a0200e61.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf b/test/shape/data/in-house/fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf
rename to test/shape/data/in-house/fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf b/test/shape/data/in-house/fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf
rename to test/shape/data/in-house/fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf b/test/shape/data/in-house/fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf
rename to test/shape/data/in-house/fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf b/test/shape/data/in-house/fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf
rename to test/shape/data/in-house/fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf b/test/shape/data/in-house/fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf
new file mode 100644
index 0000000..21b2dca
--- /dev/null
+++ b/test/shape/data/in-house/fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf b/test/shape/data/in-house/fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf
rename to test/shape/data/in-house/fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf b/test/shape/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf
rename to test/shape/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf b/test/shape/data/in-house/fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
rename to test/shape/data/in-house/fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf b/test/shape/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
rename to test/shape/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf b/test/shape/data/in-house/fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf
rename to test/shape/data/in-house/fonts/932ad5132c2761297c74e9976fe25b08e5ffa10b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf b/test/shape/data/in-house/fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf
rename to test/shape/data/in-house/fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf b/test/shape/data/in-house/fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf
rename to test/shape/data/in-house/fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf b/test/shape/data/in-house/fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf
rename to test/shape/data/in-house/fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf b/test/shape/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf
rename to test/shape/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/AdobeBlank2.ttf b/test/shape/data/in-house/fonts/AdobeBlank2.ttf
new file mode 100644
index 0000000..8a4fb00
--- /dev/null
+++ b/test/shape/data/in-house/fonts/AdobeBlank2.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/DFONT.dfont b/test/shape/data/in-house/fonts/DFONT.dfont
similarity index 100%
rename from test/shaping/data/in-house/fonts/DFONT.dfont
rename to test/shape/data/in-house/fonts/DFONT.dfont
Binary files differ
diff --git a/test/shape/data/in-house/fonts/HBTest-VF.ttf b/test/shape/data/in-house/fonts/HBTest-VF.ttf
new file mode 100644
index 0000000..01c2230
--- /dev/null
+++ b/test/shape/data/in-house/fonts/HBTest-VF.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/MORXTwentyeight.ttf b/test/shape/data/in-house/fonts/MORXTwentyeight.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/MORXTwentyeight.ttf
rename to test/shape/data/in-house/fonts/MORXTwentyeight.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/TRAK.ttf b/test/shape/data/in-house/fonts/TRAK.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/TRAK.ttf
rename to test/shape/data/in-house/fonts/TRAK.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/TTC.ttc b/test/shape/data/in-house/fonts/TTC.ttc
similarity index 100%
rename from test/shaping/data/in-house/fonts/TTC.ttc
rename to test/shape/data/in-house/fonts/TTC.ttc
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf b/test/shape/data/in-house/fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf
rename to test/shape/data/in-house/fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf b/test/shape/data/in-house/fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf
rename to test/shape/data/in-house/fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf b/test/shape/data/in-house/fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf
rename to test/shape/data/in-house/fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/a6b17da98b9f1565ba428719777bbf94a66403c1.ttf b/test/shape/data/in-house/fonts/a6b17da98b9f1565ba428719777bbf94a66403c1.ttf
new file mode 100644
index 0000000..84e8a59
--- /dev/null
+++ b/test/shape/data/in-house/fonts/a6b17da98b9f1565ba428719777bbf94a66403c1.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf b/test/shape/data/in-house/fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf
rename to test/shape/data/in-house/fonts/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf b/test/shape/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf
new file mode 100644
index 0000000..7d217ba
--- /dev/null
+++ b/test/shape/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a919b33197965846f21074b24e30250d67277bce.ttf b/test/shape/data/in-house/fonts/a919b33197965846f21074b24e30250d67277bce.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a919b33197965846f21074b24e30250d67277bce.ttf
rename to test/shape/data/in-house/fonts/a919b33197965846f21074b24e30250d67277bce.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf b/test/shape/data/in-house/fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf
rename to test/shape/data/in-house/fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf b/test/shape/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf
rename to test/shape/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf b/test/shape/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf
new file mode 100644
index 0000000..a82aa21
--- /dev/null
+++ b/test/shape/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf b/test/shape/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf
rename to test/shape/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf b/test/shape/data/in-house/fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf
rename to test/shape/data/in-house/fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf b/test/shape/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf
rename to test/shape/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/b082211be29a3e2cf91f0fd43497e40b2a27b344.ttf b/test/shape/data/in-house/fonts/b082211be29a3e2cf91f0fd43497e40b2a27b344.ttf
new file mode 100644
index 0000000..6e59fd4
--- /dev/null
+++ b/test/shape/data/in-house/fonts/b082211be29a3e2cf91f0fd43497e40b2a27b344.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/b121d4306b2e3add5abbaad21d95fcf04aacbd64.ttf b/test/shape/data/in-house/fonts/b121d4306b2e3add5abbaad21d95fcf04aacbd64.ttf
new file mode 100644
index 0000000..7075592
--- /dev/null
+++ b/test/shape/data/in-house/fonts/b121d4306b2e3add5abbaad21d95fcf04aacbd64.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf b/test/shape/data/in-house/fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf
rename to test/shape/data/in-house/fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf b/test/shape/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf
new file mode 100644
index 0000000..4d0b3cd
--- /dev/null
+++ b/test/shape/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/b31e6c52a31edadc16f1bec9efe6019e2d59824a.ttf b/test/shape/data/in-house/fonts/b31e6c52a31edadc16f1bec9efe6019e2d59824a.ttf
new file mode 100644
index 0000000..3a17b92
--- /dev/null
+++ b/test/shape/data/in-house/fonts/b31e6c52a31edadc16f1bec9efe6019e2d59824a.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf b/test/shape/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf
rename to test/shape/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf b/test/shape/data/in-house/fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf
rename to test/shape/data/in-house/fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf b/test/shape/data/in-house/fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf
rename to test/shape/data/in-house/fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf b/test/shape/data/in-house/fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf
rename to test/shape/data/in-house/fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf b/test/shape/data/in-house/fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf
rename to test/shape/data/in-house/fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf b/test/shape/data/in-house/fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf
rename to test/shape/data/in-house/fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf b/test/shape/data/in-house/fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
rename to test/shape/data/in-house/fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf b/test/shape/data/in-house/fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf
rename to test/shape/data/in-house/fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf b/test/shape/data/in-house/fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf
rename to test/shape/data/in-house/fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf b/test/shape/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf
rename to test/shape/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf b/test/shape/data/in-house/fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf
rename to test/shape/data/in-house/fonts/d629e7fedc0b350222d7987345fe61613fa3929a.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf b/test/shape/data/in-house/fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf
rename to test/shape/data/in-house/fonts/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf b/test/shape/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf
rename to test/shape/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf b/test/shape/data/in-house/fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf
rename to test/shape/data/in-house/fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/e207635780b42f898d58654b65098763e340f5c7.ttf b/test/shape/data/in-house/fonts/e207635780b42f898d58654b65098763e340f5c7.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/e207635780b42f898d58654b65098763e340f5c7.ttf
rename to test/shape/data/in-house/fonts/e207635780b42f898d58654b65098763e340f5c7.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf b/test/shape/data/in-house/fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf
new file mode 100644
index 0000000..b499ce0
--- /dev/null
+++ b/test/shape/data/in-house/fonts/e2b17207c4b7ad78d843e1b0c4d00b09398a1137.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf b/test/shape/data/in-house/fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf
rename to test/shape/data/in-house/fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/e5ff44940364c2247abed50bdda30d2ef5aedfe4.ttf b/test/shape/data/in-house/fonts/e5ff44940364c2247abed50bdda30d2ef5aedfe4.ttf
new file mode 100644
index 0000000..a7c569f
--- /dev/null
+++ b/test/shape/data/in-house/fonts/e5ff44940364c2247abed50bdda30d2ef5aedfe4.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/e6185e88b04432fbf373594d5971686bb7dd698d.ttf b/test/shape/data/in-house/fonts/e6185e88b04432fbf373594d5971686bb7dd698d.ttf
new file mode 100644
index 0000000..5234b06
--- /dev/null
+++ b/test/shape/data/in-house/fonts/e6185e88b04432fbf373594d5971686bb7dd698d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf b/test/shape/data/in-house/fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf
rename to test/shape/data/in-house/fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/e8691822f6a705e3e9fb48a0405c645b1a036590.ttf b/test/shape/data/in-house/fonts/e8691822f6a705e3e9fb48a0405c645b1a036590.ttf
new file mode 100644
index 0000000..7c3a5b1
--- /dev/null
+++ b/test/shape/data/in-house/fonts/e8691822f6a705e3e9fb48a0405c645b1a036590.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf b/test/shape/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf
rename to test/shape/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf b/test/shape/data/in-house/fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf
rename to test/shape/data/in-house/fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf b/test/shape/data/in-house/fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
rename to test/shape/data/in-house/fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf b/test/shape/data/in-house/fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf
rename to test/shape/data/in-house/fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf b/test/shape/data/in-house/fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf
rename to test/shape/data/in-house/fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf b/test/shape/data/in-house/fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf
rename to test/shape/data/in-house/fonts/f499fbc23865022234775c43503bba2e63978fe1.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf b/test/shape/data/in-house/fonts/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf
rename to test/shape/data/in-house/fonts/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf b/test/shape/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf
rename to test/shape/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf b/test/shape/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf
rename to test/shape/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf b/test/shape/data/in-house/fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf
rename to test/shape/data/in-house/fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf b/test/shape/data/in-house/fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf
rename to test/shape/data/in-house/fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf b/test/shape/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf
rename to test/shape/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf b/test/shape/data/in-house/fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf
rename to test/shape/data/in-house/fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf b/test/shape/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf
new file mode 100644
index 0000000..c867877
--- /dev/null
+++ b/test/shape/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf
Binary files differ
diff --git a/test/shape/data/in-house/fonts/fd07ea46e4d8368ada1776208c07fd596f727852.ttf b/test/shape/data/in-house/fonts/fd07ea46e4d8368ada1776208c07fd596f727852.ttf
new file mode 100644
index 0000000..21e2246
--- /dev/null
+++ b/test/shape/data/in-house/fonts/fd07ea46e4d8368ada1776208c07fd596f727852.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf b/test/shape/data/in-house/fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf
similarity index 100%
rename from test/shaping/data/in-house/fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf
rename to test/shape/data/in-house/fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf
Binary files differ
diff --git a/test/shape/data/in-house/meson.build b/test/shape/data/in-house/meson.build
new file mode 100644
index 0000000..70b1a1c
--- /dev/null
+++ b/test/shape/data/in-house/meson.build
@@ -0,0 +1,69 @@
+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-stch.tests',
+  'automatic-fractions.tests',
+  'cluster.tests',
+  'collections.tests',
+  'color-fonts.tests',
+  'context-matching.tests',
+  'cursive-positioning.tests',
+  'default-ignorables.tests',
+  'digits.tests',
+  'emoji.tests',
+  'emoji-clusters.tests',
+  'fallback-positioning.tests',
+  'hangul-jamo.tests',
+  'hyphens.tests',
+  'indic-consonant-with-stacker.tests',
+  'indic-decompose.tests',
+  'indic-init.tests',
+  'indic-joiner-candrabindu.tests',
+  'indic-joiners.tests',
+  'indic-old-spec.tests',
+  'indic-pref-blocking.tests',
+  'indic-script-extensions.tests',
+  'indic-special-cases.tests',
+  'indic-syllable.tests',
+  'indic-vowel-letter-spoofing.tests',
+  'item-context.tests',
+  'kern-format2.tests',
+  'khmer-mark-order.tests',
+  'khmer-misc.tests',
+  'language-tags.tests',
+  'ligature-id.tests',
+  'macos.tests',
+  'mark-attachment.tests',
+  'mark-filtering-sets.tests',
+  'mongolian-variation-selector.tests',
+  'myanmar-misc.tests',
+  'myanmar-syllable.tests',
+  'myanmar-zawgyi.tests',
+  'none-directional.tests',
+  'positioning-features.tests',
+  'rand.tests',
+  'reverse-sub.tests',
+  'rotation.tests',
+  'simple.tests',
+  'sinhala.tests',
+  'spaces.tests',
+  'tibetan-contractions-1.tests',
+  'tibetan-contractions-2.tests',
+  'tibetan-vowels.tests',
+  'tt-kern-gpos.tests',
+  'use-indic3.tests',
+  'use-marchen.tests',
+  'use-syllable.tests',
+  'use-vowel-letter-spoofing.tests',
+  'use.tests',
+  'variations.tests',
+  'variations-rvrn.tests',
+  'vertical.tests',
+  'zero-width-marks.tests',
+]
diff --git a/test/shape/data/in-house/tests/aat-morx.tests b/test/shape/data/in-house/tests/aat-morx.tests
new file mode 100644
index 0000000..b1b5079
--- /dev/null
+++ b/test/shape/data/in-house/tests/aat-morx.tests
@@ -0,0 +1,2 @@
+../fonts/MORXTwentyeight.ttf;;U+0041,U+0078,U+0045,U+0079,U+0044,U+0079,U+0079;[A_E_D=0+1394|x=0+529|y=0+510|y=5+510|y=6+510]
+../fonts/e6185e88b04432fbf373594d5971686bb7dd698d.ttf;;U+0B95,U+0BCD,U+0020,U+0B9A,U+0BCD;[ka-tamil=0+825|pulli-tamil=0@-392,0+0|space=2+260|ca-tamil=3+723|pulli-tamil=3@-320,0+0]
diff --git a/test/shape/data/in-house/tests/aat-trak.tests b/test/shape/data/in-house/tests/aat-trak.tests
new file mode 100644
index 0000000..75c8704
--- /dev/null
+++ b/test/shape/data/in-house/tests/aat-trak.tests
@@ -0,0 +1,11 @@
+../fonts/TRAK.ttf;;U+0041,U+0042,U+0043;[A.alt=0+1000|B=1+1000|C.alt=2+1000]
+../fonts/TRAK.ttf;--font-ptem=.5;U+0041,U+0042,U+0043;[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TRAK.ttf;--font-ptem=1;U+0041,U+0042,U+0043;[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TRAK.ttf;--font-ptem=2;U+0041,U+0042,U+0043;[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TRAK.ttf;--font-ptem=9;U+0041,U+0042,U+0043;[A.alt=0@30,0+1060|B=1@30,0+1060|C.alt=2@30,0+1060]
+../fonts/TRAK.ttf;--font-ptem=24;U+0041,U+0042,U+0043;[A.alt=0@-7,0+986|B=1@-7,0+986|C.alt=2@-7,0+986]
+../fonts/TRAK.ttf;--font-ptem=72;U+0041,U+0042,U+0043;[A.alt=0@-35,0+929|B=1@-35,0+929|C.alt=2@-35,0+929]
+../fonts/TRAK.ttf;--font-ptem=144;U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
+../fonts/TRAK.ttf;--font-ptem=144;U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
+../fonts/TRAK.ttf;--font-ptem=144 --features=-trak;U+0041,U+0042,U+0043;[A.alt=0+1000|B=1+1000|C.alt=2+1000]
+../fonts/TRAK.ttf;--font-ptem=144 --features=-trak[1:3];U+0041,U+0042,U+0043,U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1+1000|C.alt=2+1000|A.alt=3@-78,0+843|B=4@-78,0+843|C.alt=5@-78,0+843]
diff --git a/test/shape/data/in-house/tests/arabic-fallback-shaping.tests b/test/shape/data/in-house/tests/arabic-fallback-shaping.tests
new file mode 100644
index 0000000..14f8919
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-fallback-shaping.tests
@@ -0,0 +1 @@
+../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]
diff --git a/test/shape/data/in-house/tests/arabic-feature-order.tests b/test/shape/data/in-house/tests/arabic-feature-order.tests
new file mode 100644
index 0000000..8d7a094
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-feature-order.tests
@@ -0,0 +1,4 @@
+../fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf;;U+1820,U+180B;[uni2048.E81A=0+1550]
+../fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf;;U+1820,U+180B;[uni2048.E81A=0+1550]
+../fonts/a919b33197965846f21074b24e30250d67277bce.ttf;;U+0644,U+0644,U+0647;[Lellah=0+1503]
+../fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf;;U+0644,U+064E,U+0670,U+0653,U+0626;[afii57414.zz04=4+1202|uni0670_uni0653=0@50,350+0|afii57454=0@550,1425+0|afii57444.calt=0+1065]
diff --git a/test/shape/data/in-house/tests/arabic-like-joining.tests b/test/shape/data/in-house/tests/arabic-like-joining.tests
new file mode 100644
index 0000000..9e69457
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-like-joining.tests
@@ -0,0 +1 @@
+../fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf;;U+1E922,U+1E923,U+1E924,U+1E925,U+1E926,U+1E927,U+1E928,U+1E929,U+1E92A,U+1E92B,U+1E92C,U+1E92D,U+1E92E,U+1E92F,U+1E930,U+1E931,U+1E932,U+1E933,U+1E934,U+1E935,U+1E936,U+1E937,U+1E938,U+1E939,U+1E93A,U+1E93B,U+1E93C,U+1E93D,U+1E93E,U+1E93F,U+1E940,U+1E941,U+1E942,U+1E943;[sha_adlam.fina=33+711|kpo_adlam.medi=32+573|zal_adlam.medi=31+773|gbe_adlam.medi=30+594|kha_adlam.medi=29+686|va_adlam.medi=28+621|nha_adlam.medi=27+587|tu_adlam.medi=26+772|nya_adlam.medi=25+577|ga_adlam.medi=24+552|qaaf_adlam.medi=23+694|ha_adlam.medi=22+600|chi_adlam.medi=21+662|jiim_adlam.medi=20+781|u_adlam.medi=19+678|ya_adlam.medi=18+553|kaf_adlam.medi=17+808|nun_adlam.medi=16+561|waw_adlam.medi=15+651|yhe_adlam.medi=14+674|dha_adlam.medi=13+674|o_adlam.medi=12+640|i_adlam.medi=11+657|fa_adlam.medi=10+590|e_adlam.medi=9+628|ra_adlam.medi=8+599|bhe_adlam.medi=7+594|pe_adlam.medi=6+492|sinnyiiyhe_adlam.medi=5+777|ba_adlam.medi=4+655|miim_adlam.medi=3+525|laam_adlam.medi=2+554|daali_adlam.medi=1+600|alif_adlam.init=0+597]
diff --git a/test/shape/data/in-house/tests/arabic-mark-attach.tests b/test/shape/data/in-house/tests/arabic-mark-attach.tests
new file mode 100644
index 0000000..906fbf6
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-mark-attach.tests
@@ -0,0 +1 @@
+../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-mark-order.tests b/test/shape/data/in-house/tests/arabic-mark-order.tests
new file mode 100644
index 0000000..c089eb3
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-mark-order.tests
@@ -0,0 +1,6 @@
+../fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf;;U+064A,U+064E,U+0670,U+0653,U+0640,U+0654,U+064E,U+0627;[afii57415.zz04=7+481|afii57454=4@25,975+0|uni0654=4@-50,50+0|afii57440=4+650|uni0670_uni0653=0@75,400+0|afii57454=0@750,1125+0|afii57450.calt=0+1331]
+../fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf;;U+0628,U+0618,U+0619,U+064E,U+064F,U+0654,U+0658,U+0653,U+0654,U+0651,U+0656,U+0651,U+065C,U+0655,U+0650;[uni0653.small=0@266,2508+0|uni0654=0@308,2151+0|uni0655=0@518,-1544+0|uni065C=0@501,-1453+0|uni0656=0@573,-659+0|uni0650=0@500,133+0|uni0619=0@300,1807+0|uni0618=0@357,1674+0|uni0651064E=0@387,1178+0|uni0651=0@402,764+0|uni0658=0@424,404+0|uni0654064F=0@540,-435+0|uni0628=0+1352]
+../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf;;U+0649,U+0655,U+034F,U+0650;[uni0650.small2=0@727,-774+0|space=0+0|uni0655=0@727,-209+0|uni0649=0+1566]
+../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf;;U+0649,U+0655,U+0650;[uni0650.small2=0@727,-774+0|uni0655=0@727,-209+0|uni0649=0+1566]
+../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf;;U+0649,U+0650,U+0655;[uni0650.small2=0@727,-774+0|uni0655=0@727,-209+0|uni0649=0+1566]
+../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf;;U+0649,U+0650,U+034F,U+0655;[uni0655=0+0|space=0+0|uni0650=0@166,0+0|uni0649=0+1566]
diff --git a/test/shape/data/in-house/tests/arabic-normalization.tests b/test/shape/data/in-house/tests/arabic-normalization.tests
new file mode 100644
index 0000000..35e3a65
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-normalization.tests
@@ -0,0 +1,64 @@
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0622;[uni0622=0+217]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0627,U+0653;[uni0622=0+217]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0622;[uni0622.fina=1+327|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0627,U+0653;[uni0622.fina=1+327|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0623;[uni0623=0+234]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0627,U+0654;[uni0623=0+234]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0623;[uni0623.fina=1+289|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0627,U+0654;[uni0623.fina=1+289|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0624;[uni0624=0+400]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0648,U+0654;[uni0624=0+400]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0624;[uni0624.fina=1+345|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0648,U+0654;[uni0624.fina=1+345|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0625;[uni0625=0+217]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0627,U+0655;[uni0625=0+217]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0625;[uni0625.fina=1+229|uni0628.init_Wide=0+285]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0627,U+0655;[uni0625.fina=1+229|uni0628.init_Wide=0+285]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0626;[uni0626=0+764]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+064A,U+0654;[uni0626=0+764]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0626,U+0626,U+0626;[uni0626.fina_BaaBaaYaa=2+457|uni0626.medi_BaaBaaYaa=1+357|uni0626.init_BaaBaaYaa=0+203]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+064A,U+0654,U+064A,U+0654,U+064A,U+0654;[uni0626.fina_BaaBaaYaa=4+457|uni0626.medi_BaaBaaYaa=2+357|uni0626.init_BaaBaaYaa=0+203]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06C0;[uni06C0=0+369]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06D5,U+0654;[uni06C0=0+369]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06C0;[hamza.above=1@195,73+0|uni06D5.fina=1+379|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06D5,U+0654;[hamza.above=1@195,73+0|uni06D5.fina=1+379|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06C2;[uni06C2=0+369]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06C1,U+0654;[uni06C2=0+369]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06C2;[hamza.above=1@171,-130+0|uni06C1.fina=1+408|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06C1,U+0654;[hamza.above=1@171,-130+0|uni06C1.fina=1+408|uni0628.init=0+190]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06D3;[uni06D3=0+1159]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+06D2,U+0654;[uni06D3=0+1159]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06D3;[uni06D2.fina_PostToothFina=1+312|uni0626.medi_YaaBari=1+205|uni0628.init_BaaBaaYaaBari=0+642]
+../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+06D2,U+0654;[uni06D2.fina_PostToothFina=1+312|uni0626.medi_YaaBari=1+205|uni0628.init_BaaBaaYaaBari=0+642]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0622;[MaddaNS=0@211,18+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0622;[MaddaNS=1@208,-13+0|AlefFin.narrow=1+239|OneDotBelowNS=0@73,-165+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0623;[HamzaAboveNS=0@211,57+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0623;[HamzaAboveNS=1@208,26+0|AlefFin.narrow=1+239|OneDotBelowNS=0@73,-165+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0624;[HamzaAboveNS=0@216,-309+0|WawSep=0+422]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0624;[HamzaAboveNS=1@191,-309+0|WawFin.inD2=1+371|OneDotBelowNS=0@108,-97+0|sp0=0+0|BehxIni.outD2WQ=0@0,323+158]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0625;[HamzaBelowNS=0@103,102+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0625;[HamzaBelowAltNS=1@116,-235+0|AlefFin.narrow=1+239|OneDotBelowAltNS=0@118,-77+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0626;[HamzaAboveNS=0@274,-374+0|YehxSep=0+860]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0626,U+0626,U+0626;[HamzaAboveNS=2@274,-375+0|YehxFin=2+520|HamzaAboveAltNS=1@65,-45+0|BehxMed.inT2outD2Y=1@0,379+294|HamzaAboveNS=0@101,-111+0|sp0=0+0|BehxIni.outT2=0@0,429+156]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06C0;[HamzaAboveNS=0@159,-266+0|HehSep=0+314]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06C0;[HamzaAboveNS=1@91,-587+0|HehFin=1+230|OneDotBelowNS=0@151,-188+0|sp0=0+0|BehxIni.outS1=0@0,-34+235]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06C2;[HamzaAboveNS=0@159,-266+0|HehSep=0+314]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06C2;[HamzaAboveNS=1@91,-587+0|HehFin=1+230|OneDotBelowNS=0@151,-188+0|sp0=0+0|BehxIni.outS1=0@0,-34+235]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06D3;[HamzaAboveNS=0@144,-395+0|YehBarreeSep=0+1409]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06D3;[HamzaAboveNS=1@118,-477+0|YehBarreeFin=1+355|OneDotBelowNS=0@116,-151+0|BehxIni.outD2YB=0@0,419+984]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0627,U+0653;[MaddaNS=0@211,18+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0627,U+0653;[MaddaNS=1@208,-13+0|AlefFin.narrow=1+239|OneDotBelowNS=0@73,-165+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0627,U+0654;[HamzaAboveNS=0@211,57+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0627,U+0654;[HamzaAboveNS=1@208,26+0|AlefFin.narrow=1+239|OneDotBelowNS=0@73,-165+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0648,U+0654;[HamzaAboveNS=0@216,-309+0|WawSep=0+422]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0648,U+0654;[HamzaAboveNS=1@191,-309+0|WawFin.inD2=1+371|OneDotBelowNS=0@108,-97+0|sp0=0+0|BehxIni.outD2WQ=0@0,323+158]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0627,U+0655;[HamzaBelowNS=0@103,102+0|AlefSep=0+330]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+0627,U+0655;[HamzaBelowAltNS=1@116,-235+0|AlefFin.narrow=1+239|OneDotBelowAltNS=0@118,-77+0|sp0=0+0|BehxIni.A=0+236]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+064A,U+0654;[HamzaAboveNS=0@274,-374+0|YehxSep=0+860]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+064A,U+0654,U+064A,U+0654,U+064A,U+0654;[HamzaAboveNS=4@274,-375+0|YehxFin=4+520|HamzaAboveAltNS=2@65,-45+0|BehxMed.inT2outD2Y=2@0,379+294|HamzaAboveNS=0@101,-111+0|sp0=0+0|BehxIni.outT2=0@0,429+156]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06D5,U+0654;[HamzaAboveNS=0@159,-266+0|HehSep=0+314]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06D5,U+0654;[HamzaAboveNS=1@91,-587+0|HehFin=1+230|OneDotBelowNS=0@151,-188+0|sp0=0+0|BehxIni.outS1=0@0,-34+235]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06C1,U+0654;[HamzaAboveNS=0@159,-266+0|HehSep=0+314]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06C1,U+0654;[HamzaAboveNS=1@91,-587+0|HehFin=1+230|OneDotBelowNS=0@151,-188+0|sp0=0+0|BehxIni.outS1=0@0,-34+235]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+06D2,U+0654;[HamzaAboveNS=0@144,-395+0|YehBarreeSep=0+1409]
+../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf;;U+0628,U+06D2,U+0654;[HamzaAboveNS=1@118,-477+0|YehBarreeFin=1+355|OneDotBelowNS=0@116,-151+0|BehxIni.outD2YB=0@0,419+984]
diff --git a/test/shape/data/in-house/tests/arabic-stch.tests b/test/shape/data/in-house/tests/arabic-stch.tests
new file mode 100644
index 0000000..491b242
--- /dev/null
+++ b/test/shape/data/in-house/tests/arabic-stch.tests
@@ -0,0 +1 @@
+../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]
diff --git a/test/shape/data/in-house/tests/automatic-fractions.tests b/test/shape/data/in-house/tests/automatic-fractions.tests
new file mode 100644
index 0000000..36f5796
--- /dev/null
+++ b/test/shape/data/in-house/tests/automatic-fractions.tests
@@ -0,0 +1,3 @@
+../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]
diff --git a/test/shape/data/in-house/tests/cluster.tests b/test/shape/data/in-house/tests/cluster.tests
new file mode 100644
index 0000000..2663e23
--- /dev/null
+++ b/test/shape/data/in-house/tests/cluster.tests
@@ -0,0 +1,4 @@
+../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf;--cluster-level=2;U+0078,U+030A,U+0058,U+030A;[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
+../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf;--cluster-level=1;U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD;[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338]
+../fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf;--cluster-level=1;U+099B,U+09CB,U+09C8,U+09C2,U+09CB,U+098C;[evowelsigninibeng=0+346|aivowelsignbeng=0+346|evowelsignbeng=0+346|chabeng=0+687|uuvowelsignlongbeng=0@-96,0+0|aavowelsignbeng=0+266|aavowelsignbeng=4+266|lvocalicbeng=5+639]
+../fonts/fd07ea46e4d8368ada1776208c07fd596f727852.ttf;--cluster-level=1;U+0D4E,U+0D4D,U+200D;[uni0D4E=0+0|uni25CC=0+418|uni0D4D=0+0|space=0+0]
diff --git a/test/shape/data/in-house/tests/collections.tests b/test/shape/data/in-house/tests/collections.tests
new file mode 100644
index 0000000..50d6d92
--- /dev/null
+++ b/test/shape/data/in-house/tests/collections.tests
@@ -0,0 +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/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]
diff --git a/test/shape/data/in-house/tests/color-fonts.tests b/test/shape/data/in-house/tests/color-fonts.tests
new file mode 100644
index 0000000..42636ed
--- /dev/null
+++ b/test/shape/data/in-house/tests/color-fonts.tests
@@ -0,0 +1,2 @@
+../fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf;--font-funcs=ot --show-extents;U+1F42F;[gid1=0+2963<0,2179,2963,-2789>]
+../fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf;--font-funcs=ot --show-extents;U+1F600;[gid4=0+2550<0,1898,2555,-2405>]
diff --git a/test/shape/data/in-house/tests/context-matching.tests b/test/shape/data/in-house/tests/context-matching.tests
new file mode 100644
index 0000000..ad71721
--- /dev/null
+++ b/test/shape/data/in-house/tests/context-matching.tests
@@ -0,0 +1,3 @@
+../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]
diff --git a/test/shape/data/in-house/tests/cursive-positioning.tests b/test/shape/data/in-house/tests/cursive-positioning.tests
new file mode 100644
index 0000000..aca4fba
--- /dev/null
+++ b/test/shape/data/in-house/tests/cursive-positioning.tests
@@ -0,0 +1,5 @@
+../fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf;;U+0643,U+0645,U+0645,U+062B,U+0644;[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+452|gid9=1@0,977+452|gid10=0@20,1577+207]
+../fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf;;U+0643,U+0645,U+0645,U+062B,U+0644;[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207]
+#../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]
diff --git a/test/shape/data/in-house/tests/default-ignorables.tests b/test/shape/data/in-house/tests/default-ignorables.tests
new file mode 100644
index 0000000..68659b2
--- /dev/null
+++ b/test/shape/data/in-house/tests/default-ignorables.tests
@@ -0,0 +1,5 @@
+../fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf;;U+0075,U+0361,U+034F,U+0301,U+0069;[gid2=0+1266|gid7=0@-617,442+0|gid5=0@-7,0+0|gid1=4+528]
+../fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf;;U+0020,U+06CC,U+064E,U+034F,U+0651;[uni0651=1+0|space=1+0|uni064E=1@236,-432+0|uni06CC=1+1266|space=0+452]
+../fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf;;U+0647,U+200D;[terminal=0+0|uni0647.init=0+702]
+../fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf;;U+0647,U+200D;[uni0647200D=0+702]
+../fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf;;U+0647,U+200D;[terminal=0+0|terminal=0+0|uni0647.init=0+702]
diff --git a/test/shape/data/in-house/tests/digits.tests b/test/shape/data/in-house/tests/digits.tests
new file mode 100644
index 0000000..e19ca62
--- /dev/null
+++ b/test/shape/data/in-house/tests/digits.tests
@@ -0,0 +1,5 @@
+../fonts/a6b17da98b9f1565ba428719777bbf94a66403c1.ttf;--direction=ltr --script=arab;U+06DD,U+0661,U+0662,U+0663;[uni06DD=0+1279|uni0661.small=1@-1079,0+0|uni0662.small=2@-786,0+0|uni0663.small=3@-493,0+0]
+../fonts/e5ff44940364c2247abed50bdda30d2ef5aedfe4.ttf;--direction=ltr --script=arab --features=pnum;U+0661,U+0662,U+0668,U+0663,U+0667;[uni0661.prop=0+361|uni0662.prop=1+436|uni0668.prop=2+478|uni0663.prop=3+597|uni0667.prop=4+527]
+../fonts/b082211be29a3e2cf91f0fd43497e40b2a27b344.ttf;--direction=ltr --script=arab;U+06DD,U+0661,U+0662,U+0628;[uni06DD=0+1279|uni0661=1+585|uni0662=2+585|uni0628=3+926]
+../fonts/3b791518a9ba89675df02f1eefbc9026a50648a6.ttf;--direction=ltr --script=arab;U+06DD,U+0661,U+0662,U+0663;[AyahEnd.alt3=0+1724|OneArabic.encl=0@-1143,444+0|TwoArabic.encl=0@-864,444+0|ThreeArabic.encl=0@-584,444+0]
+../fonts/3b791518a9ba89675df02f1eefbc9026a50648a6.ttf;--direction=rtl --script=arab;U+06DD,U+0661,U+0662,U+0663;[ThreeArabic.encl=0@1140,444+0|TwoArabic.encl=0@860,444+0|OneArabic.encl=0@581,444+0|AyahEnd.alt3=0+1724]
diff --git a/test/shape/data/in-house/tests/emoji-clusters.tests b/test/shape/data/in-house/tests/emoji-clusters.tests
new file mode 100644
index 0000000..be6a4e1
--- /dev/null
+++ b/test/shape/data/in-house/tests/emoji-clusters.tests
@@ -0,0 +1,3261 @@
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;263A,FE0F;[1=0|1=0]
+../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;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;2763,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2764,FE0F,200D,1F525;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2764,200D,1F525;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2764,FE0F,200D,1FA79;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2764,200D,1FA79;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2764,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F573,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F441,FE0F,200D,1F5E8,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F441,200D,1F5E8,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F441,FE0F,200D,1F5E8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F441,200D,1F5E8;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5E8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5EF,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44B,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44B,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44B,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44B,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44B,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91A,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91A,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91A,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91A,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91A,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F590,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270B,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270B,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270B,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270B,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270B,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F596,1F3FC;[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;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;1F44C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90C,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90C,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90F,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90F,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90F,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90F,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F90F,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91E,1F3FC;[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;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;1F91F,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91F,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F918,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F918,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F918,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F918,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F918,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F919,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F919,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F919,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F919,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F919,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F448,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F448,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F448,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F448,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F448,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F449,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F449,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F449,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F449,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F449,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F446,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F446,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F446,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F446,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F446,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F595,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F595,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F595,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F595,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F595,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F447,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F447,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F447,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F447,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F447,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;261D,1F3FC;[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;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;1F44D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44E,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44E,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44E,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44E,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270A,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270A,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270A,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270A,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270A,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44A,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44A,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44A,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44A,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44A,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91B,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91B,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91B,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91B,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91B,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91C,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91C,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F91C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44F,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44F,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44F,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44F,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F44F,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64C,1F3FC;[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;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;1F450,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F450,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F932,1F3FC;[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;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;1F64F,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64F,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F485,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F485,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F485,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F485,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F485,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F933,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F933,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F933,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F933,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F933,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4AA,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4AA,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4AA,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4AA,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4AA,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B5,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B6,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B6,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B6,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B6,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B6,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F442,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F442,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F442,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F442,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F442,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9BB,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9BB,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9BB,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9BB,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9BB,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F443,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F443,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F443,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F443,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F443,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F441,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F476,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F476,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F476,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F476,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F476,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D2,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D2,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D2,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D2,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D2,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F466,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F466,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F466,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F466,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F466,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F467,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F467,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F467,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F467,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F467,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D4,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;1F9D4,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9B0;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9B1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9B3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F9B2;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9B0;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9B0;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9B0;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9B1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9B1;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9B1;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9B3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9B3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9B3;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F9B2;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F9B2;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F9B2;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,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;1F471,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F471,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F474,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F474,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F474,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F474,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F474,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F475,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F475,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F475,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F475,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F475,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64D,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;1F64D,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64E,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;1F64E,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F645,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;1F645,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F646,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;1F646,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F481,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;1F481,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F64B,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;1F64B,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CF,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;1F9CF,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F647,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;1F647,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F926,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;1F926,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F937,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;1F937,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2695,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2695;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2695,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2695;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2695,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2695;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2695,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2695;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F393;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F393;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F393;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F393;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F3EB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F3EB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F3EB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F3EB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2696,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2696;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2696,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2696;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2696,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2696;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2696,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2696;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F33E;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F33E;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F33E;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F33E;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F373;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F373;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F373;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F373;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F527;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F527;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F527;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F527;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F3ED;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F3ED;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F3ED;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F3ED;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F4BC;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F4BC;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F4BC;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F4BC;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F52C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F52C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F52C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F52C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F4BB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F4BB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F4BB;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F4BB;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F3A4;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F3A4;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F3A4;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F3A4;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F3A8;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F3A8;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F3A8;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F3A8;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2708,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,2708;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2708,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,2708;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2708,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,2708;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2708,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,2708;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F680;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F680;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F680;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F680;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F692;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F692;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F692;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F692;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46E,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;1F46E,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,FE0F,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,FE0F,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,FE0F,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,FE0F,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F575,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;1F575,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F482,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;1F482,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F977,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F977,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F977,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F977,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F977,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FF,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FB,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,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FC,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,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FD,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,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F477,1F3FE,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,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;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;1F934,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F934,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F478,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F478,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F478,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F478,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F478,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F473,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;1F473,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F472,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F472,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F472,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F472,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F472,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D5,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F935,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;1F935,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F470,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;1F470,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F930,1F3FC;[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;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;1F931,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F931,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F37C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FF,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F37C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FF,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F37C;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F37C;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F47C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F47C,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F47C,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F47C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F47C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F385,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F385,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F385,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F385,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F385,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F936,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F936,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F936,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F936,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F936,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F384;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F384;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FC,200D,1F384;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FD,200D,1F384;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FE,200D,1F384;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FF,200D,1F384;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B8,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;1F9B8,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9B9,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;1F9B9,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D9,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;1F9D9,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DA,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;1F9DA,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DB,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;1F9DB,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DC,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;1F9DC,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DD,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;1F9DD,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DE,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DE,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DE,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DE,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DF,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DF,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DF,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9DF,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F486,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;1F486,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F487,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;1F487,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FF,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FB,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,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FC,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,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FD,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,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B6,1F3FE,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,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;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;1F9CD,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CD,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;1F9CD,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FF,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FB,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,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FC,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,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FD,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,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9CE,1F3FE,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,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;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;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;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;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;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;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;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;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;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;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;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FF,200D,2642,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,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FB,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,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FC,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,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FD,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,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C3,1F3FE,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,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;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;1F483,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F483,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F57A,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F57A,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F57A,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F57A,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F57A,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F574,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46F,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46F,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46F,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46F,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D6,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;1F9D6,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D7,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;1F9D7,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C7,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C7,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C7,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C7,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C7,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F7,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C2,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C2,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C2,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C2,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C2,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,FE0F,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,FE0F,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,FE0F,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,FE0F,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CC,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;1F3CC,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3C4,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;1F3C4,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6A3,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;1F6A3,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CA,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;1F3CA,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,FE0F,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,FE0F,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,FE0F,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,FE0F,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F9,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;26F9,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,FE0F,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,FE0F,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,FE0F,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,FE0F,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CB,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;1F3CB,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B4,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;1F6B4,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6B5,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;1F6B5,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F938,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;1F938,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93C,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93C,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93C,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93C,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93D,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;1F93D,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F93E,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;1F93E,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F939,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;1F939,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,200D,2642,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,200D,2642;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FB,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FB,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FC,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FC,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FD,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FD,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FE,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FE,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FF,200D,2642,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FF,200D,2642;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,200D,2640,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,200D,2640;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FB,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FB,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FC,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FC,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FD,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FD,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FE,200D,2640,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,1F3FE,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D8,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;1F9D8,1F3FF,200D,2640;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6C0,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6C0,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6C0,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6C0,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6C0,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CC,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CC,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CC,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CC,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CC,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,200D,1F91D,200D,1F9D1;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,1F91D,200D,1F9D1,1F3FB;[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,1F91D,200D,1F9D1,1F3FC;[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,1F91D,200D,1F9D1,1F3FD;[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,1F91D,200D,1F9D1,1F3FE;[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,1F91D,200D,1F9D1,1F3FF;[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,1F91D,200D,1F9D1,1F3FB;[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,1F91D,200D,1F9D1,1F3FC;[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,1F91D,200D,1F9D1,1F3FD;[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,1F91D,200D,1F9D1,1F3FE;[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,1F91D,200D,1F9D1,1F3FF;[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,1F91D,200D,1F9D1,1F3FB;[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,1F91D,200D,1F9D1,1F3FC;[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,1F91D,200D,1F9D1,1F3FD;[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,1F91D,200D,1F9D1,1F3FE;[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,1F91D,200D,1F9D1,1F3FF;[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,1F91D,200D,1F9D1,1F3FB;[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,1F91D,200D,1F9D1,1F3FC;[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,1F91D,200D,1F9D1,1F3FD;[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,1F91D,200D,1F9D1,1F3FE;[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,1F91D,200D,1F9D1,1F3FF;[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,1F91D,200D,1F9D1,1F3FB;[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,1F91D,200D,1F9D1,1F3FC;[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,1F91D,200D,1F9D1,1F3FD;[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,1F91D,200D,1F9D1,1F3FE;[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,1F91D,200D,1F9D1,1F3FF;[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;1F46D,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F91D,200D,1F469,1F3FC;[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,1F91D,200D,1F469,1F3FD;[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,1F91D,200D,1F469,1F3FE;[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,1F91D,200D,1F469,1F3FF;[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,1F91D,200D,1F469,1F3FB;[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;1F46D,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F91D,200D,1F469,1F3FD;[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,1F91D,200D,1F469,1F3FE;[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,1F91D,200D,1F469,1F3FF;[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,1F91D,200D,1F469,1F3FB;[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,1F91D,200D,1F469,1F3FC;[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;1F46D,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F91D,200D,1F469,1F3FE;[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,1F91D,200D,1F469,1F3FF;[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,1F91D,200D,1F469,1F3FB;[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,1F91D,200D,1F469,1F3FC;[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,1F91D,200D,1F469,1F3FD;[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;1F46D,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F91D,200D,1F469,1F3FF;[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,1F91D,200D,1F469,1F3FB;[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,1F91D,200D,1F469,1F3FC;[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,1F91D,200D,1F469,1F3FD;[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,1F91D,200D,1F469,1F3FE;[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;1F46D,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46B,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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;1F46B,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FC,200D,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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;1F46B,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FD,200D,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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;1F46B,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FE,200D,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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;1F46B,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F46C,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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;1F46C,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FC,200D,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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;1F46C,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FD,200D,1F91D,200D,1F468,1F3FE;[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,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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;1F46C,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FE,200D,1F91D,200D,1F468,1F3FF;[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,1F91D,200D,1F468,1F3FB;[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,1F91D,200D,1F468,1F3FC;[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,1F91D,200D,1F468,1F3FD;[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,1F91D,200D,1F468,1F3FE;[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;1F46C,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F48F,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F48F,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F48F,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F48F,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F48F,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FC;[1=0|1=0|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;1F9D1,1F3FB,200D,2764,200D,1F48B,200D,1F9D1,1F3FC;[1=0|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;1F9D1,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FD;[1=0|1=0|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;1F9D1,1F3FB,200D,2764,200D,1F48B,200D,1F9D1,1F3FD;[1=0|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;1F9D1,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FE;[1=0|1=0|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;1F9D1,1F3FB,200D,2764,200D,1F48B,200D,1F9D1,1F3FE;[1=0|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;1F9D1,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FF;[1=0|1=0|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;1F9D1,1F3FB,200D,2764,200D,1F48B,200D,1F9D1,1F3FF;[1=0|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;1F9D1,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FB;[1=0|1=0|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;1F9D1,1F3FC,200D,2764,200D,1F48B,200D,1F9D1,1F3FB;[1=0|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;1F9D1,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FD;[1=0|1=0|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;1F9D1,1F3FC,200D,2764,200D,1F48B,200D,1F9D1,1F3FD;[1=0|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;1F9D1,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FE;[1=0|1=0|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;1F9D1,1F3FC,200D,2764,200D,1F48B,200D,1F9D1,1F3FE;[1=0|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;1F9D1,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FF;[1=0|1=0|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;1F9D1,1F3FC,200D,2764,200D,1F48B,200D,1F9D1,1F3FF;[1=0|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;1F9D1,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FB;[1=0|1=0|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;1F9D1,1F3FD,200D,2764,200D,1F48B,200D,1F9D1,1F3FB;[1=0|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;1F9D1,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FC;[1=0|1=0|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;1F9D1,1F3FD,200D,2764,200D,1F48B,200D,1F9D1,1F3FC;[1=0|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;1F9D1,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FE;[1=0|1=0|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;1F9D1,1F3FD,200D,2764,200D,1F48B,200D,1F9D1,1F3FE;[1=0|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;1F9D1,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FF;[1=0|1=0|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;1F9D1,1F3FD,200D,2764,200D,1F48B,200D,1F9D1,1F3FF;[1=0|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;1F9D1,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FB;[1=0|1=0|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;1F9D1,1F3FE,200D,2764,200D,1F48B,200D,1F9D1,1F3FB;[1=0|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;1F9D1,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FC;[1=0|1=0|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;1F9D1,1F3FE,200D,2764,200D,1F48B,200D,1F9D1,1F3FC;[1=0|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;1F9D1,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FD;[1=0|1=0|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;1F9D1,1F3FE,200D,2764,200D,1F48B,200D,1F9D1,1F3FD;[1=0|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;1F9D1,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FF;[1=0|1=0|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;1F9D1,1F3FE,200D,2764,200D,1F48B,200D,1F9D1,1F3FF;[1=0|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;1F9D1,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FB;[1=0|1=0|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;1F9D1,1F3FF,200D,2764,200D,1F48B,200D,1F9D1,1F3FB;[1=0|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;1F9D1,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FC;[1=0|1=0|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;1F9D1,1F3FF,200D,2764,200D,1F48B,200D,1F9D1,1F3FC;[1=0|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;1F9D1,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FD;[1=0|1=0|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;1F9D1,1F3FF,200D,2764,200D,1F48B,200D,1F9D1,1F3FD;[1=0|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;1F9D1,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F9D1,1F3FE;[1=0|1=0|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;1F9D1,1F3FF,200D,2764,200D,1F48B,200D,1F9D1,1F3FE;[1=0|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;1F469,200D,2764,FE0F,200D,1F48B,200D,1F468;[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;1F469,200D,2764,200D,1F48B,200D,1F468;[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,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F468,200D,2764,FE0F,200D,1F48B,200D,1F468;[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;1F468,200D,2764,200D,1F48B,200D,1F468;[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,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F468,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F468,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F468,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F468,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F468,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F468,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F468,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F468,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F468,1F3FB,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F468,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F468,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F468,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F468,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F468,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F468,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F468,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F468,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F468,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F468,1F3FC,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F468,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F468,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F468,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F468,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F468,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F468,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F468,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F468,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F468,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F468,1F3FD,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F468,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F468,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F468,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F468,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F468,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F468,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F468,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F468,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F468,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F468,1F3FE,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F468,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FB;[1=0|1=0|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;1F468,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FB;[1=0|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;1F468,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FC;[1=0|1=0|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;1F468,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FC;[1=0|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;1F468,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FD;[1=0|1=0|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;1F468,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FD;[1=0|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;1F468,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FE;[1=0|1=0|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;1F468,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FE;[1=0|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;1F468,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F468,1F3FF;[1=0|1=0|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;1F468,1F3FF,200D,2764,200D,1F48B,200D,1F468,1F3FF;[1=0|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;1F469,200D,2764,FE0F,200D,1F48B,200D,1F469;[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;1F469,200D,2764,200D,1F48B,200D,1F469;[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,2764,FE0F,200D,1F48B,200D,1F469,1F3FB;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F469,1F3FB;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FC;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F469,1F3FC;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FD;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F469,1F3FD;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FE;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F469,1F3FE;[1=0|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;1F469,1F3FB,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FF;[1=0|1=0|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;1F469,1F3FB,200D,2764,200D,1F48B,200D,1F469,1F3FF;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FB;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F469,1F3FB;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FC;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F469,1F3FC;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FD;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F469,1F3FD;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FE;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F469,1F3FE;[1=0|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;1F469,1F3FC,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FF;[1=0|1=0|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;1F469,1F3FC,200D,2764,200D,1F48B,200D,1F469,1F3FF;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FB;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F469,1F3FB;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FC;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F469,1F3FC;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FD;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F469,1F3FD;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FE;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F469,1F3FE;[1=0|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;1F469,1F3FD,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FF;[1=0|1=0|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;1F469,1F3FD,200D,2764,200D,1F48B,200D,1F469,1F3FF;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FB;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F469,1F3FB;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FC;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F469,1F3FC;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FD;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F469,1F3FD;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FE;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F469,1F3FE;[1=0|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;1F469,1F3FE,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FF;[1=0|1=0|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;1F469,1F3FE,200D,2764,200D,1F48B,200D,1F469,1F3FF;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FB;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F469,1F3FB;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FC;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F469,1F3FC;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FD;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F469,1F3FD;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FE;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F469,1F3FE;[1=0|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;1F469,1F3FF,200D,2764,FE0F,200D,1F48B,200D,1F469,1F3FF;[1=0|1=0|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;1F469,1F3FF,200D,2764,200D,1F48B,200D,1F469,1F3FF;[1=0|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;1F491,1F3FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F491,1F3FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F491,1F3FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F491,1F3FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F491,1F3FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F9D1,1F3FB,200D,2764,FE0F,200D,1F9D1,1F3FC;[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;1F9D1,1F3FB,200D,2764,200D,1F9D1,1F3FC;[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,2764,FE0F,200D,1F9D1,1F3FD;[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;1F9D1,1F3FB,200D,2764,200D,1F9D1,1F3FD;[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,2764,FE0F,200D,1F9D1,1F3FE;[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;1F9D1,1F3FB,200D,2764,200D,1F9D1,1F3FE;[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,2764,FE0F,200D,1F9D1,1F3FF;[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;1F9D1,1F3FB,200D,2764,200D,1F9D1,1F3FF;[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,2764,FE0F,200D,1F9D1,1F3FB;[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;1F9D1,1F3FC,200D,2764,200D,1F9D1,1F3FB;[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,2764,FE0F,200D,1F9D1,1F3FD;[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;1F9D1,1F3FC,200D,2764,200D,1F9D1,1F3FD;[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,2764,FE0F,200D,1F9D1,1F3FE;[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;1F9D1,1F3FC,200D,2764,200D,1F9D1,1F3FE;[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,2764,FE0F,200D,1F9D1,1F3FF;[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;1F9D1,1F3FC,200D,2764,200D,1F9D1,1F3FF;[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,2764,FE0F,200D,1F9D1,1F3FB;[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;1F9D1,1F3FD,200D,2764,200D,1F9D1,1F3FB;[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,2764,FE0F,200D,1F9D1,1F3FC;[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;1F9D1,1F3FD,200D,2764,200D,1F9D1,1F3FC;[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,2764,FE0F,200D,1F9D1,1F3FE;[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;1F9D1,1F3FD,200D,2764,200D,1F9D1,1F3FE;[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,2764,FE0F,200D,1F9D1,1F3FF;[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;1F9D1,1F3FD,200D,2764,200D,1F9D1,1F3FF;[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,2764,FE0F,200D,1F9D1,1F3FB;[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;1F9D1,1F3FE,200D,2764,200D,1F9D1,1F3FB;[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,2764,FE0F,200D,1F9D1,1F3FC;[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;1F9D1,1F3FE,200D,2764,200D,1F9D1,1F3FC;[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,2764,FE0F,200D,1F9D1,1F3FD;[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;1F9D1,1F3FE,200D,2764,200D,1F9D1,1F3FD;[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,2764,FE0F,200D,1F9D1,1F3FF;[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;1F9D1,1F3FE,200D,2764,200D,1F9D1,1F3FF;[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,2764,FE0F,200D,1F9D1,1F3FB;[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;1F9D1,1F3FF,200D,2764,200D,1F9D1,1F3FB;[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,2764,FE0F,200D,1F9D1,1F3FC;[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;1F9D1,1F3FF,200D,2764,200D,1F9D1,1F3FC;[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,2764,FE0F,200D,1F9D1,1F3FD;[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;1F9D1,1F3FF,200D,2764,200D,1F9D1,1F3FD;[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,2764,FE0F,200D,1F9D1,1F3FE;[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;1F9D1,1F3FF,200D,2764,200D,1F9D1,1F3FE;[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,200D,2764,FE0F,200D,1F468;[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,2764,200D,1F468;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2764,FE0F,200D,1F468,1F3FB;[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;1F469,1F3FB,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F469,1F3FB,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F469,1F3FB,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F469,1F3FB,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F469,1F3FB,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F469,1F3FC,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F469,1F3FC,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F469,1F3FC,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F469,1F3FC,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F469,1F3FC,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F469,1F3FD,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F469,1F3FD,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F469,1F3FD,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F469,1F3FD,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F469,1F3FD,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F469,1F3FE,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F469,1F3FE,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F469,1F3FE,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F469,1F3FE,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F469,1F3FE,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F469,1F3FF,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F469,1F3FF,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F469,1F3FF,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F469,1F3FF,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F469,1F3FF,200D,2764,200D,1F468,1F3FF;[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,200D,2764,FE0F,200D,1F468;[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,2764,200D,1F468;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,1F3FB,200D,2764,FE0F,200D,1F468,1F3FB;[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;1F468,1F3FB,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F468,1F3FB,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F468,1F3FB,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F468,1F3FB,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F468,1F3FB,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F468,1F3FC,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F468,1F3FC,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F468,1F3FC,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F468,1F3FC,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F468,1F3FC,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F468,1F3FD,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F468,1F3FD,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F468,1F3FD,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F468,1F3FD,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F468,1F3FD,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F468,1F3FE,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F468,1F3FE,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F468,1F3FE,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F468,1F3FE,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F468,1F3FE,200D,2764,200D,1F468,1F3FF;[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,2764,FE0F,200D,1F468,1F3FB;[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;1F468,1F3FF,200D,2764,200D,1F468,1F3FB;[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,2764,FE0F,200D,1F468,1F3FC;[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;1F468,1F3FF,200D,2764,200D,1F468,1F3FC;[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,2764,FE0F,200D,1F468,1F3FD;[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;1F468,1F3FF,200D,2764,200D,1F468,1F3FD;[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,2764,FE0F,200D,1F468,1F3FE;[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;1F468,1F3FF,200D,2764,200D,1F468,1F3FE;[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,2764,FE0F,200D,1F468,1F3FF;[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;1F468,1F3FF,200D,2764,200D,1F468,1F3FF;[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,200D,2764,FE0F,200D,1F469;[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,2764,200D,1F469;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,1F3FB,200D,2764,FE0F,200D,1F469,1F3FB;[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;1F469,1F3FB,200D,2764,200D,1F469,1F3FB;[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,2764,FE0F,200D,1F469,1F3FC;[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;1F469,1F3FB,200D,2764,200D,1F469,1F3FC;[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,2764,FE0F,200D,1F469,1F3FD;[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;1F469,1F3FB,200D,2764,200D,1F469,1F3FD;[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,2764,FE0F,200D,1F469,1F3FE;[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;1F469,1F3FB,200D,2764,200D,1F469,1F3FE;[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,2764,FE0F,200D,1F469,1F3FF;[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;1F469,1F3FB,200D,2764,200D,1F469,1F3FF;[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,2764,FE0F,200D,1F469,1F3FB;[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;1F469,1F3FC,200D,2764,200D,1F469,1F3FB;[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,2764,FE0F,200D,1F469,1F3FC;[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;1F469,1F3FC,200D,2764,200D,1F469,1F3FC;[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,2764,FE0F,200D,1F469,1F3FD;[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;1F469,1F3FC,200D,2764,200D,1F469,1F3FD;[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,2764,FE0F,200D,1F469,1F3FE;[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;1F469,1F3FC,200D,2764,200D,1F469,1F3FE;[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,2764,FE0F,200D,1F469,1F3FF;[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;1F469,1F3FC,200D,2764,200D,1F469,1F3FF;[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,2764,FE0F,200D,1F469,1F3FB;[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;1F469,1F3FD,200D,2764,200D,1F469,1F3FB;[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,2764,FE0F,200D,1F469,1F3FC;[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;1F469,1F3FD,200D,2764,200D,1F469,1F3FC;[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,2764,FE0F,200D,1F469,1F3FD;[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;1F469,1F3FD,200D,2764,200D,1F469,1F3FD;[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,2764,FE0F,200D,1F469,1F3FE;[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;1F469,1F3FD,200D,2764,200D,1F469,1F3FE;[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,2764,FE0F,200D,1F469,1F3FF;[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;1F469,1F3FD,200D,2764,200D,1F469,1F3FF;[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,2764,FE0F,200D,1F469,1F3FB;[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;1F469,1F3FE,200D,2764,200D,1F469,1F3FB;[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,2764,FE0F,200D,1F469,1F3FC;[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;1F469,1F3FE,200D,2764,200D,1F469,1F3FC;[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,2764,FE0F,200D,1F469,1F3FD;[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;1F469,1F3FE,200D,2764,200D,1F469,1F3FD;[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,2764,FE0F,200D,1F469,1F3FE;[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;1F469,1F3FE,200D,2764,200D,1F469,1F3FE;[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,2764,FE0F,200D,1F469,1F3FF;[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;1F469,1F3FE,200D,2764,200D,1F469,1F3FF;[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,2764,FE0F,200D,1F469,1F3FB;[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;1F469,1F3FF,200D,2764,200D,1F469,1F3FB;[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,2764,FE0F,200D,1F469,1F3FC;[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;1F469,1F3FF,200D,2764,200D,1F469,1F3FC;[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,2764,FE0F,200D,1F469,1F3FD;[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;1F469,1F3FF,200D,2764,200D,1F469,1F3FD;[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,2764,FE0F,200D,1F469,1F3FE;[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;1F469,1F3FF,200D,2764,200D,1F469,1F3FE;[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,2764,FE0F,200D,1F469,1F3FF;[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;1F469,1F3FF,200D,2764,200D,1F469,1F3FF;[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,200D,1F469,200D,1F466;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F469,200D,1F467;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F469,200D,1F467,200D,1F466;[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,200D,1F469,200D,1F466,200D,1F466;[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,200D,1F469,200D,1F467,200D,1F467;[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,200D,1F468,200D,1F466;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F468,200D,1F467;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F468,200D,1F467,200D,1F466;[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,200D,1F468,200D,1F466,200D,1F466;[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,200D,1F468,200D,1F467,200D,1F467;[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,200D,1F469,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,1F469,200D,1F467;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F469,200D,1F467,200D,1F466;[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,200D,1F469,200D,1F466,200D,1F466;[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,200D,1F469,200D,1F467,200D,1F467;[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,200D,1F466;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F466,200D,1F466;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,200D,1F467;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F468,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;1F468,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;1F469,200D,1F466;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F469,200D,1F466,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;[1=0|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;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;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;1F336,FE0F;[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;26F0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D5,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D6,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DC,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DD,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DF,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DB,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D7,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3DA,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26E9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3D9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2668,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3CD,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E4,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6F3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F4,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E5,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2708,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6F0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23F1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23F2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F570,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F321,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2600,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2601,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26C8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F324,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F325,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F326,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F327,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F328,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F329,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F32A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F32B,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F32C,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2602,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2744,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2603,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2604,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F397,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F39F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F396,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26F8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F579,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2660,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2665,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2666,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2663,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;265F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5BC,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F576,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CD,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26D1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F399,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F39A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F39B,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;260E,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5A5,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5A8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2328,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5B1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5B2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F39E,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F4FD,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F56F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5DE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F7,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2709,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5F3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;270F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2712,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F58B,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F58A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F58C,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F58D,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5C2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5D2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5D3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F587,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2702,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5C3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5C4,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5D1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5DD,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26CF,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2692,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F5E1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2694,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6E1,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;[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]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F6CB,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26B0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26B1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26A0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2622,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2623,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2B06,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2197,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;27A1,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2198,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2B07,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2199,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2B05,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2196,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2195,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2194,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;21A9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;21AA,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2934,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2935,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;269B,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F549,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2721,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2638,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;262F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;271D,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2626,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;262A,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;262E,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25B6,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23ED,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23EF,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25C0,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23EE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23F8,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23F9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23FA,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;23CF,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2640,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2642,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;26A7,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2716,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;267E,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;203C,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2049,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;3030,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2695,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;267B,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;269C,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2611,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2714,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;303D,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2733,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2734,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2747,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;00A9,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;00AE,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2122,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0023,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0023,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;002A,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;002A,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0030,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0030,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0031,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0031,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0032,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0032,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0033,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0033,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0034,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0034,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0035,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0035,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0036,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0036,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0037,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0037,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0038,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0038,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0039,FE0F,20E3;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;0039,20E3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F170,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F171,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;2139,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;24C2,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F17E,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F17F,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F202,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F237,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;3297,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;3299,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25FC,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25FB,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25AA,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;25AB,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,FE0F;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,FE0F,200D,1F308;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,200D,1F308;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,FE0F,200D,26A7,FE0F;[1=0|1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,200D,26A7,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,FE0F,200D,26A7;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F3,200D,26A7;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F4,200D,2620,FE0F;[1=0|1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F4,200D,2620;[1=0|1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E6,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1E7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1EF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E7,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E8,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1EF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1E9,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EA,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1EF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EB,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1E7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EC,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1ED,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EE,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EF,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EF,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EF,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1EF,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F0,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1E7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F1,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F2,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1F5;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F3,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F4,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F5,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F6,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F7,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F7,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F7,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F7,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F7,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1E7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1EF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1FD;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F8,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1E9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1ED;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1EF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F1;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F4;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F7;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1FB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1F9,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1FE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FA,1F1FF;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1E8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1EC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1EE;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1F3;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FB,1F1FA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FC,1F1EB;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FC,1F1F8;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FD,1F1F0;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FE,1F1EA;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FE,1F1F9;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FF,1F1E6;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FF,1F1F2;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F1FF,1F1FC;[1=0|1=0]
+../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot;1F3F4,E0067,E0062,E0065,E006E,E0067,E007F;[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;1F3F4,E0067,E0062,E0073,E0063,E0074,E007F;[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;1F3F4,E0067,E0062,E0077,E006C,E0073,E007F;[1=0|1=0|1=0|1=0|1=0|1=0|1=0]
diff --git a/test/shape/data/in-house/tests/emoji.tests b/test/shape/data/in-house/tests/emoji.tests
new file mode 100644
index 0000000..557b65f
--- /dev/null
+++ b/test/shape/data/in-house/tests/emoji.tests
@@ -0,0 +1,5 @@
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf;;U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F;[u1F3F4=0+2126|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf;;U+1F3F4,U+E0064,U+E0065,U+E007F;[de=0+3200]
+../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf;--font-funcs=ot --direction=l;U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F;[gid7=0+2550]
+../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf;--font-funcs=ot --direction=r;U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F;[gid7=0+2550]
+../fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf;;U+1F3F4,U+E0067,U+E0062,U+E0077,U+E006C,U+E0073,U+E007F;[.notdef=0+1229|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
diff --git a/test/shape/data/in-house/tests/fallback-positioning.tests b/test/shape/data/in-house/tests/fallback-positioning.tests
new file mode 100644
index 0000000..4c52d53
--- /dev/null
+++ b/test/shape/data/in-house/tests/fallback-positioning.tests
@@ -0,0 +1,2 @@
+../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf;;U+0078,U+0301,U+0058,U+0301;[x=0+1030|acutecomb=0@-19,-27+0|X=2+1295|acutecomb=2@-151,320+0]
+../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf;;U+0061,U+035C,U+0062;[uni0061=0+512|uni035C=0@0,-128+0|uni0062=2+512]
diff --git a/test/shape/data/in-house/tests/hangul-jamo.tests b/test/shape/data/in-house/tests/hangul-jamo.tests
new file mode 100644
index 0000000..69b34a5
--- /dev/null
+++ b/test/shape/data/in-house/tests/hangul-jamo.tests
@@ -0,0 +1,2 @@
+../fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf;;U+115F,U+11A2;[gid3=0+920|gid4=0+0]
+../fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf;;U+11A2;[gid1=0+920]
diff --git a/test/shape/data/in-house/tests/hyphens.tests b/test/shape/data/in-house/tests/hyphens.tests
new file mode 100644
index 0000000..e2b255a
--- /dev/null
+++ b/test/shape/data/in-house/tests/hyphens.tests
@@ -0,0 +1,2 @@
+../fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf;;U+2010;[gid1=0+739]
+../fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf;;U+2011;[gid1=0+739]
diff --git a/test/shape/data/in-house/tests/indic-consonant-with-stacker.tests b/test/shape/data/in-house/tests/indic-consonant-with-stacker.tests
new file mode 100644
index 0000000..d6baca4
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-consonant-with-stacker.tests
@@ -0,0 +1,4 @@
+../fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf;--no-glyph-names;U+0CF1,U+0C95;[2=0+1129|3=1+358]
+../fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf;--no-glyph-names;U+0CF2,U+0CAA;[2=0+1539|3=1+245]
+../fonts/341421e629668b1a1242245d39238ca48432d35d.ttf;--no-glyph-names;U+0CF1;[1=0+1129]
+../fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf;--no-glyph-names;U+0CF2;[1=0+1539]
diff --git a/test/shape/data/in-house/tests/indic-decompose.tests b/test/shape/data/in-house/tests/indic-decompose.tests
new file mode 100644
index 0000000..132011f
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-decompose.tests
@@ -0,0 +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]
diff --git a/test/shape/data/in-house/tests/indic-init.tests b/test/shape/data/in-house/tests/indic-init.tests
new file mode 100644
index 0000000..8be43fb
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-init.tests
@@ -0,0 +1 @@
+../fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf;--no-glyph-names;U+09AC,U+09C7,U+09AC,U+09C7;[3=0+273|1=0+460|2=2+307|1=2+460]
diff --git a/test/shape/data/in-house/tests/indic-joiner-candrabindu.tests b/test/shape/data/in-house/tests/indic-joiner-candrabindu.tests
new file mode 100644
index 0000000..fcc24ad
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-joiner-candrabindu.tests
@@ -0,0 +1,2 @@
+../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf;;U+0B13,U+200D,U+0B01;[omorya=0+1450]
+../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf;;U+0B13,U+200C,U+0B01;[oorya=0+1309|space=1+0|candrabinduorya=1+0]
diff --git a/test/shape/data/in-house/tests/indic-joiners.tests b/test/shape/data/in-house/tests/indic-joiners.tests
new file mode 100644
index 0000000..047876b
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-joiners.tests
@@ -0,0 +1,6 @@
+../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf;;U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020;[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=4+0|uni17ca=4+0|uni17b8=4@0,300+0|space=7+600]
+../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf;;U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8;[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf;;U+091F,U+094D,U+200C,U+092F,U+093F;[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf;;U+091F,U+094D,U+200D,U+092F,U+093F;[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf;;U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F;[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf;;U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F;[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
diff --git a/test/shape/data/in-house/tests/indic-old-spec.tests b/test/shape/data/in-house/tests/indic-old-spec.tests
new file mode 100644
index 0000000..38a0054
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-old-spec.tests
@@ -0,0 +1,4 @@
+../fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf;;U+0C9A,U+0CCD,U+0C9A,U+0CCD;[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
+../fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf;;U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D;[glyph201=0+1183|U0D4D=0+0]
+../fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf;;U+091F,U+094D,U+0930,U+094D,U+0020;[Tra=0+550|virAma=0@-73,-110+0|space=4+500]
+../fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf;;U+091F,U+094D,U+0930,U+0942;[Tra=0+550|UT=0@42,-150+0]
diff --git a/test/shape/data/in-house/tests/indic-pref-blocking.tests b/test/shape/data/in-house/tests/indic-pref-blocking.tests
new file mode 100644
index 0000000..d477214
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-pref-blocking.tests
@@ -0,0 +1,2 @@
+../fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf;;U+0D2F,U+0D4D,U+0D30,U+0D46;[evowelsignmlym=0+1465|rapostmlym=0+499|yamlym=0+2120]
+../fonts/e207635780b42f898d58654b65098763e340f5c7.ttf;;U+0D2F,U+0D4D,U+0D30,U+0D46;[yamlym=0+2120|viramamlym=0+0|evowelsignmlym=0+1465|ramlym=0+1507]
diff --git a/test/shape/data/in-house/tests/indic-script-extensions.tests b/test/shape/data/in-house/tests/indic-script-extensions.tests
new file mode 100644
index 0000000..8e07eaa
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-script-extensions.tests
@@ -0,0 +1,2 @@
+../fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf;;U+0BA4,U+0BC6,U+1133C,U+0BAA,U+1133C,U+0BC6,U+1133C;[u0BC6=0+2093|u1133C=0+0|u0BA4=0+1863|u0BC6=3+2093|u1133C=3+0|u0BAA=3+1706|u1133C=3+0]
+../fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf;--no-glyph-names;U+0BAA,U+11301,U+11303;[1=0+535|2=0+0|3=0+310]
diff --git a/test/shape/data/in-house/tests/indic-special-cases.tests b/test/shape/data/in-house/tests/indic-special-cases.tests
new file mode 100644
index 0000000..8610658
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-special-cases.tests
@@ -0,0 +1,3 @@
+../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]
diff --git a/test/shape/data/in-house/tests/indic-syllable.tests b/test/shape/data/in-house/tests/indic-syllable.tests
new file mode 100644
index 0000000..275fb13
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-syllable.tests
@@ -0,0 +1,13 @@
+../fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf;;U+0BA4,U+0BCD,U+00B3;[taprehalftamil=0+1509|uni00B3=2+674]
+../fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf;;U+0CF1;[gid1=0+1129]
+../fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf;;U+0CF2;[gid2=0+1539]
+../fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf;--font-funcs=ot;U+0980,U+0981;[anjibeng=0+520|candrabindubeng=0+0]
+../fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf;;U+0A15,U+0A51,U+0A47;[kaguru=0+1273|udaatguru=0@75,0+0|eematraguru=0@-40,0+0]
+../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf;;U+0A51;[uni25CC=0+1044|udaatguru=0+0]
+../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf;;U+25CC,U+0A51;[uni25CC=0+1044|udaatguru=0+0]
+../fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf;--no-glyph-names;U+0C80,U+0C82;[1=0+502|2=0+502]
+../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf;;U+0A20,U+0A75,U+0A47;[tthaguru=0+1352|yakashguru=0@-90,0+0|eematraguru=0@-411,0+0]
+../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf;;U+0A20,U+0A75,U+0A42;[tthaguru=0+1352|yakashuuguru=0+0]
+../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]
diff --git a/test/shape/data/in-house/tests/indic-vowel-letter-spoofing.tests b/test/shape/data/in-house/tests/indic-vowel-letter-spoofing.tests
new file mode 100644
index 0000000..c53d4be
--- /dev/null
+++ b/test/shape/data/in-house/tests/indic-vowel-letter-spoofing.tests
@@ -0,0 +1,53 @@
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0904,U+0020,U+0905,U+0946;[ashortdeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|eshortvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0906,U+0020,U+0905,U+093E;[aadeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|aavowelsigndeva=2+259]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0908,U+0020,U+0930,U+094D,U+0907;[iideva=0+491|space=1+260|uni25CC=2+510|rephdeva=2+0|ideva=2+491]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+090A,U+0020,U+0909,U+0941;[uudeva=0+765|space=1+260|udeva=2+548|uni25CC=2+510|uvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+090D,U+0020,U+090F,U+0945;[ecandradeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|ecandravowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+090E,U+0020,U+090F,U+0946;[eshortdeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|eshortvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0910,U+0020,U+090F,U+0947;[aideva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|evowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0911,U+0020,U+0905,U+0949,U+0020,U+0906,U+0945;[ocandradeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ocandravowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|ecandravowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0912,U+0020,U+0905,U+094A,U+0020,U+0906,U+0946;[oshortdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|oshortvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|eshortvowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0913,U+0020,U+0905,U+094B,U+0020,U+0906,U+0947;[odeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ovowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|evowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0914,U+0020,U+0905,U+094C,U+0020,U+0906,U+0948;[audeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|auvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|aivowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0972,U+0020,U+0905,U+0945;[acandradeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|ecandravowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0973,U+0020,U+0905,U+093A;[oedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|oevowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0974,U+0020,U+0905,U+093B,U+0020,U+0906,U+093A;[ooedeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ooevowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|oevowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0975,U+0020,U+0905,U+094F;[awdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|awvowelsigndeva=2+259]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0976,U+0020,U+0905,U+0956;[uedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uevowelsigndeva=2@50,0+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf;;U+0977,U+0020,U+0905,U+0957;[uuedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uuevowelsigndeva=2@50,0+0]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf;;U+0986,U+0020,U+0985,U+09BE;[aabeng=0+1158|space=1+260|abeng=2+893|uni25CC=2+510|aavowelsignbeng=2+266]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf;;U+09E0,U+0020,U+098B,U+09C3;[rrvocalicbeng=0+853|space=1+260|rvocalicbeng=2+853|uni25CC=2+510|rvocalicvowelsignbeng=2+0]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf;;U+09E1,U+0020,U+098C,U+09E2;[llvocalicbeng=0+639|space=1+260|lvocalicbeng=2+639|uni25CC=2+510|lvocalicvowelsignbeng=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A06,U+0020,U+0A05,U+0A3E;[aaguru=0+2001|space=1+532|aguru=2+1520|uni25CC=2+1044|aamatraguru=2+481]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A07,U+0020,U+0A72,U+0A3F;[iguru=0+1671|space=1+532|iriguru=2+1141|imatraguru=2+530|uni25CC=2+1044]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A08,U+0020,U+0A72,U+0A40;[iiguru=0+1671|space=1+532|iriguru=2+1141|uni25CC=2+1044|iimatraguru=2+530]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A09,U+0020,U+0A73,U+0A41;[uguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|umatraguru=2@102,0+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A0A,U+0020,U+0A73,U+0A42;[uuguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|uumatraguru=2@102,0+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A0F,U+0020,U+0A72,U+0A47;[eeguru=0+1141|space=1+532|iriguru=2+1141|uni25CC=2+1044|eematraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A10,U+0020,U+0A05,U+0A48;[aiguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aimatraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A13,U+0020,U+0A73,U+0A4B;[ooguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|oomatraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf;;U+0A14,U+0020,U+0A05,U+0A4C;[auguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aumatraguru=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A86,U+0020,U+0A85,U+0ABE;[gid3=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid10=2+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A8D,U+0020,U+0A85,U+0AC5;[gid4=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid11=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A8F,U+0020,U+0A85,U+0AC7;[gid5=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid12=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A90,U+0020,U+0A85,U+0AC8;[gid6=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid13=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A91,U+0020,U+0A85,U+0AC9;[gid7=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid14=2+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A93,U+0020,U+0A85,U+0ACB,U+0020,U+0A85,U+0ABE,U+0AC5;[gid8=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid15=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid11=5+0|gid10=5+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0A94,U+0020,U+0A85,U+0ACC,U+0020,U+0A85,U+0ABE,U+0AC8;[gid9=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid16=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid13=5+0|gid10=5+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf;;U+0AC9,U+0020,U+0AC5,U+0ABE;[gid17=0+1044|gid14=0+543|gid1=1+612|gid17=1+1044|gid11=1+0|gid17=1+1044|gid10=1+543]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf;;U+0B06,U+0020,U+0B05,U+0B3E;[aaorya=0+1681|space=1+881|aorya=2+1284|uni25CC=2+1044|aavowelsignorya=2+387]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf;;U+0B10,U+0020,U+0B0F,U+0B57;[aiorya=0+1681|space=1+881|eorya=2+1315|uni25CC=2+1044|aulengthmarkorya=2+387]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf;;U+0B14,U+0020,U+0B13,U+0B57;[auorya=0+1679|space=1+881|oorya=2+1309|uni25CC=2+1044|aulengthmarkorya=2+387]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf;;U+0C13,U+0020,U+0C12,U+0C55;[gid3=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid12=2+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf;;U+0C14,U+0020,U+0C12,U+0C4C;[gid4=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid11=2+634]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf;;U+0C40,U+0020,U+0C3F,U+0C55;[gid13=0+1184|gid6=0+0|gid1=1+580|gid13=1+1184|gid5=1+0|gid13=1+1184|gid12=1+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf;;U+0C47,U+0020,U+0C46,U+0C55;[gid13=0+1184|gid8=0+0|gid1=1+580|gid13=1+1184|gid7=1+0|gid13=1+1184|gid12=1+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf;;U+0C4B,U+0020,U+0C4A,U+0C55;[gid13=0+1184|gid10=0+634|gid1=1+580|gid13=1+1184|gid9=1+634|gid13=1+1184|gid12=1+0]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf;;U+0C8A,U+0020,U+0C89,U+0CBE;[gid3=0+3269|gid1=1+590|gid2=2+2502|gid10=2+1184|gid7=2+919]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf;;U+0C94,U+0020,U+0C92,U+0CCC;[gid6=0+1596|gid1=1+590|gid5=2+1590|gid10=2+1184|gid8=2+880]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf;;U+0CE0,U+0020,U+0C8B,U+0CBE;[gid9=0+3214|gid1=1+590|gid4=2+2440|gid10=2+1184|gid7=2+919]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf;;U+0D08,U+0020,U+0D07,U+0D57;[gid3=0+3574|gid1=1+632|gid2=2+2019|gid14=2+1184|gid13=2+1555]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf;;U+0D0A,U+0020,U+0D09,U+0D57;[gid5=0+2972|gid1=1+632|gid4=2+1417|gid14=2+1184|gid13=2+1555]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf;;U+0D10,U+0020,U+0D0E,U+0D46;[gid7=0+4073|gid1=1+632|gid6=2+2608|gid12=2+1465|gid14=2+1184]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf;;U+0D13,U+0020,U+0D12,U+0D3E;[gid9=0+2557|gid1=1+632|gid8=2+1524|gid14=2+1184|gid11=2+1033]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf;;U+0D14,U+0020,U+0D12,U+0D57;[gid10=0+3073|gid1=1+632|gid8=2+1524|gid14=2+1184|gid13=2+1555]
diff --git a/test/shape/data/in-house/tests/item-context.tests b/test/shape/data/in-house/tests/item-context.tests
new file mode 100644
index 0000000..b9f1b1f
--- /dev/null
+++ b/test/shape/data/in-house/tests/item-context.tests
@@ -0,0 +1,11 @@
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=9+316|uni064E=7@169,-24+0|uniFEE8=7+341|uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643,U+0650;U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=7+316|uni064E=5@169,-24+0|uniFEE8=5+341|uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643;U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=7+316|uni064E=5@169,-24+0|uniFEE8=5+341|uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0646,U+064E,U+0627;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0646;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643,U+0650 --unicodes-after=U+0646,U+064E,U+0627;U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643 --unicodes-after=U+0646;U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0627;U+0643,U+062A,U+0628;[uniFE90=2+821|uniFE98=1+391|uniFEDB=0+576]
+../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0627;U+0643,U+062A,U+0628,U+0627;[uniFE8E=3+316|uniFE92=2+341|uniFE98=1+391|uniFEDB=0+576]
+../fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf;--bot;U+064E;[uni25CC=0+679|uni064E=0@-607,-210+0]
+../fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf;--bot --unicodes-before=0627;U+064E;[uni064E=0+0]
diff --git a/test/shape/data/in-house/tests/kern-format2.tests b/test/shape/data/in-house/tests/kern-format2.tests
new file mode 100644
index 0000000..ad85cd7
--- /dev/null
+++ b/test/shape/data/in-house/tests/kern-format2.tests
@@ -0,0 +1,3 @@
+../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf;;U+0061,U+0062,U+0063,U+0064,U+0065,U+0066,U+0067,U+0068,U+0069,U+006A,U+006B,U+006C,U+006D,U+006E,U+006F,U+0070;[a=0+626|b=1+672|c=2+564|d=3@-15,0+657|e=4+621|f=5+403|g=6@-10,0+662|h=7+666|i=8+316|j=9+316|k=10+591|l=11+316|m=12+1021|n=13+666|o=14+644|p=15+672]
+../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf;;U+0063,U+006B,U+0063,U+006B,U+0063,U+006B;[c=0+579|k=1+591|c=2+579|k=3+591|c=4+579|k=5+591]
+../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf;;U+0041,U+0056;[A=0+701|V=1@-40,0+703]
diff --git a/test/shape/data/in-house/tests/khmer-mark-order.tests b/test/shape/data/in-house/tests/khmer-mark-order.tests
new file mode 100644
index 0000000..6108265
--- /dev/null
+++ b/test/shape/data/in-house/tests/khmer-mark-order.tests
@@ -0,0 +1,25 @@
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17BE,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni1794=3+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17BE,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+1794;[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17BE,U+17BB,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+17BB,U+1794;[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17BE,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+1794;[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17BE,U+17BB,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+17BB,U+1794;[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17BE,U+17B8,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17B8,U+17BE,U+1794;[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17BE,U+17B8,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17C9,U+17B8,U+17BE,U+17BB,U+1794;[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17BE,U+17B8,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17B8,U+17BE,U+1794;[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17BE,U+17B8,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17CA,U+17B8,U+17BE,U+17BB,U+1794;[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17BE,U+17B8,U+17BB,U+1794;[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17BE,U+17BB,U+17B8,U+1794;[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17B8,U+17BE,U+17BB,U+1794;[uni179F=0+928|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf;;U+179F,U+17B8,U+17BB,U+17BE,U+1794;[uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
diff --git a/test/shape/data/in-house/tests/khmer-misc.tests b/test/shape/data/in-house/tests/khmer-misc.tests
new file mode 100644
index 0000000..dff4fc1
--- /dev/null
+++ b/test/shape/data/in-house/tests/khmer-misc.tests
@@ -0,0 +1,90 @@
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1781,U+17D2,U+1798,U+17C2;[uni17C2=0+288|uni1781=0+635|uni17D21798=0@22,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1787,U+17B6;[uni178717B6=0+923]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1790,U+17D2,U+1784,U+17C3;[uni17C3=0+288|uni1790=0+635|uni17D21784=0@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17B6;[uni179817B6=0+923]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17D2,U+1796,U+17BB;[uni1798=0+635|uni17D21796=0@-1,-26+0|uni17BB=0@-22,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179A;[uni179A=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179A,U+17B8;[uni179A=0+288|uni17B8.r=0@76,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179A,U+17CD;[uni179A=0+288|uni17CD.r=0@18,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17C5;[uni17C1=0+288|uni179F17C5=0+1216]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179A,U+17D2,U+17A5;[uni179A=0+288|uni17D2=0+0|uni17A5=2+635]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1784,U+17B9,U+17D2,U+1788;[uni1784=0+635|uni17B9=0@-46,30+0|uni17D21788=0+234]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1784,U+17D2,U+1788,U+17B9;[uni1784=0+635|uni17D21788=0+234|uni17B9=0@8,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1784,U+17D2,U+1782,U+17D2,U+179A;[uni17D2179A.low=0+287|uni1784=0+635|uni17D21782=0@0,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1784,U+17D2,U+179A,U+17D2,U+1782;[uni17D2179A.low=0+287|uni1784=0+635|uni17D21782=0@0,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17C9,U+17D2,U+179B,U+17C1,U+17C7;[uni17C1=0+288|uni1798=0+635|uni17C9=0@-46,-29+0|uni17D2179B=0@-1,-26+0|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+200C,U+17C9,U+17D2,U+179B,U+17C1,U+17C7;[uni17C1=0+288|uni1798=0+635|space=0+0|uni17C9=0@-46,-29+0|uni17D2179B=0@-1,-26+0|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1794,U+17CA,U+17D0;[uni1794=0+635|uni17CA=0@-46,-29+0|uni17D0=0@-46,113+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1793,U+17C2,U+17CE;[uni17C2=0+288|uni1793=0+635|uni17CE=0@-36,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17C1,U+17D2,U+179A;[uni17D2179A=0+287|uni17C1=0+288|uni1780=0+636]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17C0,U+17D2,U+179A;[uni17D2179A=0+287|uni17C1=0+288|uni1780=0+636|uni17C0.right1=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17C4,U+17D2,U+179A;[uni17D2179A=0+287|uni17C1=0+288|uni178017B6=0+924]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17C5,U+17D2,U+179A;[uni17D2179A=0+287|uni17C1=0+288|uni178017C5=0+924]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1796,U+17D1,U+17B6;[uni179617B6=0+923|uni17D1=0@-311,-19+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+1793,U+17D2,U+178F,U+17D2,U+179A,U+17B6,U+1780,U+17CB;[uni1780=0+636|uni17D2179A.low=1+287|uni179317B6=1+924|uni17D2178F=1@-290,-26+0|uni1780=7+636|uni17CB=7@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+1793,U+17D2,U+179A,U+17D2,U+179F,U+17B7,U+1780,U+17CB;[uni1780=0+636|uni17D2179A=1+287|uni1793=1+635|uni17D2179F=1+302|uni17B7=1@-4,30+0|uni1780=7+636|uni17CB=7@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+1793,U+17D2,U+179A,U+17D2,U+179F,U+17B8,U+1780,U+17CB;[uni1780=0+636|uni17D2179A=1+287|uni1793=1+635|uni17D2179F=1+302|uni17B8=1@-4,30+0|uni1780=7+636|uni17CB=7@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17B6,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F17B6=0+584|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17B7,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17B7=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17B8,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17B8=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17B9,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17B9=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17BA,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17BA=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17BB,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17BB=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17BC,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17BC=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17BD,U+1793,U+17D2,U+178F;[uni1780=0+636|uni17D2179F=0+302|uni17BD=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1780,U+17D2,U+179F,U+17BF,U+1793,U+17D2,U+178F;[uni17C1=0+288|uni1780=0+636|uni17D2179F=0+302|uni17BF.right2=0+288|uni1793=4+635|uni17D2178F=4@-1,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17B6,U+17C6;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F17B6.low=0+584|uni17C6=0@39,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17B7,U+17C7;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17B7=0@-4,30+0|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17BB,U+17C6;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17C6=0@-4,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17BB,U+17C7;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C1,U+17C7;[uni17C1=0+288|uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C4,U+17C7;[uni17C1=0+288|uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F17B6.low=0+584|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C6;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C6=0@-4,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C7;[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C7=0+386]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1789,U+17BC;[uni1789=0+952|uni17BC=0@-173,-260+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1789,U+17D2,U+1789;[uni1789.a=0+952|uni17D21789.a=0@19,-22+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1789,U+17D2,U+1789,U+17BB;[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BB=0@-160,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1789,U+17D2,U+1789,U+17BC;[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BC=0@-160,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1789,U+17D2,U+1789,U+17BD;[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BD=0@-160,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C0;[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302|uni17C0.right2=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C1;[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C2;[uni17C2=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C3;[uni17C3=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C4;[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F17B6=0+584]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C5;[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F17C5=0+584]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1792,U+17D2,U+179B,U+17BB,U+17C6,U+1780,U+17CB;[uni1792=0+635|uni17D2179B=0@-2,-26+0|uni17BB=0@-19,-296+0|uni17C6=0@-46,-29+0|uni1780=5+636|uni17CB=5@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1792,U+17D2,U+179B,U+17C4,U+1780,U+17CB;[uni17C1=0+288|uni179217B6=0+923|uni17D2179B=0@-290,-26+0|uni1780=4+636|uni17CB=4@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1792,U+17D2,U+179B,U+17C5,U+1780,U+17CB;[uni17C1=0+288|uni179217C5=0+923|uni17D2179B=0@-290,-26+0|uni1780=4+636|uni17CB=4@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1792,U+17D2,U+179B,U+17C6,U+1780,U+17CB;[uni1792=0+635|uni17D2179B=0@-2,-26+0|uni17C6=0@-46,-29+0|uni1780=4+636|uni17CB=4@-23,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17B6;[uni179817B6=0+923|uni17D2178F=0@-289,-26+0|uni17D2179B=0@-289,-296+0|uni17C9=0@-334,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17BB;[uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17BB=0@-18,-566+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17BF;[uni17C1=0+288|uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17BF.right1=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17C0;[uni17C1=0+288|uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17C0.right1=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+1799,U+17D2,U+1799,U+17BE,U+17A0,U+17D2,U+179C,U+17D2,U+179B,U+17C3;[uni17C1=0+288|uni1799=0+953|uni17D21799=0+298|uni17B8=0@1,30+0|uni17C3=4+288|uni17A0=4+928|uni17D2179C=4@20,-26+0|uni17D2179B=4@19,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179A,U+17D2,U+179A;[uni17D2179A=0+287|uni179A=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B6;[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni178417B6=10+923]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B7;[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni1784=10+635|uni17B7=10@-46,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B8;[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni1784=10+635|uni17B8=10@-46,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+178F,U+17D2,U+179A,U+17B8,U+179C,U+17D0,U+1781,U+17D2,U+1789,U+17D2,U+179F,U+17B6;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0|uni179C=6+326|uni17D0=6@139,40+0|uni1781=8+635|uni17D21789=8@-4,-26+0|uni17D2179F17B6.low=8+584]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B6;[uni17D2179A=0+287|uni179F17B6=0+1216|uni17D2178F=0@-274,-26+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B7;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B7=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B8;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B9;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B9=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BA;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BA=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BB;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BB=0@-6,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BC;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BC=0@-6,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BD;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BD=0@-6,-296+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BE;[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BF;[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BF.right2=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17BF;[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17BF.right1=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C0;[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17C0.right1.high=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C1;[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C2;[uni17C2=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C3;[uni17C3=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C6;[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17C6=0@-32,113+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17BE;[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17B8=0@-4,30+0]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17BF;[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17CA=0@-4,30+0|uni17BF.right1=0+288]
+../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf;;U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17C0;[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17CA=0@-4,30+0|uni17C0.right1.high=0+288]
+../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]
diff --git a/test/shape/data/in-house/tests/language-tags.tests b/test/shape/data/in-house/tests/language-tags.tests
new file mode 100644
index 0000000..9fb3faf
--- /dev/null
+++ b/test/shape/data/in-house/tests/language-tags.tests
@@ -0,0 +1,13 @@
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=fa;U+004A;[gid2=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=ja;U+004A;[gid2=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh;U+004A;[gid4=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-cn;U+004A;[gid4=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-sg;U+004A;[gid4=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-tw;U+004A;[gid5=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-hans;U+004A;[gid4=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-hant;U+004A;[gid5=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-hant-hk;U+004A;[gid6=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-HK;U+004A;[gid6=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-mo;U+004A;[gid6=0+1000]
+../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf;--language=zh-Hant-mo;U+004A;[gid6=0+1000]
+../fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf;--language=dv --no-glyph-names;U+007C;[2=0+156]
diff --git a/test/shape/data/in-house/tests/ligature-id.tests b/test/shape/data/in-house/tests/ligature-id.tests
new file mode 100644
index 0000000..5fd5825
--- /dev/null
+++ b/test/shape/data/in-house/tests/ligature-id.tests
@@ -0,0 +1,37 @@
+../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf;;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|space=3+213|u0995_u09B0_u09CD.blwf.vatu=4+643|u0995_u09CD.half_u09B2.pres=7+602]
+../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf;;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|space=6+213|u0995_u09B0_u09CD.blwf.vatu=7+643|u0995_u09CD.half_u09B2.pres=10+602]
+../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf;;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|space=9+213|u0995_u09B0_u09CD.blwf.vatu=10+643|u0995_u09CD.half_u09B2.pres=13+602]
+../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+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|space=12+213|u0995_u09B0_u09CD.blwf.vatu=13+643|u0995_u09CD.half_u09B2.pres=16+602]
+../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+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|space=15+213|u0995_u09B0_u09CD.blwf.vatu=16+643|u0995_u09CD.half_u09B2.pres=19+602]
+../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+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|space=18+213|u0995_u09B0_u09CD.blwf.vatu=19+643|u0995_u09CD.half_u09B2.pres=22+602]
+../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+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|space=21+213|u0995_u09B0_u09CD.blwf.vatu=22+643|u0995_u09CD.half_u09B2.pres=25+602]
+../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+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|space=24+213|u0995_u09B0_u09CD.blwf.vatu=25+643|u0995_u09CD.half_u09B2.pres=28+602]
+../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+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|space=27+213|u0995_u09B0_u09CD.blwf.vatu=28+643|u0995_u09CD.half_u09B2.pres=31+602]
+../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+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|space=30+213|u0995_u09B0_u09CD.blwf.vatu=31+643|u0995_u09CD.half_u09B2.pres=34+602]
+../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+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|space=33+213|u0995_u09B0_u09CD.blwf.vatu=34+643|u0995_u09CD.half_u09B2.pres=37+602]
+../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+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|space=36+213|u0995_u09B0_u09CD.blwf.vatu=37+643|u0995_u09CD.half_u09B2.pres=40+602]
+../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+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|space=39+213|u0995_u09B0_u09CD.blwf.vatu=40+643|u0995_u09CD.half_u09B2.pres=43+602]
+../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+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|space=42+213|u0995_u09B0_u09CD.blwf.vatu=43+643|u0995_u09CD.half_u09B2.pres=46+602]
+../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+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|space=45+213|u0995_u09B0_u09CD.blwf.vatu=46+643|u0995_u09CD.half_u09B2.pres=49+602]
+../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+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|space=48+213|u0995_u09B0_u09CD.blwf.vatu=49+643|u0995_u09CD.half_u09B2.pres=52+602]
+../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+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|space=51+213|u0995_u09B0_u09CD.blwf.vatu=52+643|u0995_u09CD.half_u09B2.pres=55+602]
+../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+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|space=54+213|u0995_u09B0_u09CD.blwf.vatu=55+643|u0995_u09CD.half_u09B2.pres=58+602]
+../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+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|space=57+213|u0995_u09B0_u09CD.blwf.vatu=58+643|u0995_u09CD.half_u09B2.pres=61+602]
+../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+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|space=60+213|u0995_u09B0_u09CD.blwf.vatu=61+643|u0995_u09CD.half_u09B2.pres=64+602]
+../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+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|space=63+213|u0995_u09B0_u09CD.blwf.vatu=64+643|u0995_u09CD.half_u09B2.pres=67+602]
+../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+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|space=66+213|u0995_u09B0_u09CD.blwf.vatu=67+643|u0995_u09CD.half_u09B2.pres=70+602]
+../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+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|space=69+213|u0995_u09B0_u09CD.blwf.vatu=70+643|u0995_u09CD.half_u09B2.pres=73+602]
+../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+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|space=72+213|u0995_u09B0_u09CD.blwf.vatu=73+643|u0995_u09CD.half_u09B2.pres=76+602]
+../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+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|space=75+213|u0995_u09B0_u09CD.blwf.vatu=76+643|u0995_u09CD.half_u09B2.pres=79+602]
+../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+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|space=78+213|u0995_u09B0_u09CD.blwf.vatu=79+643|u0995_u09CD.half_u09B2.pres=82+602]
+../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+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|space=81+213|u0995_u09B0_u09CD.blwf.vatu=82+643|u0995_u09CD.half_u09B2.pres=85+602]
+../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+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|space=84+213|u0995_u09B0_u09CD.blwf.vatu=85+643|u0995_u09CD.half_u09B2.pres=88+602]
+../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+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|space=87+213|u0995_u09B0_u09CD.blwf.vatu=88+643|u0995_u09CD.half_u09B2.pres=91+602]
+../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+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|space=90+213|u0995_u09B0_u09CD.blwf.vatu=91+643|u0995_u09CD.half_u09B2.pres=94+602]
+../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+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|space=93+213|u0995_u09B0_u09CD.blwf.vatu=94+643|u0995_u09CD.half_u09B2.pres=97+602]
+../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+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|space=96+213|u0995_u09B0_u09CD.blwf.vatu=97+643|u0995_u09CD.half_u09B2.pres=100+602]
+../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+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|space=99+213|u0995_u09B0_u09CD.blwf.vatu=100+643|u0995_u09CD.half_u09B2.pres=103+602]
+../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+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|space=102+213|u0995_u09B0_u09CD.blwf.vatu=103+643|u0995_u09CD.half_u09B2.pres=106+602]
+../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]
diff --git a/test/shape/data/in-house/tests/macos.tests b/test/shape/data/in-house/tests/macos.tests
new file mode 100644
index 0000000..7c7b806
--- /dev/null
+++ b/test/shape/data/in-house/tests/macos.tests
@@ -0,0 +1,140 @@
+# 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]
+
+# 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/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062;--font-funcs ot;U+006D,U+0300;[mgrave=0+1912]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39;--font-funcs ot;U+0066,U+0069;[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc@5f5b1072df99b7355d3066ea85fe82969d13c94a;--font-funcs ot;U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A;[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
+/Library/Fonts/Tamil MN.ttc@37a2020c3f86ebcc45e02c1de5fdf81e2676989d;--font-funcs ot;U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1;[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39;--font-funcs ot;U+0041,U+0066,U+0300,U+0066,U+0069,U+005A;[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062;--font-funcs ot;U+05E1,U+05B0;[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot;U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A;[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
+/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820;--font-funcs ot;U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820;--font-funcs ot;U+0628,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820;--font-funcs ot;U+0631,U+0628;[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
+/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820;--font-funcs ot;U+0628,U+064F;[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
+/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820;--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/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced;--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;[gid225=0+1105|gid584=1@-105,0+979|gid3=2+490|gid4=3+1227|gid265=4@-65,0+1227|gid3=5+490|gid225=6+1130|gid728=7@-80,0+569|gid3=8+490|gid265=9+1227|gid505=10@-65,0+997|gid3=11+490|gid728=12+609|gid225=13@-40,0+1170|gid3=14+490|gid584=15+1004|gid225=16@-80,0+1130|gid3=17+490|gid225=18+1105|gid576=19@-105,0+1068]
+/System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced;--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;[gid225=0@65,0+1235|gid584=1@-40,0+1109|gid3=2@65,0+620|gid4=3@65,0+1357|gid265=4+1357|gid3=5@65,0+620|gid225=6@65,0+1260|gid728=7@-15,0+699|gid3=8@65,0+620|gid265=9@65,0+1357|gid505=10+1127|gid3=11@65,0+620|gid728=12@65,0+739|gid225=13@25,0+1300|gid3=14@65,0+620|gid584=15@65,0+1134|gid225=16@-15,0+1260|gid3=17@65,0+620|gid225=18@65,0+1235|gid576=19@-40,0+1198]
+/System/Library/Fonts/Apple Color Emoji.ttc@d2fe8a134483aa48a43a9d1e4b7204d37a4abdf5;--remove-default-ignorables --font-funcs ot;U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466;[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@9ee799ffb09516ead6b0cf6f2ca807276e150748;--font-funcs ot;U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F;[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
+# https;//github.com/harfbuzz/harfbuzz/pull/2130
+/System/Library/Fonts/ヒラギノ明朝 ProN W3.ttc@e3bd65c7209ceab2c70ef22d3ebe0967ab319ed3;--font-funcs ot --direction=ttb;U+005B,U+0048,U+0065,U+006C,U+006C,U+006F,U+0034,U+005D;[gid60=0@-157,-880+0,-1000|gid41=1@-398,-880+0,-1000|gid70=2@-267,-880+0,-1000|gid77=3@-148,-880+0,-1000|gid77=4@-148,-880+0,-1000|gid80=5@-291,-880+0,-1000|gid21=6@-294,-880+0,-1000|gid62=7@-157,-880+0,-1000]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39;--font-funcs ot;U+0066,U+0069,U+006e,U+0065;[fi=0+1139|n=2+1024|e=3+909]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39;--font-funcs ot --features liga=0;U+0066,U+0069,U+006e,U+0065;[f=0+682|i=1+569|n=2+1024|e=3+909]
+/Library/Fonts/Kokonor.ttf@fe9d518bb4e20e77f7a0444c82f4d41467dd714d;--font-funcs ot;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Kokonor.ttf@fe9d518bb4e20e77f7a0444c82f4d41467dd714d;--font-funcs ot --features liga=0;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features liga=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features dlig=1,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features liga=0,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features smcp=1;U+0066,U+0069,U+0072,U+0073,U+0074;[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075]
+/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562;--font-funcs ot --features liga=0,dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s_t=3+1438]
+
+# 10.13.6 https;//gist.github.com/ebraminio/d432e831b3f7ebe30245dde5775e1c7e
+/System/Library/Fonts/Helvetica.ttc@8a928f9866299d2455f41360202b7a3b48503a5e;--font-funcs ot;U+006D,U+0300;[m=0+1706|gravecmb=0@-284,10+0]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269;--font-funcs ot;U+006D,U+0300;[mgrave=0+1912]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c;--font-funcs ot;U+0066,U+0069;[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc@782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c;--font-funcs ot;U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A;[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
+/Library/Fonts/Tamil MN.ttc@3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d;--font-funcs ot;U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1;[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c;--font-funcs ot;U+0041,U+0066,U+0300,U+0066,U+0069,U+005A;[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269;--font-funcs ot;U+05E1,U+05B0;[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A;[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/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/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa;--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;[gid282=0+1055|gid658=1@-135,0+914|gid3=2+420|gid4=3+1227|gid332=4@-65,0+1227|gid3=5+420|gid282=6+1075|gid813=7@-115,0+516|gid3=8+420|gid332=9+1217|gid572=10@-75,0+953|gid3=11+420|gid813=12+546|gid282=13@-85,0+1105|gid3=14+420|gid658=15+914|gid282=16@-135,0+1055|gid3=17+420|gid282=18+1055|gid649=19@-135,0+999]
+/System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa;--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;[gid282=0@65,0+1185|gid658=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid332=4+1357|gid3=5@65,0+550|gid282=6@65,0+1205|gid813=7@-50,0+646|gid3=8@65,0+550|gid332=9@65,0+1347|gid572=10@-10,0+1083|gid3=11@65,0+550|gid813=12@65,0+676|gid282=13@-20,0+1235|gid3=14@65,0+550|gid658=15@65,0+1044|gid282=16@-70,0+1185|gid3=17@65,0+550|gid282=18@65,0+1185|gid649=19@-70,0+1129]
+/System/Library/Fonts/Apple Color Emoji.ttc@2e09b1f3d42c3821cc6c4ac5b6ce16237ab0d496;--remove-default-ignorables --font-funcs ot;U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466;[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08;--font-funcs ot;U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F;[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
+/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897;--font-funcs ot;U+0E17,U+0E35,U+0E48,U+0E4A;[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c;--font-funcs ot;U+0066,U+0069,U+006e,U+0065;[fi=0+1139|n=2+1024|e=3+909]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c;--font-funcs ot --features liga=0;U+0066,U+0069,U+006e,U+0065;[f=0+682|i=1+569|n=2+1024|e=3+909]
+/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot --features liga=0;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features smcp=1;U+0066,U+0069,U+0072,U+0073,U+0074;[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s_t=3+1438]
+
+# 10.14.2 https;//gist.github.com/ebraminio/4b731a82f11a662b2164622ebb93086a
+/System/Library/Fonts/Helvetica.ttc@992d29a0fa4ed91773457c29b661e94843619cde;--font-funcs ot;U+006D,U+0300;[m=0+1706|gravecmb=0@-284,10+0]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269;--font-funcs ot;U+006D,U+0300;[mgrave=0+1912]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518;--font-funcs ot;U+0066,U+0069;[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc@37687fe0bd2548e08e29c92a30e476367ae6356b;--font-funcs ot;U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A;[km_qa=0+1230|km_ka=1+1230|km_sa.sub=1+620|km_ro=4+712|km_vs_ae=5+726|km_kha=5+1230|km_mo.sub=5+0|km_ro=9+712]
+/Library/Fonts/Tamil MN.ttc@e1df5e056be08937fd65990efbafff0814c03677;--font-funcs ot;U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1;[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518;--font-funcs ot;U+0041,U+0066,U+0300,U+0066,U+0069,U+005A;[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269;--font-funcs ot;U+05E1,U+05B0;[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A;[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/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/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9;--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;[gid283=0+1055|gid659=1@-135,0+914|gid3=2+420|gid4=3+1227|gid333=4@-65,0+1227|gid3=5+420|gid283=6+1075|gid815=7@-115,0+516|gid3=8+420|gid333=9+1217|gid573=10@-75,0+953|gid3=11+420|gid815=12+546|gid283=13@-85,0+1105|gid3=14+420|gid659=15+914|gid283=16@-135,0+1055|gid3=17+420|gid283=18+1055|gid650=19@-135,0+999]
+/System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9;--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;[gid283=0@65,0+1185|gid659=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid333=4+1357|gid3=5@65,0+550|gid283=6@65,0+1205|gid815=7@-50,0+646|gid3=8@65,0+550|gid333=9@65,0+1347|gid573=10@-10,0+1083|gid3=11@65,0+550|gid815=12@65,0+676|gid283=13@-20,0+1235|gid3=14@65,0+550|gid659=15@65,0+1044|gid283=16@-70,0+1185|gid3=17@65,0+550|gid283=18@65,0+1185|gid650=19@-70,0+1129]
+/System/Library/Fonts/Apple Color Emoji.ttc@60f77161021b1b87e99c3690e1a9b56341cf8792;--remove-default-ignorables --font-funcs ot;U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466;[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08;--font-funcs ot;U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F;[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
+/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897;--font-funcs ot;U+0E17,U+0E35,U+0E48,U+0E4A;[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518;--font-funcs ot;U+0066,U+0069,U+006e,U+0065;[fi=0+1139|n=2+1024|e=3+909]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518;--font-funcs ot --features liga=0;U+0066,U+0069,U+006e,U+0065;[f=0+682|i=1+569|n=2+1024|e=3+909]
+/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot --features liga=0;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features smcp=1;U+0066,U+0069,U+0072,U+0073,U+0074;[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s_t=3+1438]
+
+# 10.15 https;//gist.github.com/ebraminio/d52dd780fec59f8e2dfffe8e1a841823
+/System/Library/Fonts/Helvetica.ttc@98c12f0d63168b20635fb51d638929753b4e6aed;--font-funcs ot;U+006D,U+0300;[m=0+1706|gravecmb=0@-284,10+0]
+/System/Library/Fonts/LucidaGrande.ttc@b2b9aa73d0d9ddabbe73549949fc7444b8528cc2;--font-funcs ot;U+006D,U+0300;[mgrave=0+1912]
+/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb;--font-funcs ot;U+0066,U+0069;[fi=0+1139]
+/System/Library/Fonts/Supplemental/Khmer MN.ttc@37687fe0bd2548e08e29c92a30e476367ae6356b;--font-funcs ot;U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A;[km_qa=0+1230|km_ka=1+1230|km_sa.sub=1+620|km_ro=4+712|km_vs_ae=5+726|km_kha=5+1230|km_mo.sub=5+0|km_ro=9+712]
+/System/Library/Fonts/Supplemental/Tamil MN.ttc@e1df5e056be08937fd65990efbafff0814c03677;--font-funcs ot;U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1;[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
+/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb;--font-funcs ot;U+0041,U+0066,U+0300,U+0066,U+0069,U+005A;[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@b2b9aa73d0d9ddabbe73549949fc7444b8528cc2;--font-funcs ot;U+05E1,U+05B0;[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A;[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064A,U+064E,U+0651,U+0629;[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/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]
+# 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]
+/System/Library/Fonts/Apple Color Emoji.ttc@ef22d55c551e2af0193d75105346c6e7e21af389;--remove-default-ignorables --font-funcs ot;U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466;[u1F46A.MWGB=0+800]
+/System/Library/Fonts/Supplemental/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08;--font-funcs ot;U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F;[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
+/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897;--font-funcs ot;U+0E17,U+0E35,U+0E48,U+0E4A;[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300]
+/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb;--font-funcs ot;U+0066,U+0069,U+006e,U+0065;[fi=0+1139|n=2+1024|e=3+909]
+/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb;--font-funcs ot --features liga=0;U+0066,U+0069,U+006e,U+0065;[f=0+682|i=1+569|n=2+1024|e=3+909]
+/System/Library/Fonts/Supplemental/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/System/Library/Fonts/Supplemental/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4;--font-funcs ot --features liga=0;U+0F62,U+0F92,U+0FB1,U+0F74;[r_g_y_u=0+1579]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s=3+728|t=4+725]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features dlig=1,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f_i=0+1097|r=2+853|s_t=3+1438]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,sups=0,tnum=0;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features smcp=1;U+0066,U+0069,U+0072,U+0073,U+0074;[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075]
+/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac;--font-funcs ot --features liga=0,dlig=1;U+0066,U+0069,U+0072,U+0073,U+0074;[f=0+639|i=1+606|r=2+853|s_t=3+1438]
+/System/Library/Fonts/Supplemental/Skia.ttf@caee56fc4085009c1a29a863500908050ea6248f;--font-funcs ot;U+0041,U+0056;[A=0+1345|V=1@-12,0+1346]
+/System/Library/Fonts/Supplemental/Devanagari Sangam MN.ttc@214b7ffa672bc936745df5a72644f2b705b24b4b;--font-funcs ot;U+092D,U+0941;[dn_bha=0+1339|dn_u_matra.mrk=0@-296,11+0]
+
+# 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]
diff --git a/test/shape/data/in-house/tests/mark-attachment.tests b/test/shape/data/in-house/tests/mark-attachment.tests
new file mode 100644
index 0000000..315684e
--- /dev/null
+++ b/test/shape/data/in-house/tests/mark-attachment.tests
@@ -0,0 +1 @@
+../fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf;;U+100F,U+103C,U+102F,U+1036;[uni103C102F=0+150|uni100F=0+550|uni1036=0@-150,0+0]
diff --git a/test/shape/data/in-house/tests/mark-filtering-sets.tests b/test/shape/data/in-house/tests/mark-filtering-sets.tests
new file mode 100644
index 0000000..a64e9c7
--- /dev/null
+++ b/test/shape/data/in-house/tests/mark-filtering-sets.tests
@@ -0,0 +1,5 @@
+../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf;;U+062A,U+062E,U+062A,U+0629;[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph837=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
+../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf;;U+062A,U+062E,U+0646,U+0629;[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph836=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
+../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf;;U+062A,U+062E,U+0626,U+0629;[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph847=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
+../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf;;U+062A,U+062E,U+062B,U+0629;[glyph837=3@299,1520+0|uni06C1.1=3+502|glyph838=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
+../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf;;U+062A,U+062E,U+0679,U+0629;[glyph837=3@299,1520+0|uni06C1.1=3+502|glyph842=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
diff --git a/test/shape/data/in-house/tests/mongolian-variation-selector.tests b/test/shape/data/in-house/tests/mongolian-variation-selector.tests
new file mode 100644
index 0000000..35b4701
--- /dev/null
+++ b/test/shape/data/in-house/tests/mongolian-variation-selector.tests
@@ -0,0 +1,19 @@
+../fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf;;U+1826,U+180B,U+1826;[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
+../fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf;;U+1820,U+180B;[uni1820.E821_a.isol1=0+1199]
+../fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf;;U+180A,U+1868,U+180A,U+1868,U+180B,U+180A,U+1868,U+180C,U+180A,U+1868,U+180D,U+180A;[gid1=0+268|gid10=1+778|gid1=2+268|gid9=3+575|gid1=5+268|gid10=6+778|gid1=8+268|gid8=9+575|gid1=11+268]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837;[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+182D,U+180B;[uni182D.E8E2_g.init=0+1000|uni182D.E8E8_g.fina1=1+1250]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+180C;[uni182D.EA1B_g.isol2=0+1000]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+180D,U+200D;[uni182D.EA1E_g.init3=0+650|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+200D,U+182D,U+180B,U+200D;[uni182D.E8E2_g.init=0+1000|space=0+0|uni182D.E8E5_g.medi1=2+800|space=2+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+180C,U+200D;[uni182D.EA1D_g.init2=0+950|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182D,U+180D,U+200D;[uni182D.EA1E_g.init3=0+650|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D;[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|space=1+0|uni182D.E8E5_g.medi1=4+800|space=4+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+180C,U+200D;[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+180D,U+200D;[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+200D,U+182D,U+180B;[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|uni182D.E8E8_g.fina1=3+1250]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+180C;[space=0+0|uni182D.E8E9_g.fina2=1+1050]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+1820,U+200C,U+182D,U+1820,U+1837;[uni1820.E820_a.isol=0+1550|space=1+0|uni182D.E8E2_g.init=2+1000|uni1820.E823_a.medi=3+400|uni1837.E931_r.fina=4+750]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D;[uni1830.E90B_s.init=0+850|uni1824.E844_u.medi=1+600|uni1837.E930_r.medi=2+600|space=2+0|space=2+0|uni182D.E8E5_g.medi1=5+800|uni1820.E823_a.medi=6+400|space=6+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+200D,U+182D,U+1824,U+182F,U+1822;[space=0+0|uni182D.E8E5_g.medi1=1+800|uni1824.E844_u.medi=2+600|uni182F.E908_l.medi=3+400|uni1822.E837_i.fina=4+600]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf;;U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828;[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|uni180E.E80E_mvs=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850]
diff --git a/test/shape/data/in-house/tests/myanmar-misc.tests b/test/shape/data/in-house/tests/myanmar-misc.tests
new file mode 100644
index 0000000..5273863
--- /dev/null
+++ b/test/shape/data/in-house/tests/myanmar-misc.tests
@@ -0,0 +1 @@
+../fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf;;U+101A,U+1035;[ya_e_above=0+1000]
diff --git a/test/shape/data/in-house/tests/myanmar-syllable.tests b/test/shape/data/in-house/tests/myanmar-syllable.tests
new file mode 100644
index 0000000..65a4b0b
--- /dev/null
+++ b/test/shape/data/in-house/tests/myanmar-syllable.tests
@@ -0,0 +1 @@
+../fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf;--no-glyph-names;U+101D,U+FE00,U+1031,U+FE00,U+1031,U+FE00;[6=0+465|6=0+465|5=0+502]
diff --git a/test/shape/data/in-house/tests/myanmar-zawgyi.tests b/test/shape/data/in-house/tests/myanmar-zawgyi.tests
new file mode 100644
index 0000000..b31435f
--- /dev/null
+++ b/test/shape/data/in-house/tests/myanmar-zawgyi.tests
@@ -0,0 +1 @@
+../fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf;--script=Qaag;U+1000,U+103A,U+1004,U+1037,U+1039,U+1041;[Ka=0+2217|Ya-Semivowel=0+286|Nga=2+1247|Dot Below=2+0|Virama-Killer=2+0|One-Myanmar=5+1247]
diff --git a/test/shape/data/in-house/tests/none-directional.tests b/test/shape/data/in-house/tests/none-directional.tests
new file mode 100644
index 0000000..e1c5657
--- /dev/null
+++ b/test/shape/data/in-house/tests/none-directional.tests
@@ -0,0 +1,3 @@
+../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf;;U+10300,U+10301;[u10300=0+1470|u10301=1+1284]
+../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf;--direction=ltr;U+10300,U+10301;[u10300=0+1470|u10301=1+1284]
+../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf;--direction=rtl;U+10300,U+10301;[u10301_r=1+1284|u10300_r=0+1470]
diff --git a/test/shape/data/in-house/tests/positioning-features.tests b/test/shape/data/in-house/tests/positioning-features.tests
new file mode 100644
index 0000000..1021a45
--- /dev/null
+++ b/test/shape/data/in-house/tests/positioning-features.tests
@@ -0,0 +1,3 @@
+../fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf;;U+0041,U+0056;[A=0+625|V=1+675]
+../fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf;;U+006D,U+0315;[m=0+945|uni0315=0@32,-178+0]
+../fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf;;U+0079,U+0325;[y=0+565|uni0325=0@-422,-240+0]
diff --git a/test/shape/data/in-house/tests/rand.tests b/test/shape/data/in-house/tests/rand.tests
new file mode 100644
index 0000000..6111828
--- /dev/null
+++ b/test/shape/data/in-house/tests/rand.tests
@@ -0,0 +1,3 @@
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf;--no-glyph-names --features=-rand;U+0054,U+0055,U+0056;[1=0+560|2=1+602|3=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf;--no-glyph-names --features=rand=2;U+0054,U+0055,U+0056;[5=0+560|8=1+602|11=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf;--no-glyph-names;U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056;[5=0+560|7=1+602|10=2+602|4=3+560|7=4+602|10=5+602|6=6+560|9=7+602|10=8+602|5=9+560|8=10+602|12=11+602]
diff --git a/test/shape/data/in-house/tests/reverse-sub.tests b/test/shape/data/in-house/tests/reverse-sub.tests
new file mode 100644
index 0000000..60a5369
--- /dev/null
+++ b/test/shape/data/in-house/tests/reverse-sub.tests
@@ -0,0 +1,3 @@
+../fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf;;U+0041,U+0020,U+0041,U+0042;[A.alt1=0+1000|space=1+1000|A.alt1=2+1000|B=3+1000]
+../fonts/3f24aff8b768e586162e9b9d03b15c36508dd2ae.ttf;--features=salt=2;U+0635,U+0644,U+0637,U+062E,U+0644,U+0637,U+062C;[gid43=6@143,-124+0|gid8=6+178|gid25=5@0,110+670|gid33=4@0,110+120|gid41=3@-8,343+0|gid10=3@0,110+88|gid26=2@0,220+670|gid34=1@0,220+120|gid21=0@0,220+670]
+../fonts/1b66a1f4b076b734caa6397b3e57231af1feaafb.ttf;;U+0031,U+0032,U+0033,U+0034,U+0035,U+0036,U+0037,U+0038,U+0039,U+0030,U+2044,U+0031,U+0032,U+0033,U+0034,U+0035,U+0036,U+0037,U+0038,U+0039,U+0030;[one.numr=0+350|two.numr=1+350|three.numr=2+350|four.numr=3+350|five.numr=4+350|six.numr=5+350|seven.numr=6+350|eight.numr=7+350|nine.numr=8+350|zero.numr=9+350|fraction=10+130|one.dnom=11+350|two.dnom=12+350|three.dnom=13+350|four.dnom=14+350|five.dnom=15+350|six.dnom=16+350|seven.dnom=17+350|eight.dnom=18+350|nine.dnom=19+350|zero.dnom=20+350]
diff --git a/test/shape/data/in-house/tests/rotation.tests b/test/shape/data/in-house/tests/rotation.tests
new file mode 100644
index 0000000..66cbc09
--- /dev/null
+++ b/test/shape/data/in-house/tests/rotation.tests
@@ -0,0 +1,4 @@
+../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf;--no-clusters --no-positions --direction=l;U+3008;[uni3008]
+../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf;--no-clusters --no-positions --direction=r;U+3008;[uni3009]
+../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf;--no-clusters --no-positions --direction=t;U+3008;[uniFE3F]
+../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf;--no-clusters --no-positions --direction=b;U+3008;[uniFE40]
diff --git a/test/shape/data/in-house/tests/simple.tests b/test/shape/data/in-house/tests/simple.tests
new file mode 100644
index 0000000..e88ed6b
--- /dev/null
+++ b/test/shape/data/in-house/tests/simple.tests
@@ -0,0 +1,2 @@
+../fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf;--shaper=ot;U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064;[V=0+1142|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
+../fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf;--shaper=fallback;U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064;[V=0+1295|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
diff --git a/test/shape/data/in-house/tests/sinhala.tests b/test/shape/data/in-house/tests/sinhala.tests
new file mode 100644
index 0000000..4748c1d
--- /dev/null
+++ b/test/shape/data/in-house/tests/sinhala.tests
@@ -0,0 +1 @@
+../fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf;;U+0DBB,U+0DCA,U+200D,U+0DBA,U+0DCA,U+200D,U+0DBA;[gid8=0+1343|gid4=0+1130]
diff --git a/test/shape/data/in-house/tests/spaces.tests b/test/shape/data/in-house/tests/spaces.tests
new file mode 100644
index 0000000..36cfc0f
--- /dev/null
+++ b/test/shape/data/in-house/tests/spaces.tests
@@ -0,0 +1,34 @@
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+0020;[gid1=0+560]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+00A0;[gid1=0+560]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+1680;[gid0=0+692]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2000;[gid1=0+1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2001;[gid1=0+2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2002;[gid1=0+1024]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2003;[gid1=0+2048]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2004;[gid1=0+683]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2005;[gid1=0+512]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2006;[gid1=0+341]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2007;[gid1=0+560]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2008;[gid1=0+560]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+2009;[gid1=0+410]
+../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf;--font-funcs=ot;U+200A;[gid1=0+128]
+../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]
diff --git a/test/shape/data/in-house/tests/tibetan-contractions-1.tests b/test/shape/data/in-house/tests/tibetan-contractions-1.tests
new file mode 100644
index 0000000..6e1eed5
--- /dev/null
+++ b/test/shape/data/in-house/tests/tibetan-contractions-1.tests
@@ -0,0 +1,60 @@
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+FEFF,U+0F40,U+0F72,U+0F72,U+0F0B,U+0F66,U+0FAD,U+0F7C,U+0F7C,U+0F0B;[uni0F40=0+680|uni0F720F72=0+0|uni0F0B=4+190|uni0F660FAD=5+680|uni0F7D=5+0|uni0F0B=9+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0F74,U+0F72,U+0F66,U+0F0B;[uni0F400F740F72=0+680|uni0F66=3+680|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0F74,U+0F7A,U+0F53,U+0F0B;[uni0F400F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0F74,U+0F7C,U+0F56,U+0F39,U+0F0B;[uni0F400F74=0+680|uni0F7C=0+0|uni0F56=3+610|uni0F39=3+0|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0F74,U+0F72,U+0F42,U+0F66,U+0F0B;[uni0F400F740F72=0+680|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0F74,U+0F7A,U+0F66,U+0F0B;[uni0F400F74=0+680|uni0F7A=0+0|uni0F66=3+680|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0FB3,U+0F74,U+0F7A,U+0F56,U+0F66,U+0F0B;[uni0F400FB30F740F7A=0+660|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F40,U+0FB3,U+0F74,U+0F7C,U+0F42,U+0F0B;[uni0F400FB30F74=0+660|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F42,U+0F0B;[uni0F51=0+600|uni0F400F7D=1+680|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F62,U+0F0B;[uni0F51=0+600|uni0F400F7D=1+680|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F40,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B;[uni0F51=0+600|uni0F400FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F66,U+0F90,U+0FB1,U+0F74,U+0F7A,U+0F0B;[uni0F660F900FB10F74=0+680|uni0F7A=0+0|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F51,U+0F0B;[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B=1+0|uni0F51=6+600|uni0F0B=7@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F51,U+0F0B;[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B0F7A=1+0|uni0F51=7+600|uni0F0B=8@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0F58,U+0F66,U+0F74,U+0F7E,U+0F0B;[uni0F41=0+660|uni0F58=1+660|uni0F660F740F7E=2+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0F74,U+0F7C,U+0F66,U+0F39,U+0F0B;[uni0F410F74=0+680|uni0F7C=0+0|uni0F66=3+680|uni0F39=3+0|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0FB1,U+0F74,U+0F7C,U+0F42,U+0F0B;[uni0F410FB10F74=0+670|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0FB2,U+0F74,U+0F7A,U+0F51,U+0F0B;[uni0F410FB20F74=0+660|uni0F7A=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0FB2,U+0F74,U+0F72,U+0F44,U+0F0B;[uni0F410FB20F74=0+660|uni0F72=0+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0FB2,U+0F74,U+0F7C,U+0F51,U+0F0B;[uni0F410FB20F74=0+660|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F41,U+0FB2,U+0F74,U+0F7E,U+0F51,U+0F0B;[uni0F410FB20F740F7E=0+660|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F58,U+0F41,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F53,U+0F0B;[uni0F58=0+660|uni0F410FB1=1+680|uni0F7B0F7A=1+0|uni0F53=6+590|uni0F0B=7@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F60,U+0F41,U+0F7C,U+0F7C,U+0F62,U+0F0B;[uni0F60=0+600|uni0F410F7D=1+660|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0F74,U+0F7C,U+0F42,U+0F0B;[uni0F420F74=0+680|uni0F7C=0+0|uni0F42=3+680|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB1,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F420FB10F74=0+700|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B;[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F74,U+0F72,U+0F0B;[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F53,U+0F0B;[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B;[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F56=4+610|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F7C,U+0F72,U+0F53,U+0F0B;[uni0F420FB2=0+680|uni0F7C0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0FB2,U+0F7C,U+0F7A,U+0F62,U+0F0B;[uni0F420FB2=0+680|uni0F7C0F7A=0+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F42,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F51=0+600|uni0F420F740F72=1+680|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F42,U+0F74,U+0F7A,U+0F53,U+0F0B;[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F42,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B;[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F42,U+0FB3,U+0F7C,U+0F7A,U+0F44,U+0F0B;[uni0F51=0+600|uni0F420FB3=1+680|uni0F7C0F7A=1+0|uni0F44=5+560|uni0F0B=6@-20,0+110]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F58,U+0F42,U+0F7C,U+0F7C,U+0F53,U+0F0B;[uni0F58=0+660|uni0F420F7D=1+680|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F44,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F440F74=0+610|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F51,U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B;[uni0F51=0+600|uni0F420FB20F74=1+680|uni0F7C=1+0|uni0F56=5+610|uni0F0B=6+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F45,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F56=0+610|uni0F450F740F72=1+630|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F45,U+0F74,U+0F72,U+0F66,U+0F0B;[uni0F56=0+610|uni0F450F740F72=1+630|uni0F66=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F45,U+0FB2,U+0F74,U+0F42,U+0F0B;[uni0F56=0+610|uni0F450FB20F74=1+640|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F45,U+0F74,U+0F72,U+0F0B;[uni0F56=0+610|uni0F450F740F72=1+630|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F45,U+0F74,U+0F7E,U+0F0B;[uni0F56=0+610|uni0F450F740F7E=1+630|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0F74,U+0F72,U+0F63,U+0F0B;[uni0F460F74=0+650|uni0F72=0+0|uni0F63=3+700|uni0F0B=4+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B;[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B;[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0F74,U+0F7E,U+0F51,U+0F0B;[uni0F460F740F7E=0+650|uni0F51=3+600|uni0F0B=4@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0F39,U+0F74,U+0F7C,U+0F51,U+0F0B;[uni0F46=0+620|uni0F39=0+0|uni0F74=0+0|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B;[uni0F460FB20F740F72=0+660|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F46,U+0FB2,U+0F74,U+0F7C,U+0F63,U+0F0B;[uni0F460FB20F74=0+660|uni0F7C=0+0|uni0F63=4+700|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F58,U+0F46,U+0F7C,U+0F7A,U+0F53,U+0F0B;[uni0F58=0+660|uni0F46=1+620|uni0F7C0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F60,U+0F46,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B;[uni0F60=0+600|uni0F460FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F47,U+0F7C,U+0F7C,U+0F0B;[uni0F470F7D=0+570|uni0F0B=3+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F62,U+0F97,U+0F74,U+0F7A,U+0F53,U+0F39,U+0F0B;[uni0F620F970F74=0+600|uni0F7A=0+0|uni0F53=4+590|uni0F39=4+0|uni0F0B=6+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F49,U+0F74,U+0F72,U+0F0B;[uni0F490F74=0+580|uni0F72=0+0|uni0F0B=3+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F49,U+0F74,U+0F72,U+0F44,U+0F0B;[uni0F490F74=0+580|uni0F72=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F58,U+0F49,U+0F72,U+0F7E,U+0F51,U+0F0B;[uni0F58=0+660|uni0F49=1+580|uni0F720F7E=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F42,U+0F4F,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F42=0+680|uni0F4F0F740F72=1+600|uni0F42=4+680|uni0F0B=5+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F56,U+0F4F,U+0F44,U+0F7C,U+0F7E,U+0F66,U+0F0B;[uni0F56=0+610|uni0F4F=1+560|uni0F44=2+560|uni0F7C0F7E=2+0|uni0F66=5+680|uni0F0B=6+190]
+../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf;;U+0F50,U+0F39,U+0F74,U+0F7A,U+0F4A,U+0F0B;[uni0F50=0+600|uni0F39=0+0|uni0F74=0+0|uni0F7A=0+0|uni0F4A=4+590|uni0F0B=5+190]
diff --git a/test/shape/data/in-house/tests/tibetan-contractions-2.tests b/test/shape/data/in-house/tests/tibetan-contractions-2.tests
new file mode 100644
index 0000000..495a8df
--- /dev/null
+++ b/test/shape/data/in-house/tests/tibetan-contractions-2.tests
@@ -0,0 +1,53 @@
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F50,U+0F74,U+0F72,U+0F53,U+0F0B;[uni0F500F74=0+600|uni0F72=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F50,U+0F74,U+0F7C,U+0F44,U+0F0B;[uni0F58=0+660|uni0F500F74=1+600|uni0F7C=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F50,U+0F7C,U+0F7A,U+0F44,U+0F0B;[uni0F58=0+660|uni0F50=1+600|uni0F7C0F7A=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F50,U+0F7C,U+0F72,U+0F66,U+0F0B;[uni0F58=0+660|uni0F50=1+600|uni0F7C0F72=1+0|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F51,U+0F74,U+0F62,U+0FB2,U+0F7C,U+0F51,U+0F0B;[uni0F510F74=0+600|uni0F620FB2=2+600|uni0F7C=2+0|uni0F51=5+600|uni0F0B=6@-70,0+106]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F51,U+0FB2,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F510FB20F74=0+600|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F51,U+0F74,U+0F7A,U+0F53,U+0F0B;[uni0F42=0+680|uni0F510F740F7A=1+600|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F56,U+0F51,U+0F7B,U+0F42,U+0F66,U+0F0B;[uni0F56=0+610|uni0F510F7B=1+579|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F60,U+0F51,U+0F74,U+0F7A,U+0F51,U+0F0B;[uni0F60=0+600|uni0F510F740F7A=1+600|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F62,U+0FA1,U+0F7C,U+0F7A,U+0F0B;[uni0F620FA10F7C0F7A=0+580|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0FA1,U+0F74,U+0F72,U+0F56,U+0F0B;[uni0F660FA10F74=0+680|uni0F72=0+0|uni0F56=4+610|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F53,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B;[uni0F530F74=0+600|uni0F7C=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F53,U+0F74,U+0F7C,U+0F62,U+0F0B;[uni0F530F74=0+600|uni0F7C=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F53,U+0FB1,U+0F7C,U+0F7E,U+0F62,U+0F0B;[uni0F42=0+680|uni0F530FB1=1+600|uni0F7C0F7E=1+0|uni0F62=5+620|uni0F0B=6@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F51,U+0F54,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B;[uni0F51=0+600|uni0F540F74=1+610|uni0F7C=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F56,U+0FB1,U+0F74,U+0F7E,U+0F56,U+0F0B;[uni0F560FB10F74=0+620|uni0F7E=0+0|uni0F56=4+610|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F56,U+0FB3,U+0F74,U+0F7C,U+0F53,U+0F0B;[uni0F560FB30F74=0+650|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F56,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B;[uni0F560FB3=0+650|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F51,U+0F56,U+0F74,U+0F7C,U+0F51,U+0F0B;[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F51,U+0F56,U+0F74,U+0F7C,U+0F56,U+0F66,U+0F0B;[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B;[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F74,U+0F72,U+0F42,U+0F0B;[uni0F580F74=0+680|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B;[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F74,U+0F7A,U+0F53,U+0F0B;[uni0F580F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F9F,U+0F7C,U+0F7A,U+0F42,U+0F0B;[uni0F580F9F0F7C0F7A=0+660|uni0F42=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F7C,U+0F7A,U+0F44,U+0F0B;[uni0F58=0+660|uni0F7C0F7A=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F59,U+0F74,U+0F7C,U+0F62,U+0F0B;[uni0F42=0+680|uni0F590F74=1+620|uni0F7C=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F58,U+0F5A,U+0FAE,U+0F74,U+0F7E,U+0F66,U+0F0B;[uni0F58=0+660|uni0F5A0FAE0F740F7E=1+620|uni0F66=5+680|uni0F0B=6+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F66,U+0F0B;[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F53,U+0F0B;[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F5E,U+0F74,U+0F7C,U+0F63,U+0F0B;[uni0F5E0F74=0+660|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F42,U+0F0B;[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F42=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F58,U+0F66,U+0F0B;[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F58=4+660|uni0F66=5+680|uni0F0B=6+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5F,U+0F74,U+0F7C,U+0F0B;[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7C=1+0|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5F,U+0F74,U+0F72,U+0F44,U+0F0B;[uni0F42=0+680|uni0F5F0F740F72=1+610|uni0F44=4+560|uni0F0B=5@-20,0+110]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B;[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B;[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F51,U+0F0B;[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F60,U+0F7C,U+0F7A,U+0F62,U+0F0B;[uni0F60=0+600|uni0F7C0F7A=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F61,U+0F72,U+0F7A,U+0F0B;[uni0F61=0+700|uni0F720F7A=0+0|uni0F0B=3+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F61,U+0F7A,U+0F7A,U+0F66,U+0F0B;[uni0F61=0+700|uni0F7B=0+0|uni0F66=3+680|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F62,U+0F72,U+0F53,U+0F7C,U+0F7A,U+0F0B;[uni0F620F72=0+620|uni0F530F7C0F7A=2+590|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F62,U+0F74,U+0F7C,U+0F63,U+0F0B;[uni0F620F74=0+601|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0F7A,U+0F7E,U+0F53,U+0F0B;[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0F7A,U+0F7E,U+0F51,U+0F60,U+0F0B;[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F51=3+600|uni0F60=4+600|uni0F0B=5@-40,0+150]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0F7C,U+0F7C,U+0F56,U+0F0B;[uni0F660F7D=0+680|uni0F56=3+610|uni0F0B=4+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0F7C,U+0F7C,U+0F62,U+0F0B;[uni0F660F7D=0+680|uni0F62=3+620|uni0F0B=4@-65,0+130]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0FB2,U+0F7C,U+0F7A,U+0F66,U+0F0B;[uni0F660FB2=0+680|uni0F7C0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F51,U+0F0B;[uni0F660FB3=0+680|uni0F7D=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B;[uni0F660FB3=0+680|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F56,U+0F66,U+0F99,U+0F7C,U+0F7E,U+0F51,U+0F66,U+0F0B;[uni0F56=0+610|uni0F660F99=1+670|uni0F7C0F7E=1+0|uni0F51=5+600|uni0F66=6+680|uni0F0B=7+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F63,U+0FB7,U+0FB1,U+0F7C,U+0F42,U+0F66,U+0F0B;[uni0F630FB70FB1=0+680|uni0F7C=0+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf;;U+0F68,U+0FB1,U+0F7C,U+0F53,U+0F0B;[uni0F680FB1=0+740|uni0F7C=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
diff --git a/test/shape/data/in-house/tests/tibetan-vowels.tests b/test/shape/data/in-house/tests/tibetan-vowels.tests
new file mode 100644
index 0000000..bc0e32d
--- /dev/null
+++ b/test/shape/data/in-house/tests/tibetan-vowels.tests
@@ -0,0 +1,11 @@
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F72;[uni0F680F72=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F74;[uni0F680F74=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7A;[uni0F680F7A=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7C;[uni0F680F7C=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F71,U+0F72;[uni0F680F710F72=0+720]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F71,U+0F74;[uni0F680F75=0+720]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7B;[uni0F680F7B=0+720]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7D;[uni0F680F7D=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7E;[uni0F680F7E=0+730]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F68,U+0F7F;[uni0F68=0+730|uni0F7F=0+408]
+../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf;;U+0F00;[uni0F00=0+730]
diff --git a/test/shape/data/in-house/tests/tt-kern-gpos.tests b/test/shape/data/in-house/tests/tt-kern-gpos.tests
new file mode 100644
index 0000000..756e9e0
--- /dev/null
+++ b/test/shape/data/in-house/tests/tt-kern-gpos.tests
@@ -0,0 +1 @@
+../fonts/b121d4306b2e3add5abbaad21d95fcf04aacbd64.ttf;;U+0041,U+0043,U+0041,U+0042;[A=0+1275|C=1@-20,0+1272|A=2+1296|B=3+1327]
diff --git a/test/shape/data/in-house/tests/use-indic3.tests b/test/shape/data/in-house/tests/use-indic3.tests
new file mode 100644
index 0000000..d3d010e
--- /dev/null
+++ b/test/shape/data/in-house/tests/use-indic3.tests
@@ -0,0 +1 @@
+../fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf;;U+0C95,U+0CCD,U+0CB0;[uni0C95=0+1176|uni0CB0_uni0CCD.blwf=0+275]
diff --git a/test/shape/data/in-house/tests/use-marchen.tests b/test/shape/data/in-house/tests/use-marchen.tests
new file mode 100644
index 0000000..8eeeaaa
--- /dev/null
+++ b/test/shape/data/in-house/tests/use-marchen.tests
@@ -0,0 +1,35 @@
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8F;[u11C8F=0+3000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C71;[u11C71=0+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8A,U+11CB5;[u11C8A=0+2000|u11CB5=0@-2000,0+0]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C84,U+11C71;[u11C84=0+2200|u11C71=1+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C7E,U+11C8A;[u11C7E=0+2600|u11C8A=1+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8A,U+11C92,U+11CA9;[u11C8A.11C92.11CA9=0+2600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8A,U+11C94,U+11CA9;[u11C8A.11C94.11CA9=0+2600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C92,U+11CA9;[u11C8D.11C92.11CA9=0+2600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C94,U+11CA9;[u11C8D.11C94.11CA9=0+2600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C9E,U+11CA9;[u11C8D.11C9E.11CA9=0+3200]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11CA0,U+11CA9;[u11C8D.11CA0.11CA9=0+3000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C92,U+11CAA;[u11C8D.11C92.11CAA=0+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C94,U+11CAA;[u11C8D.11C94.11CAA=0+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C9D,U+11CAA;[u11C8D.11C9D.11CAA=0+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11C9E,U+11CAA;[u11C8D.11C9E.11CAA=0+2600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11CA0,U+11CAA;[u11C8D.11CA0.11CAA=0+2400]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C80,U+11C72,U+11CAA;[u11C80=0+2400|u11C72.11CAA=1+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8C,U+11CB1,U+11C8D;[u11C8C.11CB1=0+2793|u11C8D=2+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C80,U+11C7C,U+11CB3;[u11C80=0+2400|u11C7C.11CB3=1+2200]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C7F,U+11CB2,U+11C7D;[u11C7F.11CB2=0+2400|u11C7D=2+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11CB2,U+11C81;[u11C8D.11CB2=0+2000|u11C81=2+2400]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8C,U+11CB4,U+11C74;[u11C8C.11CB4=0+2800|u11C74=2+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8A,U+11CA1,U+11CA9,U+11C71;[u11C8A.11CA1.11CA9=0+3000|u11C71=3+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11CA1,U+11CA9,U+11C71;[u11C8D.11CA1.11CA9=0+3000|u11C71=3+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8D,U+11CA1,U+11CAA,U+11C71;[u11C8D.11CA1.11CAA=0+2400|u11C71=3+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8F,U+11CB0,U+11CB4,U+11CB6;[u11C8F.11CB0.11CB4=0+3600|u11CB6=0@-3200,0+0]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8E,U+11CB0,U+11CB2,U+11CB5;[u11C8E.11CB0.11CB2=0+2000|u11CB5=0@-2000,0+0]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C74,U+11C89,U+11CB2,U+11C75;[u11C74=0+2000|u11C89.11CB2=1+2000|u11C75=3+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C7C,U+11CAA,U+11CB2,U+11C75;[u11C7C.11CAA.11CB2=0+2200|u11C75=3+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C81,U+11C74,U+11CB2,U+11C8B;[u11C81=0+2400|u11C74.11CB2=1+2000|u11C8B=3+2400]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8B,U+11CB3,U+11C74,U+11C8D;[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C83,U+11CB4,U+11C74,U+11C8D;[u11C83.11CB4=0+2800|u11C74=2+2000|u11C8D=3+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C8B,U+11CB3,U+11C74,U+11C8D,U+11C71;[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000|u11C71=4+1600]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C80,U+11C76,U+11CB1,U+11C75,U+11C8D;[u11C80=0+2400|u11C76.11CB1=1+3200|u11C75=3+2000|u11C8D=4+2000]
+../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf;;U+11C80,U+11C8D,U+11C94,U+11CAA,U+11CB1,U+11C74,U+11C8D;[u11C80=0+2400|u11C8D.11C94.11CAA.11CB1.shorti=1+2600|u11C74=5+2000|u11C8D=6+2000]
diff --git a/test/shape/data/in-house/tests/use-syllable.tests b/test/shape/data/in-house/tests/use-syllable.tests
new file mode 100644
index 0000000..1cc52fd
--- /dev/null
+++ b/test/shape/data/in-house/tests/use-syllable.tests
@@ -0,0 +1,22 @@
+../fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf;;U+AA00,U+AA2D,U+AA29;[a_cham=0+1121|uSign_cham=0@14,0+0|.notdef=0+600]
+../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf;;U+AA00,U+AA34,U+AA36;[raMedial_cham_pre=0+400|a_cham=0+1121|waMedial_cham=0@-32,0+0]
+../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/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]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf;;U+11013,U+11042,U+11046;[brm_KA=0+754|brm_vowelEE=0@-383,0+0|brm_virama=0@-524,0+0]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf;;U+11013,U+11044,U+11046;[brm_KA=0+754|brm_vowelOO=0@-647,0+0|brm_virama=0@-524,0+0]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf;;U+11013,U+1103C;[brm_KA=0+754|brm_vowelU=0@-403,0+0]
+../fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf;;U+111C8,U+111C9,U+111C9;[u111C8=0+500|u111C9=0@-500,0+0|u111C9=0@-500,0+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf;;U+1A3D,U+1A5A,U+1A63;[uni1A3D=0+250|uni1A5A=0+0|uni1A63=0+250]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf;;U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A59;[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A59=5+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf;;U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A5A;[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni25CC=5+250|uni1A5A=5+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf;;U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A60;[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A60=5+0]
+../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf;--font-funcs=ft;U+11410,U+11442,U+200C,U+11411;[Ga=0+576|Virama=0@70,70+0|Gha=3+566]
+../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf;--font-funcs=ft;U+11410,U+11442,U+200C,U+034F,U+11411;[Ga=0+576|Virama=0@70,70+0|Gha=4+566]
+../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf;--font-funcs=ft;U+11410,U+200C,U+11442,U+034F,U+11411;[Ga.icd=0+367|Gha.diag=1@100,0+386]
+../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]
diff --git a/test/shape/data/in-house/tests/use-vowel-letter-spoofing.tests b/test/shape/data/in-house/tests/use-vowel-letter-spoofing.tests
new file mode 100644
index 0000000..03b6bef
--- /dev/null
+++ b/test/shape/data/in-house/tests/use-vowel-letter-spoofing.tests
@@ -0,0 +1,94 @@
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+093A;[uni0905=0+500|uni25CC=0+500|uni093A=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+093B;[uni0905=0+500|uni25CC=0+500|uni093B=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+093E;[uni0905=0+500|uni25CC=0+500|uni093E=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+0945;[uni0905=0+500|uni25CC=0+500|uni0945=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+0946;[uni0905=0+500|uni25CC=0+500|uni0946=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+0949;[uni0905=0+500|uni25CC=0+500|uni0949=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+094A;[uni0905=0+500|uni25CC=0+500|uni094A=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+094B;[uni0905=0+500|uni25CC=0+500|uni094B=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+094C;[uni0905=0+500|uni25CC=0+500|uni094C=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+094F;[uni0905=0+500|uni25CC=0+500|uni094F=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+0956;[uni0905=0+500|uni25CC=0+500|uni0956=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0905,U+0957;[uni0905=0+500|uni25CC=0+500|uni0957=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0906,U+093A;[uni0906=0+500|uni25CC=0+500|uni093A=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0906,U+0945;[uni0906=0+500|uni25CC=0+500|uni0945=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0906,U+0946;[uni0906=0+500|uni25CC=0+500|uni0946=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0906,U+0947;[uni0906=0+500|uni25CC=0+500|uni0947=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0906,U+0948;[uni0906=0+500|uni25CC=0+500|uni0948=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0909,U+0941;[uni0909=0+500|uni25CC=0+500|uni0941=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+090F,U+0945;[uni090F=0+500|uni25CC=0+500|uni0945=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+090F,U+0946;[uni090F=0+500|uni25CC=0+500|uni0946=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+090F,U+0947;[uni090F=0+500|uni25CC=0+500|uni0947=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0930,U+094D,U+0907;[uni0930=0+500|uni094D=0+500|uni25CC=2+500|uni0907=2+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0985,U+09BE;[uni0985=0+500|uni25CC=0+500|.notdef=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+098B,U+09C3;[uni098B=0+500|uni25CC=0+500|uni09C3=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+098C,U+09E2;[uni098C=0+500|uni25CC=0+500|uni09E2=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A05,U+0A3E;[uni0A05=0+500|uni25CC=0+500|uni0A3E=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A05,U+0A48;[uni0A05=0+500|uni25CC=0+500|uni0A48=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A05,U+0A4C;[uni0A05=0+500|uni25CC=0+500|uni0A4C=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A72,U+0A3F;[uni0A72=0+500|uni0A3F=0+500|uni25CC=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A72,U+0A40;[uni0A72=0+500|uni25CC=0+500|uni0A40=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A72,U+0A47;[uni0A72=0+500|uni25CC=0+500|uni0A47=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A73,U+0A41;[uni0A73=0+500|uni25CC=0+500|uni0A41=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A73,U+0A42;[uni0A73=0+500|uni25CC=0+500|uni0A42=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A73,U+0A4B;[uni0A73=0+500|uni25CC=0+500|uni0A4B=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0ABE,U+0AC5;[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC5=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0ABE,U+0AC8;[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC8=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0ABE;[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0AC5;[uni0A85=0+500|uni25CC=0+500|uni0AC5=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0AC7;[uni0A85=0+500|uni25CC=0+500|uni0AC7=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0AC8;[uni0A85=0+500|uni25CC=0+500|uni0AC8=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0AC9;[uni0A85=0+500|uni25CC=0+500|uni0AC9=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0ACB;[uni0A85=0+500|uni25CC=0+500|uni0ACB=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0A85,U+0ACC;[uni0A85=0+500|uni25CC=0+500|uni0ACC=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0AC5,U+0ABE;[uni25CC=0+500|uni0AC5=0+500|uni25CC=0+500|uni0ABE=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0B05,U+0B3E;[uni0B05=0+500|uni25CC=0+500|uni0B3E=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0B0F,U+0B57;[uni0B0F=0+500|uni25CC=0+500|uni0B57=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0B13,U+0B57;[uni0B13=0+500|uni25CC=0+500|uni0B57=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C12,U+0C4C;[uni0C12=0+500|uni25CC=0+500|uni0C4C=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C12,U+0C55;[uni0C12=0+500|uni25CC=0+500|uni0C55=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C3F,U+0C55;[uni25CC=0+500|uni0C3F=0+500|uni25CC=0+500|uni0C55=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C46,U+0C55;[uni25CC=0+500|uni0C46=0+500|uni25CC=0+500|uni0C55=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C4A,U+0C55;[uni25CC=0+500|uni0C4A=0+500|uni25CC=0+500|uni0C55=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C89,U+0CBE;[uni0C89=0+500|uni25CC=0+500|uni0CBE=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C8B,U+0CBE;[uni0C8B=0+500|uni25CC=0+500|uni0CBE=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0C92,U+0CCC;[uni0C92=0+500|uni25CC=0+500|uni0CCC=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D07,U+0D57;[uni0D07=0+500|uni25CC=0+500|uni0D57=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D09,U+0D57;[uni0D09=0+500|uni25CC=0+500|uni0D57=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D0E,U+0D46;[uni0D0E=0+500|uni0D46=0+500|uni25CC=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D12,U+0D3E;[uni0D12=0+500|uni25CC=0+500|uni0D3E=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D12,U+0D57;[uni0D12=0+500|uni25CC=0+500|uni0D57=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D85,U+0DCF;[uni0D85=0+500|uni25CC=0+500|uni0DCF=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D85,U+0DD0;[uni0D85=0+500|uni25CC=0+500|uni0DD0=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D85,U+0DD1;[uni0D85=0+500|uni25CC=0+500|uni0DD1=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D8B,U+0DDF;[uni0D8B=0+500|uni25CC=0+500|uni0DDF=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D8D,U+0DD8;[uni0D8D=0+500|uni25CC=0+500|uni0DD8=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D8F,U+0DDF;[uni0D8F=0+500|uni25CC=0+500|uni0DDF=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DCA;[uni0D91=0+500|uni25CC=0+500|uni0DCA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DD9;[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DDA;[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DDC;[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DDD;[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D91,U+0DDD;[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+0D94,U+0DDF;[uni0D94=0+500|uni25CC=0+500|uni0DDF=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11005,U+11038;[u11005=0+500|uni25CC=0+500|u11038=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+1100B,U+1103E;[u1100B=0+500|uni25CC=0+500|u1103E=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+1100F,U+11042;[u1100F=0+500|uni25CC=0+500|u11042=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+112B0,U+112E0;[u112B0=0+500|uni25CC=0+500|u112E0=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+112B0,U+112E5;[u112B0=0+500|uni25CC=0+500|u112E5=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+112B0,U+112E6;[u112B0=0+500|uni25CC=0+500|u112E6=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+112B0,U+112E7;[u112B0=0+500|uni25CC=0+500|u112E7=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+112B0,U+112E8;[u112B0=0+500|uni25CC=0+500|u112E8=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11481,U+114B0;[u11481=0+500|uni25CC=0+500|u114B0=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+1148B,U+114BA;[u1148B=0+500|uni25CC=0+500|u114BA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+1148D,U+114BA;[u1148D=0+500|uni25CC=0+500|u114BA=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+114AA,U+114B5;[u114AA=0+500|uni25CC=0+500|u114B5=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+114AA,U+114B6;[u114AA=0+500|uni25CC=0+500|u114B6=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11600,U+11639;[u11600=0+500|uni25CC=0+500|u11639=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11600,U+1163A;[u11600=0+500|uni25CC=0+500|u1163A=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11601,U+11639;[u11601=0+500|uni25CC=0+500|u11639=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11601,U+1163A;[u11601=0+500|uni25CC=0+500|u1163A=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11680,U+116AD;[u11680=0+500|uni25CC=0+500|u116AD=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11680,U+116B4;[u11680=0+500|uni25CC=0+500|u116B4=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11680,U+116B5;[u11680=0+500|uni25CC=0+500|u116B5=0+500]
+../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf;;U+11686,U+116B2;[u11686=0+500|uni25CC=0+500|u116B2=0+500]
diff --git a/test/shape/data/in-house/tests/use.tests b/test/shape/data/in-house/tests/use.tests
new file mode 100644
index 0000000..ebeda47
--- /dev/null
+++ b/test/shape/data/in-house/tests/use.tests
@@ -0,0 +1,15 @@
+../fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf;;U+1B1B,U+1B44,U+1B13,U+1B3E;[gid3=0+990|gid7=0+2473|gid5=0@-293,-400+0]
+../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/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.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+1211|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
+../fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf;--font-funcs=ot;U+11103,U+11128;[u11103=0+837|u11128=0+0]
+../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+1112E;[u11124=0+514|u11131=0+0|u11127=0+0]
+../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+11131,U+11127;[u11124=0+514|u11131=0+0|u11127=0+0]
+../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+11127,U+11131;[u11124=0+514|u11127=0+0|uni25CC=0+547|u11131=0+0]
+../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf;;U+11124,U+11134,U+11131;[u11124=0+514|u11134=0+0|u11131=0+0]
+../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/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]
diff --git a/test/shape/data/in-house/tests/variations-rvrn.tests b/test/shape/data/in-house/tests/variations-rvrn.tests
new file mode 100644
index 0000000..3efcc93
--- /dev/null
+++ b/test/shape/data/in-house/tests/variations-rvrn.tests
@@ -0,0 +1,100 @@
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=1;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=11;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=21;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=31;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=41;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=51;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=61;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=71;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=81;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=91;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=101;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=111;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=121;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=131;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=141;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=151;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=161;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=171;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=181;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=191;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=201;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=211;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=221;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=231;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=241;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=251;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=261;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=271;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=281;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=291;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=301;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=311;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=321;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=331;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=341;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=351;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=361;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=371;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=381;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=391;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=401;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=411;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=421;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=431;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=441;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=451;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=461;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=471;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=481;U+0072;[rvrn_base=0+1529]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=491;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=501;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=511;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=521;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=531;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=541;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=551;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=561;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=571;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=581;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=591;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=601;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=611;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=621;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=631;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=641;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=651;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=661;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=671;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=681;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=691;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=701;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=711;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=721;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=731;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=741;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=751;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=761;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=771;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=781;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=791;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=801;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=811;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=821;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=831;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=841;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=851;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=861;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=871;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=881;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=891;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=901;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=911;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=921;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=931;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=941;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=951;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=961;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=971;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=981;U+0072;[rvrn_subst=0+1825]
+../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf;--variations=FVTT=991;U+0072;[rvrn_subst=0+1825]
diff --git a/test/shape/data/in-house/tests/variations.tests b/test/shape/data/in-house/tests/variations.tests
new file mode 100644
index 0000000..52f74f2
--- /dev/null
+++ b/test/shape/data/in-house/tests/variations.tests
@@ -0,0 +1,5 @@
+../fonts/HBTest-VF.ttf;--variations=TEST=491;U+0041;[A=0+496]
+../fonts/HBTest-VF.ttf;--variations=TEST=509;U+0041;[A=0+505]
+../fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf;--variations=wdth=60;U+0020;[space=0+266]
+../fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf;--variations=wdth=402;U+0020;[space=0+639]
+../fonts/e8691822f6a705e3e9fb48a0405c645b1a036590.ttf;--variations=0001=500;U+002E,U+0065;[period=0+681|e=1+650]
diff --git a/test/shape/data/in-house/tests/vertical.tests b/test/shape/data/in-house/tests/vertical.tests
new file mode 100644
index 0000000..22bf266
--- /dev/null
+++ b/test/shape/data/in-house/tests/vertical.tests
@@ -0,0 +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/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf;--direction=t --font-funcs=ot;U+FF38;[gid2=0@-500,-867+0,-1000]
diff --git a/test/shape/data/in-house/tests/zero-width-marks.tests b/test/shape/data/in-house/tests/zero-width-marks.tests
new file mode 100644
index 0000000..ef7a66e
--- /dev/null
+++ b/test/shape/data/in-house/tests/zero-width-marks.tests
@@ -0,0 +1,11 @@
+../fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf;;U+1030;[circledash=0+636|u1030.med=0@-162,0+0]
+../fonts/8454d22037f892e76614e1645d066689a0200e61.ttf;;U+05E0,U+05B8,U+0591,U+05DA,U+05B0;[uni05DA05B0=3+991|uni2009=0+200|uni0591=0@75,0+0|uni05B8=0@495,0+0|uni05E0=0+683]
+../fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf;;U+0E01,U+0E34,U+0E01;[gid1=0+1264|gid2=0@20,0+0|gid1=2+1264]
+../fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf;;U+0E01,U+0E34,U+0E01;[gid1=0+1264|gid2=0@20,0+1000|gid1=2+1264]
+../fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf;;U+0E01,U+0E34,U+0E01;[gid1=0+1264|gid2=0+0|gid1=2+1264]
+../fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf;;U+0E01,U+0E34,U+0E01;[gid1=0+1264|gid2=0+0|gid1=2+1264]
+../fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf;;U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A;[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
+../fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf;;U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A;[gid1=0+1200|gid6=0@-1029,340+1200|gid3=2+1083|gid6=2@-992,0+1200|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+1200|gid5=8+528|gid6=8@-693,0+1200|gid2=10+528|gid2=11+528]
+../fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf;;U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A;[gid1=0+1200|gid6=0+0|gid3=2+1083|gid6=2+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6+0|gid5=8+528|gid6=8+0|gid2=10+528|gid2=11+528]
+../fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf;;U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A;[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
+../fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf;;U+0041,U+0042,U+0041;[A=0+1368|B=1+0|A=2+1368]
diff --git a/test/shaping/data/text-rendering-tests/COPYING b/test/shape/data/text-rendering-tests/COPYING
similarity index 100%
rename from test/shaping/data/text-rendering-tests/COPYING
rename to test/shape/data/text-rendering-tests/COPYING
diff --git a/test/shape/data/text-rendering-tests/DISABLED b/test/shape/data/text-rendering-tests/DISABLED
new file mode 100644
index 0000000..2728522
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/DISABLED
@@ -0,0 +1,21 @@
+# Non-Unicode cmap
+tests/CMAP-3.tests
+
+# Rounding differences
+tests/SHARAN-1.tests
+tests/SHBALI-1.tests
+tests/SHBALI-2.tests
+tests/SHKNDA-2.tests
+tests/SHKNDA-3.tests
+
+# TODO: Needs investigation
+tests/SHLANA-1.tests
+tests/SHLANA-2.tests
+tests/SHLANA-3.tests
+tests/SHLANA-4.tests
+tests/SHLANA-5.tests
+tests/SHLANA-6.tests
+tests/SHLANA-7.tests
+tests/SHLANA-8.tests
+tests/SHLANA-9.tests
+tests/SHLANA-10.tests
diff --git a/test/shape/data/text-rendering-tests/Makefile.am b/test/shape/data/text-rendering-tests/Makefile.am
new file mode 100644
index 0000000..19ac3b3
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/Makefile.am
@@ -0,0 +1,32 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
+update:
+	(cd $(srcdir) && ./update.sh)
+
+EXTRA_DIST = \
+	README \
+	COPYING \
+	DISABLED \
+	update.py \
+	meson.build \
+	fonts \
+	$(TESTS) \
+	$(NULL)
+
+TEST_EXTENSIONS = .tests
+if HAVE_FREETYPE
+TESTS_ENVIRONMENT = HAVE_FREETYPE=1
+else
+TESTS_ENVIRONMENT = HAVE_FREETYPE=0
+endif
+TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
+
+include Makefile.sources
+
+-include $(top_srcdir)/git.mk
diff --git a/test/shape/data/text-rendering-tests/Makefile.sources b/test/shape/data/text-rendering-tests/Makefile.sources
new file mode 100644
index 0000000..78d48eb
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/Makefile.sources
@@ -0,0 +1,95 @@
+TESTS = \
+	tests/AVAR-1.tests \
+	tests/CFF-1.tests \
+	tests/CFF-2.tests \
+	tests/CFF2-1.tests \
+	tests/CMAP-1.tests \
+	tests/CMAP-2.tests \
+	tests/CVAR-1.tests \
+	tests/CVAR-2.tests \
+	tests/GLYF-1.tests \
+	tests/GPOS-1.tests \
+	tests/GPOS-2.tests \
+	tests/GPOS-3.tests \
+	tests/GPOS-4.tests \
+	tests/GPOS-5.tests \
+	tests/GSUB-1.tests \
+	tests/GSUB-2.tests \
+	tests/GSUB-3.tests \
+	tests/GVAR-1.tests \
+	tests/GVAR-2.tests \
+	tests/GVAR-3.tests \
+	tests/GVAR-4.tests \
+	tests/GVAR-5.tests \
+	tests/GVAR-6.tests \
+	tests/GVAR-7.tests \
+	tests/GVAR-8.tests \
+	tests/GVAR-9.tests \
+	tests/HVAR-1.tests \
+	tests/HVAR-2.tests \
+	tests/KERN-1.tests \
+	tests/KERN-2.tests \
+	tests/MORX-1.tests \
+	tests/MORX-10.tests \
+	tests/MORX-11.tests \
+	tests/MORX-12.tests \
+	tests/MORX-13.tests \
+	tests/MORX-14.tests \
+	tests/MORX-16.tests \
+	tests/MORX-17.tests \
+	tests/MORX-18.tests \
+	tests/MORX-19.tests \
+	tests/MORX-2.tests \
+	tests/MORX-20.tests \
+	tests/MORX-21.tests \
+	tests/MORX-22.tests \
+	tests/MORX-23.tests \
+	tests/MORX-24.tests \
+	tests/MORX-25.tests \
+	tests/MORX-26.tests \
+	tests/MORX-27.tests \
+	tests/MORX-28.tests \
+	tests/MORX-29.tests \
+	tests/MORX-3.tests \
+	tests/MORX-30.tests \
+	tests/MORX-31.tests \
+	tests/MORX-32.tests \
+	tests/MORX-33.tests \
+	tests/MORX-34.tests \
+	tests/MORX-35.tests \
+	tests/MORX-36.tests \
+	tests/MORX-37.tests \
+	tests/MORX-38.tests \
+	tests/MORX-39.tests \
+	tests/MORX-4.tests \
+	tests/MORX-40.tests \
+	tests/MORX-41.tests \
+	tests/MORX-5.tests \
+	tests/MORX-6.tests \
+	tests/MORX-7.tests \
+	tests/MORX-8.tests \
+	tests/MORX-9.tests \
+	tests/SFNT-1.tests \
+	tests/SFNT-2.tests \
+	tests/SHBALI-3.tests \
+	tests/SHKNDA-1.tests \
+	$(NULL)
+
+DISBALED_TESTS = \
+	tests/CMAP-3.tests \
+	tests/SHARAN-1.tests \
+	tests/SHBALI-1.tests \
+	tests/SHBALI-2.tests \
+	tests/SHKNDA-2.tests \
+	tests/SHKNDA-3.tests \
+	tests/SHLANA-1.tests \
+	tests/SHLANA-10.tests \
+	tests/SHLANA-2.tests \
+	tests/SHLANA-3.tests \
+	tests/SHLANA-4.tests \
+	tests/SHLANA-5.tests \
+	tests/SHLANA-6.tests \
+	tests/SHLANA-7.tests \
+	tests/SHLANA-8.tests \
+	tests/SHLANA-9.tests \
+	$(NULL)
diff --git a/test/shaping/data/text-rendering-tests/README b/test/shape/data/text-rendering-tests/README
similarity index 100%
rename from test/shaping/data/text-rendering-tests/README
rename to test/shape/data/text-rendering-tests/README
diff --git a/test/shaping/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf b/test/shape/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf
rename to test/shape/data/text-rendering-tests/fonts/AdobeVFPrototype-Subset.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/FDArrayTest257.otf b/test/shape/data/text-rendering-tests/fonts/FDArrayTest257.otf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/FDArrayTest257.otf
rename to test/shape/data/text-rendering-tests/fonts/FDArrayTest257.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/FDArrayTest65535.otf b/test/shape/data/text-rendering-tests/fonts/FDArrayTest65535.otf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/FDArrayTest65535.otf
rename to test/shape/data/text-rendering-tests/fonts/FDArrayTest65535.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/NotoSansBalinese-Regular.ttf b/test/shape/data/text-rendering-tests/fonts/NotoSansBalinese-Regular.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/NotoSansBalinese-Regular.ttf
rename to test/shape/data/text-rendering-tests/fonts/NotoSansBalinese-Regular.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/NotoSansKannada-Regular.ttf b/test/shape/data/text-rendering-tests/fonts/NotoSansKannada-Regular.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/NotoSansKannada-Regular.ttf
rename to test/shape/data/text-rendering-tests/fonts/NotoSansKannada-Regular.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/NotoSerifKannada-Regular.ttf b/test/shape/data/text-rendering-tests/fonts/NotoSerifKannada-Regular.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/NotoSerifKannada-Regular.ttf
rename to test/shape/data/text-rendering-tests/fonts/NotoSerifKannada-Regular.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/Selawik-README.md b/test/shape/data/text-rendering-tests/fonts/Selawik-README.md
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/Selawik-README.md
rename to test/shape/data/text-rendering-tests/fonts/Selawik-README.md
diff --git a/test/shaping/data/text-rendering-tests/fonts/Selawik-variable.ttf b/test/shape/data/text-rendering-tests/fonts/Selawik-variable.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/Selawik-variable.ttf
rename to test/shape/data/text-rendering-tests/fonts/Selawik-variable.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestAVAR.ttf b/test/shape/data/text-rendering-tests/fonts/TestAVAR.ttf
new file mode 100644
index 0000000..4a16594
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestAVAR.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestCMAP14.otf b/test/shape/data/text-rendering-tests/fonts/TestCMAP14.otf
new file mode 100644
index 0000000..94b5ba9
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestCMAP14.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestCMAPMacTurkish.ttf b/test/shape/data/text-rendering-tests/fonts/TestCMAPMacTurkish.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestCMAPMacTurkish.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestCMAPMacTurkish.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestCVARGVAROne.ttf b/test/shape/data/text-rendering-tests/fonts/TestCVARGVAROne.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestCVARGVAROne.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestCVARGVAROne.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestCVARGVARTwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestCVARGVARTwo.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestCVARGVARTwo.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestCVARGVARTwo.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGLYFOne.ttf b/test/shape/data/text-rendering-tests/fonts/TestGLYFOne.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGLYFOne.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGLYFOne.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSFour.ttf b/test/shape/data/text-rendering-tests/fonts/TestGPOSFour.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGPOSFour.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGPOSFour.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSOne.ttf b/test/shape/data/text-rendering-tests/fonts/TestGPOSOne.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGPOSOne.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGPOSOne.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestGPOSThree.ttf b/test/shape/data/text-rendering-tests/fonts/TestGPOSThree.ttf
new file mode 100644
index 0000000..1ed3df4
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestGPOSThree.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestGPOSTwo.otf b/test/shape/data/text-rendering-tests/fonts/TestGPOSTwo.otf
new file mode 100644
index 0000000..55cceb7
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestGPOSTwo.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBOne.otf b/test/shape/data/text-rendering-tests/fonts/TestGSUBOne.otf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGSUBOne.otf
rename to test/shape/data/text-rendering-tests/fonts/TestGSUBOne.otf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shape/data/text-rendering-tests/fonts/TestGSUBThree.ttf
new file mode 100644
index 0000000..ec27e03
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestGSUBThree.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-0.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVAR-Composite-Missing.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAREight.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVAREight.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVAREight.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVAREight.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARFour.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVARFour.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVARFour.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVARFour.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestGVARNine.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVARNine.ttf
new file mode 100644
index 0000000..3dddf69
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestGVARNine.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVAROne.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVAROne.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVAROne.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVAROne.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARThree.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVARThree.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVARThree.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVARThree.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARTwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestGVARTwo.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestGVARTwo.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestGVARTwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestHVAROne.otf b/test/shape/data/text-rendering-tests/fonts/TestHVAROne.otf
new file mode 100644
index 0000000..07a3c54
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestHVAROne.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestHVARTwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestHVARTwo.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestHVARTwo.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestHVARTwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestKERNOne.otf b/test/shape/data/text-rendering-tests/fonts/TestKERNOne.otf
new file mode 100644
index 0000000..d3f7c0c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestKERNOne.otf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXEight.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXEight.ttf
new file mode 100644
index 0000000..a53de2e
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXEight.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXEighteen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXEighteen.ttf
new file mode 100644
index 0000000..c6e6343
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXEighteen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXEleven.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXEleven.ttf
new file mode 100644
index 0000000..b7e0f45
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXEleven.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXForty.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXForty.ttf
new file mode 100644
index 0000000..1d348dd
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXForty.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXFour.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXFour.ttf
new file mode 100644
index 0000000..07512ab
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXFour.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXFourteen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXFourteen.ttf
new file mode 100644
index 0000000..fb96112
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXFourteen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
new file mode 100644
index 0000000..be18c75
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXNine.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXNine.ttf
new file mode 100644
index 0000000..edbf4b1
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXNine.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXOne.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXOne.ttf
new file mode 100644
index 0000000..53d6466
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXOne.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf
new file mode 100644
index 0000000..4fe4fc2
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXSixteen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXSixteen.ttf
new file mode 100644
index 0000000..7cbc0eb
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXSixteen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTen.ttf
new file mode 100644
index 0000000..1d43897
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirteen.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirteen.ttf
new file mode 100644
index 0000000..48f81d1
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirteen.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
new file mode 100644
index 0000000..0968544
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
new file mode 100644
index 0000000..88d67ef
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
new file mode 100644
index 0000000..94d064f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
new file mode 100644
index 0000000..189061a
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
new file mode 100644
index 0000000..39455ea
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
new file mode 100644
index 0000000..9bdea11
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
new file mode 100644
index 0000000..28a522e
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
new file mode 100644
index 0000000..af887d9
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
new file mode 100644
index 0000000..e8314c7
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXThree.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXThree.ttf
new file mode 100644
index 0000000..33cc72b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXThree.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwelve.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwelve.ttf
new file mode 100644
index 0000000..b660833
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwelve.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwenty.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwenty.ttf
new file mode 100644
index 0000000..9d7d9ec
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwenty.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf
new file mode 100644
index 0000000..e02d354
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf
new file mode 100644
index 0000000..88c0866
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
new file mode 100644
index 0000000..3706325
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
new file mode 100644
index 0000000..10368bc
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf
new file mode 100644
index 0000000..e9e8413
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf
new file mode 100644
index 0000000..a459cb3
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf
new file mode 100644
index 0000000..040fd87
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf
new file mode 100644
index 0000000..18a90fd
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf
new file mode 100644
index 0000000..f2b6f6c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestMORXTwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestMORXTwo.ttf
new file mode 100644
index 0000000..365a635
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestMORXTwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestSFNTOne.otf b/test/shape/data/text-rendering-tests/fonts/TestSFNTOne.otf
new file mode 100644
index 0000000..974e286
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestSFNTOne.otf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestSFNTTwo.ttf b/test/shape/data/text-rendering-tests/fonts/TestSFNTTwo.ttf
new file mode 100644
index 0000000..a1d62cf
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestSFNTTwo.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf b/test/shape/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf
new file mode 100644
index 0000000..59cfc5a
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestSVGgzip.otf b/test/shape/data/text-rendering-tests/fonts/TestSVGgzip.otf
new file mode 100644
index 0000000..69d976f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestSVGgzip.otf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf b/test/shape/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf
new file mode 100644
index 0000000..50fdc19
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestShapeAran.ttf b/test/shape/data/text-rendering-tests/fonts/TestShapeAran.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestShapeAran.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestShapeAran.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestShapeEthi.ttf b/test/shape/data/text-rendering-tests/fonts/TestShapeEthi.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestShapeEthi.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestShapeEthi.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestShapeKndaV3.ttf b/test/shape/data/text-rendering-tests/fonts/TestShapeKndaV3.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/TestShapeKndaV3.ttf
rename to test/shape/data/text-rendering-tests/fonts/TestShapeKndaV3.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestShapeLana.ttf b/test/shape/data/text-rendering-tests/fonts/TestShapeLana.ttf
new file mode 100644
index 0000000..f7c3f81
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestShapeLana.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/fonts/TestTRAKOne.ttf b/test/shape/data/text-rendering-tests/fonts/TestTRAKOne.ttf
new file mode 100644
index 0000000..85f1d97
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/fonts/TestTRAKOne.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/Zycon.ttf b/test/shape/data/text-rendering-tests/fonts/Zycon.ttf
similarity index 100%
rename from test/shaping/data/text-rendering-tests/fonts/Zycon.ttf
rename to test/shape/data/text-rendering-tests/fonts/Zycon.ttf
Binary files differ
diff --git a/test/shape/data/text-rendering-tests/meson.build b/test/shape/data/text-rendering-tests/meson.build
new file mode 100644
index 0000000..0d950f5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/meson.build
@@ -0,0 +1,95 @@
+text_rendering_tests = [
+  'AVAR-1.tests',
+  'CFF-1.tests',
+  'CFF-2.tests',
+  'CFF2-1.tests',
+  'CMAP-1.tests',
+  'CMAP-2.tests',
+  'CVAR-1.tests',
+  'CVAR-2.tests',
+  'GLYF-1.tests',
+  'GPOS-1.tests',
+  'GPOS-2.tests',
+  'GPOS-3.tests',
+  'GPOS-4.tests',
+  'GPOS-5.tests',
+  'GSUB-1.tests',
+  'GSUB-2.tests',
+  'GSUB-3.tests',
+  'GVAR-1.tests',
+  'GVAR-2.tests',
+  'GVAR-3.tests',
+  'GVAR-4.tests',
+  'GVAR-5.tests',
+  'GVAR-6.tests',
+  'GVAR-7.tests',
+  'GVAR-8.tests',
+  'GVAR-9.tests',
+  'HVAR-1.tests',
+  'HVAR-2.tests',
+  'KERN-1.tests',
+  'KERN-2.tests',
+  'MORX-1.tests',
+  'MORX-10.tests',
+  'MORX-11.tests',
+  'MORX-12.tests',
+  'MORX-13.tests',
+  'MORX-14.tests',
+  'MORX-16.tests',
+  'MORX-17.tests',
+  'MORX-18.tests',
+  'MORX-19.tests',
+  'MORX-2.tests',
+  'MORX-20.tests',
+  'MORX-21.tests',
+  'MORX-22.tests',
+  'MORX-23.tests',
+  'MORX-24.tests',
+  'MORX-25.tests',
+  'MORX-26.tests',
+  'MORX-27.tests',
+  'MORX-28.tests',
+  'MORX-29.tests',
+  'MORX-3.tests',
+  'MORX-30.tests',
+  'MORX-31.tests',
+  'MORX-32.tests',
+  'MORX-33.tests',
+  'MORX-34.tests',
+  'MORX-35.tests',
+  'MORX-36.tests',
+  'MORX-37.tests',
+  'MORX-38.tests',
+  'MORX-39.tests',
+  'MORX-4.tests',
+  'MORX-40.tests',
+  'MORX-41.tests',
+  'MORX-5.tests',
+  'MORX-6.tests',
+  'MORX-7.tests',
+  'MORX-8.tests',
+  'MORX-9.tests',
+  'SFNT-1.tests',
+  'SFNT-2.tests',
+  'SHBALI-3.tests',
+  'SHKNDA-1.tests',
+]
+
+disabled_text_rendering_tests = [
+  'CMAP-3.tests',
+  'SHARAN-1.tests',
+  'SHBALI-1.tests',
+  'SHBALI-2.tests',
+  'SHKNDA-2.tests',
+  'SHKNDA-3.tests',
+  'SHLANA-1.tests',
+  'SHLANA-10.tests',
+  'SHLANA-2.tests',
+  'SHLANA-3.tests',
+  'SHLANA-4.tests',
+  'SHLANA-5.tests',
+  'SHLANA-6.tests',
+  'SHLANA-7.tests',
+  'SHLANA-8.tests',
+  'SHLANA-9.tests',
+]
diff --git a/test/shape/data/text-rendering-tests/tests/AVAR-1.tests b/test/shape/data/text-rendering-tests/tests/AVAR-1.tests
new file mode 100644
index 0000000..b6203c0
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/AVAR-1.tests
@@ -0,0 +1,17 @@
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=100;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=150;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=200;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=250;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=300;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=350;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=400;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=450;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=500;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=550;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=600;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=650;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=700;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=750;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=800;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=850;U+2A01;[gid1]
+../fonts/TestAVAR.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=900;U+2A01;[gid1]
diff --git a/test/shape/data/text-rendering-tests/tests/CFF-1.tests b/test/shape/data/text-rendering-tests/tests/CFF-1.tests
new file mode 100644
index 0000000..0d0d252
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CFF-1.tests
@@ -0,0 +1,13 @@
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[gid66]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+211D;[gid30]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+24EA;[gid235]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2460;[gid97]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2461;[gid98]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+4EFF;[gid256]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+FF21;[gid34]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+10133;[gid52]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1D4D0;[gid209]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F33A;[gid59]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F33B;[gid60]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F4A7;[gid168]
+../fonts/FDArrayTest257.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F95D;[gid94]
diff --git a/test/shape/data/text-rendering-tests/tests/CFF-2.tests b/test/shape/data/text-rendering-tests/tests/CFF-2.tests
new file mode 100644
index 0000000..3893b14
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CFF-2.tests
@@ -0,0 +1,13 @@
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[gid66]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+211D;[gid8478]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+24EA;[gid9451]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2460;[gid9313]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2461;[gid9314]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+4EFF;[gid20224]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+FF21;[gid65314]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+10133;[gid308]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1D4D0;[gid54481]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F33A;[gid62267]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F33B;[gid62268]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F4A7;[gid62632]
+../fonts/FDArrayTest65535.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1F95D;[gid63838]
diff --git a/test/shape/data/text-rendering-tests/tests/CFF2-1.tests b/test/shape/data/text-rendering-tests/tests/CFF2-1.tests
new file mode 100644
index 0000000..97ead22
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CFF2-1.tests
@@ -0,0 +1,9 @@
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=100;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700;U+0024;[dollar]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800;U+0024;[dollar.nostroke]
+../fonts/AdobeVFPrototype-Subset.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=900;U+0024;[dollar.nostroke]
diff --git a/test/shape/data/text-rendering-tests/tests/CMAP-1.tests b/test/shape/data/text-rendering-tests/tests/CMAP-1.tests
new file mode 100644
index 0000000..708c0be
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CMAP-1.tests
@@ -0,0 +1,4 @@
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+82A6;[uni82A6_uE0100]
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+82A6,U+E0100;[uni82A6_uE0100]
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+82A6,U+E0101;[uni82A6_uE0101]
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+82A6,U+E0102;[uni82A6_uE0100]
diff --git a/test/shape/data/text-rendering-tests/tests/CMAP-2.tests b/test/shape/data/text-rendering-tests/tests/CMAP-2.tests
new file mode 100644
index 0000000..d035f7c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CMAP-2.tests
@@ -0,0 +1,2 @@
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2269;[uni2269]
+../fonts/TestCMAP14.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+2269,U+FE00;[uni2269FE00]
diff --git a/test/shape/data/text-rendering-tests/tests/CMAP-3.tests b/test/shape/data/text-rendering-tests/tests/CMAP-3.tests
new file mode 100644
index 0000000..2ad17ea
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CMAP-3.tests
@@ -0,0 +1,20 @@
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+201C;[gid200]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[gid34]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[gid35]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00C7;[gid126]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+011E;[gid176]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0049;[gid42]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0130;[gid178]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00D6;[gid140]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+015E;[gid181]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00DC;[gid145]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+201D;[gid201]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0061;[gid66]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0062;[gid67]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00E7;[gid154]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+011F;[gid177]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0131;[gid222]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0069;[gid74]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00F6;[gid168]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+015F;[gid182]
+../fonts/TestCMAPMacTurkish.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+00FC;[gid174]
diff --git a/test/shape/data/text-rendering-tests/tests/CVAR-1.tests b/test/shape/data/text-rendering-tests/tests/CVAR-1.tests
new file mode 100644
index 0000000..a4dd2a5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CVAR-1.tests
@@ -0,0 +1,3 @@
+../fonts/TestCVARGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=28,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@595,0|uni006E@1126,0]
+../fonts/TestCVARGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=94,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@635,0|uni006E@1212,0]
+../fonts/TestCVARGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=194,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@691,0|uni006E@1331,0]
diff --git a/test/shape/data/text-rendering-tests/tests/CVAR-2.tests b/test/shape/data/text-rendering-tests/tests/CVAR-2.tests
new file mode 100644
index 0000000..f797c94
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/CVAR-2.tests
@@ -0,0 +1,3 @@
+../fonts/TestCVARGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=28,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@595,0|uni006E@1126,0]
+../fonts/TestCVARGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=94,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@635,0|uni006E@1212,0]
+../fonts/TestCVARGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=194,wdth=100,opsz=72;U+0068,U+006F,U+006E;[uni0068|uni006F@691,0|uni006E@1331,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GLYF-1.tests b/test/shape/data/text-rendering-tests/tests/GLYF-1.tests
new file mode 100644
index 0000000..6b49191
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GLYF-1.tests
@@ -0,0 +1 @@
+../fonts/TestGLYFOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0123;[gcommaabove]
diff --git a/test/shape/data/text-rendering-tests/tests/GPOS-1.tests b/test/shape/data/text-rendering-tests/tests/GPOS-1.tests
new file mode 100644
index 0000000..dfdf0b4
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GPOS-1.tests
@@ -0,0 +1,19 @@
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0104,U+004A;[Aogonek|J@732,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0104,U+0067;[Aogonek|g@692,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0104,U+0123;[Aogonek|gcommaabove@692,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0104,U+006A;[Aogonek|j@752,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0104,U+0237;[Aogonek|dotlessj@752,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0051,U+0237;[Q|dotlessj@734,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0105,U+006A;[aogonek|j@588,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0105,U+0237;[aogonek|dotlessj@588,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0067,U+0237;[g|dotlessj@563,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0123,U+0237;[gcommaabove|dotlessj@563,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0131,U+0237;[dotlessi|dotlessj@334,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0173,U+0237;[uogonek|dotlessj@656,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0076,U+0237;[v|dotlessj@587,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+0061;[V|a@594,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+00E1;[V|aacute@594,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+0105;[V|aogonek@594,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+0066;[V|f@634,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+FB02;[V|fl@634,0]
+../fonts/TestGPOSOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0056,U+002E;[V|period@504,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GPOS-2.tests b/test/shape/data/text-rendering-tests/tests/GPOS-2.tests
new file mode 100644
index 0000000..3784c40
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GPOS-2.tests
@@ -0,0 +1,3 @@
+../fonts/TestGPOSTwo.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+25EF;[uni25EF]
+../fonts/TestGPOSTwo.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+263C;[sun]
+../fonts/TestGPOSTwo.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+25EF,U+263C;[uni25EF|sun]
diff --git a/test/shape/data/text-rendering-tests/tests/GPOS-3.tests b/test/shape/data/text-rendering-tests/tests/GPOS-3.tests
new file mode 100644
index 0000000..e72d82b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GPOS-3.tests
@@ -0,0 +1,4 @@
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1208;[uni1208]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1208,U+135E;[uni1208|uni135E@303,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1208,U+135F;[uni1208|uni135F@303,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1208,U+135D;[uni1208|uni135D@303,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GPOS-4.tests b/test/shape/data/text-rendering-tests/tests/GPOS-4.tests
new file mode 100644
index 0000000..7596c50
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GPOS-4.tests
@@ -0,0 +1,4 @@
+../fonts/TestGPOSThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0075,U+0308,U+0301;[u|uni0308@529,-31|acutecomb@537,138]
+../fonts/TestGPOSThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0075,U+0308,U+0304;[u|uni0308@529,-31|uni0304@526,138]
+../fonts/TestGPOSThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0075,U+0308,U+0308;[u|uni0308@529,-31|uni0308@529,138]
+../fonts/TestGPOSThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0075,U+0308,U+0308,U+0308;[u|uni0308@529,-31|uni0308@529,138|uni0308@529,307]
diff --git a/test/shape/data/text-rendering-tests/tests/GPOS-5.tests b/test/shape/data/text-rendering-tests/tests/GPOS-5.tests
new file mode 100644
index 0000000..821a19b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GPOS-5.tests
@@ -0,0 +1,5 @@
+../fonts/TestGPOSFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=100;U+0634,U+0652;[uni0652@663,144|uni0634]
+../fonts/TestGPOSFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+0634,U+0652;[uni0652@680,165|uni0634]
+../fonts/TestGPOSFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+0634,U+0652;[uni0652@730,246|uni0634]
+../fonts/TestGPOSFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700;U+0634,U+0652;[uni0652@750,282|uni0634]
+../fonts/TestGPOSFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=900;U+0634,U+0652;[uni0652@784,351|uni0634]
diff --git a/test/shape/data/text-rendering-tests/tests/GSUB-1.tests b/test/shape/data/text-rendering-tests/tests/GSUB-1.tests
new file mode 100644
index 0000000..7e185f7
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GSUB-1.tests
@@ -0,0 +1 @@
+../fonts/TestGSUBOne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0061,U+0020,U+0061;[a.alt|space@500,0|a@1000,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GSUB-2.tests b/test/shape/data/text-rendering-tests/tests/GSUB-2.tests
new file mode 100644
index 0000000..ef418c2
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GSUB-2.tests
@@ -0,0 +1,11 @@
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1373;[uni1373]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+136B;[uni136B]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1375;[uni1375]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+136D;[uni136D]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1373,U+136B;[uni1373.init|uni136B.fina@621,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1375,U+136D;[uni1375.init|uni136D.fina@662,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+137B;[uni137B]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1373,U+136B,U+137B;[uni1373.init|uni136B.medi@621,0|uni137B.fina@1102,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1373,U+136B,U+137B,U+1373,U+136B;[uni1373.init|uni136B.medi@621,0|uni137B.medi@1102,0|uni1373.medi@1489,0|uni136B.fina@2110,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1373,U+136B,U+137B,U+1375,U+136D;[uni1373.init|uni136B.medi@621,0|uni137B.medi@1102,0|uni1375.medi@1489,0|uni136D.fina@2157,0]
+../fonts/TestShapeEthi.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1375,U+136D,U+137B,U+1373,U+136B;[uni1375.init|uni136D.medi@662,0|uni137B.medi@1203,0|uni1373.medi@1590,0|uni136B.fina@2211,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GSUB-3.tests b/test/shape/data/text-rendering-tests/tests/GSUB-3.tests
new file mode 100644
index 0000000..6fcc09c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GSUB-3.tests
@@ -0,0 +1 @@
+../fonts/TestGSUBThree.ttf;;U+006C,U+006F,U+006C;*
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-1.tests b/test/shape/data/text-rendering-tests/tests/GVAR-1.tests
new file mode 100644
index 0000000..8c36b36
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-1.tests
@@ -0,0 +1,9 @@
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650;U+5F4C;[gid2]
+../fonts/TestGVAROne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700;U+5F4C;[gid2]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-2.tests b/test/shape/data/text-rendering-tests/tests/GVAR-2.tests
new file mode 100644
index 0000000..414eca5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-2.tests
@@ -0,0 +1,9 @@
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650;U+5F4C;[gid2]
+../fonts/TestGVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700;U+5F4C;[gid2]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-3.tests b/test/shape/data/text-rendering-tests/tests/GVAR-3.tests
new file mode 100644
index 0000000..e9ba906
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-3.tests
@@ -0,0 +1,9 @@
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650;U+5F4C;[gid2]
+../fonts/TestGVARThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700;U+5F4C;[gid2]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-4.tests b/test/shape/data/text-rendering-tests/tests/GVAR-4.tests
new file mode 100644
index 0000000..2fc216f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-4.tests
@@ -0,0 +1,11 @@
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-1.0,T1=0.0;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.8,T1=0.1;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.6,T1=0.2;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.4,T1=0.3;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.2,T1=0.4;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.0,T1=0.5;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.2,T1=0.6;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.4,T1=0.7;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.6,T1=0.8;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.8,T1=0.9;U+1F98E;[gid5]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=1.0,T1=1.0;U+1F98E;[gid5]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-5.tests b/test/shape/data/text-rendering-tests/tests/GVAR-5.tests
new file mode 100644
index 0000000..4df737d
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-5.tests
@@ -0,0 +1,11 @@
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-1.0;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.8;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.6;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.4;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.2;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.0;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.2;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.4;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.6;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.8;U+1F31D;[gid15]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=1.0;U+1F31D;[gid15]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-6.tests b/test/shape/data/text-rendering-tests/tests/GVAR-6.tests
new file mode 100644
index 0000000..500337b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-6.tests
@@ -0,0 +1,11 @@
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.0;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.1;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.2;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.3;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.4;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.5;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.6;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.7;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.8;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.9;U+1F422;[gid12]
+../fonts/Zycon.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=1.0;U+1F422;[gid12]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-7.tests b/test/shape/data/text-rendering-tests/tests/GVAR-7.tests
new file mode 100644
index 0000000..a246ec3
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-7.tests
@@ -0,0 +1,7 @@
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=150;U+004F,U+0049,U+004F;[uni004F|uni0049@706,0|uni004F@1072,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200;U+004F,U+0049,U+004F;[uni004F|uni0049@707,0|uni004F@1074,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=250;U+004F,U+0049,U+004F;[uni004F|uni0049@707,0|uni004F@1075,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300;U+004F,U+0049,U+004F;[uni004F|uni0049@707,0|uni004F@1076,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350;U+004F,U+0049,U+004F;[uni004F|uni0049@707,0|uni004F@1077,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+004F,U+0049,U+004F;[uni004F|uni0049@707,0|uni004F@1078,0]
+../fonts/TestGVARFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450;U+004F,U+0049,U+004F;[uni004F|uni0049@706,0|uni004F@1079,0]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-8.tests b/test/shape/data/text-rendering-tests/tests/GVAR-8.tests
new file mode 100644
index 0000000..4b4b54d
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-8.tests
@@ -0,0 +1,6 @@
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=0.0;U+0048;[H]
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.2;U+0048;[H]
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.4;U+0048;[H]
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.6;U+0048;[H]
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.8;U+0048;[H]
+../fonts/TestGVAREight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-1.0;U+0048;[H]
diff --git a/test/shape/data/text-rendering-tests/tests/GVAR-9.tests b/test/shape/data/text-rendering-tests/tests/GVAR-9.tests
new file mode 100644
index 0000000..bf0f3e5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/GVAR-9.tests
@@ -0,0 +1,10 @@
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=-1.0;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=-0.5;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.0;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.5;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.6;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.7;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.8;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.9;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.944444;U+0041;[A]
+../fonts/TestGVARNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=1.0;U+0041;[A]
diff --git a/test/shape/data/text-rendering-tests/tests/HVAR-1.tests b/test/shape/data/text-rendering-tests/tests/HVAR-1.tests
new file mode 100644
index 0000000..dbc4ba1
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/HVAR-1.tests
@@ -0,0 +1,6 @@
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=0;U+0041,U+0042,U+0043;[A|B@520,0|C@1094,0]
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200;U+0041,U+0042,U+0043;[A|B@533,0|C@1115,0]
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+0041,U+0042,U+0043;[A|B@546,0|C@1135,0]
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+0041,U+0042,U+0043;[A|B@558,0|C@1155,0]
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800;U+0041,U+0042,U+0043;[A|B@571,0|C@1175,0]
+../fonts/TestHVAROne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=1000;U+0041,U+0042,U+0043;[A|B@584,0|C@1196,0]
diff --git a/test/shape/data/text-rendering-tests/tests/HVAR-2.tests b/test/shape/data/text-rendering-tests/tests/HVAR-2.tests
new file mode 100644
index 0000000..aa086e3
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/HVAR-2.tests
@@ -0,0 +1,6 @@
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=0;U+0041,U+0042;[uni0041|uni0042@450,0]
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200;U+0041,U+0042;[uni0041|uni0042@515,0]
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400;U+0041,U+0042;[uni0041|uni0042@584,0]
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600;U+0041,U+0042;[uni0041|uni0042@673,0]
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800;U+0041,U+0042;[uni0041|uni0042@761,0]
+../fonts/TestHVARTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=1000;U+0041,U+0042;[uni0041|uni0042@850,0]
diff --git a/test/shape/data/text-rendering-tests/tests/KERN-1.tests b/test/shape/data/text-rendering-tests/tests/KERN-1.tests
new file mode 100644
index 0000000..e72beff
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/KERN-1.tests
@@ -0,0 +1 @@
+../fonts/TestKERNOne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0131,U+0054,U+0075,U+0054,U+0075,U+0054,U+0131;[dotlessi|T|u@400,0|T@600,0|u@1000,0|T@1200,0|dotlessi@1600,0]
diff --git a/test/shape/data/text-rendering-tests/tests/KERN-2.tests b/test/shape/data/text-rendering-tests/tests/KERN-2.tests
new file mode 100644
index 0000000..1601eef
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/KERN-2.tests
@@ -0,0 +1 @@
+../fonts/TestKERNOne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0075,U+0131,U+0131,U+0054,U+0131,U+0131,U+0054,U+0131,U+0131,U+0075;[u|dotlessi@400,0|dotlessi@1100,0|T@1100,0|dotlessi@1500,0|dotlessi@2200,0|T@2200,0|dotlessi@2600,0|dotlessi@3300,0|u@3500,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-1.tests b/test/shape/data/text-rendering-tests/tests/MORX-1.tests
new file mode 100644
index 0000000..175fd73
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-1.tests
@@ -0,0 +1 @@
+../fonts/TestMORXOne.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043;[A.alt|B@1000,0|C.alt@2000,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-10.tests b/test/shape/data/text-rendering-tests/tests/MORX-10.tests
new file mode 100644
index 0000000..ea9a6d5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-10.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0041,U+0042,U+0041,U+0042;[A|B@638,0|A@1288,0|B@1926,0|B@2576,0|A@3226,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-11.tests b/test/shape/data/text-rendering-tests/tests/MORX-11.tests
new file mode 100644
index 0000000..adbad2a
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-11.tests
@@ -0,0 +1 @@
+../fonts/TestMORXEleven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041,U+0042,U+0042,U+0041,U+0041,U+0042,U+0058;[B|A@650,0|B@1288,0|B@1938,0|A@2588,0|X@3226,0|A@3812,0|B@4450,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-12.tests b/test/shape/data/text-rendering-tests/tests/MORX-12.tests
new file mode 100644
index 0000000..a37aa72
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-12.tests
@@ -0,0 +1,3 @@
+../fonts/TestMORXTwelve.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0041,U+0042,U+0043,U+0058,U+0031;[X|C@598,0|A@1230,0|B@1868,0|X@2518,0|one@3116,0]
+../fonts/TestMORXTwelve.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0041,U+0042,U+0043,U+0058,U+0032;[X|C@598,0|A@1230,0|B@1868,0|X@2518,0|two@3116,0]
+../fonts/TestMORXTwelve.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0041,U+0042,U+0043,U+0058,U+0033;[X|B@598,0|C@1248,0|A@1880,0|X@2518,0|three@3116,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-13.tests b/test/shape/data/text-rendering-tests/tests/MORX-13.tests
new file mode 100644
index 0000000..3273b57
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-13.tests
@@ -0,0 +1 @@
+../fonts/TestMORXThirteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-14.tests b/test/shape/data/text-rendering-tests/tests/MORX-14.tests
new file mode 100644
index 0000000..9526005
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-14.tests
@@ -0,0 +1,2 @@
+../fonts/TestMORXFourteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
+../fonts/TestMORXFourteen.ttf;;U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045;*
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-16.tests b/test/shape/data/text-rendering-tests/tests/MORX-16.tests
new file mode 100644
index 0000000..a87e84b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-16.tests
@@ -0,0 +1 @@
+../fonts/TestMORXSixteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-17.tests b/test/shape/data/text-rendering-tests/tests/MORX-17.tests
new file mode 100644
index 0000000..066137f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-17.tests
@@ -0,0 +1 @@
+../fonts/TestMORXSeventeen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[B|A@626,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-18.tests b/test/shape/data/text-rendering-tests/tests/MORX-18.tests
new file mode 100644
index 0000000..c065439
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-18.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[A|B.alt@639,0|C@1639,0|D.alt1@2235,0|E@3235,0]
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0042,U+0042,U+0044,U+0045;[A|B@639,0|B@1265,0|B.alt@1891,0|D.alt1@2891,0|E@3891,0]
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0044,U+0045;[A|B.alt@639,0|D.alt1@1639,0|E@2639,0]
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0045;[A|B@639,0|E@1265,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-19.tests b/test/shape/data/text-rendering-tests/tests/MORX-19.tests
new file mode 100644
index 0000000..ccc03ac
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-19.tests
@@ -0,0 +1,2 @@
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0043,U+0044,U+0045;[A.alt|C@1000,0|D.alt1@1596,0|E@2596,0]
+../fonts/TestMORXEighteen.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0044;[D.alt]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-2.tests b/test/shape/data/text-rendering-tests/tests/MORX-2.tests
new file mode 100644
index 0000000..a1ff184
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-2.tests
@@ -0,0 +1,16 @@
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24FF;[O|O@418,0|O@836,0|A@1254,0|B@2084,0|X@2914,0|Y@3744,0|Z@4574,0|C@5404,0|D@6234,0|O@7064,0|O@7482,0|O@7900,0|zero@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+278A;[O|O@418,0|O@836,0|B@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|D@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+278B;[O|O@418,0|O@836,0|D@1254,0|A@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|C@6234,0|O@7064,0|O@7482,0|O@7900,0|two@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0033;[O|O@418,0|O@836,0|D@1254,0|B@2084,0|X@2914,0|Y@3744,0|Z@4574,0|C@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|three@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0034;[O|O@418,0|O@836,0|X@1254,0|Y@2084,0|Z@2914,0|C@3744,0|D@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|four@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0035;[O|O@418,0|O@836,0|X@1254,0|Y@2084,0|Z@2914,0|C@3744,0|D@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|five@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0036;[O|O@418,0|O@836,0|C@1254,0|D@2084,0|A@2914,0|B@3744,0|X@4574,0|Y@5404,0|Z@6234,0|O@7064,0|O@7482,0|O@7900,0|six@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0037;[O|O@418,0|O@836,0|D@1254,0|C@2084,0|A@2914,0|B@3744,0|X@4574,0|Y@5404,0|Z@6234,0|O@7064,0|O@7482,0|O@7900,0|seven@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0038;[O|O@418,0|O@836,0|C@1254,0|D@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|eight@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0039;[O|O@418,0|O@836,0|D@1254,0|C@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|nine@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+2793;[O|O@418,0|O@836,0|D@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_zero@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EB;[O|O@418,0|O@836,0|D@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_one@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EC;[O|O@418,0|O@836,0|C@1254,0|D@2084,0|X@2914,0|Y@3744,0|Z@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_two@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24ED;[O|O@418,0|O@836,0|C@1254,0|D@2084,0|X@2914,0|Y@3744,0|Z@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_three@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EE;[O|O@418,0|O@836,0|D@1254,0|C@2084,0|X@2914,0|Y@3744,0|Z@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_four@8318,0]
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EF;[O|O@418,0|O@836,0|D@1254,0|C@2084,0|X@2914,0|Y@3744,0|Z@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_five@8318,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-20.tests b/test/shape/data/text-rendering-tests/tests/MORX-20.tests
new file mode 100644
index 0000000..1f599a1
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-20.tests
@@ -0,0 +1,7 @@
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[A|B@639,0|C.alt@1265,0|D@2265,0|E.alt1@2939,0]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043;[A|B@639,0|C.alt@1265,0]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0045;[A|B.alt@639,0|E.alt1@1639,0]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045;[A.alt|E.alt1@1000,0]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0045,U+0045;[E|E@556,0]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[A.alt]
+../fonts/TestMORXTwenty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0045;[E]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-21.tests b/test/shape/data/text-rendering-tests/tests/MORX-21.tests
new file mode 100644
index 0000000..0014de7
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-21.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwentyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[A|B.alt@639,0|C@1639,0|D@2235,0|E@2909,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-22.tests b/test/shape/data/text-rendering-tests/tests/MORX-22.tests
new file mode 100644
index 0000000..76136d6
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-22.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwentytwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[C]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-23.tests b/test/shape/data/text-rendering-tests/tests/MORX-23.tests
new file mode 100644
index 0000000..3ae018f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-23.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwentythree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[E|E@556,0|E@1112,0|E@1668,0|E@2224,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-24.tests b/test/shape/data/text-rendering-tests/tests/MORX-24.tests
new file mode 100644
index 0000000..9c1af89
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-24.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwentyfour.ttf;;U+0041,U+0042,U+0043,U+0044,U+0045;*
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-25.tests b/test/shape/data/text-rendering-tests/tests/MORX-25.tests
new file mode 100644
index 0000000..cec3be4
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-25.tests
@@ -0,0 +1,9 @@
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043,U+0044,U+0045;[A.alt|B.alt@1000,0|C.alt@2000,0|D.alt@3000,0|E.alt@4000,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0045,U+0042,U+0043,U+0044,U+0041;[E|B@556,0|C@1182,0|D@1778,0|A@2452,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0043,U+0042,U+0041,U+0042,U+0043;[C|B@596,0|A.alt@1222,0|B.alt@2222,0|C.alt@3222,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0043;[A.alt|B.alt@1000,0|C.alt@2000,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0043,U+0042,U+0041;[C|B@596,0|A@1222,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A.alt|B.alt@1000,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041;[B|A@626,0]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[A]
+../fonts/TestMORXTwentyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[B]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-26.tests b/test/shape/data/text-rendering-tests/tests/MORX-26.tests
new file mode 100644
index 0000000..18683e9
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-26.tests
@@ -0,0 +1,2 @@
+../fonts/TestMORXTwentysix.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A|B@639,0]
+../fonts/TestMORXTwentysix.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[B.alt]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-27.tests b/test/shape/data/text-rendering-tests/tests/MORX-27.tests
new file mode 100644
index 0000000..b830f75
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-27.tests
@@ -0,0 +1,3 @@
+../fonts/TestMORXTwentyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045,U+0042;[A_E_B]
+../fonts/TestMORXTwentyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045,U+0043;[A_E_C]
+../fonts/TestMORXTwentyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045,U+0044;[A_E_D]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-28.tests b/test/shape/data/text-rendering-tests/tests/MORX-28.tests
new file mode 100644
index 0000000..19d930c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-28.tests
@@ -0,0 +1,5 @@
+../fonts/TestMORXTwentyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045,U+0044;[A_E_D]
+../fonts/TestMORXTwentyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0078,U+0045,U+0044;[A_E_D|x@1394,0]
+../fonts/TestMORXTwentyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0045,U+0079,U+0044;[A_E_D|y@1394,0]
+../fonts/TestMORXTwentyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0078,U+0045,U+0079,U+0044;[A_E_D|x@1394,0|y@1923,0]
+../fonts/TestMORXTwentyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0078,U+0078,U+0078,U+0045,U+0079,U+0079,U+0079,U+0044;[A_E_D|x@1394,0|x@1923,0|x@2452,0|y@2981,0|y@3491,0|y@4001,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-29.tests b/test/shape/data/text-rendering-tests/tests/MORX-29.tests
new file mode 100644
index 0000000..7ef9112
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-29.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0041,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|I@4268,0|N@5098,0|S@5928,0|M@6758,0|Y@7588,0|Y@7920,0|A@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0042,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|I@5098,0|N@5928,0|S@6758,0|Y@7588,0|Y@7920,0|B@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0043,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|I@5762,0|N@6592,0|S@7422,0|C@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0044,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|D@5762,0|I@6592,0|N@7422,0|S@8252,0|Z@9082,0|Z@9404,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-3.tests b/test/shape/data/text-rendering-tests/tests/MORX-3.tests
new file mode 100644
index 0000000..cbb8c15
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-3.tests
@@ -0,0 +1,16 @@
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0030;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|zero@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0031;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0032;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|two@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0033;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|three@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0034;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|four@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0035;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|five@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0036;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|six@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0037;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|seven@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0038;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|eight@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+0039;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|nine@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+2793;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_zero@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+24EB;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_one@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+24EC;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_two@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+24ED;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_three@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+24EE;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_four@1793,0]
+../fonts/TestMORXThree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0043,U+0044,U+24EF;[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_five@1793,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-30.tests b/test/shape/data/text-rendering-tests/tests/MORX-30.tests
new file mode 100644
index 0000000..aa0f3a7
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-30.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|I@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|I@2710,0|N@3540,0|S@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|M@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A;[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|I@2710,0|N@3540,0|S@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-31.tests b/test/shape/data/text-rendering-tests/tests/MORX-31.tests
new file mode 100644
index 0000000..e6a3014
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-31.tests
@@ -0,0 +1,8 @@
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A;[I|N@830,0|I@1660,0|N@2490,0|S@3320,0|S@4150,0|X@4980,0|X@5344,0|A@5708,0|Y@6538,0|Y@6870,0|A@7202,0|Z@8032,0|Z@8354,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+0059,U+0059;[I|N@830,0|S@1660,0|I@2490,0|N@3320,0|S@4150,0|X@4980,0|X@5344,0|A@5708,0|Y@6538,0|Y@6870,0|B@7202,0|Y@8032,0|Y@8364,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A;[X|I@364,0|I@1194,0|N@2024,0|S@2854,0|N@3684,0|S@4514,0|X@5344,0|B@5708,0|Y@6538,0|Y@6870,0|A@7202,0|Z@8032,0|Z@8354,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A;[X|I@364,0|N@1194,0|I@2024,0|N@2854,0|S@3684,0|S@4514,0|X@5344,0|B@5708,0|Y@6538,0|Y@6870,0|B@7202,0|Z@8032,0|Z@8354,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0041;[I|N@830,0|S@1660,0|M@2490,0|I@3320,0|N@4150,0|S@4980,0|P@5810,0|Q@6143,0|R@6509,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0042;[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|I@3653,0|N@4483,0|S@5313,0|Q@6143,0|R@6509,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0041;[M|I@830,0|N@1660,0|S@2490,0|I@3320,0|N@4150,0|S@4980,0|P@5810,0|Q@6143,0|R@6509,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
+../fonts/TestMORXThirtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0042;[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|I@3653,0|N@4483,0|S@5313,0|Q@6143,0|R@6509,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-32.tests b/test/shape/data/text-rendering-tests/tests/MORX-32.tests
new file mode 100644
index 0000000..4419135
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-32.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtytwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[I|N@830,0|S@1660,0|A@2490,0]
+../fonts/TestMORXThirtytwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0041,U+0059;[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
+../fonts/TestMORXThirtytwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[B|I@830,0|N@1660,0|S@2490,0]
+../fonts/TestMORXThirtytwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0042,U+0059;[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-33.tests b/test/shape/data/text-rendering-tests/tests/MORX-33.tests
new file mode 100644
index 0000000..ddff193
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-33.tests
@@ -0,0 +1,3 @@
+../fonts/TestMORXThirtythree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0068,U+0061;[h|a@618,0|h@1179,0|a@1797,0]
+../fonts/TestMORXThirtythree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0068,U+0061,U+0068,U+0061;[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0]
+../fonts/TestMORXThirtythree.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0061,U+0068;[a|h@561,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-34.tests b/test/shape/data/text-rendering-tests/tests/MORX-34.tests
new file mode 100644
index 0000000..cb89ba8
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-34.tests
@@ -0,0 +1 @@
+../fonts/TestMORXThirtyfour.ttf;;U+0068,U+0061;*
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-35.tests b/test/shape/data/text-rendering-tests/tests/MORX-35.tests
new file mode 100644
index 0000000..f804943
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-35.tests
@@ -0,0 +1,2 @@
+../fonts/TestMORXThirtyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[A|B@639,0|C@1265,0|E@1861,0]
+../fonts/TestMORXThirtyfive.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0058,U+0041,U+0059;[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-36.tests b/test/shape/data/text-rendering-tests/tests/MORX-36.tests
new file mode 100644
index 0000000..7739c03
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-36.tests
@@ -0,0 +1 @@
+../fonts/TestMORXThirtysix.ttf;;U+0041;*
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-37.tests b/test/shape/data/text-rendering-tests/tests/MORX-37.tests
new file mode 100644
index 0000000..1105e1c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-37.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A.alt|B.alt@1000,0]
+../fonts/TestMORXThirtyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041;[B|A@650,0]
+../fonts/TestMORXThirtyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D0,U+05D1;[uni05D1|uni05D0@542,0]
+../fonts/TestMORXThirtyseven.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D1,U+05D0;[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-38.tests b/test/shape/data/text-rendering-tests/tests/MORX-38.tests
new file mode 100644
index 0000000..c2cd147
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-38.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A.alt|B.alt@1000,0]
+../fonts/TestMORXThirtyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041;[B|A@650,0]
+../fonts/TestMORXThirtyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D0,U+05D1;[uni05D1.alt|uni05D0.alt@1000,0]
+../fonts/TestMORXThirtyeight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D1,U+05D0;[uni05D0|uni05D1@606,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-39.tests b/test/shape/data/text-rendering-tests/tests/MORX-39.tests
new file mode 100644
index 0000000..1eaba46
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-39.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A|B@639,0]
+../fonts/TestMORXThirtynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041;[B.alt|A.alt@1000,0]
+../fonts/TestMORXThirtynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D0,U+05D1;[uni05D1.alt|uni05D0.alt@1000,0]
+../fonts/TestMORXThirtynine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D1,U+05D0;[uni05D0|uni05D1@606,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-4.tests b/test/shape/data/text-rendering-tests/tests/MORX-4.tests
new file mode 100644
index 0000000..12e0d98
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-4.tests
@@ -0,0 +1,15 @@
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0031;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0032;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|two@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0044,U+0058,U+0059,U+005A,U+0033;[P|Q@333,0|R@699,0|D@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|three@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0034;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|four@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0035;[P|Q@333,0|R@699,0|B@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|five@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0036;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|six@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0037;[P|Q@333,0|R@699,0|B@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|seven@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0043,U+0044,U+0058,U+0059,U+005A,U+0038;[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|eight@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0043,U+0044,U+0058,U+0059,U+005A,U+0039;[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|nine@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0044,U+0058,U+0059,U+005A,U+2793;[P|Q@333,0|R@699,0|D@1050,0|A@1880,0|B@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_zero@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0044,U+0058,U+0059,U+005A,U+24EB;[P|Q@333,0|R@699,0|D@1050,0|B@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_one@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EC;[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|A@2710,0|B@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_two@5388,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24ED;[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|B@2710,0|A@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_three@5388,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EE;[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|A@2710,0|B@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_four@5388,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EF;[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|B@2710,0|A@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_five@5388,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-40.tests b/test/shape/data/text-rendering-tests/tests/MORX-40.tests
new file mode 100644
index 0000000..a25fafd
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-40.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXForty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042;[A|B@639,0]
+../fonts/TestMORXForty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042,U+0041;[B.alt|A.alt@1000,0]
+../fonts/TestMORXForty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D0,U+05D1;[uni05D1|uni05D0@542,0]
+../fonts/TestMORXForty.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+05D1,U+05D0;[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-41.tests b/test/shape/data/text-rendering-tests/tests/MORX-41.tests
new file mode 100644
index 0000000..2e75e71
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-41.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXFourtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0061,U+0063;[a_c]
+../fonts/TestMORXFourtyone.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0062,U+0063;[b_c]
+../fonts/TestMORXFourtyone.ttf;;U+0063,U+0063;*
+../fonts/TestMORXFourtyone.ttf;;U+0061,U+0062,U+0063,U+0063;*
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-5.tests b/test/shape/data/text-rendering-tests/tests/MORX-5.tests
new file mode 100644
index 0000000..f46172f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-5.tests
@@ -0,0 +1,25 @@
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0033;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|three@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0034;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|four@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0035;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|five@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0036;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|six@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0037;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|seven@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0038;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|eight@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0038;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|eight@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0039;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|nine@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0039;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|nine@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+2793;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_zero@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+2793;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_zero@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EB;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_one@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EB;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_one@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EC;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_two@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EC;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_two@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EC;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_two@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24ED;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_three@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24ED;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_three@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24ED;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_three@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EE;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_four@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EE;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_four@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EE;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_four@4558,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EF;[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_five@2898,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EF;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_five@3728,0]
+../fonts/TestMORXFour.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EF;[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_five@4558,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-6.tests b/test/shape/data/text-rendering-tests/tests/MORX-6.tests
new file mode 100644
index 0000000..c5b1841
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-6.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+004F,U+004F,U+0041,U+0042,U+0043,U+0044,U+0045,U+0046,U+0047,U+004F,U+004F,U+004F,U+0033,U+0031,U+0034,U+0031;[O|O@418,0|O@836,0|E@1254,0|F@2084,0|A@2914,0|G@3744,0|B@4574,0|C@5404,0|D@6234,0|O@7064,0|O@7482,0|O@7900,0|three@8318,0|one@9168,0|four@10018,0|one@10868,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-7.tests b/test/shape/data/text-rendering-tests/tests/MORX-7.tests
new file mode 100644
index 0000000..05e6bdc
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-7.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+004F,U+0042,U+0043,U+0044,U+0031;[B|C@830,0|D@1660,0|O@2490,0|one@2908,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-8.tests b/test/shape/data/text-rendering-tests/tests/MORX-8.tests
new file mode 100644
index 0000000..68323c5
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-8.tests
@@ -0,0 +1,3 @@
+../fonts/TestMORXEight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0030,U+0041,U+0042,U+0043;[zero|A@914,0|B@1552,0|C@2202,0]
+../fonts/TestMORXEight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0031,U+0041,U+0042,U+0043;[one|B@914,0|C@1564,0|A@2196,0]
+../fonts/TestMORXEight.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0032,U+0041,U+0042,U+0043;[two|C@914,0|A@1546,0|B@2184,0]
diff --git a/test/shape/data/text-rendering-tests/tests/MORX-9.tests b/test/shape/data/text-rendering-tests/tests/MORX-9.tests
new file mode 100644
index 0000000..1eed22b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/MORX-9.tests
@@ -0,0 +1 @@
+../fonts/TestMORXNine.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041,U+0042,U+0058,U+0041,U+0042;[B|A@650,0|X@1288,0|A@1874,0|B@2512,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SFNT-1.tests b/test/shape/data/text-rendering-tests/tests/SFNT-1.tests
new file mode 100644
index 0000000..b069cf6
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SFNT-1.tests
@@ -0,0 +1,2 @@
+../fonts/TestSFNTOne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[A]
+../fonts/TestSFNTOne.otf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[B]
diff --git a/test/shape/data/text-rendering-tests/tests/SFNT-2.tests b/test/shape/data/text-rendering-tests/tests/SFNT-2.tests
new file mode 100644
index 0000000..28efff1
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SFNT-2.tests
@@ -0,0 +1,2 @@
+../fonts/TestSFNTTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0041;[A]
+../fonts/TestSFNTTwo.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0042;[B]
diff --git a/test/shape/data/text-rendering-tests/tests/SHARAN-1.tests b/test/shape/data/text-rendering-tests/tests/SHARAN-1.tests
new file mode 100644
index 0000000..9dcf59d
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHARAN-1.tests
@@ -0,0 +1,6 @@
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0644,U+0633,U+0627,U+0646;[OneDotEnclNS@398,-1|NoonxSep|AlefFin@861,0|SeenMed.inT2outT1@1125,0|sp0@1664,0|LamIni.outT2@1664,223]
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+06CC,U+0648,U+0646,U+06CC,U+06A9,U+0648,U+0688;[TahSmallNS@118,-213|DalSep|WawFin.cut@300,0|KafMed.outT3@573,206|TwoDotsBelowNS@1115,220|BehxMed.inT2outT1@903,304|OneDotAboveNS@1271,-71|sp1@1170,0|BehxIni.outT2@1170,449|WawFin.inD2@1387,0|TwoDotsBelowNS@1867,1|sp0@1758,0|BehxIni.outD2WQ@1758,323]
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0641,U+0648,U+0646,U+0679;[TahSmallNS@595,-331|BehxFin.soft|OneDotAboveNS@1163,-182|sp0@1184,0|BehxIni.outT2B@1184,300|WawFin.inD2alt@1340,0|OneDotAboveNS@1784,108|sp0@1599,0|FehxIni.outD2WQ@1599,237]
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0679,U+0627,U+0626,U+067E,U+0020,U+0641,U+06CC,U+0633;[SeenFin|TwoDotsBelowNS@1216,269|BehxMed.inT1outT2SeenWide@1041,455|OneDotAboveNS@1454,224|sp0@1271,0|FehxIni@1271,490|space@1584,0|ThreeDotsDownBelowNS@2290,-159|BehxFin.soft@1715,0|HamzaAboveNS@2878,-201|sp0@2899,0|BehxIni.outT2B@2899,300|AlefFin.narrow@3056,0|TahSmallNS@3442,-420|sp0@3295,0|BehxIni.A@3295,0]
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0641,U+0646,U+0020,U+062E,U+0637,U+0627,U+0637,U+06CC;[YehxFin|sp0@521,0|TahIni.outD2@521,380|AlefFin@1119,0|TahMed.inD1outT1@1382,0|OneDotAboveNS@2081,-47|sp0@1451,0|HahIni.outD1@1451,36|space@2326,0|OneDotEnclNS@2855,-2|NoonxFin@2458,0|OneDotAboveNS@3361,188|sp0@3208,0|FehxIni.outT2N@3208,336]
+../fonts/TestShapeAran.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0646,U+0633,U+062A,U+0639,U+0644,U+06CC,U+0642;[TwoDotsAboveNS@519,-199|QafxFin.cut|TwoDotsBelowNS@977,141|BehxMed.inT2outD2WQ@692,272|LamMed.outT2@1023,434|AinMed.inT3outT1@1301,507|TwoDotsAboveNS@1785,209|BehxMed.inT2outT3@1563,603|SeenMed.inT2outT2@1865,735|OneDotAboveNS@2574,670|sp0@2434,0|BehxIni.outT2tall@2434,952]
diff --git a/test/shape/data/text-rendering-tests/tests/SHBALI-1.tests b/test/shape/data/text-rendering-tests/tests/SHBALI-1.tests
new file mode 100644
index 0000000..388d440
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHBALI-1.tests
@@ -0,0 +1,22 @@
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B38,U+1B00;[gid23|gid60@1113,0|gid4@1064,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B15,U+1B44,U+1B16,U+1B02;[gid25|gid132@1092,0|gid6@942,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B18,U+1B3B;[gid28|gid62@796,0|gid57@794,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B19,U+1B40;[gid66|gid29@483,0|gid57@1536,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B1A,U+1B3F;[gid67|gid30@483,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B14,U+1B36;[gid24|gid58@828,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B13,U+1B01;[gid23|gid129@1111,0|gid5@1064,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B1B,U+1B01;[gid23|gid137@1111,0|gid5@1379,181]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B26,U+1B03;[gid23|gid148@1111,0|gid7@991,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B13,U+1B38;[gid23|gid129@1111,0|gid60@1111,-488]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B13,U+1B3C;[gid23|gid129@1111,0|gid70@1128,0|gid170@1113,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B13,U+1B3D;[gid23|gid129@1111,0|gid70@1128,0|gid170@1113,0|gid57@1111,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B3E;[gid66|gid23@483,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B36,U+1B3E;[gid23|gid58@1064,0|gid66@1111,0|gid128@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B38,U+1B3E;[gid23|gid60@1113,0|gid66@1111,0|gid128@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B15,U+1B3E;[gid66|gid23@483,0|gid131@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B40;[gid66|gid23@483,0|gid57@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B3E;[gid66|gid23@483,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B3E,U+1B36;[gid66|gid23@483,0|gid58@1548,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B3E,U+1B38;[gid66|gid23@483,0|gid60@1597,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B15,U+1B3E;[gid66|gid23@483,0|gid131@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B40;[gid66|gid23@483,0|gid57@1594,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHBALI-2.tests b/test/shape/data/text-rendering-tests/tests/SHBALI-2.tests
new file mode 100644
index 0000000..dbde07d
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHBALI-2.tests
@@ -0,0 +1,12 @@
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B27,U+1B3E;[gid66|gid23@483,0|gid149@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B28,U+1B3F;[gid67|gid23@483,0|gid150@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B31,U+1B3E;[gid66|gid23@483,0|gid159@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B32,U+1B3E;[gid66|gid23@483,0|gid60@1597,0|gid149@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B4A,U+1B3E;[gid66|gid23@483,0|gid60@1597,0|gid165@1594,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B1B,U+1B44,U+1B13;[gid181|gid129@1064,-195]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B1B,U+1B44,U+1B13,U+1B3E;[gid66|gid181@483,0|gid129@1548,-195]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B1B,U+1B44,U+1B13,U+1B38,U+1B00;[gid181|gid129@1064,-195|gid60@1064,-684|gid4@855,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B13,U+1B38;[gid23|gid129@1111,0|gid60@1111,-488]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B1B,U+1B39;[gid23|gid137@1111,0|gid61@1261,-488]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B31,U+1B3A;[gid23|gid159@1111,0|gid62@1753,0]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B13,U+1B44,U+1B45,U+1B38;[gid23|gid162@1111,0|gid60@1111,-488]
diff --git a/test/shape/data/text-rendering-tests/tests/SHBALI-3.tests b/test/shape/data/text-rendering-tests/tests/SHBALI-3.tests
new file mode 100644
index 0000000..2e73dca
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHBALI-3.tests
@@ -0,0 +1,9 @@
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B6B;[gid102|gid107@560,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B6C;[gid102|gid108@573,49]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B6D;[gid102|gid109@652,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B6E;[gid102|gid110@652,-98]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B6F;[gid102|gid111@667,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B70;[gid102|gid112@667,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B71;[gid102|gid113@667,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B72;[gid102|gid114@667,-10]
+../fonts/NotoSansBalinese-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1B66,U+1B73;[gid102|gid115@599,-10]
diff --git a/test/shape/data/text-rendering-tests/tests/SHKNDA-1.tests b/test/shape/data/text-rendering-tests/tests/SHKNDA-1.tests
new file mode 100644
index 0000000..cb8dc85
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHKNDA-1.tests
@@ -0,0 +1,34 @@
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB2,U+0CCD,U+0CB2,U+0CBF;[knLI|knLAc2@757,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9F,U+0CCD,U+0CB8,U+0CCD;[knTT|knSAc2@1021,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB3,U+0CBF;[knLLI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA1,U+0CBF;[knDDI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAE,U+0CC6;[knME]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB0,U+0CBF;[knRI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C96,U+0CCD,U+0CAF,U+0CC6;[knKHE|knYAc2@846,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAB,U+0CCD,U+0CB0,U+0CBF;[knPHI|knRAc2@735,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CC6;[knNE]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C97,U+0CBF;[knGI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB7,U+0CCD,U+0C9F,U+0CBF;[knSSI|knTTAc2@746,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAF,U+0CBF,U+0C82;[knYI|knAnusvara@1252,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9A,U+0CC0;[knCI|knLengthmark@766,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CBF;[knNI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C97,U+0CCD,U+0CB2,U+0CBF;[knGI|knLAc2@621,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB7,U+0CBF;[knSSI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C97,U+0CC6;[knGE]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA6,U+0CCD,U+0CB5,U+0CBF;[knDI|knVAc2@740,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA4,U+0CC0;[knTI|knLengthmark@613,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAE,U+0CBF;[knMI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB2,U+0CBF;[knLI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C97,U+0CBF;[knGI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CCD;[knN]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAC,U+0CBF;[knBI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB2,U+0CBF;[knLI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CCD,U+0CA8,U+0CBF,U+0C82;[knNI|knNAc2@678,0|knAnusvara@755,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB2,U+0CCD,U+0CB2,U+0CBF;[knLI|knLAc2@757,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA7,U+0CBF;[knDHI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAA,U+0CCC;[knPA.base|knmAU@739,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB5,U+0CBF,U+0C82;[knVI|knAnusvara@749,0]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA1,U+0CBF;[knDDI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9F,U+0CBF;[knTTI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CBF;[knNI]
+../fonts/NotoSerifKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA7,U+0CBF;[knDHI]
diff --git a/test/shape/data/text-rendering-tests/tests/SHKNDA-2.tests b/test/shape/data/text-rendering-tests/tests/SHKNDA-2.tests
new file mode 100644
index 0000000..c78a082
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHKNDA-2.tests
@@ -0,0 +1,16 @@
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CCD,U+0CA8,U+0CBE;[gid150|gid57@711,0|gid116@1160,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CCD,U+0CA8,U+0CBE;[gid150|gid57@711,0|gid116@1160,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA4,U+0CCD,U+0CA4,U+0CBE;[gid146|gid57@623,0|gid112@1071,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9F,U+0CCD,U+0C9F,U+0CBE;[gid141|gid57@815,0|gid107@1264,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA1,U+0CCB,U+0C82,U+0C97,U+0CBF;[gid249|gid61@768,0|gid71@1513,0|gid4@1925,0|gid207@2475,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9C,U+0CBF,U+0CBC,U+0CD5,U+0CAC,U+0CC6,U+0CA8,U+0CCD;[gid211|gid55@652,0|gid71@776,0|gid259@1188,0|gid186@1994,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9C,U+0CBE,U+0CBC,U+0C95,U+0CBF,U+0CB0,U+0CCD;[gid139|gid57@776,0|gid55@652,0|gid205@1225,0|gid193@1799,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C87,U+0CA8,U+0CCD,U+0CAB,U+0CCD,U+0CB2,U+0CC6,U+0C95,U+0CCD,U+0CB7,U+0CA8,U+0CB2,U+0CCD;[gid8|gid256@711,0|gid118@1422,0|gid335@1591,0|gid282@1978,0|gid39@2552,0|gid195@3263,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C87,U+0CA8,U+0CCD,U+0CAB,U+0CCD,U+0CB2,U+0CC6,U+0C95,U+0CCD,U+0CB7,U+0CA8,U+0CCD;[gid8|gid256@711,0|gid118@1422,0|gid335@1591,0|gid282@1978,0|gid186@2552,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA6,U+0C9F,U+0CCD,U+0CB8,U+0CCD;[gid37|gid177@765,0|gid130@1814,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C8E,U+0C95,U+0CCD,U+0CB8,U+0CCD;[gid14|gid167@787,0|gid130@1596,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAE,U+0CBE,U+0CB0,U+0CCD,U+0C9A,U+0CCD;[gid155|gid57@1156,0|gid172@1605,0|gid94@2718,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9F,U+0CC6,U+0C95,U+0CCD,U+0CB8,U+0CCD,U+0C9F,U+0CCD;[gid247|gid167@815,0|gid130@1624,0|gid317@1792,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAC,U+0CC1,U+0C95,U+0CCD,U+0CB8,U+0CCD;[gid42|gid60@801,0|gid167@1165,0|gid130@1974,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB8,U+0CBE,U+0CAB,U+0CCD,U+0C9F,U+0CCD;[gid163|gid57@709,0|gid188@1158,0|gid107@2184,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9C,U+0CB8,U+0CCD,U+0C9F,U+0CCD;[gid27|gid200@776,0|gid107@1720,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHKNDA-3.tests b/test/shape/data/text-rendering-tests/tests/SHKNDA-3.tests
new file mode 100644
index 0000000..c007135
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHKNDA-3.tests
@@ -0,0 +1,31 @@
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C95,U+0CCB,U+0C82;[gid239|gid61@574,0|gid71@1319,0|gid4@1731,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C96,U+0CCB,U+0C82;[gid240|gid61@865,0|gid71@1610,0|gid4@2022,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C97,U+0CCB,U+0C82;[gid241|gid61@648,0|gid71@1393,0|gid4@1805,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C98,U+0CCB,U+0C82;[gid242|gid279@997,0|gid71@1742,0|gid4@2153,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C99,U+0CCB,U+0C82;[gid24|gid67@737,0|gid71@1718,0|gid4@2130,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9A,U+0CCB,U+0C82;[gid243|gid61@795,0|gid71@1540,0|gid4@1952,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9B,U+0CCB,U+0C82;[gid244|gid61@843,0|gid71@1588,0|gid4@2000,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9C,U+0CCB,U+0C82;[gid245|gid61@776,0|gid71@1522,0|gid4@1933,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9D,U+0CCB,U+0C82;[gid246|gid61@1379,0|gid71@2124,0|gid4@2536,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9E,U+0CCB,U+0C82;[gid29|gid67@968,0|gid71@1949,0|gid4@2360,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C9F,U+0CCB,U+0C82;[gid247|gid61@815,0|gid71@1560,0|gid4@1972,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA0,U+0CCB,U+0C82;[gid248|gid61@651,0|gid71@1397,0|gid4@1808,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA1,U+0CCB,U+0C82;[gid249|gid61@768,0|gid71@1513,0|gid4@1925,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA2,U+0CCB,U+0C82;[gid250|gid61@768,0|gid71@1513,0|gid4@1925,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA3,U+0CCB,U+0C82;[gid251|gid61@867,0|gid71@1612,0|gid4@2023,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA4,U+0CCB,U+0C82;[gid252|gid61@623,0|gid71@1368,0|gid4@1779,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA5,U+0CCB,U+0C82;[gid253|gid61@765,0|gid71@1510,0|gid4@1921,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA6,U+0CCB,U+0C82;[gid254|gid61@765,0|gid71@1510,0|gid4@1921,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA7,U+0CCB,U+0C82,U+0020;[gid255|gid61@765,0|gid71@1510,0|gid4@1921,0|gid3@2472,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CA8,U+0CCB,U+0C82;[gid256|gid61@711,0|gid71@1456,0|gid4@1868,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAA,U+0CCB,U+0C82;[gid257|gid275@792,0|gid71@1434,0|gid4@1846,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAB,U+0CCB,U+0C82;[gid258|gid277@792,0|gid71@1434,0|gid4@1846,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAC,U+0CCB,U+0C82;[gid259|gid61@806,0|gid71@1551,0|gid4@1963,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAD,U+0CCB,U+0C82;[gid260|gid61@806,0|gid71@1551,0|gid4@1963,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAE,U+0CCB,U+0C82;[gid280|gid71@1539,0|gid4@1951,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CAF,U+0CCB,U+0C82;[gid281|gid71@1712,0|gid4@2124,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB0,U+0CCB,U+0C82;[gid263|gid61@651,0|gid71@1397,0|gid4@1808,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB1,U+0CCB,U+0C82;[gid47|gid67@831,0|gid71@1812,0|gid4@2223,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB2,U+0CCB,U+0C82;[gid264|gid61@769,0|gid71@1514,0|gid4@1925,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0CB5,U+0CCB,U+0C82;[gid266|gid275@794,0|gid71@1437,0|gid4@1848,0]
+../fonts/NotoSansKannada-Regular.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+0C86,U+0CCD,U+0CAF,U+0C95,U+0CCD,U+0CB7,U+0CBF,U+0CB8,U+0CCD,U+200C;[gid7|gid122@838,0|gid285@1098,0|gid200@1672,0|gid3@2694,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-1.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-1.tests
new file mode 100644
index 0000000..3c16c1f
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-1.tests
@@ -0,0 +1,52 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6B;[uni1A20|uni1A6B@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A74;[uni1A23|uni1A74@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A27,U+1A62;[uni1A27|uni1A62@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A60,U+1A45,U+1A6B,U+1A61;[uni1A32|uni1A601A45@762,0|uni1A6B@762,0|uni1A61@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A60,U+1A45,U+1A6B;[uni1A37|uni1A601A45@592,0|uni1A6B@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A60,U+1A45;[uni1A20|uni1A601A45@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A21,U+1A6C,U+1A74;[uni1A21|uni1A6C@592,-98|uni1A74@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6C;[uni1A20|uni1A6C.wide@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A26,U+1A61;[uni1A26|uni1A61@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A63;[uni1A20|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A64;[uni1A34|uni1A64@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4C,U+1A63,U+1A74;[uni1A4C|uni1A74@762,0|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A64,U+1A74;[uni1A23|uni1A74@592,0|uni1A64@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A33,U+1A65;[uni1A33|uni1A65@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3A,U+1A66,U+0020;[uni1A3A|uni1A66@738,0|space@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A29,U+1A67;[uni1A29|uni1A67@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A68;[uni1A3E.v2|uni1A68@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A35,U+1A69;[uni1A35|uni1A69@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A26,U+1A6A;[uni1A26|uni1A6A@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A6E,U+1A61;[uni1A6E|uni1A32@592,0|uni1A61@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3D,U+1A6E;[uni1A6E|uni1A3D@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A24,U+1A6F,U+1A61;[uni1A6F|uni1A24@1096,0|uni1A61@1688,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A27,U+1A6F;[uni1A6F|uni1A27@1096,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A38,U+1A6E,U+1A6C,U+1A65,U+1A61;[uni1A6E|uni1A38@592,0|uni1A6C@1184,0|uni1A65@1098,0|uni1A61@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A6E,U+1A6C,U+1A65;[uni1A6E|uni1A36@592,0|uni1A6C@1184,0|uni1A65@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A6C,U+1A68,U+1A61;[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0|uni1A61@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A6C,U+1A68;[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A6E,U+1A62,U+1A63;[uni1A6E|uni1A41@592,0|uni1A62@1184,0|uni1A63@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A73;[uni1A3E.v2|uni1A73@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A63;[uni1A6E|uni1A20@592,0|uni1A63@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A39,U+1A60,U+1A3F,U+1A6E,U+1A61;[uni1A6E|uni1A39@592,0|uni1A601A3F@1324,0|uni1A61@1551,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A60,U+1A3F,U+1A6E;[uni1A6E|uni1A3B@592,0|uni1A601A3F@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A60,U+1A3F;[uni1A20|uni1A601A3F@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A6E,U+1A6C,U+1A65,U+1A4B,U+1A61;[uni1A6E|uni1A3E.v2@592,0|uni1A6C@1184,0|uni1A65@1184,0|uni1A4B@1324,0|uni1A61@1916,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A56,U+1A6E,U+1A6C,U+1A65,U+1A4B;[uni1A6E|uni1A20@592,0|uni1A56.wide@1524,0|uni1A6C.wide@1524,-547|uni1A65@1524,0|uni1A4B@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A70,U+1A61;[uni1A70|uni1A48@592,0|uni1A61@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A70;[uni1A70|uni1A3E.v2@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2A,U+1A70,U+1A6C,U+1A61;[uni1A70|uni1A2A@592,0|uni1A6C@1184,0|uni1A61@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A29,U+1A62,U+1A60,U+1A3F;[uni1A29|uni1A62@592,0|uni1A601A3F@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A72;[uni1A72|uni1A36@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A22,U+1A71;[uni1A71|uni1A22@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A71,U+1A60,U+1A3F;[uni1A71|uni1A34@592,0|uni1A601A3F@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A6C,U+1A68,U+1A61;[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0|uni1A61@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A6C,U+1A68;[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A70,U+1A62;[uni1A70|uni1A20@592,0|uni1A62@1354,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A58;[uni1A48|uni1A58@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A62,U+1A60,U+1A26;[uni1A34|uni1A62@592,0|uni1A601A26@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4C,U+1A65,U+1A74,U+0020;[uni1A4C|uni1A65@762,0|uni1A74@1211,0|space@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A65,U+1A60,U+1A26;[uni1A20|uni1A65@762,0|uni1A601A26@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A62,U+1A60,U+1A3E;[uni1A20|uni1A62@762,0|uni1A601A3E@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A62,U+1A3E;[uni1A20|uni1A62@762,0|uni1A3E.v2@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A6D;[uni1A2F|uni1A6D@592,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-10.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-10.tests
new file mode 100644
index 0000000..5e14843
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-10.tests
@@ -0,0 +1,47 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A53,U+1A6F;[uni1A6F|uni1A53@1096,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A50,U+1A63;[uni1A50|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A50,U+1A75,U+1A63;[uni1A50|uni1A75@738,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A6A,U+1A55,U+1A63;[uni1A55|uni1A2F@227,0|uni1A6A@818,0|uni1A63@818,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A6E,U+1A6C,U+1A65,U+1A41,U+1A39,U+1A6B,U+1A56,U+1A23,U+1A69,U+1A31,U+1A7A;[uni1A6E|uni1A2F@592,0|uni1A6C@1184,-188|uni1A65@1184,0|uni1A41@1184,0|uni1A39@1775,0|uni1A6B@2367,0|uni1A56@2367,0|uni1A23@2508,0|uni1A69@3100,0|uni1A31@3100,0|uni1A7A@3861,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A63,U+1A37,U+1A70,U+1A56;[uni1A3B|uni1A63@933,0|uni1A70@1524,0|uni1A37@2116,0|uni1A56@2708,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A76,U+1A6D;[uni1A36|uni1A76@592,0|uni1A6D@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A39,U+1A65,U+1A56,U+1A69,U+1A75,U+1A7B;[uni1A39|uni1A65@592,0|uni1A56@592,0|uni1A69@592,-547|uni1A75@592,357|uni1A78@864,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A56,U+1A60,U+1A45,U+1A26;[uni1A49|uni1A56.wide@933,0|uni1A601A45@762,-547|uni1A26@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A56,U+1A60,U+1A45,U+1A63;[uni1A49|uni1A56.wide@933,0|uni1A601A45@762,-547|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A55,U+1A60,U+1A3F,U+1A6E,U+1A61;[uni1A6E|uni1A55@592,0|uni1A3B@818,0|uni1A601A3F@1751,0|uni1A61@1978,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A69,U+1A76,U+1A63,U+1A60,U+1A36,U+1A60,U+1A26;[uni1A20|uni1A69@762,0|uni1A76@762,0|uni1A63@933,0|uni1A601A36@1524,0|uni1A601A26@1524,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4B,U+1A62,U+1A60,U+1A2D,U+1A5B;[uni1A4B|uni1A62@592,0|uni1A601A2D1A5B@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A46,U+1A62,U+1A20,U+1A60,U+1A2F,U+1A65,U+1A7A;[uni1A46|uni1A62@592,0|uni1A20@681,0|uni1A601A2F@1442,0|uni1A65@1442,0|uni1A7A@1442,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A46,U+1A62,U+1A20,U+1A60,U+1A2F,U+1A65,U+1A7C;[uni1A46|uni1A62@592,0|uni1A20@681,0|uni1A601A2F@1442,0|uni1A65@1442,0|uni1A7C@1442,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A49,U+1A63,U+1A49,U+1A65,U+1A26,U+1A60,U+1A23,U+1A69,U+1A7A;[uni1A3E.v2|uni1A49@732,0|uni1A63@1665,0|uni1A49@2257,0|uni1A65@3019,0|uni1A26@3189,0|uni1A601A23@3781,0|uni1A69@3781,-547|uni1A7A@3781,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A49,U+1A63,U+1A49,U+1A65,U+1A26,U+1A60,U+1A23,U+1A69,U+1A7C;[uni1A3E.v2|uni1A49@732,0|uni1A63@1665,0|uni1A49@2257,0|uni1A65@3019,0|uni1A26@3189,0|uni1A601A23@3781,0|uni1A69@3781,-547|uni1A7C@3781,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A46,U+1A63,U+1A48,U+1A60,U+1A32,U+1A55,U+1A7A;[uni1A46|uni1A63@681,0|uni1A55@1272,0|uni1A48@1499,0|uni1A601A32@2091,0|uni1A7A@2091,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A63,U+1A48,U+1A60,U+1A32,U+1A55,U+1A7C;[uni1A48|uni1A63@592,0|uni1A55@1184,0|uni1A48@1410,0|uni1A601A32@2002,0|uni1A7C@2002,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A6A,U+1A60,U+1A37;[uni1A41|uni1A601A37@592,0|uni1A6A@725,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A66,U+1A75,U+1A60,U+1A36,U+1A6C,U+1A76,U+1A26;[uni1A3B|uni1A66@762,0|uni1A75@762,357|uni1A601A36@762,0|uni1A6C@762,-367|uni1A76@1087,357|uni1A26@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A38,U+1A62,U+1A63;[uni1A38|uni1A62@506,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A43,U+1A6A,U+1A62;[uni1A43|uni1A6A@762,0|uni1A62@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A6C,U+1A62;[uni1A2F|uni1A6C@592,-188|uni1A62@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A6C,U+1A62,U+1A61;[uni1A2F|uni1A6C@592,-188|uni1A62@592,0|uni1A61@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A60,U+1A45,U+1A62,U+1A61;[uni1A3B|uni1A601A45@762,0|uni1A62@762,0|uni1A61@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A6F,U+1A60,U+1A36,U+1A6C,U+1A74,U+1A75;[uni1A6F|uni1A32@1096,0|uni1A601A36@1857,0|uni1A6C@1857,-367|uni1A74@1857,0|uni1A75@1857,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A6C,U+1A74,U+1A75,U+034F,U+1A6F,U+1A60,U+1A36;[uni1A6F|uni1A32@1096,0|uni1A6C.wide@2028,0|uni1A74@2028,0|uni1A75@2028,357|uni1A601A36@1857,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A6C,U+1A74,U+1A75,U+1A6F,U+1A60,U+1A36;[uni1A6F|uni1A32@1096,0|uni1A6C.wide@2028,0|uni1A74@2028,0|uni1A75@2028,357|uni1A601A36@1857,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A60,U+1A36,U+1A6B,U+1A7B;[uni1A48|uni1A601A36@592,0|uni1A6B@592,0|uni1A78@592,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A3E,U+1A5B,U+1A66;[uni1A20|uni1A3E1A5B@933,0|uni1A66@1549,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A65,U+1A3B,U+1A5B,U+1A63,U+1A60,U+1A36;[uni1A36|uni1A65@592,0|uni1A3B1A5B@592,0|uni1A63@1524,0|uni1A601A36@2116,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A35,U+1A3E,U+1A5C,U+1A65,U+1A20;[uni1A35|uni1A3E.v2@592,0|uni1A5C@1184,0|uni1A65@1184,0|uni1A20@1324,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A35,U+1A69,U+1A60,U+1A37;[uni1A48|uni1A35@592,0|uni1A601A37@1184,0|uni1A69@1317,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A65,U+1A48,U+1A6E,U+1A60,U+1A48;[uni1A45|uni1A65@592,0|uni1A6E@592,0|uni1A48@1184,0|uni1A601A48@1775,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A22,U+1A76,U+1A63;[uni1A22|uni1A76@738,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A63,U+1A48,U+1A36,U+1A63;[uni1A48|uni1A63@592,0|uni1A48@1184,0|uni1A361A63@1775,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A63,U+1A48,U+1A60,U+1A36,U+1A7B,U+1A63;[uni1A48|uni1A63@592,0|uni1A48@1184,0|uni1A601A36@1775,0|uni1A78@1775,0|uni1A63@1775,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A60,U+1A36,U+1A7B,U+1A6E,U+1A62,U+1A76,U+1A63;[uni1A6E|uni1A48@592,0|uni1A601A36@1184,0|uni1A78@1184,0|uni1A621A76@1599,0|uni1A63@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A60,U+1A36,U+1A7B,U+1A6E,U+1A62,U+1A62,U+1A76,U+1A63;[uni1A6E|uni1A48@592,0|uni1A601A36@1184,0|uni1A78@1184,0|uni1A621A621A76@1599,0|uni1A63@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A66,U+034F,U+1A63,U+1A60,U+1A3F;[uni1A32|uni1A66@762,0|uni1A63@933,0|uni1A601A3F@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A75,U+1A63,U+1A74,U+1A7B;[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A78@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A43,U+1A6E,U+1A5E;[uni1A6E|uni1A43@592,0|uni1A5E@1354,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4B,U+1A36,U+1A63,U+1A33,U+1A37,U+1A65,U+1A31,U+1A60,U+1A2F,U+1A65,U+1A20,U+1A48,U+1A5E;[uni1A4B|uni1A361A63@592,0|uni1A33@1184,0|uni1A37@1775,0|uni1A65@2367,0|uni1A31@2367,0|uni1A601A2F@3129,0|uni1A65@3129,0|uni1A20@3300,0|uni1A48@4232,0|uni1A5E@4824,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A63,U+1A74,U+1A7B;[uni1A2F|uni1A74@592,0|uni1A63@592,0|uni1A78@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A74,U+1A75,U+1A63,U+1A7B;[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A78@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A74,U+1A63,U+1A7B;[uni1A2F|uni1A74@592,0|uni1A63@592,0|uni1A78@1184,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-2.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-2.tests
new file mode 100644
index 0000000..379fdac
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-2.tests
@@ -0,0 +1,37 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A93,U+1A60,U+1A34;[uni1A93|uni1A601A34@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A75,U+1A63,U+1A60,U+1A26,U+1A7B;[uni1A32|uni1A75@762,0|uni1A63@933,0|uni1A601A26@1524,0|uni1A78@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A33,U+1A60,U+1A36,U+1A7B,U+1A6B,U+1A41;[uni1A33|uni1A601A36@592,0|uni1A78@592,0|uni1A6B@954,0|uni1A41@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A21,U+1A62,U+1A76,U+1A7B,U+1A6C,U+1A26;[uni1A21|uni1A621A76@592,0|uni1A78@1007,0|uni1A6C@592,-98|uni1A26@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1AAD,U+1A63;[uni1AAD|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A36,U+1A66;[uni1A49|uni1A601A36@762,0|uni1A66@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A24,U+1A60,U+1A45,U+1A6F,U+1A76,U+1A41;[uni1A6F|uni1A24@1096,0|uni1A601A45@1688,0|uni1A76@1688,0|uni1A41@1688,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A45,U+1A6B;[uni1A49|uni1A601A45@762,0|uni1A6B@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A62,U+1A75,U+1A26,U+1A60,U+1A36,U+1A66,U+1A76;[uni1A2F|uni1A621A75@592,0|uni1A26@592,0|uni1A601A36@1184,0|uni1A66@1184,0|uni1A76@1184,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A65,U+1A60,U+1A36;[uni1A49|uni1A65@762,0|uni1A601A36@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A63,U+1A60,U+1A3E;[uni1A32|uni1A63@933,0|uni1A601A3E@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A60,U+1A3F,U+1A63,U+1A60,U+1A35,U+1A65;[uni1A3B|uni1A601A3F@933,0|uni1A63@1159,0|uni1A601A35@1751,0|uni1A65@1751,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A38,U+1A60,U+1A43,U+1A60,U+1A3F,U+1A75,U+1A41;[uni1A38|uni1A601A43@592,0|uni1A601A3F@818,0|uni1A75@1049,0|uni1A41@1045,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A6F,U+1A76,U+1A60,U+1A36,U+1A60,U+1A45,U+1A75,U+1A63;[uni1A6F|uni1A3E.v2@1096,0|uni1A76@1688,0|uni1A601A36@1688,0|uni1A601A45@1688,-367|uni1A75@2013,0|uni1A63@1828,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A60,U+1A45,U+1A6F,U+1A75;[uni1A6F|uni1A48@1096,0|uni1A601A45@1688,0|uni1A75@1688,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A75,U+1A6F,U+1A60,U+1A45;[uni1A6F|uni1A48@1096,0|uni1A75@1688,0|uni1A601A45@1688,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3F,U+1A6A;[uni1A3F|uni1A6A@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A66;[uni1A3E.v2|uni1A66@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A6A;[uni1A49|uni1A601A3E@762,0|uni1A6A@762,-367]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A66;[uni1A49|uni1A601A3E@762,0|uni1A66@762,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A39,U+1A60,U+1A45,U+1A6B;[uni1A39|uni1A601A45@592,0|uni1A6B@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A43,U+1A6C,U+1A74,U+1A75;[uni1A49|uni1A601A43@933,0|uni1A6C@1060,-547|uni1A74@1164,0|uni1A75@1164,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A63;[uni1A3E.v2|uni1A63@732,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A71,U+1A75;[uni1A71|uni1A49@592,0|uni1A75@1354,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A60,U+1A3F,U+1A26;[uni1A45|uni1A601A3F@592,0|uni1A26@818,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A63,U+1A60,U+1A3E;[uni1A49|uni1A63@933,0|uni1A601A3E@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A63,U+1A74;[uni1A2F|uni1A74@592,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A63;[uni1A49|uni1A601A3E@762,0|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A55,U+1A63,U+1A60,U+1A38;[uni1A55|uni1A20@227,0|uni1A63@1159,0|uni1A601A37@1751,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A55,U+1A75,U+1A63,U+1A74;[uni1A55|uni1A3B@227,0|uni1A74@988,0|uni1A75@988,357|uni1A63@1159,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A55,U+1A6C,U+1A26;[uni1A55|uni1A20@227,0|uni1A6C.wide@1159,0|uni1A26@1159,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A55,U+1A6B,U+1A3E,U+1A60,U+1A31,U+1A7A;[uni1A55|uni1A48@227,0|uni1A6B@818,0|uni1A3E.v2@818,0|uni1A601A31.narrow@1410,0|uni1A7A@1410,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A55,U+1A60,U+1A45,U+1A6B,U+1A3E;[uni1A55|uni1A48@227,0|uni1A601A45@818,0|uni1A6B@818,0|uni1A3E.v2@818,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A75,U+1A63,U+1A74;[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3E,U+1A6E,U+1A6C,U+1A68,U+1A26;[uni1A6E|uni1A49@592,0|uni1A601A3E@1524,0|uni1A6C@1524,-367|uni1A68@1524,0|uni1A26@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A3F,U+1A6E,U+1A6C,U+1A68,U+1A26;[uni1A6E|uni1A49@592,0|uni1A601A3F@1524,0|uni1A6C@1729,-367|uni1A68@1755,0|uni1A26@1751,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A43,U+1A63,U+1A60,U+1A3F;[uni1A49|uni1A601A43@933,0|uni1A63@1159,0|uni1A601A3F@1751,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-3.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-3.tests
new file mode 100644
index 0000000..a37f3ce
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-3.tests
@@ -0,0 +1,13 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6C,U+1A62,U+1A43,U+1A60,U+1A3C,U+1A7A;[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A601A3C.wide@1865,0|uni1A7A@1964,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6C,U+1A62,U+1A43,U+1A7A,U+1A60,U+1A3C;[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A7A@1964,0|uni1A601A3C.wide@1865,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6C,U+1A62,U+1A43,U+1A60,U+1A7A,U+1A3C;[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A7A@1964,0|uni1A601A3C.wide@1865,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A55,U+1A63,U+1A60,U+1A3C;[uni1A55|uni1A20@227,0|uni1A63@1159,0|antler@1159,0|uni1A601A3C@1751,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A6C,U+1A3C,U+1A60,U+1A3C,U+1A66,U+1A75;[uni1A34|uni1A6C@592,0|uni1A3C@592,0|antler@771,0|uni1A601A3C.wide@1524,0|uni1A66@1558,0|uni1A75@1558,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A3D,U+1A5A;[uni1A20|uni1A3D@933,0|uni1A5A@1865,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A31,U+1A5B,U+1A63,U+1A60,U+1A36;[uni1A48|uni1A311A5B@592,0|uni1A63@1524,0|uni1A601A36@2116,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A2D,U+1A5B,U+1A37,U+1A63,U+1A60,U+1A43;[uni1A41|uni1A2D1A5B@592,0|uni1A37@1184,0|uni1A63@1775,0|uni1A601A43@2367,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A62,U+1A2D,U+1A5B,U+1A37,U+1A63,U+1A60,U+1A43;[uni1A41|uni1A62@592,0|uni1A2D1A5B@592,0|uni1A37@1184,0|uni1A63@1775,0|uni1A601A43@2367,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A3B,U+1A5B;[uni1A48|uni1A3B1A5B@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4B,U+1A3E,U+1A5B;[uni1A4B|uni1A3E1A5B@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A63,U+1A29,U+1A3D,U+1A62,U+1A60,U+1A2E;[uni1A41|uni1A63@592,0|uni1A29@1184,0|uni1A3D@1775,0|uni1A62@2537,0|uni1A601A2E@2537,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A62,U+1A31,U+1A60,U+1A3B,U+1A37,U+1A69,U+1A41,U+1A69,U+1A48;[uni1A37|uni1A62@592,0|uni1A31@592,0|uni1A601A3B.wide@1524,0|uni1A37@1524,0|uni1A69@2116,0|uni1A41@2116,0|uni1A69@2708,0|uni1A48@2708,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-4.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-4.tests
new file mode 100644
index 0000000..6ce33fc
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-4.tests
@@ -0,0 +1,3 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A58,U+1A60,U+1A43,U+1A63,U+1A60,U+1A3F;[uni1A34|uni1A58@592,0|uni1A601A43@592,0|uni1A63@818,0|uni1A601A3F@1410,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63;[uni1A48|uni1A6E@592,0|uni1A25@1184,0|uni1A58@1945,0|uni1A63@2117,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A58,U+1A48,U+1A66;[uni1A41|uni1A58@592,0|uni1A48@592,0|uni1A66@1184,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-5.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-5.tests
new file mode 100644
index 0000000..da1918b
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-5.tests
@@ -0,0 +1,13 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A63,U+1A74;[uni1A361A63|uni1A74@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3E,U+1A36,U+1A6E,U+1A63;[uni1A3E.v2|uni1A6E@732,0|uni1A361A63@1324,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A6E,U+1A62,U+1A63;[uni1A6E|uni1A361A63@592,0|uni1A62@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A63,U+1A60,U+1A3F;[uni1A361A63|uni1A601A3F@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A75,U+1A63,U+1A60,U+1A36;[uni1A361A63|uni1A75@592,0|uni1A601A36@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4D,U+1A36,U+1A60,U+1A34,U+1A63;[uni1A4D|uni1A361A63@933,0|uni1A601A34@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A4B,U+1A6B,U+1A36,U+1A60,U+1A32,U+1A55,U+1A63,U+1A60,U+1A3F;[uni1A4B|uni1A6B@592,0|uni1A55@592,0|uni1A361A63@818,0|uni1A601A32@1410,0|uni1A601A3F@1410,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A76,U+1A63,U+1A74;[uni1A361A63|uni1A74@592,0|uni1A76@592,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A60,U+1A45,U+1A63,U+1A60,U+1A37;[uni1A361A63|uni1A601A45@592,0|uni1A601A37@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A64,U+1A74,U+1A36,U+1A60,U+1A45,U+200C,U+1A63,U+1A60,U+1A3F;[uni1A34|uni1A74@592,0|uni1A64@592,0|uni1A36@818,0|uni1A601A45@1410,0|uni1A63@1410,0|uni1A601A3F@2002,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A32,U+1A75,U+1A63,U+1A74,U+1A36,U+1A60,U+1A45,U+1A63,U+1A60,U+1A3F;[uni1A32|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A361A63@1524,0|uni1A601A45@2116,0|uni1A601A3F@2116,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+200C,U+1A63;[uni1A36|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A36,U+1A76,U+1A63;[uni1A49|uni1A601A36@762,0|uni1A76@762,0|uni1A63@933,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-6.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-6.tests
new file mode 100644
index 0000000..fd4bd12
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-6.tests
@@ -0,0 +1,7 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6F,U+1A62,U+1A60,U+1A48;[uni1A6F|uni1A20@1096,0|uni1A62@1857,0|uni1A601A48@2028,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A55,U+1A6F,U+1A60,U+1A20,U+1A34,U+1A6E,U+1A6C,U+1A65,U+1A41,U+1A7A;[uni1A6F|uni1A55@1096,0|uni1A34@1322,0|uni1A601A20@1914,0|uni1A6E@1914,0|uni1A34@2506,0|uni1A6C@3098,0|uni1A65@3098,0|uni1A41@3098,0|uni1A7A@3689,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A36,U+1A70,U+1A6B,U+1A76,U+1A60,U+1A32;[uni1A70|uni1A36@592,0|uni1A6B@1184,0|uni1A76@1184,357|uni1A601A32@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A55,U+1A70,U+1A34,U+1A66,U+1A60,U+1A36;[uni1A70|uni1A55@592,0|uni1A37@818,0|uni1A34@1410,0|uni1A66@2002,0|uni1A601A36@2002,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3C,U+1A65,U+1A45,U+1A60,U+1A48,U+1A7A;[uni1A3C|uni1A65@859,0|uni1A45@933,0|uni1A601A48@1524,0|uni1A7A@1755,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A32,U+1A6F,U+1A3E,U+1A60,U+1A37,U+1A7A;[uni1A48|uni1A6F@592,0|uni1A32@1688,0|uni1A3E.v2@2620,0|uni1A601A37@3353,0|uni1A7A@3584,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A6E,U+1A65,U+1A41,U+1A7A,U+1A60,U+1A37;[uni1A6E|uni1A48@592,0|uni1A65@1184,0|uni1A41@1184,0|uni1A7A@1775,0|uni1A601A37@1775,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-7.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-7.tests
new file mode 100644
index 0000000..292bb64
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-7.tests
@@ -0,0 +1,18 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A62,U+1A75,U+1A57,U+1A63;[uni1A34|uni1A621A75@592,0|uni1A57@592,0|uni1A63@818,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A21,U+1A36,U+1A60,U+1A35,U+1A63;[uni1A21|uni1A361A63@592,0|uni1A601A35@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A76,U+1A60,U+1A2F,U+1A66,U+00A0;[uni1A23|uni1A76@592,0|uni1A601A2F@592,0|uni1A66@1095,0|space_nb@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A76,U+1A60,U+1A3E,U+1A63;[uni1A37|uni1A76@592,0|uni1A601A3E@592,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A60,U+1A76,U+1A3E,U+1A63;[uni1A37|uni1A76@592,0|uni1A601A3E@592,0|uni1A63@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A37,U+1A76,U+1A60,U+1A2F,U+1A63,U+1A60,U+1A3F;[uni1A37|uni1A76@592,0|uni1A601A2F@592,0|uni1A63@592,0|uni1A601A3F@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A27,U+1A62,U+1A60,U+1A45,U+1A64;[uni1A27|uni1A62@592,0|uni1A601A45@592,0|uni1A64@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A6E,U+1A60,U+1A53,U+1A60,U+1A45;[uni1A6E|uni1A48@592,0|uni1A601A53@1184,0|uni1A601A45@1311,-547]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A34,U+1A6F,U+1A60,U+1A36,U+1A73;[uni1A6F|uni1A34@1096,0|uni1A601A36@1688,0|uni1A73@1688,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A53,U+1A60,U+1A3E,U+1A63;[uni1A53|uni1A601A3E@762,0|uni1A63@933,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A20,U+1A6E,U+1A60,U+1A48,U+1A63;[uni1A6E|uni1A20@592,0|uni1A601A48@1524,0|uni1A63@1751,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A71,U+1A60,U+1A3E,U+1A63;[uni1A71|uni1A3B@592,0|uni1A601A3E@1354,0|uni1A63@1524,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A6E,U+1A60,U+1A45,U+1A76,U+1A64;[uni1A6E|uni1A48@592,0|uni1A601A45@1184,0|uni1A76@1184,0|uni1A64@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A6E,U+1A60,U+1A43,U+1A63;[uni1A6E|uni1A45@592,0|uni1A601A43@1184,0|uni1A63@1410,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A35,U+1A64,U+1A60,U+1A32,U+1A69;[uni1A35|uni1A64@592,0|uni1A601A32@863,0|uni1A69@863,-547]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A29,U+1A60,U+1A53;[uni1A29|uni1A601A53@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A6D,U+1A60,U+1A45,U+1A7B,U+1A63;[uni1A3B|uni1A6D@933,0|uni1A601A45@1137,-547|uni1A78@1204,195|uni1A63@1159,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A6B,U+1A60,U+1A26,U+1A63,U+1A60,U+1A36;[uni1A48|uni1A6B@592,0|uni1A601A26@592,0|uni1A63@592,0|uni1A601A36@1184,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-8.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-8.tests
new file mode 100644
index 0000000..9db085c
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-8.tests
@@ -0,0 +1,13 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A6C,U+1A73,U+1A75;[uni1A3B|uni1A6C.wide@933,0|uni1A73@762,0|uni1A75@762,447]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A48,U+1A37,U+1A77,U+1A63,U+1A60,U+1A3F;[uni1A48|uni1A37@592,0|uni1A77@1184,0|uni1A63@1184,0|uni1A601A3F@1775,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A60,U+1A3F,U+1A59;[uni1A45|uni1A601A3F@592,0|uni1A59@823,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A6A,U+1A7A;[uni1A23|uni1A6A@592,0|uni1A7A@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A81,U+1A82,U+00A0,U+1A3B,U+1A62,U+1A60,U+1A36,U+1A7B,U+1A63;[uni1A81|uni1A82@592,0|space_nb@1184,0|uni1A3B@1501,0|uni1A62@2263,0|uni1A601A36@2263,0|uni1A78@2263,357|uni1A63@2434,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A3B,U+1A71,U+1A7B,U+1A63,U+1A60,U+1A3F;[uni1A71|uni1A3B@592,0|uni1A78@1354,0|uni1A63@1524,0|uni1A601A3F@2116,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A29,U+1A60,U+1A3F,U+1A59,U+1A32,U+1A69,U+1A74;[uni1A29|uni1A601A3F@592,0|uni1A59@823,0|uni1A32@818,0|uni1A69@1580,0|uni1A74@1580,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A32,U+1A5B,U+1A69;[uni1A45|uni1A321A5B@592,0|uni1A69@1184,-734]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A45,U+1A32,U+1A60,U+1A33,U+1A69;[uni1A45|uni1A32@592,0|uni1A601A33@1354,0|uni1A69@1354,-547]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A2F,U+1A60,U+1A3F,U+1A74;[uni1A2F|uni1A601A3F@592,0|uni1A74@823,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A49,U+1A60,U+1A36,U+1A66,U+1A62,U+1A76;[uni1A49|uni1A601A36@762,0|uni1A66@762,0|uni1A621A76@1265,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A6E,U+1A42,U+1A60,U+1A20;[uni1A6E|uni1A41@592,0|uni1A42@1184,0|uni1A601A20@1775,-547]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A41,U+1A60,U+1A3F,U+1A7A;[uni1A41|uni1A601A3F@592,0|uni1A7A@823,0]
diff --git a/test/shape/data/text-rendering-tests/tests/SHLANA-9.tests b/test/shape/data/text-rendering-tests/tests/SHLANA-9.tests
new file mode 100644
index 0000000..ffdcdc4
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/tests/SHLANA-9.tests
@@ -0,0 +1,6 @@
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A74,U+1A37,U+1A74,U+1A75;[uni1A23|uni1A74@592,0|uni1A37@592,0|uni1A74@1184,0|uni1A75@1184,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A74,U+1A37,U+1A74;[uni1A23|uni1A74@592,0|uni1A37@592,0|uni1A74@1184,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A5D,U+1A74,U+1A75;[uni1A23|uni1A5D@592,0|uni1A74@592,0|uni1A75@592,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A74,U+1A5D,U+1A75;[uni1A23|uni1A74@592,0|uni1A5D@592,0|uni1A75@592,357]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A5D,U+1A74;[uni1A23|uni1A5D@592,0|uni1A74@592,0]
+../fonts/TestShapeLana.ttf;--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft;U+1A23,U+1A74,U+1A5D;[uni1A23|uni1A74@592,0|uni1A5D@592,0]
diff --git a/test/shape/data/text-rendering-tests/update.py b/test/shape/data/text-rendering-tests/update.py
new file mode 100755
index 0000000..cf119be
--- /dev/null
+++ b/test/shape/data/text-rendering-tests/update.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+
+import sys, os, subprocess, shutil, glob
+import xml.etree.ElementTree as ET
+
+# Can we extract this from HTML element itself? I couldn't.
+namespaces = {
+	'ft': 'https://github.com/OpenType/fonttest',
+	'xlink': 'http://www.w3.org/1999/xlink',
+}
+def ns (s):
+	ns,s = s.split(':')
+	return '{%s}%s' % (namespaces[ns], s)
+
+def unistr (s):
+	return ','.join('U+%04X' % ord(c) for c in s)
+
+def glyphstr (glyphs):
+	out = []
+	for glyphname, x, y in glyphs:
+		if x or y:
+			out.append ('%s@%d,%d' % (glyphname, x, y))
+		else:
+			out.append (glyphname)
+	return '[' + '|'.join (out) + ']'
+
+def extract_tests (input):
+	html = ET.fromstring (input)
+	found = False
+
+	result = []
+
+	for elt in html.findall (".//*[@class='expected'][@ft:id]", namespaces):
+		found = True
+		name = elt.get (ns ('ft:id'))
+		text = elt.get (ns ('ft:render'))
+		font = elt.get (ns ('ft:font'))
+		variations = elt.get (ns ('ft:var'), '').replace (':', '=').replace (';', ',')
+		glyphs = []
+		for use in elt.findall (".//use"):
+			x = int (use.get ('x'))
+			y = int (use.get ('y'))
+			href = use.get (ns ('xlink:href'))
+			assert href[0] == '#'
+			glyphname = '.'.join (href[1:].split ('/')[1].split ('.')[1:])
+			glyphs.append ((glyphname, x, y))
+		opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft'
+		if variations:
+			opts = opts + ' --variations=%s' % variations
+		result.append ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
+
+	for elt in html.findall (".//*[@class='expected-no-crash'][@ft:id]", namespaces):
+		found = True
+		name = elt.get (ns ('ft:id'))
+		text = elt.get (ns ('ft:render'))
+		font = elt.get (ns ('ft:font'))
+		variations = elt.get (ns ('ft:var'), '').replace (':', '=').replace (';', ',')
+		opts = ''
+		if variations:
+			opts = '--variations=%s' % variations
+		result.append ("../fonts/%s:%s:%s:*" % (font, opts, unistr (text)))
+
+	assert found
+	return '\n'.join (result) + '\n'
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+git = shutil.which ('git')
+assert git
+
+if os.path.isdir ('./text-rendering-tests'):
+	subprocess.run ([git, 'pull'], cwd='text-rendering-tests', check=True)
+else:
+	subprocess.run ([git, 'clone', 'https://github.com/unicode-org/text-rendering-tests'], check=True)
+
+shutil.rmtree ('fonts', ignore_errors=True)
+assert not os.path.exists ('fonts')
+shutil.copytree ('text-rendering-tests/fonts', 'fonts')
+subprocess.run([git, 'add', 'fonts'], check=True)
+
+shutil.rmtree ('tests', ignore_errors=True)
+assert not os.path.isdir('tests')
+os.mkdir ('tests')
+
+with open ('DISABLED', 'r') as f: disabled = f.read ()
+
+tests = []
+disabled_tests = []
+
+for x in sorted (os.listdir ('text-rendering-tests/testcases')):
+	if not x.endswith ('.html') or x == 'index.html': continue
+	out = 'tests/%s.tests' % x.split('.html')[0]
+	with open ('text-rendering-tests/testcases/' + x, 'r') as f: content = f.read ()
+	with open (out, 'w') as f: f.write (extract_tests (content))
+	if out in disabled:
+		disabled_tests.append (out)
+	else:
+		tests.append (out)
+
+subprocess.run([git, 'add', 'tests'], check=True)
+
+with open ('meson.build', 'w') as f: f.write ('\n'.join (
+	['text_rendering_tests = ['] +
+	['  \'%s\',' % x.split('tests/')[1] for x in tests] +
+	[']', '', 'disabled_text_rendering_tests = ['] +
+	['  \'%s\',' % x.split('tests/')[1] for x in disabled_tests] +
+	[']', '']
+))
+
+with open ('Makefile.sources', 'w') as f: f.write ('\n'.join (
+	['TESTS = \\'] +
+	['	%s \\' % x for x in tests] +
+	['	$(NULL)', '', 'DISBALED_TESTS = \\'] +
+	['	%s \\' % x for x in disabled_tests] +
+	['	$(NULL)', '']
+))
+
+subprocess.run([git, 'add', 'Makefile.sources'], check=True)
+
+print ('Updated the testsuit, now run `git commit -e -m "[test/text-rendering-tests] Update from upstream"`')
diff --git a/test/shape/hb-diff b/test/shape/hb-diff
new file mode 100755
index 0000000..15a1e27
--- /dev/null
+++ b/test/shape/hb-diff
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+import sys, os
+
+if len (sys.argv) < 2:
+	sys.exit ("usage: %s FILES..." % sys.argv[0])
+
+ZipDiffer.diff_files (FileHelpers.open_file_or_stdin (f) for f in sys.argv[1:])
diff --git a/test/shape/hb-diff-colorize b/test/shape/hb-diff-colorize
new file mode 100755
index 0000000..7c481f5
--- /dev/null
+++ b/test/shape/hb-diff-colorize
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+formatter = ColorFormatter.Auto (sys.argv)
+colorizer = DiffColorizer (formatter=formatter)
+UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (colorizer.colorize_diff))
diff --git a/test/shape/hb-diff-filter-failures b/test/shape/hb-diff-filter-failures
new file mode 100755
index 0000000..fc868d9
--- /dev/null
+++ b/test/shape/hb-diff-filter-failures
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (DiffFilters.filter_failures))
diff --git a/test/shape/hb-diff-stat b/test/shape/hb-diff-stat
new file mode 100755
index 0000000..f847116
--- /dev/null
+++ b/test/shape/hb-diff-stat
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_files (DiffSinks.print_stat)
diff --git a/test/shape/hb-unicode-decode b/test/shape/hb-unicode-decode
new file mode 100755
index 0000000..1dc7052
--- /dev/null
+++ b/test/shape/hb-unicode-decode
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.decode, "UNICODE_STRING")
diff --git a/test/shape/hb-unicode-encode b/test/shape/hb-unicode-encode
new file mode 100755
index 0000000..99a99b3
--- /dev/null
+++ b/test/shape/hb-unicode-encode
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.encode, "UNICODE_STRING", '')
diff --git a/test/shape/hb-unicode-prettyname b/test/shape/hb-unicode-prettyname
new file mode 100755
index 0000000..41289b5
--- /dev/null
+++ b/test/shape/hb-unicode-prettyname
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.pretty_names, "UNICODE_CODEPOINTS", \
+					    concat_separator = ' ')
diff --git a/test/shape/hb_test_tools.py b/test/shape/hb_test_tools.py
new file mode 100644
index 0000000..682b919
--- /dev/null
+++ b/test/shape/hb_test_tools.py
@@ -0,0 +1,491 @@
+#!/usr/bin/env python3
+
+import sys, os, re, difflib, unicodedata, errno, cgi, itertools
+from itertools import *
+
+diff_symbols = "-+=*&^%$#@!~/"
+diff_colors = ['red', 'green', 'blue']
+
+def codepoints(s):
+	return (ord (u) for u in s)
+
+class ColorFormatter:
+
+	class Null:
+		@staticmethod
+		def start_color (c): return ''
+		@staticmethod
+		def end_color (): return ''
+		@staticmethod
+		def escape (s): return s
+		@staticmethod
+		def newline (): return '\n'
+
+	class ANSI:
+		@staticmethod
+		def start_color (c):
+			return {
+				'red': '\033[41;37;1m',
+				'green': '\033[42;37;1m',
+				'blue': '\033[44;37;1m',
+			}[c]
+		@staticmethod
+		def end_color ():
+			return '\033[m'
+		@staticmethod
+		def escape (s): return s
+		@staticmethod
+		def newline (): return '\n'
+
+	class HTML:
+		@staticmethod
+		def start_color (c):
+			return '<span style="background:%s">' % c
+		@staticmethod
+		def end_color ():
+			return '</span>'
+		@staticmethod
+		def escape (s): return cgi.escape (s)
+		@staticmethod
+		def newline (): return '<br/>\n'
+
+	@staticmethod
+	def Auto (argv = [], out = sys.stdout):
+		format = ColorFormatter.ANSI
+		if "--format" in argv:
+			argv.remove ("--format")
+			format = ColorFormatter.ANSI
+		if "--format=ansi" in argv:
+			argv.remove ("--format=ansi")
+			format = ColorFormatter.ANSI
+		if "--format=html" in argv:
+			argv.remove ("--format=html")
+			format = ColorFormatter.HTML
+		if "--no-format" in argv:
+			argv.remove ("--no-format")
+			format = ColorFormatter.Null
+		return format
+
+
+class DiffColorizer:
+
+	diff_regex = re.compile ('([a-za-z0-9_]*)([^a-za-z0-9_]?)')
+
+	def __init__ (self, formatter, colors=diff_colors, symbols=diff_symbols):
+		self.formatter = formatter
+		self.colors = colors
+		self.symbols = symbols
+
+	def colorize_lines (self, lines):
+		lines = (l if l else '' for l in lines)
+		ss = [self.diff_regex.sub (r'\1\n\2\n', l).splitlines (True) for l in lines]
+		oo = ["",""]
+		st = [False, False]
+		for l in difflib.Differ().compare (*ss):
+			if l[0] == '?':
+				continue
+			if l[0] == ' ':
+				for i in range(2):
+					if st[i]:
+						oo[i] += self.formatter.end_color ()
+						st[i] = False
+				oo = [o + self.formatter.escape (l[2:]) for o in oo]
+				continue
+			if l[0] in self.symbols:
+				i = self.symbols.index (l[0])
+				if not st[i]:
+					oo[i] += self.formatter.start_color (self.colors[i])
+					st[i] = True
+				oo[i] += self.formatter.escape (l[2:])
+				continue
+		for i in range(2):
+			if st[i]:
+				oo[i] += self.formatter.end_color ()
+				st[i] = False
+		oo = [o.replace ('\n', '') for o in oo]
+		return [s1+s2+self.formatter.newline () for (s1,s2) in zip (self.symbols, oo) if s2]
+
+	def colorize_diff (self, f):
+		lines = [None, None]
+		for l in f:
+			if l[0] not in self.symbols:
+				yield self.formatter.escape (l).replace ('\n', self.formatter.newline ())
+				continue
+			i = self.symbols.index (l[0])
+			if lines[i]:
+				# Flush
+				for line in self.colorize_lines (lines):
+					yield line
+				lines = [None, None]
+			lines[i] = l[1:]
+			if (all (lines)):
+				# Flush
+				for line in self.colorize_lines (lines):
+					yield line
+				lines = [None, None]
+		if (any (lines)):
+			# Flush
+			for line in self.colorize_lines (lines):
+				yield line
+
+
+class ZipDiffer:
+
+	@staticmethod
+	def diff_files (files, symbols=diff_symbols):
+		files = tuple (files) # in case it's a generator, copy it
+		try:
+			for lines in itertools.zip_longest (*files):
+				if all (lines[0] == line for line in lines[1:]):
+					sys.stdout.writelines ([" ", lines[0]])
+					continue
+
+				for i, l in enumerate (lines):
+					if l:
+						sys.stdout.writelines ([symbols[i], l])
+		except IOError as e:
+			if e.errno != errno.EPIPE:
+				sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror))
+
+
+class DiffFilters:
+
+	@staticmethod
+	def filter_failures (f):
+		for key, lines in DiffHelpers.separate_test_cases (f):
+			lines = list (lines)
+			if not DiffHelpers.test_passed (lines):
+				for l in lines: yield l
+
+class Stat:
+
+	def __init__ (self):
+		self.count = 0
+		self.freq = 0
+
+	def add (self, test):
+		self.count += 1
+		self.freq += test.freq
+
+class Stats:
+
+	def __init__ (self):
+		self.passed = Stat ()
+		self.failed = Stat ()
+		self.total  = Stat ()
+
+	def add (self, test):
+		self.total.add (test)
+		if test.passed:
+			self.passed.add (test)
+		else:
+			self.failed.add (test)
+
+	def mean (self):
+		return float (self.passed.count) / self.total.count
+
+	def variance (self):
+		return (float (self.passed.count) / self.total.count) * \
+		       (float (self.failed.count) / self.total.count)
+
+	def stddev (self):
+		return self.variance () ** .5
+
+	def zscore (self, population):
+		"""Calculate the standard score.
+		   Population is the Stats for population.
+		   Self is Stats for sample.
+		   Returns larger absolute value if sample is highly unlikely to be random.
+		   Anything outside of -3..+3 is very unlikely to be random.
+		   See: https://en.wikipedia.org/wiki/Standard_score"""
+
+		return (self.mean () - population.mean ()) / population.stddev ()
+
+
+
+
+class DiffSinks:
+
+	@staticmethod
+	def print_stat (f):
+		passed = 0
+		failed = 0
+		# XXX port to Stats, but that would really slow us down here
+		for key, lines in DiffHelpers.separate_test_cases (f):
+			if DiffHelpers.test_passed (lines):
+				passed += 1
+			else:
+				failed += 1
+		total = passed + failed
+		print ("%d out of %d tests passed.  %d failed (%g%%)" % (passed, total, failed, 100. * failed / total))
+
+
+class Test:
+
+	def __init__ (self, lines):
+		self.freq = 1
+		self.passed = True
+		self.identifier = None
+		self.text = None
+		self.unicodes = None
+		self.glyphs = None
+		for l in lines:
+			symbol = l[0]
+			if symbol != ' ':
+				self.passed = False
+			i = 1
+			if ':' in l:
+				i = l.index (':')
+				if not self.identifier:
+					self.identifier = l[1:i]
+				i = i + 2 # Skip colon and space
+			j = -1
+			if l[j] == '\n':
+				j -= 1
+			brackets = l[i] + l[j]
+			l = l[i+1:-2]
+			if brackets == '()':
+				self.text = l
+			elif brackets == '<>':
+				self.unicodes = Unicode.parse (l)
+			elif brackets == '[]':
+				# XXX we don't handle failed tests here
+				self.glyphs = l
+
+
+class DiffHelpers:
+
+	@staticmethod
+	def separate_test_cases (f):
+		'''Reads lines from f, and if the lines have identifiers, ie.
+		   have a colon character, groups them by identifier,
+		   yielding lists of all lines with the same identifier.'''
+
+		def identifier (l):
+			if ':' in l[1:]:
+				return l[1:l.index (':')]
+			return l
+		return groupby (f, key=identifier)
+
+	@staticmethod
+	def test_passed (lines):
+		lines = list (lines)
+		# XXX This is a hack, but does the job for now.
+		if any (l.find("space+0|space+0") >= 0 for l in lines if l[0] == '+'): return True
+		if any (l.find("uni25CC") >= 0 for l in lines if l[0] == '+'): return True
+		if any (l.find("dottedcircle") >= 0 for l in lines if l[0] == '+'): return True
+		if any (l.find("glyph0") >= 0 for l in lines if l[0] == '+'): return True
+		if any (l.find("gid0") >= 0 for l in lines if l[0] == '+'): return True
+		if any (l.find("notdef") >= 0 for l in lines if l[0] == '+'): return True
+		return all (l[0] == ' ' for l in lines)
+
+
+class FilterHelpers:
+
+	@staticmethod
+	def filter_printer_function (filter_callback):
+		def printer (f):
+			for line in filter_callback (f):
+				print (line)
+		return printer
+
+	@staticmethod
+	def filter_printer_function_no_newline (filter_callback):
+		def printer (f):
+			for line in filter_callback (f):
+				sys.stdout.writelines ([line])
+		return printer
+
+
+class Ngram:
+
+	@staticmethod
+	def generator (n):
+
+		def gen (f):
+			l = []
+			for x in f:
+				l.append (x)
+				if len (l) == n:
+					yield tuple (l)
+					l[:1] = []
+
+		gen.n = n
+		return gen
+
+
+class UtilMains:
+
+	@staticmethod
+	def process_multiple_files (callback, mnemonic = "FILE"):
+
+		if "--help" in sys.argv:
+			sys.exit ("Usage: %s %s..." % (sys.argv[0], mnemonic))
+
+		try:
+			files = sys.argv[1:] if len (sys.argv) > 1 else ['-']
+			for s in files:
+				callback (FileHelpers.open_file_or_stdin (s))
+		except IOError as e:
+			if e.errno != errno.EPIPE:
+				sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror))
+
+	@staticmethod
+	def process_multiple_args (callback, mnemonic):
+
+		if len (sys.argv) == 1 or "--help" in sys.argv:
+			sys.exit ("Usage: %s %s..." % (sys.argv[0], mnemonic))
+
+		try:
+			for s in sys.argv[1:]:
+				callback (s)
+		except IOError as e:
+			if e.errno != errno.EPIPE:
+				sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror))
+
+	@staticmethod
+	def filter_multiple_strings_or_stdin (callback, mnemonic, \
+					      separator = " ", \
+					      concat_separator = False):
+
+		if "--help" in sys.argv:
+			sys.exit ("""Usage:
+  %s %s...
+or:
+  %s
+When called with no arguments, input is read from standard input.
+""" % (sys.argv[0], mnemonic, sys.argv[0]))
+
+		try:
+			if len (sys.argv) == 1:
+				while (1):
+					line = sys.stdin.readline ()
+					if not len (line):
+						break
+					if line[-1] == '\n':
+						line = line[:-1]
+					print (callback (line))
+			else:
+				args = sys.argv[1:]
+				if concat_separator != False:
+					args = [concat_separator.join (args)]
+				print (separator.join (callback (x) for x in (args)))
+		except IOError as e:
+			if e.errno != errno.EPIPE:
+				sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror))
+
+
+class Unicode:
+
+	@staticmethod
+	def decode (s):
+		return ','.join ("U+%04X" % cp for cp in codepoints (s))
+
+	@staticmethod
+	def parse (s):
+		s = re.sub (r"0[xX]", " ", s)
+		s = re.sub (r"[<+\->{},;&#\\xXuUnNiI\n\t]", " ", s)
+		return [int (x, 16) for x in s.split ()]
+
+	@staticmethod
+	def encode (s):
+		return ''.join (chr (x) for x in Unicode.parse (s))
+
+	shorthands = {
+		"ZERO WIDTH NON-JOINER": "ZWNJ",
+		"ZERO WIDTH JOINER": "ZWJ",
+		"NARROW NO-BREAK SPACE": "NNBSP",
+		"COMBINING GRAPHEME JOINER": "CGJ",
+		"LEFT-TO-RIGHT MARK": "LRM",
+		"RIGHT-TO-LEFT MARK": "RLM",
+		"LEFT-TO-RIGHT EMBEDDING": "LRE",
+		"RIGHT-TO-LEFT EMBEDDING": "RLE",
+		"POP DIRECTIONAL FORMATTING": "PDF",
+		"LEFT-TO-RIGHT OVERRIDE": "LRO",
+		"RIGHT-TO-LEFT OVERRIDE": "RLO",
+	}
+
+	@staticmethod
+	def pretty_name (u):
+		try:
+			s = unicodedata.name (u)
+		except ValueError:
+			return "XXX"
+		s = re.sub (".* LETTER ", "", s)
+		s = re.sub (".* VOWEL SIGN (.*)", r"\1-MATRA", s)
+		s = re.sub (".* SIGN ", "", s)
+		s = re.sub (".* COMBINING ", "", s)
+		if re.match (".* VIRAMA", s):
+			s = "HALANT"
+		if s in Unicode.shorthands:
+			s = Unicode.shorthands[s]
+		return s
+
+	@staticmethod
+	def pretty_names (s):
+		s = re.sub (r"[<+>\\uU]", " ", s)
+		s = re.sub (r"0[xX]", " ", s)
+		s = [chr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)]
+		return ' + '.join (Unicode.pretty_name (x) for x in s)
+
+
+class FileHelpers:
+
+	@staticmethod
+	def open_file_or_stdin (f):
+		if f == '-':
+			return sys.stdin
+		return open (f)
+
+
+class Manifest:
+
+	@staticmethod
+	def read (s, strict = True):
+
+		if not os.path.exists (s):
+			if strict:
+				sys.exit ("%s: %s does not exist" % (sys.argv[0], s))
+			return
+
+		s = os.path.normpath (s)
+
+		if os.path.isdir (s):
+
+			try:
+				m = open (os.path.join (s, "MANIFEST"))
+				items = [x.strip () for x in m.readlines ()]
+				for f in items:
+					for p in Manifest.read (os.path.join (s, f)):
+						yield p
+			except IOError:
+				if strict:
+					sys.exit ("%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST")))
+				return
+		else:
+			yield s
+
+	@staticmethod
+	def update_recursive (s):
+
+		for dirpath, dirnames, filenames in os.walk (s, followlinks=True):
+
+			for f in ["MANIFEST", "README", "LICENSE", "COPYING", "AUTHORS", "SOURCES", "ChangeLog"]:
+				if f in dirnames:
+					dirnames.remove (f)
+				if f in filenames:
+					filenames.remove (f)
+			dirnames.sort ()
+			filenames.sort ()
+			ms = os.path.join (dirpath, "MANIFEST")
+			print ("  GEN    %s" % ms)
+			m = open (ms, "w")
+			for f in filenames:
+				print (f, file=m)
+			for f in dirnames:
+				print (f, file=m)
+			for f in dirnames:
+				Manifest.update_recursive (os.path.join (dirpath, f))
+
+if __name__ == '__main__':
+	pass
diff --git a/test/shape/meson.build b/test/shape/meson.build
new file mode 100644
index 0000000..dfc9f32
--- /dev/null
+++ b/test/shape/meson.build
@@ -0,0 +1,51 @@
+
+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')
+
+env = environment()
+env.set('HAVE_FREETYPE', '@0@'.format(conf.get('HAVE_FREETYPE', 0)))
+
+foreach file_name : in_house_tests
+  test_name = file_name.split('.')[0]
+
+  test(test_name, shaping_run_tests_py,
+    args: [
+      hb_shape,
+      join_paths(meson.current_source_dir(), 'data', 'in-house', 'tests', file_name),
+    ],
+    env: env,
+    workdir: join_paths(meson.current_build_dir(), '..', '..'),
+    suite: ['shaping', 'in-house'],
+  )
+endforeach
+
+foreach file_name : aots_tests
+  test_name = file_name.split('.')[0]
+
+  test(test_name, shaping_run_tests_py,
+    args: [
+      hb_shape,
+      join_paths(meson.current_source_dir(), 'data', 'aots', 'tests', file_name),
+    ],
+    env: env,
+    workdir: join_paths(meson.current_build_dir(), '..', '..'),
+    suite: ['shaping', 'aots'],
+  )
+endforeach
+
+foreach file_name : text_rendering_tests
+  test_name = file_name.split('.')[0]
+
+  test(test_name, shaping_run_tests_py,
+    args: [
+      hb_shape,
+      join_paths(meson.current_source_dir(), 'data', 'text-rendering-tests', 'tests', file_name),
+    ],
+    env: env,
+    workdir: join_paths(meson.current_build_dir(), '..', '..'),
+    suite: ['shaping', 'text-rendering-tests'],
+  )
+endforeach
diff --git a/test/shape/record-test.sh b/test/shape/record-test.sh
new file mode 100755
index 0000000..41e13c3
--- /dev/null
+++ b/test/shape/record-test.sh
@@ -0,0 +1,128 @@
+#!/bin/bash
+
+dir=`mktemp -d`
+
+if which sha1sum 2>/dev/null >/dev/null; then
+	SHA1SUM=sha1sum
+elif which shasum 2>/dev/null >/dev/null; then
+	SHA1SUM='shasum -a 1'
+elif which digest 2>/dev/null >/dev/null; then
+	SHA1SUM='digest -a sha1'
+else
+	echo "'sha1sum' not found"
+	exit 2
+fi
+
+out=/dev/stdout
+if test "x$1" == 'x-o'; then
+	shift
+	out=$1
+	shift
+fi
+hb_shape=$1
+shift
+fontfile=$1
+if test "x${fontfile:0:1}" == 'x-'; then
+	echo "Specify font file before other options." >&2
+	exit 1
+fi
+shift
+if ! echo "$hb_shape" | grep -q 'hb-shape'; then
+	echo "Specify hb-shape (not hb-view, etc): got "$hb_shape"." >&2
+	exit 1
+fi
+options=
+have_text=false
+for arg in "$@"; do
+	if test "x${arg:0:1}" == 'x-'; then
+		if echo "$arg" | grep -q ' '; then
+			echo "Space in argument is not supported: '$arg'." >&2
+			exit 1
+		fi
+		options="$options${options:+ }$arg"
+		continue
+	fi
+	if $have_text; then
+		echo "Too many arguments found...  Use '=' notation for options: '$arg'" >&2
+		exit 1;
+	fi
+	text="$arg"
+	have_text=true
+done
+if ! $have_text; then
+	text=`cat`
+fi
+unicodes=`echo "$text" | ./hb-unicode-decode`
+glyphs=`echo "$text" | $hb_shape $options "$fontfile"`
+if test $? != 0; then
+	echo "hb-shape failed." >&2
+	exit 2
+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 \
+	--glyph-names \
+	--no-hinting \
+	--layout-features='*' \
+	--gids="$glyph_ids" \
+	--text="$text" \
+	--output-file="$dir/font.subset.ttf" \
+	"$dir/font.ttf"
+fonttools subset \
+	--glyph-names \
+	--no-hinting \
+	--layout-features='*' \
+	--gids="$glyph_ids" \
+	--text="$text" \
+	--output-file="$dir/font.subset.ttf" \
+	"$dir/font.ttf"
+if ! test -s "$dir/font.subset.ttf"; then
+	echo "Subsetter didn't produce nonempty subset font in $dir/font.subset.ttf" >&2
+	exit 2
+fi
+
+# Verify that subset font produces same glyphs!
+glyphs_subset=`echo "$text" | $hb_shape $options "$dir/font.subset.ttf"`
+
+if ! test "x$glyphs" = "x$glyphs_subset"; then
+	echo "Subset font produced different glyphs!" >&2
+	echo "Perhaps font doesn't have glyph names; checking visually..." >&2
+	hb_view=${hb_shape/shape/view}
+	echo "$text" | $hb_view $options "$dir/font.ttf" --output-format=png --output-file="$dir/orig.png"
+	echo "$text" | $hb_view $options "$dir/font.subset.ttf" --output-format=png --output-file="$dir/subset.png"
+	if ! cmp "$dir/orig.png" "$dir/subset.png"; then
+		echo "Images differ.  Please inspect $dir/*.png." >&2
+		echo "$glyphs" >> "$out"
+		echo "$glyphs_subset" >> "$out"
+		exit 2
+	fi
+	echo "Yep; all good." >&2
+	rm -f "$dir/orig.png"
+	rm -f "$dir/subset.png"
+	glyphs=$glyphs_subset
+fi
+
+sha1sum=`$SHA1SUM "$dir/font.subset.ttf" | cut -d' ' -f1`
+subset="data/in-house/fonts/$sha1sum.ttf"
+mv "$dir/font.subset.ttf" "$subset"
+
+# There ought to be an easier way to do this, but it escapes me...
+unicodes_file=`mktemp`
+glyphs_file=`mktemp`
+echo "$unicodes" > "$unicodes_file"
+echo "$glyphs" > "$glyphs_file"
+# Open the "file"s
+exec 3<"$unicodes_file"
+exec 4<"$glyphs_file"
+relative_subset="$subset"
+if test "$out" != "/dev/stdout"; then
+	relative_subset="$(/usr/bin/env python3 -c 'import os, sys; print (os.path.relpath (sys.argv[1], sys.argv[2]))' "$subset" "$(dirname "$out")")"
+fi
+while read uline <&3 && read gline <&4; do
+	echo "$relative_subset;$options;$uline;$gline" >> "$out"
+done
+
+
+rm -f "$dir/font.ttf"
+rmdir "$dir"
diff --git a/test/shape/run-tests.py b/test/shape/run-tests.py
new file mode 100755
index 0000000..83f1fec
--- /dev/null
+++ b/test/shape/run-tests.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+
+import sys, os, subprocess, hashlib
+
+def shape_cmd(command):
+	global hb_shape, process
+	print (hb_shape + ' ' + " ".join(command))
+	process.stdin.write ((';'.join (command) + '\n').encode ("utf-8"))
+	process.stdin.flush ()
+	return process.stdout.readline().decode ("utf-8").strip ()
+
+args = sys.argv[1:]
+
+have_freetype = bool(int(os.getenv ('HAVE_FREETYPE', '1')))
+
+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.""")
+hb_shape, args = args[0], args[1:]
+
+process = subprocess.Popen ([hb_shape, '--batch'],
+			    stdin=subprocess.PIPE,
+			    stdout=subprocess.PIPE,
+			    stderr=sys.stdout)
+
+passes = 0
+fails = 0
+skips = 0
+
+if not len (args):
+	args = ['-']
+
+for filename in args:
+	if filename == '-':
+		print ("Running tests from standard input")
+	else:
+		print ("Running tests in " + filename)
+
+	if filename == '-':
+		f = sys.stdin
+	else:
+		f = open (filename, encoding='utf8')
+
+	for line in f:
+		comment = False
+		if line.startswith ("#"):
+			comment = True
+			line = line[1:]
+
+			if line.startswith (' '):
+				print ("#%s" % line)
+				continue
+
+		line = line.strip ()
+		if not line:
+			continue
+
+		fontfile, options, unicodes, glyphs_expected = line.split (';')
+		options = options.split ()
+		if fontfile.startswith ('/') or fontfile.startswith ('"/'):
+			if os.name == 'nt': # Skip on Windows
+				continue
+
+			fontfile, expected_hash = (fontfile.split('@') + [''])[:2]
+
+			try:
+				with open (fontfile, 'rb') as ff:
+					if expected_hash:
+						actual_hash = hashlib.sha1 (ff.read()).hexdigest ().strip ()
+						if actual_hash != expected_hash:
+							print ('different version of %s found; Expected hash %s, got %s; skipping.' %
+								   (fontfile, expected_hash, actual_hash))
+							skips += 1
+							continue
+			except IOError:
+				print ('%s not found, skip.' % fontfile)
+				skips += 1
+				continue
+		else:
+			cwd = os.path.dirname(filename)
+			fontfile = os.path.normpath (os.path.join (cwd, fontfile))
+
+		extra_options = ["--shaper=ot"]
+		if glyphs_expected != '*':
+			extra_options.append("--verify")
+
+		if comment:
+			print ('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
+			continue
+
+		if "--font-funcs=ft" in options and not have_freetype:
+			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:
+			glyphs1 = shape_cmd ([fontfile, "--font-funcs=ft"] + extra_options + ["--unicodes", unicodes] + options)
+			glyphs2 = shape_cmd ([fontfile, "--font-funcs=ot"] + extra_options + ["--unicodes", unicodes] + options)
+
+			if glyphs1 != glyphs2 and glyphs_expected != '*':
+				print ("FT funcs: " + glyphs1, file=sys.stderr)
+				print ("OT funcs: " + glyphs2, file=sys.stderr)
+				fails += 1
+			else:
+				passes += 1
+
+		if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
+			print ("Actual:   " + glyphs1, file=sys.stderr)
+			print ("Expected: " + glyphs_expected, file=sys.stderr)
+			fails += 1
+		else:
+			passes += 1
+
+print ("%d tests passed; %d failed; %d skipped." % (passes, fails, skips), file=sys.stderr)
+if not (fails + passes):
+	print ("No tests ran.")
+elif not (fails + skips):
+	print ("All tests passed.")
+
+if fails:
+	sys.exit (1)
+elif passes:
+	sys.exit (0)
+else:
+	sys.exit (77)
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/language-persian/mehran.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
rename to test/shape/texts/in-house/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
diff --git a/test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
rename to test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt
rename to test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/non-joining.txt
diff --git a/test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt b/test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
rename to test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/poem.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt
rename to test/shape/texts/in-house/shaper-arabic/script-mongolian/misc/variation-selectors.txt
diff --git a/test/shaping/texts/in-house/shaper-arabic/script-nko/misc/misc.txt b/test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
rename to test/shape/texts/in-house/shaper-arabic/script-nko/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt
rename to test/shape/texts/in-house/shaper-arabic/script-phags-pa/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
rename to test/shape/texts/in-house/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
diff --git a/test/shaping/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt b/test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
rename to test/shape/texts/in-house/shaper-arabic/script-syriac/misc/alaph.txt
diff --git a/test/shaping/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
rename to test/shape/texts/in-house/shaper-default/script-ethiopic/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt
rename to test/shape/texts/in-house/shaper-default/script-han/misc/cjk-compat.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
rename to test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt
rename to test/shape/texts/in-house/shaper-default/script-hiragana/misc/kazuraki-liga.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-linear-b/misc/misc.txt
rename to test/shape/texts/in-house/shaper-default/script-linear-b/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt b/test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
rename to test/shape/texts/in-house/shaper-default/script-tifinagh/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt b/test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
rename to test/shape/texts/in-house/shaper-hangul/script-hangul/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt b/test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
rename to test/shape/texts/in-house/shaper-hebrew/script-hebrew/misc/diacritics.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/misc/reph.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/dottedcircle.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/eyelash.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/joiners.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/spec-deviations.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/misc/tricky-reordering.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/misc/right-matras.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/misc/cibu.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/misc/dot-reph.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/misc/bindu.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/misc/extensive.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt b/test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/misc/reph.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/misc/split-matras.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-tamil/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/misc/misc.txt b/test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/misc/misc.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/LICENSE
diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/README b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/README
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/README
diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES b/test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/SOURCES
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
rename to test/shape/texts/in-house/shaper-indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-house/shaper-khmer/misc.txt b/test/shape/texts/in-house/shaper-khmer/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-khmer/misc.txt
rename to test/shape/texts/in-house/shaper-khmer/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-khmer/other-marks-invalid.txt b/test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-khmer/other-marks-invalid.txt
rename to test/shape/texts/in-house/shaper-khmer/other-marks-invalid.txt
diff --git a/test/shaping/texts/in-house/shaper-khmer/other-marks.txt b/test/shape/texts/in-house/shaper-khmer/other-marks.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-khmer/other-marks.txt
rename to test/shape/texts/in-house/shaper-khmer/other-marks.txt
diff --git a/test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
rename to test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
rename to test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/otspec.txt
diff --git a/test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt b/test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
rename to test/shape/texts/in-house/shaper-myanmar/script-myanmar/misc/utn11.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt
rename to test/shape/texts/in-house/shaper-thai/script-lao/misc/sara-am.txt
diff --git a/test/shaping/texts/in-house/shaper-thai/script-thai/misc/misc.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-thai/script-thai/misc/misc.txt
rename to test/shape/texts/in-house/shaper-thai/script-thai/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt b/test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
rename to test/shape/texts/in-house/shaper-thai/script-thai/misc/phinthu.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt
rename to test/shape/texts/in-house/shaper-thai/script-thai/misc/pua-shaping.txt
diff --git a/test/shaping/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
similarity index 100%
rename from test/shaping/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt
rename to test/shape/texts/in-house/shaper-thai/script-thai/misc/sara-am.txt
diff --git a/test/shaping/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
rename to test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/contractions.txt
diff --git a/test/shaping/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt b/test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
rename to test/shape/texts/in-house/shaper-tibetan/script-tibetan/misc/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-batak/misc.txt b/test/shape/texts/in-house/shaper-use/script-batak/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-batak/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-batak/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-buginese/misc.txt b/test/shape/texts/in-house/shaper-use/script-buginese/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-buginese/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-buginese/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-cham/misc.txt b/test/shape/texts/in-house/shaper-use/script-cham/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-cham/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-cham/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-javanese/misc.txt b/test/shape/texts/in-house/shaper-use/script-javanese/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-javanese/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-javanese/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-kaithi/misc.txt b/test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-kaithi/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-kaithi/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-kharoshti/misc.txt b/test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-kharoshti/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-kharoshti/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-tai-tham/misc.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-tai-tham/misc.txt
rename to test/shape/texts/in-house/shaper-use/script-tai-tham/misc.txt
diff --git a/test/shaping/texts/in-house/shaper-use/script-tai-tham/torture.txt b/test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt
similarity index 100%
rename from test/shaping/texts/in-house/shaper-use/script-tai-tham/torture.txt
rename to test/shape/texts/in-house/shaper-use/script-tai-tham/torture.txt
diff --git a/test/shaping/CMakeLists.txt b/test/shaping/CMakeLists.txt
deleted file mode 100644
index 8e33ede..0000000
--- a/test/shaping/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-if (HB_BUILD_UTILS)
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/in-house/Makefile.sources" INHOUSE)
-  extract_make_variable (TESTS ${INHOUSE})
-  foreach (test IN ITEMS ${TESTS})
-    add_test (NAME ${test}
-      COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $<TARGET_FILE:hb-shape> "data/in-house/${test}"
-      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-    set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77)
-  endforeach ()
-
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/aots/Makefile.sources" INHOUSE)
-  extract_make_variable (TESTS ${INHOUSE})
-  foreach (test IN ITEMS ${TESTS})
-    add_test (NAME ${test}
-      COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $<TARGET_FILE:hb-shape> "data/aots/${test}"
-      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-    set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77)
-  endforeach ()
-
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/text-rendering-tests/Makefile.sources" TEXTRENDERING)
-  extract_make_variable (TESTS ${TEXTRENDERING})
-  foreach (test IN ITEMS ${TESTS})
-    add_test (NAME ${test}
-      COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $<TARGET_FILE:hb-shape> "data/text-rendering-tests/${test}"
-      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-    set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77)
-  endforeach ()
-endif ()
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
deleted file mode 100644
index 66272da..0000000
--- a/test/shaping/Makefile.am
+++ /dev/null
@@ -1,39 +0,0 @@
-# Process this file with automake to produce Makefile.in
-
-NULL =
-EXTRA_DIST =
-CLEANFILES =
-DISTCLEANFILES =
-MAINTAINERCLEANFILES =
-SUBDIRS = data
-
-# Convenience targets:
-lib:
-	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-libs:
-	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
-
-EXTRA_DIST += \
-	README.md \
-	CMakeLists.txt \
-	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)
-
-# TODO Figure out Python stuff
-EXTRA_DIST += \
-	hb_test_tools.py \
-	$(NULL)
-CLEANFILES += \
-	hb_test_tools.py[co] \
-	$(NULL)
-
--include $(top_srcdir)/git.mk
diff --git a/test/shaping/data/aots/Makefile.am b/test/shaping/data/aots/Makefile.am
deleted file mode 100644
index 3b1faee..0000000
--- a/test/shaping/data/aots/Makefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-# Process this file with automake to produce Makefile.in
-
-NULL =
-
-# Convenience targets:
-lib:
-	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-
-EXTRA_DIST = \
-	COPYING \
-	fonts \
-	$(TESTS) \
-	$(NULL)
-
-TEST_EXTENSIONS = .tests
-TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
-
-init-aots:
-	git clone https://github.com/adobe-type-tools/aots $(srcdir)/aots
-	make -C$(srcdir)/aots
-	make -C$(srcdir)/aots/harfbuzz
-	touch $(srcdir)/init-aots
-
-update-tests: init-aots lib
-	cp $(srcdir)/hb-aots-tester.cpp $(srcdir)/aots/harfbuzz/hb-aots-tester.cpp
-	$(CXX) -Wno-narrowing $(srcdir)/aots/harfbuzz/hb-aots-tester.cpp \
-		-I$(top_srcdir)/src/ -o $(srcdir)/aots/harfbuzz/aots \
-		-L$(top_builddir)/src/.libs -lharfbuzz
-	rm -rf $(srcdir)/tests/
-	mkdir $(srcdir)/tests/
-	export LD_LIBRARY_PATH=$(realpath $(top_builddir)/src/.libs); cd $(srcdir)/aots/harfbuzz; ./aots
-
-.PHONY: update-tests
-
-include Makefile.sources
-
--include $(top_srcdir)/git.mk
diff --git a/test/shaping/data/aots/Makefile.sources b/test/shaping/data/aots/Makefile.sources
deleted file mode 100644
index 9339682..0000000
--- a/test/shaping/data/aots/Makefile.sources
+++ /dev/null
@@ -1,126 +0,0 @@
-TESTS = \
-	tests/classdef1_empty.tests \
-	tests/classdef1_multiple.tests \
-	tests/classdef1_single.tests \
-	tests/classdef1.tests \
-	tests/classdef2_empty.tests \
-	tests/classdef2_multiple.tests \
-	tests/classdef2_single.tests \
-	tests/classdef2.tests \
-	tests/gpos_chaining1_boundary.tests \
-	tests/gpos_chaining1_lookupflag.tests \
-	tests/gpos_chaining1_multiple_subrules.tests \
-	tests/gpos_chaining1_next_glyph.tests \
-	tests/gpos_chaining1_simple.tests \
-	tests/gpos_chaining1_successive.tests \
-	tests/gpos_chaining2_boundary.tests \
-	tests/gpos_chaining2_lookupflag.tests \
-	tests/gpos_chaining2_multiple_subrules.tests \
-	tests/gpos_chaining2_next_glyph.tests \
-	tests/gpos_chaining2_simple.tests \
-	tests/gpos_chaining2_successive.tests \
-	tests/gpos_chaining3_boundary.tests \
-	tests/gpos_chaining3_lookupflag.tests \
-	tests/gpos_chaining3_next_glyph.tests \
-	tests/gpos_chaining3_simple.tests \
-	tests/gpos_chaining3_successive.tests \
-	tests/gpos_context1_boundary.tests \
-	tests/gpos_context1_expansion.tests \
-	tests/gpos_context1_lookupflag.tests \
-	tests/gpos_context1_multiple_subrules.tests \
-	tests/gpos_context1_next_glyph.tests \
-	tests/gpos_context1_simple.tests \
-	tests/gpos_context1_successive.tests \
-	tests/gpos_context2_boundary.tests \
-	tests/gpos_context2_classes.tests \
-	tests/gpos_context2_expansion.tests \
-	tests/gpos_context2_lookupflag.tests \
-	tests/gpos_context2_multiple_subrules.tests \
-	tests/gpos_context2_next_glyph.tests \
-	tests/gpos_context2_simple.tests \
-	tests/gpos_context2_successive.tests \
-	tests/gpos_context3_boundary.tests \
-	tests/gpos_context3_lookupflag.tests \
-	tests/gpos_context3_next_glyph.tests \
-	tests/gpos_context3_simple.tests \
-	tests/gpos_context3_successive.tests \
-	tests/gpos1_1_lookupflag.tests \
-	tests/gpos1_1_simple.tests \
-	tests/gpos1_2_lookupflag.tests \
-	tests/gpos1_2.tests \
-	tests/gpos2_1_lookupflag.tests \
-	tests/gpos2_1_next_glyph.tests \
-	tests/gpos2_1_simple.tests \
-	tests/gpos2_1.tests \
-	tests/gpos2_2.tests \
-	tests/gpos3_lookupflag.tests \
-	tests/gpos3.tests \
-	tests/gpos4_lookupflag.tests \
-	tests/gpos4_multiple_anchors.tests \
-	tests/gpos4_simple.tests \
-	tests/gpos5.tests \
-	tests/gpos6.tests \
-	tests/gpos7_1.tests \
-	tests/gpos9.tests \
-	tests/gsub_chaining1_boundary.tests \
-	tests/gsub_chaining1_lookupflag.tests \
-	tests/gsub_chaining1_multiple_subrules.tests \
-	tests/gsub_chaining1_next_glyph.tests \
-	tests/gsub_chaining1_simple.tests \
-	tests/gsub_chaining1_successive.tests \
-	tests/gsub_chaining2_boundary.tests \
-	tests/gsub_chaining2_lookupflag.tests \
-	tests/gsub_chaining2_multiple_subrules.tests \
-	tests/gsub_chaining2_next_glyph.tests \
-	tests/gsub_chaining2_simple.tests \
-	tests/gsub_chaining2_successive.tests \
-	tests/gsub_chaining3_boundary.tests \
-	tests/gsub_chaining3_lookupflag.tests \
-	tests/gsub_chaining3_next_glyph.tests \
-	tests/gsub_chaining3_simple.tests \
-	tests/gsub_chaining3_successive.tests \
-	tests/gsub_context1_boundary.tests \
-	tests/gsub_context1_expansion.tests \
-	tests/gsub_context1_lookupflag.tests \
-	tests/gsub_context1_multiple_subrules.tests \
-	tests/gsub_context1_next_glyph.tests \
-	tests/gsub_context1_simple.tests \
-	tests/gsub_context1_successive.tests \
-	tests/gsub_context2_boundary.tests \
-	tests/gsub_context2_classes.tests \
-	tests/gsub_context2_expansion.tests \
-	tests/gsub_context2_lookupflag.tests \
-	tests/gsub_context2_multiple_subrules.tests \
-	tests/gsub_context2_next_glyph.tests \
-	tests/gsub_context2_simple.tests \
-	tests/gsub_context2_successive.tests \
-	tests/gsub_context3_boundary.tests \
-	tests/gsub_context3_lookupflag.tests \
-	tests/gsub_context3_next_glyph.tests \
-	tests/gsub_context3_simple.tests \
-	tests/gsub_context3_successive.tests \
-	tests/gsub1_1_lookupflag.tests \
-	tests/gsub1_1_modulo.tests \
-	tests/gsub1_1_simple.tests \
-	tests/gsub1_2_lookupflag.tests \
-	tests/gsub1_2_simple.tests \
-	tests/gsub2_1_lookupflag.tests \
-	tests/gsub2_1_multiple_sequences.tests \
-	tests/gsub2_1_simple.tests \
-	tests/gsub3_1_lookupflag.tests \
-	tests/gsub3_1_multiple.tests \
-	tests/gsub3_1_simple.tests \
-	tests/gsub4_1_lookupflag.tests \
-	tests/gsub4_1_multiple_ligatures.tests \
-	tests/gsub4_1_multiple_ligsets.tests \
-	tests/gsub4_1_simple.tests \
-	tests/gsub7.tests \
-	tests/lookupflag_ignore_attach.tests \
-	tests/lookupflag_ignore_base.tests \
-	tests/lookupflag_ignore_combination.tests \
-	tests/lookupflag_ignore_ligatures.tests \
-	tests/lookupflag_ignore_marks.tests \
-	$(NULL)
-
-DISABLED_TESTS = \
-	$(NULL)
diff --git a/test/shaping/data/aots/hb-aots-tester.cpp b/test/shaping/data/aots/hb-aots-tester.cpp
deleted file mode 100644
index bd46dec..0000000
--- a/test/shaping/data/aots/hb-aots-tester.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-/*____________________________________________________________________________
-
-    Copyright 2000-2016 Adobe Systems Incorporated. All Rights Reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use these files except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-____________________________________________________________________________*/
-
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "hb.h"
-#include "hb-ot.h"
-
-static const bool verbose = true;
-
-
-hb_feature_t *gFeatures;
-int gNbFeatures;
-
- hb_buffer_t *runTest(const char *testName,
-                      const char *fontfileName,
-                      unsigned int *in, int nbIn,
-                      unsigned int *select, int nbSelect)
-{
-    FILE *f = fopen (fontfileName, "rb");
-    fseek(f, 0, SEEK_END);
-    long fontsize = ftell(f);
-    fseek(f, 0, SEEK_SET);
-    char *fontdata = (char *)malloc (fontsize);
-    fread(fontdata, fontsize, 1, f);
-    fclose(f);
-
-    if (verbose) {
-        printf ("------------------------------- %s\n", testName);
-    }
-
-    // setup font
-    hb_blob_t *blob = hb_blob_create(fontdata, fontsize,
-                                     HB_MEMORY_MODE_WRITABLE,
-                                     0, 0);
-    hb_face_t *face = hb_face_create(blob, 0);
-    hb_font_t *font = hb_font_create(face);
-    unsigned int upem = hb_face_get_upem (face);
-
-    hb_font_set_scale(font, upem, upem);
-    hb_ot_font_set_funcs (font);
-
-    // setup buffer
-    hb_buffer_t *buffer = hb_buffer_create();
-    hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
-    hb_buffer_set_script(buffer, HB_SCRIPT_LATIN);
-    hb_buffer_set_language(buffer, hb_language_from_string("en", 2));
-
-    hb_buffer_add_utf32(buffer, in, nbIn, 0, nbIn);
-
-    // setup features
-    hb_feature_t *features;
-    int nbFeatures;
-
-    if (nbSelect == 0)
-    {
-        nbFeatures = 1;
-
-        features = (hb_feature_t *) malloc (sizeof (*features));
-        features[0].tag = HB_TAG('t', 'e', 's', 't');
-        features[0].value = 1;
-        features[0].start = 0;
-        features[0].end = 0xffffffff;
-    }
-    else
-    {
-        nbFeatures = 0;
-
-        features = (hb_feature_t *) malloc (sizeof (*features) * nbSelect);
-        for (int i = 0; i < nbSelect; i++) {
-            if (select[i] != -1) {
-                features[nbFeatures].tag = HB_TAG('t', 'e', 's', 't');
-                features[nbFeatures].value = select[i];
-                features[nbFeatures].start = i;
-                features[nbFeatures].end = i + 1;
-                nbFeatures++;
-            }
-        }
-    }
-    gFeatures = features;
-    gNbFeatures = nbFeatures;
-
-    // shape
-    hb_shape(font, buffer, features, nbFeatures);
-
-    hb_blob_destroy(blob);
-    hb_font_destroy(font);
-    hb_face_destroy(face);
-    //free(features);
-
-    return buffer;
-}
-
-
-void printArray (const char* s, int *a, int n)
-{
-    printf ("%s  %d : ", s, n);
-    for (int i = 0; i < n; i++) {
-        printf (" %d", a[i]);
-    }
-    printf ("\n");
-}
-
-void printUArray (const char* s, unsigned int *a, int n)
-{
-    printArray (s, (int *) a, n);
-}
-
-bool gsub_test(const char *testName,
-               const char *fontfileName,
-               int nbIn, unsigned int *in,
-               int nbSelect, unsigned int *select,
-               int nbExpected, unsigned int *expected)
-{
-    hb_buffer_t *buffer = runTest(testName,
-                                  fontfileName,
-                                  in, nbIn,
-                                  select, nbSelect);
-
-    // verify
-    hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(buffer, 0);
-    unsigned int nbActual = hb_buffer_get_length(buffer);
-
-    bool ok = true;
-
-    if (nbActual != nbExpected)
-        ok = false;
-    else {
-        for (int i = 0; i < nbActual; i++) {
-            if (actual[i].codepoint != expected [i]) {
-                ok = false;
-                break;
-            }
-        }
-    }
-
-
-    char test_name[255];
-    sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
-    FILE *tests_file = fopen (test_name, "a+");
-    if (!ok) fprintf (tests_file, "#");
-    fprintf (tests_file, "../fonts/%s:--features=\"", fontfileName + 9);
-    for (unsigned int i = 0; i < gNbFeatures; i++)
-    {
-        if (i != 0) fprintf (tests_file, ",");
-        char buf[255];
-        hb_feature_to_string (&gFeatures[i], buf, sizeof (buf));
-        fprintf (tests_file, "%s", buf);
-    }
-    free (gFeatures);
-    fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions:");
-
-    for (unsigned int i = 0; i < nbIn; i++)
-    {
-        if (i != 0) fprintf (tests_file, ",");
-        fprintf (tests_file, "U+%04X", in[i]);
-    }
-
-    fprintf (tests_file, ":[");
-    for (unsigned int i = 0; i < nbActual; i++)
-    {
-        if (i != 0) fprintf (tests_file, "|");
-        fprintf (tests_file, "%d", expected[i]);
-    }
-    fprintf (tests_file, "]");
-
-    fprintf (tests_file, "\n");
-    fclose (tests_file);
-
-
-    if (! ok) {
-        printf ("******* GSUB %s\n", testName);
-
-        printf ("expected %d:", nbExpected);
-        for (int i = 0; i < nbExpected; i++) {
-            printf (" %d", expected[i]); }
-        printf ("\n");
-
-        printf ("  actual %d:", nbActual);
-        for (int i = 0; i < nbActual; i++) {
-            printf (" %d", actual[i].codepoint); }
-        printf ("\n");
-
-    }
-
-    hb_buffer_destroy(buffer);
-
-    return ok;
-}
-
-bool gpos_test(const char *testName,
-               const char *fontfileName,
-               int nbIn,
-               unsigned int *in,
-               int nbOut,
-               unsigned int *out,
-               int *x,
-               int *y)
-{
-    hb_buffer_t *buffer = runTest(testName,
-                                  fontfileName,
-                                  in, nbIn,
-                                  0, 0);
-
-    // verify
-    unsigned int nbActual;
-    hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(buffer, &nbActual);
-    hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
-
-    unsigned int *actualG = (unsigned int *) malloc(sizeof(*actualG) * nbActual);
-    int *actualX = (int *) malloc(sizeof(*actualX) * nbActual);
-    int *actualY = (int *) malloc(sizeof(*actualY) * nbActual);
-    int curX = 0;
-    int curY = 0;
-    for (int i = 0; i < nbActual; i++) {
-        actualG[i] = actual[i].codepoint;
-        actualX[i] = curX + pos[i].x_offset;
-        actualY[i] = curY + pos[i].y_offset;
-
-        actualX[i] -= 1500 * i;
-
-        curX += pos[i].x_advance;
-        curY += pos[i].y_advance;
-    }
-
-    bool nbOk = true;
-    bool xOk = true;
-    bool yOk = true;
-
-    if (nbActual != nbOut)
-        nbOk = false;
-    else {
-        for (int i = 0; i < nbActual; i++) {
-            if (actualX[i] != x[i]) {
-                xOk = false;
-            }
-            if (actualY[i] != y[i]) {
-                yOk = false;
-            }
-        }
-    }
-
-    bool ok = (nbOk && xOk && yOk);
-    if (! ok) {
-        printf ("******* GPOS %s\n", testName);
-
-        if (! (nbOk && xOk)) {
-            printArray ("expectedX", x, nbOut);
-            printArray ("actualX  ", actualX, nbActual);
-
-            printf ("xadv/pos:");
-            for (int i = 0; i < nbOut; i++) {
-                printf (" %d/%d", pos[i].x_advance, pos[i].x_offset);
-            }
-            printf ("\n");
-        }
-
-        if (! (nbOk && yOk)) {
-            printArray ("expectedY", y, nbOut);
-            printArray ("actualY  ", actualY, nbActual);
-
-            printf ("yadv/pos:");
-            for (int i = 0; i < nbOut; i++) {
-                printf (" %d/%d", pos[i].y_advance, pos[i].y_offset);
-            }
-            printf ("\n");
-        }
-    }
-
-
-    char test_name[255];
-    sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
-    FILE *tests_file = fopen (test_name, "a+");
-    if (!ok) fprintf (tests_file, "#");
-    fprintf (tests_file, "../fonts/%s:--features=\"", fontfileName + 9);
-    for (unsigned int i = 0; i < gNbFeatures; i++)
-    {
-        if (i != 0) fprintf (tests_file, ",");
-        char buf[255];
-        hb_feature_to_string (&gFeatures[i], buf, sizeof (buf));
-        fprintf (tests_file, "%s", buf);
-    }
-    free (gFeatures);
-    fprintf (tests_file, "\" --no-clusters --no-glyph-names --ned:");
-
-    for (unsigned int i = 0; i < nbIn; i++)
-    {
-        if (i != 0) fprintf (tests_file, ",");
-        fprintf (tests_file, "U+%04X", in[i]);
-    }
-
-    fprintf (tests_file, ":[");
-    for (unsigned int i = 0; i < nbActual; i++)
-    {
-        if (i != 0) fprintf (tests_file, "|");
-        fprintf (tests_file, "%d", /*it should be "out[i]"*/ actualG[i]);
-
-        int expected_x = x[i] + 1500*i;
-        int expected_y = y[i];
-        if (expected_x || expected_y) fprintf (tests_file, "@%d,%d", expected_x, expected_y);
-    }
-    fprintf (tests_file, "]");
-
-    fprintf (tests_file, "\n");
-    fclose (tests_file);
-
-
-    hb_buffer_destroy(buffer);
-
-    free(actualG);
-    free(actualX);
-    free(actualY);
-
-    return ok;
-}
-
-
-int main(int argc, char **argv)
-{
-    int failures = 0;
-    int pass = 0;
-
-#include "hb-aots-tester.h"
-
-    printf ("%d failures, %d pass\n", failures, pass);
-}
-
-
-
diff --git a/test/shaping/data/aots/tests/classdef1.tests b/test/shaping/data/aots/tests/classdef1.tests
deleted file mode 100644
index 40ded45..0000000
--- a/test/shaping/data/aots/tests/classdef1.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef1_font4.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18|19|20|21]
diff --git a/test/shaping/data/aots/tests/classdef1_empty.tests b/test/shaping/data/aots/tests/classdef1_empty.tests
deleted file mode 100644
index 71d87f1..0000000
--- a/test/shaping/data/aots/tests/classdef1_empty.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef1_font2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
diff --git a/test/shaping/data/aots/tests/classdef1_multiple.tests b/test/shaping/data/aots/tests/classdef1_multiple.tests
deleted file mode 100644
index c813f49..0000000
--- a/test/shaping/data/aots/tests/classdef1_multiple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef1_font3.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024:[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shaping/data/aots/tests/classdef1_single.tests b/test/shaping/data/aots/tests/classdef1_single.tests
deleted file mode 100644
index b0196d3..0000000
--- a/test/shaping/data/aots/tests/classdef1_single.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef2_font1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
diff --git a/test/shaping/data/aots/tests/classdef2.tests b/test/shaping/data/aots/tests/classdef2.tests
deleted file mode 100644
index d8c7b14..0000000
--- a/test/shaping/data/aots/tests/classdef2.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef2_font4.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18|19|20|21]
diff --git a/test/shaping/data/aots/tests/classdef2_empty.tests b/test/shaping/data/aots/tests/classdef2_empty.tests
deleted file mode 100644
index a8fd629..0000000
--- a/test/shaping/data/aots/tests/classdef2_empty.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef2_font2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
diff --git a/test/shaping/data/aots/tests/classdef2_multiple.tests b/test/shaping/data/aots/tests/classdef2_multiple.tests
deleted file mode 100644
index 39e6835..0000000
--- a/test/shaping/data/aots/tests/classdef2_multiple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef2_font3.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+001B,U+001C,U+001D,U+001E,U+001F,U+0020,U+0021,U+0022,U+0023,U+0024:[20|23|24|25|24|26|27|28|28|29|30|31|34|33|34|35|37|38|38|39]
diff --git a/test/shaping/data/aots/tests/classdef2_single.tests b/test/shaping/data/aots/tests/classdef2_single.tests
deleted file mode 100644
index b0196d3..0000000
--- a/test/shaping/data/aots/tests/classdef2_single.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/classdef2_font1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|25|21]
diff --git a/test/shaping/data/aots/tests/gpos1_1_lookupflag.tests b/test/shaping/data/aots/tests/gpos1_1_lookupflag.tests
deleted file mode 100644
index 88d7dd7..0000000
--- a/test/shaping/data/aots/tests/gpos1_1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos1_1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos1_1_simple.tests b/test/shaping/data/aots/tests/gpos1_1_simple.tests
deleted file mode 100644
index 101da9c..0000000
--- a/test/shaping/data/aots/tests/gpos1_1_simple.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gpos1_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
-../fonts/gpos1_1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1500,-200|19@3000,0|20@4500,-200|21@6000,0]
-../fonts/gpos1_1_simple_f3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1500,0|19@2800,0|20@4300,0|21@5600,0]
-#../fonts/gpos1_1_simple_f4.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1500,0|19@3000,-200|20@4500,-200|21@6000,-400]
diff --git a/test/shaping/data/aots/tests/gpos1_2.tests b/test/shaping/data/aots/tests/gpos1_2.tests
deleted file mode 100644
index 3ddfa44..0000000
--- a/test/shaping/data/aots/tests/gpos1_2.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos1_2_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1300,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos1_2_lookupflag.tests b/test/shaping/data/aots/tests/gpos1_2_lookupflag.tests
deleted file mode 100644
index 82bcc43..0000000
--- a/test/shaping/data/aots/tests/gpos1_2_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos1_2_font2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1500,0|19@3000,0|20@4200,0|21@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos2_1.tests b/test/shaping/data/aots/tests/gpos2_1.tests
deleted file mode 100644
index 4d8b5e9..0000000
--- a/test/shaping/data/aots/tests/gpos2_1.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos2_1_font6.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011:[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0]
-../fonts/gpos2_1_font7.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011,U+0012,U+0014,U+0011,U+0015,U+0016,U+0011:[17|18@1300,0|19@3000,-100|17@4500,0|18@5700,0|20@7500,-400|17@9000,0|21@10000,0|22@12000,-600|17@13500,0]
diff --git a/test/shaping/data/aots/tests/gpos2_1_lookupflag.tests b/test/shaping/data/aots/tests/gpos2_1_lookupflag.tests
deleted file mode 100644
index ce445a1..0000000
--- a/test/shaping/data/aots/tests/gpos2_1_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos2_1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011:[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
-../fonts/gpos2_1_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011:[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
diff --git a/test/shaping/data/aots/tests/gpos2_1_next_glyph.tests b/test/shaping/data/aots/tests/gpos2_1_next_glyph.tests
deleted file mode 100644
index 7f27eee..0000000
--- a/test/shaping/data/aots/tests/gpos2_1_next_glyph.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos2_1_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0012,U+0012,U+0012,U+0012:[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
-../fonts/gpos2_1_next_glyph_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0012,U+0012,U+0012,U+0012:[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos2_1_simple.tests b/test/shaping/data/aots/tests/gpos2_1_simple.tests
deleted file mode 100644
index 71e8c81..0000000
--- a/test/shaping/data/aots/tests/gpos2_1_simple.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos2_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011,U+0012,U+0014:[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
-../fonts/gpos2_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012:[17|18@1500,0]
diff --git a/test/shaping/data/aots/tests/gpos2_2.tests b/test/shaping/data/aots/tests/gpos2_2.tests
deleted file mode 100644
index 7be07f7..0000000
--- a/test/shaping/data/aots/tests/gpos2_2.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/gpos2_2_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011,U+0012,U+0014:[17|18@1300,0|19@3000,-100|17@4500,0|18@6000,0|20@7500,0]
-../fonts/gpos2_2_font2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011:[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0]
-../fonts/gpos2_2_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011:[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0]
-../fonts/gpos2_2_font4.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0012,U+0012,U+0012,U+0012:[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100]
-../fonts/gpos2_2_font5.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0012,U+0012,U+0012,U+0012:[18@-100,0|18@1400,0|18@2900,0|18@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos3.tests b/test/shaping/data/aots/tests/gpos3.tests
deleted file mode 100644
index d6f37bf..0000000
--- a/test/shaping/data/aots/tests/gpos3.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-#../fonts/gpos3_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|19@1599,99|17@4500,0]
-../fonts/gpos3_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0011,U+0013,U+0011:[17|18@1500,0|17@3000,0|19@4500,0|17@6000,0]
-#../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0012,U+0011:[17|18@1500,0|18@1600,100|17@4500,0]
-#../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|19@1599,99|17@4500,0]
-#../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0014,U+0012,U+0011:[17|20@1500,0|18@1602,102|17@4500,0]
-#../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0014,U+0013,U+0011:[17|20@1500,0|19@1601,101|17@4500,0]
-../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0014,U+0011:[17|18@1500,0|20@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0012,U+0011:[17|19@1500,0|18@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0011:[17|19@1500,0|20@3000,0|17@4500,0]
-../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012:[17|18@1500,0]
-../fonts/gpos3_font3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0015,U+0015,U+0015:[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos3_lookupflag.tests b/test/shaping/data/aots/tests/gpos3_lookupflag.tests
deleted file mode 100644
index 13d593c..0000000
--- a/test/shaping/data/aots/tests/gpos3_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos3_font2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0015,U+0013,U+0011:[17|18@1500,0|21@3000,0|19@1599,99|17@6000,0]
-#../fonts/gpos3_font2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0015,U+0015,U+0015,U+0013,U+0011:[17|18@1500,0|21@3000,0|21@4500,0|21@6000,0|19@1599,99|17@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos4_lookupflag.tests b/test/shaping/data/aots/tests/gpos4_lookupflag.tests
deleted file mode 100644
index 9d041bf..0000000
--- a/test/shaping/data/aots/tests/gpos4_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos4_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0011,U+0013,U+0011:[17|18@1500,0|17@3000,0|19@4500,0|17@6000,0]
-#../fonts/gpos4_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|19@3000,0|17@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos4_multiple_anchors.tests b/test/shaping/data/aots/tests/gpos4_multiple_anchors.tests
deleted file mode 100644
index af9a1f5..0000000
--- a/test/shaping/data/aots/tests/gpos4_multiple_anchors.tests
+++ /dev/null
@@ -1 +0,0 @@
-#../fonts/gpos4_multiple_anchors_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0013,U+0014,U+0015,U+0016,U+0012,U+0013,U+0014,U+0015,U+0016:[17|19@-100,-80|20@-91,-71|21@-102,-82|22@-93,-73|18@7500,0|19@7420,-60|20@7429,-51|21@7418,-62|22@7427,-53]
diff --git a/test/shaping/data/aots/tests/gpos4_simple.tests b/test/shaping/data/aots/tests/gpos4_simple.tests
deleted file mode 100644
index 5d60507..0000000
--- a/test/shaping/data/aots/tests/gpos4_simple.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-#../fonts/gpos4_simple_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|19@1400,-80|17@4500,0]
-#../fonts/gpos4_simple_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0011,U+0013,U+0011:[17|17@1500,0|19@3000,0|17@4500,0]
-#../fonts/gpos4_simple_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0019,U+0019,U+0013,U+0011:[25|25@1500,0|19@3000,0|17@4500,0]
-#../fonts/gpos4_simple_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0013,U+0011:[17|18@1500,0|19@1400,-80|19@1400,-80|17@6000,0]
-#../fonts/gpos4_simple_1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0014,U+0013,U+0011:[17|18@1500,0|20@3000,0|19@1400,-80|17@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos5.tests b/test/shaping/data/aots/tests/gpos5.tests
deleted file mode 100644
index a20a0b9..0000000
--- a/test/shaping/data/aots/tests/gpos5.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos5_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+001E,U+0013,U+001F,U+0011:[17|18@1500,0|19@1400,-80|17@4500,0]
-#../fonts/gpos5_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+001E,U+001F,U+0013,U+0011:[17|18@1500,0|19@1401,-79|17@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos6.tests b/test/shaping/data/aots/tests/gpos6.tests
deleted file mode 100644
index e5f9b3c..0000000
--- a/test/shaping/data/aots/tests/gpos6.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-#../fonts/gpos6_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|19@1400,-80|17@4500,0]
-#../fonts/gpos6_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0011,U+0013,U+0011:[17|17@1500,0|19@3000,0|17@4500,0]
-#../fonts/gpos6_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0014,U+0014,U+0013,U+0011:[20|20@1500,0|19@3000,0|17@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos7_1.tests b/test/shaping/data/aots/tests/gpos7_1.tests
deleted file mode 100644
index 954c8cb..0000000
--- a/test/shaping/data/aots/tests/gpos7_1.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos7_1_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1600,0|19@3200,0|20@4800,0|21@6000,0]
-../fonts/gpos7_1_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0011,U+0012,U+0013,U+0011:[17|18@1500,0|17@3000,0|18@4500,0|19@6000,0|17@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos9.tests b/test/shaping/data/aots/tests/gpos9.tests
deleted file mode 100644
index cb20333..0000000
--- a/test/shaping/data/aots/tests/gpos9.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos9_font1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18@1300,0|19@3000,0|20@4300,0|21@6000,0]
-../fonts/gpos9_font2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0011,U+0012,U+0013,U+0014,U+0015,U+0011:[17|18@1300,0|19@2700,0|20@4300,0|21@5700,0|17@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_boundary.tests b/test/shaping/data/aots/tests/gpos_chaining1_boundary.tests
deleted file mode 100644
index 646ff2c..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gpos_chaining1_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_lookupflag.tests b/test/shaping/data/aots/tests/gpos_chaining1_lookupflag.tests
deleted file mode 100644
index d0e6e2e..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-#../fonts/gpos_chaining1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20@1500,0|90@3000,0|21@4500,0|91@6000,0|22@7500,0|92@9000,0|23@10520,0|93@12000,0|94@13500,0|24@15000,0|90@16500,0|25@18000,0|91@19500,0|26@21000,0|0@22500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_multiple_subrules.tests b/test/shaping/data/aots/tests/gpos_chaining1_multiple_subrules.tests
deleted file mode 100644
index 51bbe03..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_chaining1_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
-../fonts/gpos_chaining1_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_next_glyph.tests b/test/shaping/data/aots/tests/gpos_chaining1_next_glyph.tests
deleted file mode 100644
index f8be404..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining1_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_simple.tests b/test/shaping/data/aots/tests/gpos_chaining1_simple.tests
deleted file mode 100644
index 37efa11..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gpos_chaining1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016:[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining1_successive.tests b/test/shaping/data/aots/tests/gpos_chaining1_successive.tests
deleted file mode 100644
index 7a829cf..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining1_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining1_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_boundary.tests b/test/shaping/data/aots/tests/gpos_chaining2_boundary.tests
deleted file mode 100644
index c35b8c7..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gpos_chaining2_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_lookupflag.tests b/test/shaping/data/aots/tests/gpos_chaining2_lookupflag.tests
deleted file mode 100644
index 8b50e14..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-#../fonts/gpos_chaining2_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20@1500,0|90@3000,0|21@4500,0|91@6000,0|22@7500,0|92@9000,0|23@10520,0|93@12000,0|94@13500,0|24@15000,0|90@16500,0|25@18000,0|91@19500,0|26@21000,0|0@22500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_multiple_subrules.tests b/test/shaping/data/aots/tests/gpos_chaining2_multiple_subrules.tests
deleted file mode 100644
index 8ddc8b2..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_chaining2_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
-../fonts/gpos_chaining2_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|0@9000,0|20@10500,0|21@12000,0|22@13520,0|23@15000,0|0@16500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_next_glyph.tests b/test/shaping/data/aots/tests/gpos_chaining2_next_glyph.tests
deleted file mode 100644
index 34170f2..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining2_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6020,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_simple.tests b/test/shaping/data/aots/tests/gpos_chaining2_simple.tests
deleted file mode 100644
index 32fda1b..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gpos_chaining2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016:[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining2_successive.tests b/test/shaping/data/aots/tests/gpos_chaining2_successive.tests
deleted file mode 100644
index e930863..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining2_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining2_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining3_boundary.tests b/test/shaping/data/aots/tests/gpos_chaining3_boundary.tests
deleted file mode 100644
index f74dedf..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining3_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gpos_chaining3_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining3_lookupflag.tests b/test/shaping/data/aots/tests/gpos_chaining3_lookupflag.tests
deleted file mode 100644
index 0165fb5..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining3_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-#../fonts/gpos_chaining3_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20@1500,0|90@3000,0|21@4500,0|91@6000,0|22@7500,0|92@9000,0|23@10520,0|93@12000,0|94@13500,0|24@15000,0|90@16500,0|25@18000,0|91@19500,0|26@21000,0|0@22500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining3_next_glyph.tests b/test/shaping/data/aots/tests/gpos_chaining3_next_glyph.tests
deleted file mode 100644
index 614bc2e..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining3_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining3_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000:[0|22@1500,0|21@3020,0|22@4500,0|21@6020,0|22@7500,0|21@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining3_simple.tests b/test/shaping/data/aots/tests/gpos_chaining3_simple.tests
deleted file mode 100644
index f5977c2..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining3_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gpos_chaining3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4520,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|0@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0@1500,0|21@3000,0|22@4500,0|23@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22@1500,0|23@3000,0|24@4500,0|25@6000,0|26@7500,0|0@9000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23@1500,0|24@3000,0|25@4500,0|26@6000,0|0@7500,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0|24@7500,0|25@9000,0|26@10500,0|0@12000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20@1500,0|21@3000,0|22@4500,0|23@6000,0]
-../fonts/gpos_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016:[0|20@1500,0|21@3000,0|22@4500,0]
diff --git a/test/shaping/data/aots/tests/gpos_chaining3_successive.tests b/test/shaping/data/aots/tests/gpos_chaining3_successive.tests
deleted file mode 100644
index fa5a50c..0000000
--- a/test/shaping/data/aots/tests/gpos_chaining3_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_chaining3_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25@1500,0|20@3000,0|21@4520,0|22@6020,0|23@7500,0|24@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_boundary.tests b/test/shaping/data/aots/tests/gpos_context1_boundary.tests
deleted file mode 100644
index 1db8fef..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context1_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context1_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_expansion.tests b/test/shaping/data/aots/tests/gpos_context1_expansion.tests
deleted file mode 100644
index 2fc54d5..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_expansion.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context1_expansion_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_lookupflag.tests b/test/shaping/data/aots/tests/gpos_context1_lookupflag.tests
deleted file mode 100644
index 9e8fcd6..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos_context1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1520,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9020,0|0@10500,0]
-#../fonts/gpos_context1_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1500,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_multiple_subrules.tests b/test/shaping/data/aots/tests/gpos_context1_multiple_subrules.tests
deleted file mode 100644
index b994f04..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context1_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
-../fonts/gpos_context1_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_next_glyph.tests b/test/shaping/data/aots/tests/gpos_context1_next_glyph.tests
deleted file mode 100644
index e67d635..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context1_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_simple.tests b/test/shaping/data/aots/tests/gpos_context1_simple.tests
deleted file mode 100644
index 4a88e0a..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_simple.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/gpos_context1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000:[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
-../fonts/gpos_context1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context1_successive.tests b/test/shaping/data/aots/tests/gpos_context1_successive.tests
deleted file mode 100644
index 172d350..0000000
--- a/test/shaping/data/aots/tests/gpos_context1_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context1_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_boundary.tests b/test/shaping/data/aots/tests/gpos_context2_boundary.tests
deleted file mode 100644
index ef63fbb..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context2_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context2_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_classes.tests b/test/shaping/data/aots/tests/gpos_context2_classes.tests
deleted file mode 100644
index 5a3d008..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_classes.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context2_classes_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018:[0|20@1500,0|26@3020,0|28@4500,0|24@6000,0|0@7500,0|21@9000,0|27@10520,0|26@12000,0|24@13500,0|0@15000,0|22@16500,0|27@18000,0|26@19500,0|24@21000,0]
-../fonts/gpos_context2_classes_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018:[0|22@1500,0|27@3020,0|26@4500,0|24@6000,0|0@7500,0|24@9000,0|24@10500,0|29@12020,0|22@13500,0|0@15000,0|22@16500,0|27@18020,0|26@19500,0|24@21000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_expansion.tests b/test/shaping/data/aots/tests/gpos_context2_expansion.tests
deleted file mode 100644
index 67ed978..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_expansion.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context2_expansion_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1500,0|21@3000,0|22@4500,0|0@6000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_lookupflag.tests b/test/shaping/data/aots/tests/gpos_context2_lookupflag.tests
deleted file mode 100644
index f48e825..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos_context2_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1520,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9020,0|0@10500,0]
-#../fonts/gpos_context2_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1500,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_multiple_subrules.tests b/test/shaping/data/aots/tests/gpos_context2_multiple_subrules.tests
deleted file mode 100644
index 4489372..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context2_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20@1520,0|21@3000,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
-../fonts/gpos_context2_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20@1500,0|21@3020,0|22@4500,0|0@6000,0|20@7500,0|21@9020,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_next_glyph.tests b/test/shaping/data/aots/tests/gpos_context2_next_glyph.tests
deleted file mode 100644
index e736b3b..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context2_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_simple.tests b/test/shaping/data/aots/tests/gpos_context2_simple.tests
deleted file mode 100644
index edbc0be..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_simple.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/gpos_context2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000:[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0]
-../fonts/gpos_context2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1500,0|20@3020,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context2_successive.tests b/test/shaping/data/aots/tests/gpos_context2_successive.tests
deleted file mode 100644
index 8b098d5..0000000
--- a/test/shaping/data/aots/tests/gpos_context2_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context2_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context3_boundary.tests b/test/shaping/data/aots/tests/gpos_context3_boundary.tests
deleted file mode 100644
index de3c057..0000000
--- a/test/shaping/data/aots/tests/gpos_context3_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context3_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1500,0|20@3000,0|20@4500,0|20@6000,0|20@7500,0|0@9000,0]
-../fonts/gpos_context3_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3020,0|20@4520,0|20@6020,0|20@7520,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context3_lookupflag.tests b/test/shaping/data/aots/tests/gpos_context3_lookupflag.tests
deleted file mode 100644
index 21f851b..0000000
--- a/test/shaping/data/aots/tests/gpos_context3_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-#../fonts/gpos_context3_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1520,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9020,0|0@10500,0]
-#../fonts/gpos_context3_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20@1500,0|90@3000,0|21@4520,0|91@6000,0|92@7500,0|22@9000,0|0@10500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context3_next_glyph.tests b/test/shaping/data/aots/tests/gpos_context3_next_glyph.tests
deleted file mode 100644
index 049b156..0000000
--- a/test/shaping/data/aots/tests/gpos_context3_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context3_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20@1520,0|20@3000,0|20@4520,0|20@6000,0|20@7500,0|0@9000,0]
diff --git a/test/shaping/data/aots/tests/gpos_context3_simple.tests b/test/shaping/data/aots/tests/gpos_context3_simple.tests
deleted file mode 100644
index 3e544f0..0000000
--- a/test/shaping/data/aots/tests/gpos_context3_simple.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gpos_context3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1520,0|21@3020,0|22@4520,0|0@6000,0]
-../fonts/gpos_context3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000:[0|20@1500,0|0@3000,0|20@4500,0|21@6000,0|0@7500,0|20@9020,0|21@10520,0|22@12020,0|0@13500,0]
diff --git a/test/shaping/data/aots/tests/gpos_context3_successive.tests b/test/shaping/data/aots/tests/gpos_context3_successive.tests
deleted file mode 100644
index bfcf24a..0000000
--- a/test/shaping/data/aots/tests/gpos_context3_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gpos_context3_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --ned:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20@1500,0|21@3020,0|22@4520,0|23@6000,0|0@7500,0]
diff --git a/test/shaping/data/aots/tests/gsub1_1_lookupflag.tests b/test/shaping/data/aots/tests/gsub1_1_lookupflag.tests
deleted file mode 100644
index 8865af8..0000000
--- a/test/shaping/data/aots/tests/gsub1_1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub1_1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18|24|20|21]
diff --git a/test/shaping/data/aots/tests/gsub1_1_modulo.tests b/test/shaping/data/aots/tests/gsub1_1_modulo.tests
deleted file mode 100644
index bbfff5e..0000000
--- a/test/shaping/data/aots/tests/gsub1_1_modulo.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub1_1_modulo_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015,U+0016,U+0017,U+0018:[17|18|17|24|23|18|23|24]
diff --git a/test/shaping/data/aots/tests/gsub1_1_simple.tests b/test/shaping/data/aots/tests/gsub1_1_simple.tests
deleted file mode 100644
index a3a1385..0000000
--- a/test/shaping/data/aots/tests/gsub1_1_simple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub1_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|20|21]
diff --git a/test/shaping/data/aots/tests/gsub1_2_lookupflag.tests b/test/shaping/data/aots/tests/gsub1_2_lookupflag.tests
deleted file mode 100644
index 887e047..0000000
--- a/test/shaping/data/aots/tests/gsub1_2_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub1_2_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|18|19|25|21]
diff --git a/test/shaping/data/aots/tests/gsub1_2_simple.tests b/test/shaping/data/aots/tests/gsub1_2_simple.tests
deleted file mode 100644
index d657897..0000000
--- a/test/shaping/data/aots/tests/gsub1_2_simple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub1_2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|22|19|25|21]
diff --git a/test/shaping/data/aots/tests/gsub2_1_lookupflag.tests b/test/shaping/data/aots/tests/gsub2_1_lookupflag.tests
deleted file mode 100644
index e28e59c..0000000
--- a/test/shaping/data/aots/tests/gsub2_1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub2_1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0011:[17|18|22|23|17]
diff --git a/test/shaping/data/aots/tests/gsub2_1_multiple_sequences.tests b/test/shaping/data/aots/tests/gsub2_1_multiple_sequences.tests
deleted file mode 100644
index 12cbbf6..0000000
--- a/test/shaping/data/aots/tests/gsub2_1_multiple_sequences.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub2_1_multiple_sequences_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0011:[17|20|21|22|23|17]
diff --git a/test/shaping/data/aots/tests/gsub2_1_simple.tests b/test/shaping/data/aots/tests/gsub2_1_simple.tests
deleted file mode 100644
index d1d0969..0000000
--- a/test/shaping/data/aots/tests/gsub2_1_simple.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub2_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013:[17|20|21|22|19]
-../fonts/gsub2_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0012:[17|20|21|22|19|20|21|22]
diff --git a/test/shaping/data/aots/tests/gsub3_1_lookupflag.tests b/test/shaping/data/aots/tests/gsub3_1_lookupflag.tests
deleted file mode 100644
index 193c5c4..0000000
--- a/test/shaping/data/aots/tests/gsub3_1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub3_1_lookupflag_f1.otf:--features="-test[4],test[5],test[6]=2,-test[7]" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011:[17|18|18|18|19|22|23|19|17]
diff --git a/test/shaping/data/aots/tests/gsub3_1_multiple.tests b/test/shaping/data/aots/tests/gsub3_1_multiple.tests
deleted file mode 100644
index 7b1c032..0000000
--- a/test/shaping/data/aots/tests/gsub3_1_multiple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub3_1_multiple_f1.otf:--features="-test[1],test[2],test[3]=2,-test[4],-test[5],test[6],test[7]=2,-test[8]" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0012,U+0012,U+0012,U+0013,U+0013,U+0013,U+0013,U+0011:[17|18|20|21|18|19|22|23|19|17]
diff --git a/test/shaping/data/aots/tests/gsub3_1_simple.tests b/test/shaping/data/aots/tests/gsub3_1_simple.tests
deleted file mode 100644
index b8a28d1..0000000
--- a/test/shaping/data/aots/tests/gsub3_1_simple.tests
+++ /dev/null
@@ -1 +0,0 @@
-#../fonts/gsub3_1_simple_f1.otf:--features="-test[1],test[3],test[5]=2,test[7]=3,-test[9],test[11]" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011,U+0012,U+0011:[17|18|17|20|17|21|17|22|17|18|17|20|17]
diff --git a/test/shaping/data/aots/tests/gsub4_1_lookupflag.tests b/test/shaping/data/aots/tests/gsub4_1_lookupflag.tests
deleted file mode 100644
index c2c5242..0000000
--- a/test/shaping/data/aots/tests/gsub4_1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub4_1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0018,U+0012,U+0018,U+0013,U+0018,U+0018,U+0014,U+0018,U+0011,U+0012,U+0013,U+0016,U+0014:[17|24|23|24|24|24|24|17|18|19|22|20]
diff --git a/test/shaping/data/aots/tests/gsub4_1_multiple_ligatures.tests b/test/shaping/data/aots/tests/gsub4_1_multiple_ligatures.tests
deleted file mode 100644
index 33c1a09..0000000
--- a/test/shaping/data/aots/tests/gsub4_1_multiple_ligatures.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub4_1_multiple_ligatures_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014:[17|23|17|24|22|20]
-../fonts/gsub4_1_multiple_ligatures_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014:[17|24|20|17|24|22|20]
diff --git a/test/shaping/data/aots/tests/gsub4_1_multiple_ligsets.tests b/test/shaping/data/aots/tests/gsub4_1_multiple_ligsets.tests
deleted file mode 100644
index a63aeed..0000000
--- a/test/shaping/data/aots/tests/gsub4_1_multiple_ligsets.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub4_1_multiple_ligsets_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0015,U+0014,U+0013,U+0016:[17|23|21|24|22]
diff --git a/test/shaping/data/aots/tests/gsub4_1_simple.tests b/test/shaping/data/aots/tests/gsub4_1_simple.tests
deleted file mode 100644
index aa4bb4b..0000000
--- a/test/shaping/data/aots/tests/gsub4_1_simple.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub4_1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0011,U+0012,U+0013,U+0016,U+0014:[17|23|17|18|19|22|20]
diff --git a/test/shaping/data/aots/tests/gsub7.tests b/test/shaping/data/aots/tests/gsub7.tests
deleted file mode 100644
index e95b1c7..0000000
--- a/test/shaping/data/aots/tests/gsub7.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub7_font1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|24|20|21]
-../fonts/gsub7_font2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|29|20|21]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_boundary.tests b/test/shaping/data/aots/tests/gsub_chaining1_boundary.tests
deleted file mode 100644
index 6d99d97..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gsub_chaining1_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|22|23|0]
-../fonts/gsub_chaining1_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining1_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining1_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|62|23|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_lookupflag.tests b/test/shaping/data/aots/tests/gsub_chaining1_lookupflag.tests
deleted file mode 100644
index 7883c0a..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_multiple_subrules.tests b/test/shaping/data/aots/tests/gsub_chaining1_multiple_subrules.tests
deleted file mode 100644
index 28a5225..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_chaining1_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|24|0|20|21|62|23|0]
-../fonts/gsub_chaining1_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_next_glyph.tests b/test/shaping/data/aots/tests/gsub_chaining1_next_glyph.tests
deleted file mode 100644
index 82f9d95..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining1_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|62|63|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_simple.tests b/test/shaping/data/aots/tests/gsub_chaining1_simple.tests
deleted file mode 100644
index 23e091f..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gsub_chaining1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|62|23|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20|21|22|23|24|25]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20|21|22|23|24]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20|21|22|23]
-../fonts/gsub_chaining1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016:[0|20|21|22]
diff --git a/test/shaping/data/aots/tests/gsub_chaining1_successive.tests b/test/shaping/data/aots/tests/gsub_chaining1_successive.tests
deleted file mode 100644
index ab3cfb1..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining1_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining1_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25|20|61|63|24|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_boundary.tests b/test/shaping/data/aots/tests/gsub_chaining2_boundary.tests
deleted file mode 100644
index b06c620..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gsub_chaining2_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|22|23|0]
-../fonts/gsub_chaining2_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining2_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining2_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|62|23|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_lookupflag.tests b/test/shaping/data/aots/tests/gsub_chaining2_lookupflag.tests
deleted file mode 100644
index 372b343..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining2_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_multiple_subrules.tests b/test/shaping/data/aots/tests/gsub_chaining2_multiple_subrules.tests
deleted file mode 100644
index e2fbb5c..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_chaining2_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|24|0|20|21|62|23|0]
-../fonts/gsub_chaining2_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|62|23|24|0|20|21|62|23|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_next_glyph.tests b/test/shaping/data/aots/tests/gsub_chaining2_next_glyph.tests
deleted file mode 100644
index 84c8252..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining2_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|62|63|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_simple.tests b/test/shaping/data/aots/tests/gsub_chaining2_simple.tests
deleted file mode 100644
index 53fa7e8..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gsub_chaining2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|62|23|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20|21|22|23|24|25]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20|21|22|23|24]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20|21|22|23]
-../fonts/gsub_chaining2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016:[0|20|21|22]
diff --git a/test/shaping/data/aots/tests/gsub_chaining2_successive.tests b/test/shaping/data/aots/tests/gsub_chaining2_successive.tests
deleted file mode 100644
index 71cbe0d..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining2_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining2_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25|20|61|63|24|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining3_boundary.tests b/test/shaping/data/aots/tests/gsub_chaining3_boundary.tests
deleted file mode 100644
index c01dc4b..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining3_boundary.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/gsub_chaining3_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|22|23|0]
-../fonts/gsub_chaining3_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining3_boundary_f3.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|22|23|0]
-../fonts/gsub_chaining3_boundary_f4.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|21|62|23|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining3_lookupflag.tests b/test/shaping/data/aots/tests/gsub_chaining3_lookupflag.tests
deleted file mode 100644
index be2147b..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining3_lookupflag.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining3_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+0016,U+005C,U+0017,U+005D,U+005E,U+0018,U+005A,U+0019,U+005B,U+001A,U+0000:[0|20|90|21|91|22|92|63|93|94|24|90|25|91|26|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining3_next_glyph.tests b/test/shaping/data/aots/tests/gsub_chaining3_next_glyph.tests
deleted file mode 100644
index 2493c1e..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining3_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining3_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0016,U+0015,U+0016,U+0015,U+0016,U+0015,U+0000:[0|22|61|22|61|22|21|0]
diff --git a/test/shaping/data/aots/tests/gsub_chaining3_simple.tests b/test/shaping/data/aots/tests/gsub_chaining3_simple.tests
deleted file mode 100644
index eb24167..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining3_simple.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/gsub_chaining3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|62|23|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|20|21|62|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019,U+0000,U+0000:[0|20|21|22|23|24|25|0|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018,U+0019:[0|20|21|22|23|24|25]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0018:[0|20|21|22|23|24]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0000,U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[0|0|21|22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0015,U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[21|22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0016,U+0017,U+0018,U+0019,U+001A,U+0000:[22|23|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0018,U+0019,U+001A,U+0000:[0|20|21|22|0|24|25|26|0]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017:[0|20|21|22|23]
-../fonts/gsub_chaining3_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016:[0|20|21|22]
diff --git a/test/shaping/data/aots/tests/gsub_chaining3_successive.tests b/test/shaping/data/aots/tests/gsub_chaining3_successive.tests
deleted file mode 100644
index edcade1..0000000
--- a/test/shaping/data/aots/tests/gsub_chaining3_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_chaining3_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0019,U+0014,U+0015,U+0016,U+0017,U+0018,U+0000:[0|25|20|61|63|24|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_boundary.tests b/test/shaping/data/aots/tests/gsub_context1_boundary.tests
deleted file mode 100644
index 9b11892..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context1_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20|20|20|20|20|0]
-../fonts/gsub_context1_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|60|60|60|60|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_expansion.tests b/test/shaping/data/aots/tests/gsub_context1_expansion.tests
deleted file mode 100644
index 92714c5..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_expansion.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context1_expansion_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20|61|62|63|22|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_lookupflag.tests b/test/shaping/data/aots/tests/gsub_context1_lookupflag.tests
deleted file mode 100644
index c5d9760..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context1_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|60|90|61|91|92|62|0]
-../fonts/gsub_context1_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20|90|61|91|92|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_multiple_subrules.tests b/test/shaping/data/aots/tests/gsub_context1_multiple_subrules.tests
deleted file mode 100644
index febc419..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context1_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|60|21|22|0|20|61|0]
-../fonts/gsub_context1_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20|61|22|0|20|61|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_next_glyph.tests b/test/shaping/data/aots/tests/gsub_context1_next_glyph.tests
deleted file mode 100644
index 12414c3..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context1_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|20|60|20|20|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_simple.tests b/test/shaping/data/aots/tests/gsub_context1_simple.tests
deleted file mode 100644
index 44252ec..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_simple.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/gsub_context1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000:[0|60|61|62|0]
-../fonts/gsub_context1_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000:[0|20|0|20|21|0]
-../fonts/gsub_context1_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20|60|20|20|20|0]
diff --git a/test/shaping/data/aots/tests/gsub_context1_successive.tests b/test/shaping/data/aots/tests/gsub_context1_successive.tests
deleted file mode 100644
index e68d6b2..0000000
--- a/test/shaping/data/aots/tests/gsub_context1_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context1_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|63|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_boundary.tests b/test/shaping/data/aots/tests/gsub_context2_boundary.tests
deleted file mode 100644
index 2054277..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context2_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20|20|20|20|20|0]
-../fonts/gsub_context2_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|60|60|60|60|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_classes.tests b/test/shaping/data/aots/tests/gsub_context2_classes.tests
deleted file mode 100644
index 2e44007..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_classes.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context2_classes_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+001A,U+001C,U+0018,U+0000,U+0015,U+001B,U+001A,U+0018,U+0000,U+0016,U+001B,U+001A,U+0018:[0|20|66|28|24|0|21|67|26|24|0|22|27|26|24]
-../fonts/gsub_context2_classes_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0016,U+001B,U+001A,U+0018,U+0000,U+0018,U+0018,U+001D,U+0016,U+0000,U+0016,U+001B,U+001A,U+0018:[0|22|67|26|24|0|24|24|69|22|0|22|67|26|24]
diff --git a/test/shaping/data/aots/tests/gsub_context2_expansion.tests b/test/shaping/data/aots/tests/gsub_context2_expansion.tests
deleted file mode 100644
index af0ce71..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_expansion.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context2_expansion_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000:[0|20|61|62|63|22|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_lookupflag.tests b/test/shaping/data/aots/tests/gsub_context2_lookupflag.tests
deleted file mode 100644
index ac41949..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context2_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|60|90|61|91|92|62|0]
-../fonts/gsub_context2_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20|90|61|91|92|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_multiple_subrules.tests b/test/shaping/data/aots/tests/gsub_context2_multiple_subrules.tests
deleted file mode 100644
index 75225cd..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_multiple_subrules.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context2_multiple_subrules_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|60|21|22|0|20|61|0]
-../fonts/gsub_context2_multiple_subrules_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000,U+0014,U+0015,U+0000:[0|20|61|22|0|20|61|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_next_glyph.tests b/test/shaping/data/aots/tests/gsub_context2_next_glyph.tests
deleted file mode 100644
index 020d05f..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context2_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|20|60|20|20|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_simple.tests b/test/shaping/data/aots/tests/gsub_context2_simple.tests
deleted file mode 100644
index 5863605..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_simple.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/gsub_context2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000:[0|60|61|62|0]
-../fonts/gsub_context2_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000:[0|20|0|20|21|0]
-../fonts/gsub_context2_simple_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20|60|20|20|20|0]
diff --git a/test/shaping/data/aots/tests/gsub_context2_successive.tests b/test/shaping/data/aots/tests/gsub_context2_successive.tests
deleted file mode 100644
index 9aeeac7..0000000
--- a/test/shaping/data/aots/tests/gsub_context2_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context2_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|63|0]
diff --git a/test/shaping/data/aots/tests/gsub_context3_boundary.tests b/test/shaping/data/aots/tests/gsub_context3_boundary.tests
deleted file mode 100644
index 8b40afd..0000000
--- a/test/shaping/data/aots/tests/gsub_context3_boundary.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context3_boundary_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|20|20|20|20|20|0]
-../fonts/gsub_context3_boundary_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|60|60|60|60|0]
diff --git a/test/shaping/data/aots/tests/gsub_context3_lookupflag.tests b/test/shaping/data/aots/tests/gsub_context3_lookupflag.tests
deleted file mode 100644
index 03c0647..0000000
--- a/test/shaping/data/aots/tests/gsub_context3_lookupflag.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context3_lookupflag_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|60|90|61|91|92|62|0]
-../fonts/gsub_context3_lookupflag_f2.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+005A,U+0015,U+005B,U+005C,U+0016,U+0000:[0|20|90|61|91|92|0]
diff --git a/test/shaping/data/aots/tests/gsub_context3_next_glyph.tests b/test/shaping/data/aots/tests/gsub_context3_next_glyph.tests
deleted file mode 100644
index b28381b..0000000
--- a/test/shaping/data/aots/tests/gsub_context3_next_glyph.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context3_next_glyph_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0014,U+0014,U+0014,U+0014,U+0000:[0|60|20|60|20|20|0]
diff --git a/test/shaping/data/aots/tests/gsub_context3_simple.tests b/test/shaping/data/aots/tests/gsub_context3_simple.tests
deleted file mode 100644
index ec264ea..0000000
--- a/test/shaping/data/aots/tests/gsub_context3_simple.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/gsub_context3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0000:[0|60|61|62|0]
-../fonts/gsub_context3_simple_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0000,U+0014,U+0015,U+0000,U+0014,U+0015,U+0016,U+0000:[0|20|0|20|21|0|60|61|62|0]
diff --git a/test/shaping/data/aots/tests/gsub_context3_successive.tests b/test/shaping/data/aots/tests/gsub_context3_successive.tests
deleted file mode 100644
index b987a61..0000000
--- a/test/shaping/data/aots/tests/gsub_context3_successive.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/gsub_context3_successive_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0000,U+0014,U+0015,U+0016,U+0017,U+0000:[0|20|61|63|0]
diff --git a/test/shaping/data/aots/tests/lookupflag_ignore_attach.tests b/test/shaping/data/aots/tests/lookupflag_ignore_attach.tests
deleted file mode 100644
index 55ae538..0000000
--- a/test/shaping/data/aots/tests/lookupflag_ignore_attach.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-#../fonts/lookupflag_ignore_attach_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+000A,U+000B,U+000D,U+001A,U+000A:[10|15|10]
-#../fonts/lookupflag_ignore_attach_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+000A,U+000B,U+0015,U+000D,U+0016,U+0017,U+001D,U+001A,U+000A:[10|15|21|22|23|29|10]
-#../fonts/lookupflag_ignore_attach_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+000A,U+000B,U+0015,U+000D,U+0016,U+001B,U+001A,U+000A:[10|11|21|13|22|27|26|10]
-#../fonts/lookupflag_ignore_attach_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+000A,U+000B,U+001B,U+000D,U+0016,U+0017,U+001A,U+000A:[10|11|27|13|22|23|26|10]
-#../fonts/lookupflag_ignore_attach_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+000A,U+000B,U+001B,U+000D,U+000E,U+0017,U+001A,U+000A:[10|11|27|13|14|23|26|10]
diff --git a/test/shaping/data/aots/tests/lookupflag_ignore_base.tests b/test/shaping/data/aots/tests/lookupflag_ignore_base.tests
deleted file mode 100644
index 5f0bfdb..0000000
--- a/test/shaping/data/aots/tests/lookupflag_ignore_base.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/lookupflag_ignore_base_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0013,U+0014,U+0015:[17|23|21]
-../fonts/lookupflag_ignore_base_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+0018,U+0018,U+0013,U+0019,U+0014,U+0015:[17|23|24|24|25|21]
diff --git a/test/shaping/data/aots/tests/lookupflag_ignore_combination.tests b/test/shaping/data/aots/tests/lookupflag_ignore_combination.tests
deleted file mode 100644
index d34f16a..0000000
--- a/test/shaping/data/aots/tests/lookupflag_ignore_combination.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/lookupflag_ignore_combination_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+0013,U+0014,U+0015:[17|23|26|21]
-../fonts/lookupflag_ignore_combination_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+001F,U+0014,U+0015:[17|23|26|24|30|31|21]
-../fonts/lookupflag_ignore_combination_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+0013,U+0018,U+001E,U+0020,U+0014,U+0015:[17|18|26|19|24|30|32|20|21]
diff --git a/test/shaping/data/aots/tests/lookupflag_ignore_ligatures.tests b/test/shaping/data/aots/tests/lookupflag_ignore_ligatures.tests
deleted file mode 100644
index feb31d8..0000000
--- a/test/shaping/data/aots/tests/lookupflag_ignore_ligatures.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/lookupflag_ignore_ligatures_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+001B,U+0013,U+001B,U+0014,U+0015:[17|23|26|27|27|21]
-../fonts/lookupflag_ignore_ligatures_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+0018,U+0013,U+001B,U+0014,U+0015:[17|18|26|24|19|27|20|21]
-../fonts/lookupflag_ignore_ligatures_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001A,U+002A,U+0013,U+001B,U+0014,U+0015:[17|18|26|42|19|27|20|21]
diff --git a/test/shaping/data/aots/tests/lookupflag_ignore_marks.tests b/test/shaping/data/aots/tests/lookupflag_ignore_marks.tests
deleted file mode 100644
index 9626599..0000000
--- a/test/shaping/data/aots/tests/lookupflag_ignore_marks.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/lookupflag_ignore_marks_f1.otf:--features="test" --no-clusters --no-glyph-names --no-positions:U+0011,U+0012,U+001C,U+001D,U+0013,U+001D,U+0014,U+0015:[17|23|28|29|29|21]
diff --git a/test/shaping/data/in-house/Makefile.am b/test/shaping/data/in-house/Makefile.am
deleted file mode 100644
index 8a2a076..0000000
--- a/test/shaping/data/in-house/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-# Process this file with automake to produce Makefile.in
-
-NULL =
-
-# Convenience targets:
-lib:
-	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-
-EXTRA_DIST = \
-	COPYING \
-	fonts \
-	$(TESTS) \
-	$(NULL)
-
-TEST_EXTENSIONS = .tests
-TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
-
-include Makefile.sources
-
--include $(top_srcdir)/git.mk
diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources
deleted file mode 100644
index bf14a98..0000000
--- a/test/shaping/data/in-house/Makefile.sources
+++ /dev/null
@@ -1,62 +0,0 @@
-TESTS = \
-	tests/aat-trak.tests \
-	tests/aat-morx.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-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/emoji.tests \
-	tests/fallback-positioning.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/indic-old-spec.tests \
-	tests/indic-pref-blocking.tests \
-	tests/indic-script-extensions.tests \
-	tests/indic-special-cases.tests \
-	tests/indic-syllable.tests \
-	tests/indic-vowel-letter-spoofing.tests \
-	tests/kern-format2.tests \
-	tests/khmer-mark-order.tests \
-	tests/khmer-misc.tests \
-	tests/language-tags.tests \
-	tests/ligature-id.tests \
-	tests/macos.tests \
-	tests/mark-attachment.tests \
-	tests/mark-filtering-sets.tests \
-	tests/mongolian-variation-selector.tests \
-	tests/myanmar-syllable.tests \
-	tests/myanmar-zawgyi.tests \
-	tests/none-directional.tests \
-	tests/positioning-features.tests \
-	tests/rand.tests \
-	tests/spaces.tests \
-	tests/simple.tests \
-	tests/sinhala.tests \
-	tests/tibetan-contractions-1.tests \
-	tests/tibetan-contractions-2.tests \
-	tests/tibetan-vowels.tests \
-	tests/use.tests \
-	tests/use-indic3.tests \
-	tests/use-marchen.tests \
-	tests/use-syllable.tests \
-	tests/variations-rvrn.tests \
-	tests/vertical.tests \
-	tests/zero-width-marks.tests \
-	$(NULL)
-
-DISABLED_TESTS = \
-	$(NULL)
diff --git a/test/shaping/data/in-house/tests/aat-morx.tests b/test/shaping/data/in-house/tests/aat-morx.tests
deleted file mode 100644
index 27f5bcc..0000000
--- a/test/shaping/data/in-house/tests/aat-morx.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/MORXTwentyeight.ttf::U+0041,U+0078,U+0045,U+0079,U+0044,U+0079,U+0079:[A_E_D=0+1394|x=0+529|y=0+510|y=5+510|y=6+510]
diff --git a/test/shaping/data/in-house/tests/aat-trak.tests b/test/shaping/data/in-house/tests/aat-trak.tests
deleted file mode 100644
index 6da3ba8..0000000
--- a/test/shaping/data/in-house/tests/aat-trak.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/TRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
-../fonts/TRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
-../fonts/TRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
-../fonts/TRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
-../fonts/TRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0@30,0+1060|B=1@30,0+1060|C.alt=2@30,0+1060]
-../fonts/TRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-7,0+986|B=1@-7,0+986|C.alt=2@-7,0+986]
-../fonts/TRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-35,0+929|B=1@-35,0+929|C.alt=2@-35,0+929]
-../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
-../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
-../fonts/TRAK.ttf:--font-ptem=144 --features=-trak:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
-../fonts/TRAK.ttf:--font-ptem=144 --features=-trak[1;3]:U+0041,U+0042,U+0043,U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1+1000|C.alt=2+1000|A.alt=3@-78,0+843|B=4@-78,0+843|C.alt=5@-78,0+843]
diff --git a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests b/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
deleted file mode 100644
index 8b7ced0..0000000
--- a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
+++ /dev/null
@@ -1 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/arabic-feature-order.tests b/test/shaping/data/in-house/tests/arabic-feature-order.tests
deleted file mode 100644
index 0f7f58e..0000000
--- a/test/shaping/data/in-house/tests/arabic-feature-order.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf::U+1820,U+180B:[uni2048.E81A=0+1550]
-../fonts/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf::U+1820,U+180B:[uni2048.E81A=0+1550]
-../fonts/a919b33197965846f21074b24e30250d67277bce.ttf::U+0644,U+0644,U+0647:[Lellah=0+1503]
-../fonts/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf::U+0644,U+064E,U+0670,U+0653,U+0626:[afii57414.zz04=4+1202|uni0670_uni0653=0@50,350+0|afii57454=0@550,1425+0|afii57444.calt=0+1065]
diff --git a/test/shaping/data/in-house/tests/arabic-like-joining.tests b/test/shaping/data/in-house/tests/arabic-like-joining.tests
deleted file mode 100644
index 2e34186..0000000
--- a/test/shaping/data/in-house/tests/arabic-like-joining.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf::U+1E922,U+1E923,U+1E924,U+1E925,U+1E926,U+1E927,U+1E928,U+1E929,U+1E92A,U+1E92B,U+1E92C,U+1E92D,U+1E92E,U+1E92F,U+1E930,U+1E931,U+1E932,U+1E933,U+1E934,U+1E935,U+1E936,U+1E937,U+1E938,U+1E939,U+1E93A,U+1E93B,U+1E93C,U+1E93D,U+1E93E,U+1E93F,U+1E940,U+1E941,U+1E942,U+1E943:[sha_adlam.fina=33+711|kpo_adlam.medi=32+573|zal_adlam.medi=31+773|gbe_adlam.medi=30+594|kha_adlam.medi=29+686|va_adlam.medi=28+621|nha_adlam.medi=27+587|tu_adlam.medi=26+772|nya_adlam.medi=25+577|ga_adlam.medi=24+552|qaaf_adlam.medi=23+694|ha_adlam.medi=22+600|chi_adlam.medi=21+662|jiim_adlam.medi=20+781|u_adlam.medi=19+678|ya_adlam.medi=18+553|kaf_adlam.medi=17+808|nun_adlam.medi=16+561|waw_adlam.medi=15+651|yhe_adlam.medi=14+674|dha_adlam.medi=13+674|o_adlam.medi=12+640|i_adlam.medi=11+657|fa_adlam.medi=10+590|e_adlam.medi=9+628|ra_adlam.medi=8+599|bhe_adlam.medi=7+594|pe_adlam.medi=6+492|sinnyiiyhe_adlam.medi=5+777|ba_adlam.medi=4+655|miim_adlam.medi=3+525|laam_adlam.medi=2+554|daali_adlam.medi=1+600|alif_adlam.init=0+597]
diff --git a/test/shaping/data/in-house/tests/arabic-mark-attach.tests b/test/shaping/data/in-house/tests/arabic-mark-attach.tests
deleted file mode 100644
index a577e51..0000000
--- a/test/shaping/data/in-house/tests/arabic-mark-attach.tests
+++ /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/shaping/data/in-house/tests/arabic-mark-order.tests b/test/shaping/data/in-house/tests/arabic-mark-order.tests
deleted file mode 100644
index 18ddb88..0000000
--- a/test/shaping/data/in-house/tests/arabic-mark-order.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf::U+064A,U+064E,U+0670,U+0653,U+0640,U+0654,U+064E,U+0627:[afii57415.zz04=7+481|afii57454=4@25,975+0|uni0654=4@-50,50+0|afii57440=4+650|uni0670_uni0653=0@75,400+0|afii57454=0@750,1125+0|afii57450.calt=0+1331]
-../fonts/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf::U+0628,U+0618,U+0619,U+064E,U+064F,U+0654,U+0658,U+0653,U+0654,U+0651,U+0656,U+0651,U+065C,U+0655,U+0650:[uni0653.small=0@266,2508+0|uni0654=0@308,2151+0|uni0655=0@518,-1544+0|uni065C=0@501,-1453+0|uni0656=0@573,-659+0|uni0650=0@500,133+0|uni0619=0@300,1807+0|uni0618=0@357,1674+0|uni0651064E=0@387,1178+0|uni0651=0@402,764+0|uni0658=0@424,404+0|uni0654064F=0@540,-435+0|uni0628=0+1352]
-../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf::U+0649,U+0655,U+034F,U+0650:[uni0650.small2=0@727,-774+0|space=0+0|uni0655=0@727,-209+0|uni0649=0+1566]
-../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf::U+0649,U+0655,U+0650:[uni0650.small2=0@727,-774+0|uni0655=0@727,-209+0|uni0649=0+1566]
-../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf::U+0649,U+0650,U+0655:[uni0650.small2=0@727,-774+0|uni0655=0@727,-209+0|uni0649=0+1566]
-../fonts/21b7fb9c1eeae260473809fbc1fe330f66a507cd.ttf::U+0649,U+0650,U+034F,U+0655:[uni0655=0+0|space=0+0|uni0650=0@166,0+0|uni0649=0+1566]
diff --git a/test/shaping/data/in-house/tests/arabic-stch.tests b/test/shaping/data/in-house/tests/arabic-stch.tests
deleted file mode 100644
index 1ba8f60..0000000
--- a/test/shaping/data/in-house/tests/arabic-stch.tests
+++ /dev/null
@@ -1 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/automatic-fractions.tests b/test/shaping/data/in-house/tests/automatic-fractions.tests
deleted file mode 100644
index 58ec26c..0000000
--- a/test/shaping/data/in-house/tests/automatic-fractions.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/cluster.tests b/test/shaping/data/in-house/tests/cluster.tests
deleted file mode 100644
index 928843f..0000000
--- a/test/shaping/data/in-house/tests/cluster.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
-../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf:--cluster-level=1:U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD:[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338]
diff --git a/test/shaping/data/in-house/tests/collections.tests b/test/shaping/data/in-house/tests/collections.tests
deleted file mode 100644
index 07dac9d..0000000
--- a/test/shaping/data/in-house/tests/collections.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../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/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]
diff --git a/test/shaping/data/in-house/tests/color-fonts.tests b/test/shaping/data/in-house/tests/color-fonts.tests
deleted file mode 100644
index bf0005c..0000000
--- a/test/shaping/data/in-house/tests/color-fonts.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf:--font-funcs=ot --show-extents:U+1F42F:[gid1=0+2963<0,2179,2963,-2789>]
-../fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf:--font-funcs=ot --show-extents:U+1F600:[gid4=0+2550<0,1898,2555,-2405>]
diff --git a/test/shaping/data/in-house/tests/context-matching.tests b/test/shaping/data/in-house/tests/context-matching.tests
deleted file mode 100644
index 5673edc..0000000
--- a/test/shaping/data/in-house/tests/context-matching.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/cursive-positioning.tests b/test/shaping/data/in-house/tests/cursive-positioning.tests
deleted file mode 100644
index 15a1ffc..0000000
--- a/test/shaping/data/in-house/tests/cursive-positioning.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+452|gid9=1@0,977+452|gid10=0@20,1577+207]
-../fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207]
-#../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]
diff --git a/test/shaping/data/in-house/tests/default-ignorables.tests b/test/shaping/data/in-house/tests/default-ignorables.tests
deleted file mode 100644
index a27b67a..0000000
--- a/test/shaping/data/in-house/tests/default-ignorables.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf::U+0075,U+0361,U+034F,U+0301,U+0069:[gid2=0+1266|gid7=0@-617,442+0|gid5=0@-7,0+0|gid1=4+528]
-../fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf::U+0020,U+06CC,U+064E,U+034F,U+0651:[uni0651=1+0|space=1+0|uni064E=1@236,-432+0|uni06CC=1+1266|space=0+452]
diff --git a/test/shaping/data/in-house/tests/emoji.tests b/test/shaping/data/in-house/tests/emoji.tests
deleted file mode 100644
index 7ee01f3..0000000
--- a/test/shaping/data/in-house/tests/emoji.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
-../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=l:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
-../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=r:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
-../fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf::U+1F3F4,U+E0067,U+E0062,U+E0077,U+E006C,U+E0073,U+E007F:[.notdef=0+1229|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
diff --git a/test/shaping/data/in-house/tests/fallback-positioning.tests b/test/shaping/data/in-house/tests/fallback-positioning.tests
deleted file mode 100644
index 0ffee50..0000000
--- a/test/shaping/data/in-house/tests/fallback-positioning.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf::U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-19,-27+0|X=2+1295|acutecomb=2@-151,320+0]
-../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@0,-128+0|uni0062=2+512]
diff --git a/test/shaping/data/in-house/tests/hangul-jamo.tests b/test/shaping/data/in-house/tests/hangul-jamo.tests
deleted file mode 100644
index 6e2fecc..0000000
--- a/test/shaping/data/in-house/tests/hangul-jamo.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf::U+115F,U+11A2:[gid3=0+920|gid4=0+0]
-../fonts/7e14e7883ed152baa158b80e207b66114c823a8b.ttf::U+11A2:[gid1=0+920]
diff --git a/test/shaping/data/in-house/tests/hyphens.tests b/test/shaping/data/in-house/tests/hyphens.tests
deleted file mode 100644
index acfe8f4..0000000
--- a/test/shaping/data/in-house/tests/hyphens.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf::U+2010:[gid1=0+739]
-../fonts/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf::U+2011:[gid1=0+739]
diff --git a/test/shaping/data/in-house/tests/indic-consonant-with-stacker.tests b/test/shaping/data/in-house/tests/indic-consonant-with-stacker.tests
deleted file mode 100644
index 43a3f27..0000000
--- a/test/shaping/data/in-house/tests/indic-consonant-with-stacker.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/a014549f766436cf55b2ceb40e462038938ee899.ttf:--no-glyph-names:U+0CF1,U+0C95:[2=0+1129|3=1+358]
-../fonts/55c88ebbe938680b08f92c3de20713183e0c7481.ttf:--no-glyph-names:U+0CF2,U+0CAA:[2=0+1539|3=1+245]
-../fonts/341421e629668b1a1242245d39238ca48432d35d.ttf:--no-glyph-names:U+0CF1:[1=0+1129]
-../fonts/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf:--no-glyph-names:U+0CF2:[1=0+1539]
diff --git a/test/shaping/data/in-house/tests/indic-decompose.tests b/test/shaping/data/in-house/tests/indic-decompose.tests
deleted file mode 100644
index ca887be..0000000
--- a/test/shaping/data/in-house/tests/indic-decompose.tests
+++ /dev/null
@@ -1 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/indic-init.tests b/test/shaping/data/in-house/tests/indic-init.tests
deleted file mode 100644
index fee8635..0000000
--- a/test/shaping/data/in-house/tests/indic-init.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf:--no-glyph-names:U+09AC,U+09C7,U+09AC,U+09C7:[3=0+273|1=0+460|2=2+307|1=2+460]
diff --git a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests b/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests
deleted file mode 100644
index 6b75137..0000000
--- a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200D,U+0B01:[omorya=0+1450]
-../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=1+0|candrabinduorya=1+0]
diff --git a/test/shaping/data/in-house/tests/indic-joiners.tests b/test/shaping/data/in-house/tests/indic-joiners.tests
deleted file mode 100644
index 80e392c..0000000
--- a/test/shaping/data/in-house/tests/indic-joiners.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=4+0|uni17ca=4+0|uni17b8=4@0,300+0|space=7+600]
-../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
diff --git a/test/shaping/data/in-house/tests/indic-old-spec.tests b/test/shaping/data/in-house/tests/indic-old-spec.tests
deleted file mode 100644
index eb967ad..0000000
--- a/test/shaping/data/in-house/tests/indic-old-spec.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf::U+0C9A,U+0CCD,U+0C9A,U+0CCD:[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
-../fonts/270b89df543a7e48e206a2d830c0e10e5265c630.ttf::U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D:[glyph201=0+1183|U0D4D=0+0]
-../fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf::U+091F,U+094D,U+0930,U+094D,U+0020:[Tra=0+550|virAma=0@-73,-110+0|space=4+500]
-../fonts/b722a7d09e60421f3efbc706ad348ab47b88567b.ttf::U+091F,U+094D,U+0930,U+0942:[Tra=0+550|UT=0@42,-150+0]
diff --git a/test/shaping/data/in-house/tests/indic-pref-blocking.tests b/test/shaping/data/in-house/tests/indic-pref-blocking.tests
deleted file mode 100644
index 516753d..0000000
--- a/test/shaping/data/in-house/tests/indic-pref-blocking.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/226bc2deab3846f1a682085f70c67d0421014144.ttf::U+0D2F,U+0D4D,U+0D30,U+0D46:[evowelsignmlym=0+1465|rapostmlym=0+499|yamlym=0+2120]
-../fonts/e207635780b42f898d58654b65098763e340f5c7.ttf::U+0D2F,U+0D4D,U+0D30,U+0D46:[yamlym=0+2120|viramamlym=0+0|evowelsignmlym=0+1465|ramlym=0+1507]
diff --git a/test/shaping/data/in-house/tests/indic-script-extensions.tests b/test/shaping/data/in-house/tests/indic-script-extensions.tests
deleted file mode 100644
index 0589627..0000000
--- a/test/shaping/data/in-house/tests/indic-script-extensions.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/3493e92eaded2661cadde752a39f9d58b11f0326.ttf::U+0BA4,U+0BC6,U+1133C,U+0BAA,U+1133C,U+0BC6,U+1133C:[u0BC6=0+2093|u1133C=0+0|u0BA4=0+1863|u0BC6=3+2093|u1133C=3+0|u0BAA=3+1706|u1133C=3+0]
-../fonts/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf:--no-glyph-names:U+0BAA,U+11301,U+11303:[1=0+535|2=0+0|3=0+310]
diff --git a/test/shaping/data/in-house/tests/indic-special-cases.tests b/test/shaping/data/in-house/tests/indic-special-cases.tests
deleted file mode 100644
index f51651f..0000000
--- a/test/shaping/data/in-house/tests/indic-special-cases.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../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]
diff --git a/test/shaping/data/in-house/tests/indic-syllable.tests b/test/shaping/data/in-house/tests/indic-syllable.tests
deleted file mode 100644
index 264983b..0000000
--- a/test/shaping/data/in-house/tests/indic-syllable.tests
+++ /dev/null
@@ -1,10 +0,0 @@
-../fonts/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf::U+0BA4,U+0BCD,U+00B3:[taprehalftamil=0+1509|uni00B3=2+674]
-../fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf::U+0CF1:[gid1=0+1129]
-../fonts/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf::U+0CF2:[gid2=0+1539]
-../fonts/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf:--font-funcs=ot:U+0980,U+0981:[anjibeng=0+520|candrabindubeng=0+0]
-../fonts/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf::U+0A15,U+0A51,U+0A47:[kaguru=0+1273|udaatguru=0@75,0+0|eematraguru=0@-40,0+0]
-../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+0A51:[uni25CC=0+1044|udaatguru=0+0]
-../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+25CC,U+0A51:[uni25CC=0+1044|udaatguru=0+0]
-../fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf:--no-glyph-names:U+0C80,U+0C82:[1=0+502|2=0+502]
-../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A47:[tthaguru=0+1352|yakashguru=0@-90,0+0|eematraguru=0@-411,0+0]
-../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A42:[tthaguru=0+1352|yakashuuguru=0+0]
diff --git a/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests b/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests
deleted file mode 100644
index f8305a3..0000000
--- a/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests
+++ /dev/null
@@ -1,53 +0,0 @@
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0904,U+0020,U+0905,U+0946:[ashortdeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|eshortvowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0906,U+0020,U+0905,U+093E:[aadeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|aavowelsigndeva=2+259]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0908,U+0020,U+0930,U+094D,U+0907:[iideva=0+491|space=1+260|uni25CC=2+510|rephdeva=2+0|ideva=2+491]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090A,U+0020,U+0909,U+0941:[uudeva=0+765|space=1+260|udeva=2+548|uni25CC=2+510|uvowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090D,U+0020,U+090F,U+0945:[ecandradeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|ecandravowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090E,U+0020,U+090F,U+0946:[eshortdeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|eshortvowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0910,U+0020,U+090F,U+0947:[aideva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|evowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0911,U+0020,U+0905,U+0949,U+0020,U+0906,U+0945:[ocandradeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ocandravowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|ecandravowelsigndeva=5+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0912,U+0020,U+0905,U+094A,U+0020,U+0906,U+0946:[oshortdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|oshortvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|eshortvowelsigndeva=5+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0913,U+0020,U+0905,U+094B,U+0020,U+0906,U+0947:[odeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ovowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|evowelsigndeva=5+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0914,U+0020,U+0905,U+094C,U+0020,U+0906,U+0948:[audeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|auvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|aivowelsigndeva=5+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0972,U+0020,U+0905,U+0945:[acandradeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|ecandravowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0973,U+0020,U+0905,U+093A:[oedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|oevowelsigndeva=2+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0974,U+0020,U+0905,U+093B,U+0020,U+0906,U+093A:[ooedeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ooevowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|oevowelsigndeva=5+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0975,U+0020,U+0905,U+094F:[awdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|awvowelsigndeva=2+259]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0976,U+0020,U+0905,U+0956:[uedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uevowelsigndeva=2@50,0+0]
-../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0977,U+0020,U+0905,U+0957:[uuedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uuevowelsigndeva=2@50,0+0]
-../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+0986,U+0020,U+0985,U+09BE:[aabeng=0+1158|space=1+260|abeng=2+893|uni25CC=2+510|aavowelsignbeng=2+266]
-../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E0,U+0020,U+098B,U+09C3:[rrvocalicbeng=0+853|space=1+260|rvocalicbeng=2+853|uni25CC=2+510|rvocalicvowelsignbeng=2+0]
-../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E1,U+0020,U+098C,U+09E2:[llvocalicbeng=0+639|space=1+260|lvocalicbeng=2+639|uni25CC=2+510|lvocalicvowelsignbeng=2+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A06,U+0020,U+0A05,U+0A3E:[aaguru=0+2001|space=1+532|aguru=2+1520|uni25CC=2+1044|aamatraguru=2+481]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A07,U+0020,U+0A72,U+0A3F:[iguru=0+1671|space=1+532|iriguru=2+1141|imatraguru=2+530|uni25CC=2+1044]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A08,U+0020,U+0A72,U+0A40:[iiguru=0+1671|space=1+532|iriguru=2+1141|uni25CC=2+1044|iimatraguru=2+530]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A09,U+0020,U+0A73,U+0A41:[uguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|umatraguru=2@102,0+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0A,U+0020,U+0A73,U+0A42:[uuguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|uumatraguru=2@102,0+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0F,U+0020,U+0A72,U+0A47:[eeguru=0+1141|space=1+532|iriguru=2+1141|uni25CC=2+1044|eematraguru=2+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A10,U+0020,U+0A05,U+0A48:[aiguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aimatraguru=2+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A13,U+0020,U+0A73,U+0A4B:[ooguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|oomatraguru=2+0]
-../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A14,U+0020,U+0A05,U+0A4C:[auguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aumatraguru=2+0]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A86,U+0020,U+0A85,U+0ABE:[gid3=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid10=2+543]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8D,U+0020,U+0A85,U+0AC5:[gid4=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid11=2+0]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8F,U+0020,U+0A85,U+0AC7:[gid5=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid12=2+0]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A90,U+0020,U+0A85,U+0AC8:[gid6=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid13=2+0]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A91,U+0020,U+0A85,U+0AC9:[gid7=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid14=2+543]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A93,U+0020,U+0A85,U+0ACB,U+0020,U+0A85,U+0ABE,U+0AC5:[gid8=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid15=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid11=5+0|gid10=5+543]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A94,U+0020,U+0A85,U+0ACC,U+0020,U+0A85,U+0ABE,U+0AC8:[gid9=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid16=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid13=5+0|gid10=5+543]
-../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0AC9,U+0020,U+0AC5,U+0ABE:[gid17=0+1044|gid14=0+543|gid1=1+612|gid17=1+1044|gid11=1+0|gid17=1+1044|gid10=1+543]
-../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B06,U+0020,U+0B05,U+0B3E:[aaorya=0+1681|space=1+881|aorya=2+1284|uni25CC=2+1044|aavowelsignorya=2+387]
-../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B10,U+0020,U+0B0F,U+0B57:[aiorya=0+1681|space=1+881|eorya=2+1315|uni25CC=2+1044|aulengthmarkorya=2+387]
-../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B14,U+0020,U+0B13,U+0B57:[auorya=0+1679|space=1+881|oorya=2+1309|uni25CC=2+1044|aulengthmarkorya=2+387]
-../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C13,U+0020,U+0C12,U+0C55:[gid3=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid12=2+0]
-../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C14,U+0020,U+0C12,U+0C4C:[gid4=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid11=2+634]
-../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C40,U+0020,U+0C3F,U+0C55:[gid13=0+1184|gid6=0+0|gid1=1+580|gid13=1+1184|gid5=1+0|gid13=1+1184|gid12=1+0]
-../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C47,U+0020,U+0C46,U+0C55:[gid13=0+1184|gid8=0+0|gid1=1+580|gid13=1+1184|gid7=1+0|gid13=1+1184|gid12=1+0]
-../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C4B,U+0020,U+0C4A,U+0C55:[gid13=0+1184|gid10=0+634|gid1=1+580|gid13=1+1184|gid9=1+634|gid13=1+1184|gid12=1+0]
-../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C8A,U+0020,U+0C89,U+0CBE:[gid3=0+3269|gid1=1+590|gid2=2+2502|gid10=2+1184|gid7=2+919]
-../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C94,U+0020,U+0C92,U+0CCC:[gid6=0+1596|gid1=1+590|gid5=2+1590|gid10=2+1184|gid8=2+880]
-../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0CE0,U+0020,U+0C8B,U+0CBE:[gid9=0+3214|gid1=1+590|gid4=2+2440|gid10=2+1184|gid7=2+919]
-../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D08,U+0020,U+0D07,U+0D57:[gid3=0+3574|gid1=1+632|gid2=2+2019|gid14=2+1184|gid13=2+1555]
-../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D0A,U+0020,U+0D09,U+0D57:[gid5=0+2972|gid1=1+632|gid4=2+1417|gid14=2+1184|gid13=2+1555]
-../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D10,U+0020,U+0D0E,U+0D46:[gid7=0+4073|gid1=1+632|gid6=2+2608|gid12=2+1465|gid14=2+1184]
-../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D13,U+0020,U+0D12,U+0D3E:[gid9=0+2557|gid1=1+632|gid8=2+1524|gid14=2+1184|gid11=2+1033]
-../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D14,U+0020,U+0D12,U+0D57:[gid10=0+3073|gid1=1+632|gid8=2+1524|gid14=2+1184|gid13=2+1555]
diff --git a/test/shaping/data/in-house/tests/kern-format2.tests b/test/shaping/data/in-house/tests/kern-format2.tests
deleted file mode 100644
index f7cd840..0000000
--- a/test/shaping/data/in-house/tests/kern-format2.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf::U+0061,U+0062,U+0063,U+0064,U+0065,U+0066,U+0067,U+0068,U+0069,U+006A,U+006B,U+006C,U+006D,U+006E,U+006F,U+0070:[a=0+626|b=1+672|c=2+564|d=3@-15,0+657|e=4+621|f=5+403|g=6@-10,0+662|h=7+666|i=8+316|j=9+316|k=10+591|l=11+316|m=12+1021|n=13+666|o=14+644|p=15+672]
-../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf::U+0063,U+006B,U+0063,U+006B,U+0063,U+006B:[c=0+579|k=1+591|c=2+579|k=3+591|c=4+579|k=5+591]
-../fonts/e39391c77a6321c2ac7a2d644de0396470cd4bfe.ttf::U+0041,U+0056:[A=0+701|V=1@-40,0+703]
diff --git a/test/shaping/data/in-house/tests/khmer-mark-order.tests b/test/shaping/data/in-house/tests/khmer-mark-order.tests
deleted file mode 100644
index d581dd1..0000000
--- a/test/shaping/data/in-house/tests/khmer-mark-order.tests
+++ /dev/null
@@ -1,25 +0,0 @@
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni1794=3+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17BB,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17B8=0@-20,-84+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
-../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BB,U+17BE,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
diff --git a/test/shaping/data/in-house/tests/khmer-misc.tests b/test/shaping/data/in-house/tests/khmer-misc.tests
deleted file mode 100644
index 1ea7609..0000000
--- a/test/shaping/data/in-house/tests/khmer-misc.tests
+++ /dev/null
@@ -1,90 +0,0 @@
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1781,U+17D2,U+1798,U+17C2:[uni17C2=0+288|uni1781=0+635|uni17D21798=0@22,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1787,U+17B6:[uni178717B6=0+923]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1790,U+17D2,U+1784,U+17C3:[uni17C3=0+288|uni1790=0+635|uni17D21784=0@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17B6:[uni179817B6=0+923]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17D2,U+1796,U+17BB:[uni1798=0+635|uni17D21796=0@-1,-26+0|uni17BB=0@-22,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179A:[uni179A=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179A,U+17B8:[uni179A=0+288|uni17B8.r=0@76,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179A,U+17CD:[uni179A=0+288|uni17CD.r=0@18,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17C5:[uni17C1=0+288|uni179F17C5=0+1216]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179A,U+17D2,U+17A5:[uni179A=0+288|uni17D2=0+0|uni17A5=2+635]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1784,U+17B9,U+17D2,U+1788:[uni1784=0+635|uni17B9=0@-46,30+0|uni17D21788=0+234]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1784,U+17D2,U+1788,U+17B9:[uni1784=0+635|uni17D21788=0+234|uni17B9=0@8,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1784,U+17D2,U+1782,U+17D2,U+179A:[uni17D2179A.low=0+287|uni1784=0+635|uni17D21782=0@0,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1784,U+17D2,U+179A,U+17D2,U+1782:[uni17D2179A.low=0+287|uni1784=0+635|uni17D21782=0@0,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17C9,U+17D2,U+179B,U+17C1,U+17C7:[uni17C1=0+288|uni1798=0+635|uni17C9=0@-46,-29+0|uni17D2179B=0@-1,-26+0|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+200C,U+17C9,U+17D2,U+179B,U+17C1,U+17C7:[uni17C1=0+288|uni1798=0+635|space=0+0|uni17C9=0@-46,-29+0|uni17D2179B=0@-1,-26+0|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1794,U+17CA,U+17D0:[uni1794=0+635|uni17CA=0@-46,-29+0|uni17D0=0@-46,113+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1793,U+17C2,U+17CE:[uni17C2=0+288|uni1793=0+635|uni17CE=0@-36,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17C1,U+17D2,U+179A:[uni17D2179A=0+287|uni17C1=0+288|uni1780=0+636]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17C0,U+17D2,U+179A:[uni17D2179A=0+287|uni17C1=0+288|uni1780=0+636|uni17C0.right1=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17C4,U+17D2,U+179A:[uni17D2179A=0+287|uni17C1=0+288|uni178017B6=0+924]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17C5,U+17D2,U+179A:[uni17D2179A=0+287|uni17C1=0+288|uni178017C5=0+924]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1796,U+17D1,U+17B6:[uni179617B6=0+923|uni17D1=0@-311,-19+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+1793,U+17D2,U+178F,U+17D2,U+179A,U+17B6,U+1780,U+17CB:[uni1780=0+636|uni17D2179A.low=1+287|uni179317B6=1+924|uni17D2178F=1@-290,-26+0|uni1780=7+636|uni17CB=7@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+1793,U+17D2,U+179A,U+17D2,U+179F,U+17B7,U+1780,U+17CB:[uni1780=0+636|uni17D2179A=1+287|uni1793=1+635|uni17D2179F=1+302|uni17B7=1@-4,30+0|uni1780=7+636|uni17CB=7@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+1793,U+17D2,U+179A,U+17D2,U+179F,U+17B8,U+1780,U+17CB:[uni1780=0+636|uni17D2179A=1+287|uni1793=1+635|uni17D2179F=1+302|uni17B8=1@-4,30+0|uni1780=7+636|uni17CB=7@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17B6,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F17B6=0+584|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17B7,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17B7=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17B8,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17B8=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17B9,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17B9=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17BA,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17BA=0@-4,30+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17BB,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17BB=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17BC,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17BC=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17BD,U+1793,U+17D2,U+178F:[uni1780=0+636|uni17D2179F=0+302|uni17BD=0@1,-260+0|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1780,U+17D2,U+179F,U+17BF,U+1793,U+17D2,U+178F:[uni17C1=0+288|uni1780=0+636|uni17D2179F=0+302|uni17BF.right2=0+288|uni1793=4+635|uni17D2178F=4@-1,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17B6,U+17C6:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F17B6.low=0+584|uni17C6=0@39,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17B7,U+17C7:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17B7=0@-4,30+0|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17BB,U+17C6:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17C6=0@-4,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17BB,U+17C7:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C1,U+17C7:[uni17C1=0+288|uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C4,U+17C7:[uni17C1=0+288|uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F17B6.low=0+584|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C6:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C6=0@-4,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1783,U+17D2,U+179B,U+17D2,U+179F,U+17C7:[uni1783=0+928|uni17D2179B=0@15,-26+0|uni17D2179F.low=0+302|uni17C7=0+386]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1789,U+17BC:[uni1789=0+952|uni17BC=0@-173,-260+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1789,U+17D2,U+1789:[uni1789.a=0+952|uni17D21789.a=0@19,-22+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1789,U+17D2,U+1789,U+17BB:[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BB=0@-160,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1789,U+17D2,U+1789,U+17BC:[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BC=0@-160,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1789,U+17D2,U+1789,U+17BD:[uni1789.a=0+952|uni17D21789.a=0@19,-22+0|uni17BD=0@-160,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C0:[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302|uni17C0.right2=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C1:[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C2:[uni17C2=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C3:[uni17C3=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F=0+302]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C4:[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F17B6=0+584]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+178F,U+17D2,U+179A,U+17D2,U+179F,U+17C5:[uni17C1=0+288|uni17D2179A=0+287|uni178F=0+635|uni17D2179F17C5=0+584]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1792,U+17D2,U+179B,U+17BB,U+17C6,U+1780,U+17CB:[uni1792=0+635|uni17D2179B=0@-2,-26+0|uni17BB=0@-19,-296+0|uni17C6=0@-46,-29+0|uni1780=5+636|uni17CB=5@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1792,U+17D2,U+179B,U+17C4,U+1780,U+17CB:[uni17C1=0+288|uni179217B6=0+923|uni17D2179B=0@-290,-26+0|uni1780=4+636|uni17CB=4@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1792,U+17D2,U+179B,U+17C5,U+1780,U+17CB:[uni17C1=0+288|uni179217C5=0+923|uni17D2179B=0@-290,-26+0|uni1780=4+636|uni17CB=4@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1792,U+17D2,U+179B,U+17C6,U+1780,U+17CB:[uni1792=0+635|uni17D2179B=0@-2,-26+0|uni17C6=0@-46,-29+0|uni1780=4+636|uni17CB=4@-23,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17B6:[uni179817B6=0+923|uni17D2178F=0@-289,-26+0|uni17D2179B=0@-289,-296+0|uni17C9=0@-334,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17BB:[uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17BB=0@-18,-566+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17BF:[uni17C1=0+288|uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17BF.right1=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1798,U+17D2,U+178F,U+17D2,U+179B,U+17C9,U+17C0:[uni17C1=0+288|uni1798=0+635|uni17D2178F=0@-1,-26+0|uni17D2179B=0@-1,-296+0|uni17C9=0@-46,-29+0|uni17C0.right1=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+1799,U+17D2,U+1799,U+17BE,U+17A0,U+17D2,U+179C,U+17D2,U+179B,U+17C3:[uni17C1=0+288|uni1799=0+953|uni17D21799=0+298|uni17B8=0@1,30+0|uni17C3=4+288|uni17A0=4+928|uni17D2179C=4@20,-26+0|uni17D2179B=4@19,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179A,U+17D2,U+179A:[uni17D2179A=0+287|uni179A=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B6:[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni178417B6=10+923]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B7:[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni1784=10+635|uni17B7=10@-46,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17B6,U+179F,U+17D2,U+178F,U+17D2,U+179A,U+1783,U+17D2,U+1788,U+1784,U+17B8:[uni179F17B6=0+1216|uni17D2179A=2+287|uni179F=2+928|uni17D2178F=2@14,-26+0|uni1783=7+928|uni17D21788=7+234|uni1784=10+635|uni17B8=10@-46,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+178F,U+17D2,U+179A,U+17B8,U+179C,U+17D0,U+1781,U+17D2,U+1789,U+17D2,U+179F,U+17B6:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0|uni179C=6+326|uni17D0=6@139,40+0|uni1781=8+635|uni17D21789=8@-4,-26+0|uni17D2179F17B6.low=8+584]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B6:[uni17D2179A=0+287|uni179F17B6=0+1216|uni17D2178F=0@-274,-26+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B7:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B7=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B8:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17B9:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B9=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BA:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BA=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BB:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BB=0@-6,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BC:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BC=0@-6,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BD:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BD=0@-6,-296+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BE:[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17B8=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17BF:[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17BF.right2=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17BF:[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17BF.right1=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C0:[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17C0.right1.high=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C1:[uni17C1=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C2:[uni17C2=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C3:[uni17C3=0+288|uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+179F,U+17D2,U+179A,U+17D2,U+178F,U+17CA,U+17C6:[uni17D2179A=0+287|uni179F=0+928|uni17D2178F=0@14,-26+0|uni17CA=0@-32,-29+0|uni17C6=0@-32,113+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17BE:[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17BB=0+0|uni17B8=0@-4,30+0]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17BF:[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17CA=0@-4,30+0|uni17BF.right1=0+288]
-../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17C0:[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17CA=0@-4,30+0|uni17C0.right1.high=0+288]
-../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]
diff --git a/test/shaping/data/in-house/tests/language-tags.tests b/test/shaping/data/in-house/tests/language-tags.tests
deleted file mode 100644
index c7be180..0000000
--- a/test/shaping/data/in-house/tests/language-tags.tests
+++ /dev/null
@@ -1,13 +0,0 @@
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=fa:U+004A:[gid2=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=ja:U+004A:[gid2=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh:U+004A:[gid4=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-cn:U+004A:[gid4=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-sg:U+004A:[gid4=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-tw:U+004A:[gid5=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-hans:U+004A:[gid4=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-hant:U+004A:[gid5=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-hant-hk:U+004A:[gid6=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-HK:U+004A:[gid6=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-mo:U+004A:[gid6=0+1000]
-../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-Hant-mo:U+004A:[gid6=0+1000]
-../fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf:--language=dv --no-glyph-names:U+007C:[2=0+156]
diff --git a/test/shaping/data/in-house/tests/ligature-id.tests b/test/shaping/data/in-house/tests/ligature-id.tests
deleted file mode 100644
index 3daaca3..0000000
--- a/test/shaping/data/in-house/tests/ligature-id.tests
+++ /dev/null
@@ -1,36 +0,0 @@
-../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=3+213|u0995_u09B0_u09CD.blwf.vatu=4+643|u0995_u09CD.half_u09B2.pres=7+602]
-../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=6+213|u0995_u09B0_u09CD.blwf.vatu=7+643|u0995_u09CD.half_u09B2.pres=10+602]
-../fonts/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=9+213|u0995_u09B0_u09CD.blwf.vatu=10+643|u0995_u09CD.half_u09B2.pres=13+602]
-../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+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|space=12+213|u0995_u09B0_u09CD.blwf.vatu=13+643|u0995_u09CD.half_u09B2.pres=16+602]
-../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+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|space=15+213|u0995_u09B0_u09CD.blwf.vatu=16+643|u0995_u09CD.half_u09B2.pres=19+602]
-../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+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|space=18+213|u0995_u09B0_u09CD.blwf.vatu=19+643|u0995_u09CD.half_u09B2.pres=22+602]
-../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+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|space=21+213|u0995_u09B0_u09CD.blwf.vatu=22+643|u0995_u09CD.half_u09B2.pres=25+602]
-../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+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|space=24+213|u0995_u09B0_u09CD.blwf.vatu=25+643|u0995_u09CD.half_u09B2.pres=28+602]
-../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+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|space=27+213|u0995_u09B0_u09CD.blwf.vatu=28+643|u0995_u09CD.half_u09B2.pres=31+602]
-../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+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|space=30+213|u0995_u09B0_u09CD.blwf.vatu=31+643|u0995_u09CD.half_u09B2.pres=34+602]
-../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+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|space=33+213|u0995_u09B0_u09CD.blwf.vatu=34+643|u0995_u09CD.half_u09B2.pres=37+602]
-../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+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|space=36+213|u0995_u09B0_u09CD.blwf.vatu=37+643|u0995_u09CD.half_u09B2.pres=40+602]
-../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+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|space=39+213|u0995_u09B0_u09CD.blwf.vatu=40+643|u0995_u09CD.half_u09B2.pres=43+602]
-../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+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|space=42+213|u0995_u09B0_u09CD.blwf.vatu=43+643|u0995_u09CD.half_u09B2.pres=46+602]
-../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+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|space=45+213|u0995_u09B0_u09CD.blwf.vatu=46+643|u0995_u09CD.half_u09B2.pres=49+602]
-../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+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|space=48+213|u0995_u09B0_u09CD.blwf.vatu=49+643|u0995_u09CD.half_u09B2.pres=52+602]
-../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+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|space=51+213|u0995_u09B0_u09CD.blwf.vatu=52+643|u0995_u09CD.half_u09B2.pres=55+602]
-../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+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|space=54+213|u0995_u09B0_u09CD.blwf.vatu=55+643|u0995_u09CD.half_u09B2.pres=58+602]
-../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+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|space=57+213|u0995_u09B0_u09CD.blwf.vatu=58+643|u0995_u09CD.half_u09B2.pres=61+602]
-../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+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|space=60+213|u0995_u09B0_u09CD.blwf.vatu=61+643|u0995_u09CD.half_u09B2.pres=64+602]
-../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+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|space=63+213|u0995_u09B0_u09CD.blwf.vatu=64+643|u0995_u09CD.half_u09B2.pres=67+602]
-../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+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|space=66+213|u0995_u09B0_u09CD.blwf.vatu=67+643|u0995_u09CD.half_u09B2.pres=70+602]
-../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+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|space=69+213|u0995_u09B0_u09CD.blwf.vatu=70+643|u0995_u09CD.half_u09B2.pres=73+602]
-../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+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|space=72+213|u0995_u09B0_u09CD.blwf.vatu=73+643|u0995_u09CD.half_u09B2.pres=76+602]
-../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+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|space=75+213|u0995_u09B0_u09CD.blwf.vatu=76+643|u0995_u09CD.half_u09B2.pres=79+602]
-../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+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|space=78+213|u0995_u09B0_u09CD.blwf.vatu=79+643|u0995_u09CD.half_u09B2.pres=82+602]
-../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+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|space=81+213|u0995_u09B0_u09CD.blwf.vatu=82+643|u0995_u09CD.half_u09B2.pres=85+602]
-../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+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|space=84+213|u0995_u09B0_u09CD.blwf.vatu=85+643|u0995_u09CD.half_u09B2.pres=88+602]
-../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+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|space=87+213|u0995_u09B0_u09CD.blwf.vatu=88+643|u0995_u09CD.half_u09B2.pres=91+602]
-../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+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|space=90+213|u0995_u09B0_u09CD.blwf.vatu=91+643|u0995_u09CD.half_u09B2.pres=94+602]
-../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+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|space=93+213|u0995_u09B0_u09CD.blwf.vatu=94+643|u0995_u09CD.half_u09B2.pres=97+602]
-../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+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|space=96+213|u0995_u09B0_u09CD.blwf.vatu=97+643|u0995_u09CD.half_u09B2.pres=100+602]
-../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+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|space=99+213|u0995_u09B0_u09CD.blwf.vatu=100+643|u0995_u09CD.half_u09B2.pres=103+602]
-../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+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|space=102+213|u0995_u09B0_u09CD.blwf.vatu=103+643|u0995_u09CD.half_u09B2.pres=106+602]
-../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]
diff --git a/test/shaping/data/in-house/tests/macos.tests b/test/shaping/data/in-house/tests/macos.tests
deleted file mode 100644
index 434e0a5..0000000
--- a/test/shaping/data/in-house/tests/macos.tests
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912]
-/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
-/Library/Fonts/Khmer MN.ttc@5f5b1072df99b7355d3066ea85fe82969d13c94a:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
-/Library/Fonts/Tamil MN.ttc@37a2020c3f86ebcc45e02c1de5fdf81e2676989d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
-/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
-/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
-/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
-/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
-/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
-/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
-/System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--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:[gid225=0+1105|gid584=1@-105,0+979|gid3=2+490|gid4=3+1227|gid265=4@-65,0+1227|gid3=5+490|gid225=6+1130|gid728=7@-80,0+569|gid3=8+490|gid265=9+1227|gid505=10@-65,0+997|gid3=11+490|gid728=12+609|gid225=13@-40,0+1170|gid3=14+490|gid584=15+1004|gid225=16@-80,0+1130|gid3=17+490|gid225=18+1105|gid576=19@-105,0+1068]
-/System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--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:[gid225=0@65,0+1235|gid584=1@-40,0+1109|gid3=2@65,0+620|gid4=3@65,0+1357|gid265=4+1357|gid3=5@65,0+620|gid225=6@65,0+1260|gid728=7@-15,0+699|gid3=8@65,0+620|gid265=9@65,0+1357|gid505=10+1127|gid3=11@65,0+620|gid728=12@65,0+739|gid225=13@25,0+1300|gid3=14@65,0+620|gid584=15@65,0+1134|gid225=16@-15,0+1260|gid3=17@65,0+620|gid225=18@65,0+1235|gid576=19@-40,0+1198]
-/System/Library/Fonts/Apple Color Emoji.ttc@d2fe8a134483aa48a43a9d1e4b7204d37a4abdf5:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
-/Library/Fonts/Zapfino.ttf@9ee799ffb09516ead6b0cf6f2ca807276e150748:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
-
-# 10.13.6 https://gist.github.com/ebraminio/d432e831b3f7ebe30245dde5775e1c7e
-/System/Library/Fonts/Helvetica.ttc@8a928f9866299d2455f41360202b7a3b48503a5e:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912]
-/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
-/Library/Fonts/Khmer MN.ttc@782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
-/Library/Fonts/Tamil MN.ttc@3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
-/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
-/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
-/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
-/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
-/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/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--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:[gid282=0+1055|gid658=1@-135,0+914|gid3=2+420|gid4=3+1227|gid332=4@-65,0+1227|gid3=5+420|gid282=6+1075|gid813=7@-115,0+516|gid3=8+420|gid332=9+1217|gid572=10@-75,0+953|gid3=11+420|gid813=12+546|gid282=13@-85,0+1105|gid3=14+420|gid658=15+914|gid282=16@-135,0+1055|gid3=17+420|gid282=18+1055|gid649=19@-135,0+999]
-/System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--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:[gid282=0@65,0+1185|gid658=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid332=4+1357|gid3=5@65,0+550|gid282=6@65,0+1205|gid813=7@-50,0+646|gid3=8@65,0+550|gid332=9@65,0+1347|gid572=10@-10,0+1083|gid3=11@65,0+550|gid813=12@65,0+676|gid282=13@-20,0+1235|gid3=14@65,0+550|gid658=15@65,0+1044|gid282=16@-70,0+1185|gid3=17@65,0+550|gid282=18@65,0+1185|gid649=19@-70,0+1129]
-/System/Library/Fonts/Apple Color Emoji.ttc@2e09b1f3d42c3821cc6c4ac5b6ce16237ab0d496:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
-/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
-
-# 10.14.2 https://gist.github.com/ebraminio/4b731a82f11a662b2164622ebb93086a
-/System/Library/Fonts/Helvetica.ttc@992d29a0fa4ed91773457c29b661e94843619cde:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912]
-/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
-/Library/Fonts/Khmer MN.ttc@37687fe0bd2548e08e29c92a30e476367ae6356b:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1230|km_ka=1+1230|km_sa.sub=1+620|km_ro=4+712|km_vs_ae=5+726|km_kha=5+1230|km_mo.sub=5+0|km_ro=9+712]
-/Library/Fonts/Tamil MN.ttc@e1df5e056be08937fd65990efbafff0814c03677:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
-/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
-/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--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+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
-/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
-/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
-/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/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--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:[gid283=0+1055|gid659=1@-135,0+914|gid3=2+420|gid4=3+1227|gid333=4@-65,0+1227|gid3=5+420|gid283=6+1075|gid815=7@-115,0+516|gid3=8+420|gid333=9+1217|gid573=10@-75,0+953|gid3=11+420|gid815=12+546|gid283=13@-85,0+1105|gid3=14+420|gid659=15+914|gid283=16@-135,0+1055|gid3=17+420|gid283=18+1055|gid650=19@-135,0+999]
-/System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--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:[gid283=0@65,0+1185|gid659=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid333=4+1357|gid3=5@65,0+550|gid283=6@65,0+1205|gid815=7@-50,0+646|gid3=8@65,0+550|gid333=9@65,0+1347|gid573=10@-10,0+1083|gid3=11@65,0+550|gid815=12@65,0+676|gid283=13@-20,0+1235|gid3=14@65,0+550|gid659=15@65,0+1044|gid283=16@-70,0+1185|gid3=17@65,0+550|gid283=18@65,0+1185|gid650=19@-70,0+1129]
-/System/Library/Fonts/Apple Color Emoji.ttc@60f77161021b1b87e99c3690e1a9b56341cf8792:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
-/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
diff --git a/test/shaping/data/in-house/tests/mark-attachment.tests b/test/shaping/data/in-house/tests/mark-attachment.tests
deleted file mode 100644
index 9a9b8ff..0000000
--- a/test/shaping/data/in-house/tests/mark-attachment.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf::U+100F,U+103C,U+102F,U+1036:[uni103C102F=0+150|uni100F=0+550|uni1036=0@-150,0+0]
diff --git a/test/shaping/data/in-house/tests/mark-filtering-sets.tests b/test/shaping/data/in-house/tests/mark-filtering-sets.tests
deleted file mode 100644
index d30e021..0000000
--- a/test/shaping/data/in-house/tests/mark-filtering-sets.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf::U+062A,U+062E,U+062A,U+0629:[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph837=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
-../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf::U+062A,U+062E,U+0646,U+0629:[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph836=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
-../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf::U+062A,U+062E,U+0626,U+0629:[glyph837=3@299,1170+0|uni06C1.1=3+502|glyph847=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
-../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf::U+062A,U+062E,U+062B,U+0629:[glyph837=3@299,1520+0|uni06C1.1=3+502|glyph838=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
-../fonts/f22416c692720a7d46fadf4af99f4c9e094f00b9.ttf::U+062A,U+062E,U+0679,U+0629:[glyph837=3@299,1520+0|uni06C1.1=3+502|glyph842=2@149,690+0|uni0628.8=2+532|glyph836=1@-51,1259+0|glyph514=1+196|glyph837=0@655,1751+0|glyph112=0@0,-358+905]
diff --git a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests
deleted file mode 100644
index c5e35c8..0000000
--- a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests
+++ /dev/null
@@ -1,19 +0,0 @@
-../fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf::U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
-../fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf::U+1820,U+180B:[uni1820.E821_a.isol1=0+1199]
-../fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf::U+180A,U+1868,U+180A,U+1868,U+180B,U+180A,U+1868,U+180C,U+180A,U+1868,U+180D,U+180A:[gid1=0+268|gid10=1+778|gid1=2+268|gid9=3+575|gid1=5+268|gid10=6+778|gid1=8+268|gid8=9+575|gid1=11+268]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+182D,U+180B:[uni182D.E8E2_g.init=0+1000|uni182D.E8E8_g.fina1=1+1250]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C:[uni182D.EA1B_g.isol2=0+1000]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+200D,U+182D,U+180B,U+200D:[uni182D.E8E2_g.init=0+1000|space=0+0|uni182D.E8E5_g.medi1=2+800|space=2+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C,U+200D:[uni182D.EA1D_g.init2=0+950|space=0+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|space=1+0|uni182D.E8E5_g.medi1=4+800|space=4+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180D,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+182D,U+180B:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|uni182D.E8E8_g.fina1=3+1250]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C:[space=0+0|uni182D.E8E9_g.fina2=1+1050]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1820,U+200C,U+182D,U+1820,U+1837:[uni1820.E820_a.isol=0+1550|space=1+0|uni182D.E8E2_g.init=2+1000|uni1820.E823_a.medi=3+400|uni1837.E931_r.fina=4+750]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D:[uni1830.E90B_s.init=0+850|uni1824.E844_u.medi=1+600|uni1837.E930_r.medi=2+600|space=2+0|space=2+0|uni182D.E8E5_g.medi1=5+800|uni1820.E823_a.medi=6+400|space=6+0]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+1824,U+182F,U+1822:[space=0+0|uni182D.E8E5_g.medi1=1+800|uni1824.E844_u.medi=2+600|uni182F.E908_l.medi=3+400|uni1822.E837_i.fina=4+600]
-../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|space=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850]
diff --git a/test/shaping/data/in-house/tests/myanmar-syllable.tests b/test/shaping/data/in-house/tests/myanmar-syllable.tests
deleted file mode 100644
index 4666ef9..0000000
--- a/test/shaping/data/in-house/tests/myanmar-syllable.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/af3086380b743099c54a3b11b96766039ea62fcd.ttf:--no-glyph-names:U+101D,U+FE00,U+1031,U+FE00,U+1031,U+FE00:[6=0+465|6=0+465|5=0+502]
diff --git a/test/shaping/data/in-house/tests/myanmar-zawgyi.tests b/test/shaping/data/in-house/tests/myanmar-zawgyi.tests
deleted file mode 100644
index b79d4fb..0000000
--- a/test/shaping/data/in-house/tests/myanmar-zawgyi.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf:--script=Qaag:U+1000,U+103A,U+1004,U+1037,U+1039,U+1041:[Ka=0+2217|Ya-Semivowel=0+286|Nga=2+1247|Dot Below=2+0|Virama-Killer=2+0|One-Myanmar=5+1247]
diff --git a/test/shaping/data/in-house/tests/none-directional.tests b/test/shaping/data/in-house/tests/none-directional.tests
deleted file mode 100644
index e59946d..0000000
--- a/test/shaping/data/in-house/tests/none-directional.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf::U+10300,U+10301:[u10300=0+1470|u10301=1+1284]
-../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf:--direction=ltr:U+10300,U+10301:[u10300=0+1470|u10301=1+1284]
-../fonts/73e84dac2fc6a2d1bc9250d1414353661088937d.ttf:--direction=rtl:U+10300,U+10301:[u10301_r=1+1284|u10300_r=0+1470]
diff --git a/test/shaping/data/in-house/tests/positioning-features.tests b/test/shaping/data/in-house/tests/positioning-features.tests
deleted file mode 100644
index 8cab9d8..0000000
--- a/test/shaping/data/in-house/tests/positioning-features.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf::U+0041,U+0056:[A=0+625|V=1+675]
-../fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf::U+006D,U+0315:[m=0+945|uni0315=0@32,-178+0]
-../fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf::U+0079,U+0325:[y=0+565|uni0325=0@-422,-240+0]
diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests
deleted file mode 100644
index df324b9..0000000
--- a/test/shaping/data/in-house/tests/rand.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602]
-../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
-../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[5=0+560|7=1+602|10=2+602|4=3+560|7=4+602|10=5+602|6=6+560|9=7+602|10=8+602|5=9+560|8=10+602|12=11+602]
diff --git a/test/shaping/data/in-house/tests/simple.tests b/test/shaping/data/in-house/tests/simple.tests
deleted file mode 100644
index 64cae0e..0000000
--- a/test/shaping/data/in-house/tests/simple.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf:--shaper=ot:U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064:[V=0+1142|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
-../fonts/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf:--shaper=fallback:U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064:[V=0+1295|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
diff --git a/test/shaping/data/in-house/tests/sinhala.tests b/test/shaping/data/in-house/tests/sinhala.tests
deleted file mode 100644
index 9541754..0000000
--- a/test/shaping/data/in-house/tests/sinhala.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/5af5361ed4d1e8305780b100e1730cb09132f8d1.ttf::U+0DBB,U+0DCA,U+200D,U+0DBA,U+0DCA,U+200D,U+0DBA:[gid8=0+1343|gid4=0+1130]
diff --git a/test/shaping/data/in-house/tests/spaces.tests b/test/shaping/data/in-house/tests/spaces.tests
deleted file mode 100644
index ea90998..0000000
--- a/test/shaping/data/in-house/tests/spaces.tests
+++ /dev/null
@@ -1,34 +0,0 @@
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+0020:[gid1=0+560]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+00A0:[gid1=0+560]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+1680:[gid0=0+692]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2000:[gid1=0+1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2001:[gid1=0+2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2002:[gid1=0+1024]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2003:[gid1=0+2048]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2004:[gid1=0+683]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2005:[gid1=0+512]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2006:[gid1=0+341]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2007:[gid1=0+560]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2008:[gid1=0+560]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2009:[gid1=0+410]
-../fonts/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+200A:[gid1=0+128]
-../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]
diff --git a/test/shaping/data/in-house/tests/tibetan-contractions-1.tests b/test/shaping/data/in-house/tests/tibetan-contractions-1.tests
deleted file mode 100644
index ccc0c9c..0000000
--- a/test/shaping/data/in-house/tests/tibetan-contractions-1.tests
+++ /dev/null
@@ -1,60 +0,0 @@
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+FEFF,U+0F40,U+0F72,U+0F72,U+0F0B,U+0F66,U+0FAD,U+0F7C,U+0F7C,U+0F0B:[uni0F40=0+680|uni0F720F72=0+0|uni0F0B=4+190|uni0F660FAD=5+680|uni0F7D=5+0|uni0F0B=9+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F72,U+0F66,U+0F0B:[uni0F400F740F72=0+680|uni0F66=3+680|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F400F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7C,U+0F56,U+0F39,U+0F0B:[uni0F400F74=0+680|uni0F7C=0+0|uni0F56=3+610|uni0F39=3+0|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F72,U+0F42,U+0F66,U+0F0B:[uni0F400F740F72=0+680|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7A,U+0F66,U+0F0B:[uni0F400F74=0+680|uni0F7A=0+0|uni0F66=3+680|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0FB3,U+0F74,U+0F7A,U+0F56,U+0F66,U+0F0B:[uni0F400FB30F740F7A=0+660|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0FB3,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F400FB30F74=0+660|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F42,U+0F0B:[uni0F51=0+600|uni0F400F7D=1+680|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F51=0+600|uni0F400F7D=1+680|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B:[uni0F51=0+600|uni0F400FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F66,U+0F90,U+0FB1,U+0F74,U+0F7A,U+0F0B:[uni0F660F900FB10F74=0+680|uni0F7A=0+0|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F51,U+0F0B:[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B=1+0|uni0F51=6+600|uni0F0B=7@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F51,U+0F0B:[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B0F7A=1+0|uni0F51=7+600|uni0F0B=8@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0F58,U+0F66,U+0F74,U+0F7E,U+0F0B:[uni0F41=0+660|uni0F58=1+660|uni0F660F740F7E=2+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0F74,U+0F7C,U+0F66,U+0F39,U+0F0B:[uni0F410F74=0+680|uni0F7C=0+0|uni0F66=3+680|uni0F39=3+0|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB1,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F410FB10F74=0+670|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F410FB20F74=0+660|uni0F7A=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F410FB20F74=0+660|uni0F72=0+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F410FB20F74=0+660|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7E,U+0F51,U+0F0B:[uni0F410FB20F740F7E=0+660|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F41,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F53,U+0F0B:[uni0F58=0+660|uni0F410FB1=1+680|uni0F7B0F7A=1+0|uni0F53=6+590|uni0F0B=7@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F60,U+0F41,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F60=0+600|uni0F410F7D=1+660|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F420F74=0+680|uni0F7C=0+0|uni0F42=3+680|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB1,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F420FB10F74=0+700|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F72,U+0F0B:[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F53,U+0F0B:[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B:[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F56=4+610|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F7C,U+0F72,U+0F53,U+0F0B:[uni0F420FB2=0+680|uni0F7C0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F7C,U+0F7A,U+0F62,U+0F0B:[uni0F420FB2=0+680|uni0F7C0F7A=0+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F51=0+600|uni0F420F740F72=1+680|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0FB3,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F51=0+600|uni0F420FB3=1+680|uni0F7C0F7A=1+0|uni0F44=5+560|uni0F0B=6@-20,0+110]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F42,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F58=0+660|uni0F420F7D=1+680|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F44,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F440F74=0+610|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B:[uni0F51=0+600|uni0F420FB20F74=1+680|uni0F7C=1+0|uni0F56=5+610|uni0F0B=6+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F66,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F66=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0FB2,U+0F74,U+0F42,U+0F0B:[uni0F56=0+610|uni0F450FB20F74=1+640|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F7E,U+0F0B:[uni0F56=0+610|uni0F450F740F7E=1+630|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F72,U+0F63,U+0F0B:[uni0F460F74=0+650|uni0F72=0+0|uni0F63=3+700|uni0F0B=4+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7E,U+0F51,U+0F0B:[uni0F460F740F7E=0+650|uni0F51=3+600|uni0F0B=4@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F39,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F46=0+620|uni0F39=0+0|uni0F74=0+0|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F460FB20F740F72=0+660|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0FB2,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F460FB20F74=0+660|uni0F7C=0+0|uni0F63=4+700|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F46,U+0F7C,U+0F7A,U+0F53,U+0F0B:[uni0F58=0+660|uni0F46=1+620|uni0F7C0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F60,U+0F46,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B:[uni0F60=0+600|uni0F460FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F47,U+0F7C,U+0F7C,U+0F0B:[uni0F470F7D=0+570|uni0F0B=3+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F62,U+0F97,U+0F74,U+0F7A,U+0F53,U+0F39,U+0F0B:[uni0F620F970F74=0+600|uni0F7A=0+0|uni0F53=4+590|uni0F39=4+0|uni0F0B=6+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F49,U+0F74,U+0F72,U+0F0B:[uni0F490F74=0+580|uni0F72=0+0|uni0F0B=3+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F49,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F490F74=0+580|uni0F72=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F49,U+0F72,U+0F7E,U+0F51,U+0F0B:[uni0F58=0+660|uni0F49=1+580|uni0F720F7E=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0F4F,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F42=0+680|uni0F4F0F740F72=1+600|uni0F42=4+680|uni0F0B=5+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F4F,U+0F44,U+0F7C,U+0F7E,U+0F66,U+0F0B:[uni0F56=0+610|uni0F4F=1+560|uni0F44=2+560|uni0F7C0F7E=2+0|uni0F66=5+680|uni0F0B=6+190]
-../fonts/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F50,U+0F39,U+0F74,U+0F7A,U+0F4A,U+0F0B:[uni0F50=0+600|uni0F39=0+0|uni0F74=0+0|uni0F7A=0+0|uni0F4A=4+590|uni0F0B=5+190]
diff --git a/test/shaping/data/in-house/tests/tibetan-contractions-2.tests b/test/shaping/data/in-house/tests/tibetan-contractions-2.tests
deleted file mode 100644
index b44445c..0000000
--- a/test/shaping/data/in-house/tests/tibetan-contractions-2.tests
+++ /dev/null
@@ -1,53 +0,0 @@
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F50,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F500F74=0+600|uni0F72=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F74,U+0F7C,U+0F44,U+0F0B:[uni0F58=0+660|uni0F500F74=1+600|uni0F7C=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F58=0+660|uni0F50=1+600|uni0F7C0F7A=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F7C,U+0F72,U+0F66,U+0F0B:[uni0F58=0+660|uni0F50=1+600|uni0F7C0F72=1+0|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F74,U+0F62,U+0FB2,U+0F7C,U+0F51,U+0F0B:[uni0F510F74=0+600|uni0F620FB2=2+600|uni0F7C=2+0|uni0F51=5+600|uni0F0B=6@-70,0+106]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0FB2,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F510FB20F74=0+600|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F51,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F42=0+680|uni0F510F740F7A=1+600|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0F51,U+0F7B,U+0F42,U+0F66,U+0F0B:[uni0F56=0+610|uni0F510F7B=1+579|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F60,U+0F51,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F60=0+600|uni0F510F740F7A=1+600|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FA1,U+0F7C,U+0F7A,U+0F0B:[uni0F620FA10F7C0F7A=0+580|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FA1,U+0F74,U+0F72,U+0F56,U+0F0B:[uni0F660FA10F74=0+680|uni0F72=0+0|uni0F56=4+610|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F53,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F530F74=0+600|uni0F7C=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F53,U+0F74,U+0F7C,U+0F62,U+0F0B:[uni0F530F74=0+600|uni0F7C=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F53,U+0FB1,U+0F7C,U+0F7E,U+0F62,U+0F0B:[uni0F42=0+680|uni0F530FB1=1+600|uni0F7C0F7E=1+0|uni0F62=5+620|uni0F0B=6@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F54,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F51=0+600|uni0F540F74=1+610|uni0F7C=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB1,U+0F74,U+0F7E,U+0F56,U+0F0B:[uni0F560FB10F74=0+620|uni0F7E=0+0|uni0F56=4+610|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB3,U+0F74,U+0F7C,U+0F53,U+0F0B:[uni0F560FB30F74=0+650|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F560FB3=0+650|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F56,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F56,U+0F74,U+0F7C,U+0F56,U+0F66,U+0F0B:[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F580F74=0+680|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F9F,U+0F7C,U+0F7A,U+0F42,U+0F0B:[uni0F580F9F0F7C0F7A=0+660|uni0F42=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F58=0+660|uni0F7C0F7A=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F59,U+0F74,U+0F7C,U+0F62,U+0F0B:[uni0F42=0+680|uni0F590F74=1+620|uni0F7C=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F5A,U+0FAE,U+0F74,U+0F7E,U+0F66,U+0F0B:[uni0F58=0+660|uni0F5A0FAE0F740F7E=1+620|uni0F66=5+680|uni0F0B=6+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F66,U+0F0B:[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F5E,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F5E0F74=0+660|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F42=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F58,U+0F66,U+0F0B:[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F58=4+660|uni0F66=5+680|uni0F0B=6+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7C,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7C=1+0|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F42=0+680|uni0F5F0F740F72=1+610|uni0F44=4+560|uni0F0B=5@-20,0+110]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F60,U+0F7C,U+0F7A,U+0F62,U+0F0B:[uni0F60=0+600|uni0F7C0F7A=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F61,U+0F72,U+0F7A,U+0F0B:[uni0F61=0+700|uni0F720F7A=0+0|uni0F0B=3+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F61,U+0F7A,U+0F7A,U+0F66,U+0F0B:[uni0F61=0+700|uni0F7B=0+0|uni0F66=3+680|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0F72,U+0F53,U+0F7C,U+0F7A,U+0F0B:[uni0F620F72=0+620|uni0F530F7C0F7A=2+590|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F620F74=0+601|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7A,U+0F7E,U+0F53,U+0F0B:[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7A,U+0F7E,U+0F51,U+0F60,U+0F0B:[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F51=3+600|uni0F60=4+600|uni0F0B=5@-40,0+150]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7C,U+0F7C,U+0F56,U+0F0B:[uni0F660F7D=0+680|uni0F56=3+610|uni0F0B=4+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F660F7D=0+680|uni0F62=3+620|uni0F0B=4@-65,0+130]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB2,U+0F7C,U+0F7A,U+0F66,U+0F0B:[uni0F660FB2=0+680|uni0F7C0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F51,U+0F0B:[uni0F660FB3=0+680|uni0F7D=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F660FB3=0+680|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0F66,U+0F99,U+0F7C,U+0F7E,U+0F51,U+0F66,U+0F0B:[uni0F56=0+610|uni0F660F99=1+670|uni0F7C0F7E=1+0|uni0F51=5+600|uni0F66=6+680|uni0F0B=7+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F63,U+0FB7,U+0FB1,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F630FB70FB1=0+680|uni0F7C=0+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
-../fonts/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F68,U+0FB1,U+0F7C,U+0F53,U+0F0B:[uni0F680FB1=0+740|uni0F7C=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
diff --git a/test/shaping/data/in-house/tests/tibetan-vowels.tests b/test/shaping/data/in-house/tests/tibetan-vowels.tests
deleted file mode 100644
index 0bb0743..0000000
--- a/test/shaping/data/in-house/tests/tibetan-vowels.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F72:[uni0F680F72=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F74:[uni0F680F74=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7A:[uni0F680F7A=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7C:[uni0F680F7C=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F71,U+0F72:[uni0F680F710F72=0+720]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F71,U+0F74:[uni0F680F75=0+720]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7B:[uni0F680F7B=0+720]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7D:[uni0F680F7D=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7E:[uni0F680F7E=0+730]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7F:[uni0F68=0+730|uni0F7F=0+408]
-../fonts/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F00:[uni0F00=0+730]
diff --git a/test/shaping/data/in-house/tests/use-indic3.tests b/test/shaping/data/in-house/tests/use-indic3.tests
deleted file mode 100644
index 8c3ae13..0000000
--- a/test/shaping/data/in-house/tests/use-indic3.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf::U+0C95,U+0CCD,U+0CB0:[uni0C95=0+1176|uni0CB0_uni0CCD.blwf=0+275]
diff --git a/test/shaping/data/in-house/tests/use-marchen.tests b/test/shaping/data/in-house/tests/use-marchen.tests
deleted file mode 100644
index 850c3e7..0000000
--- a/test/shaping/data/in-house/tests/use-marchen.tests
+++ /dev/null
@@ -1,35 +0,0 @@
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8F:[u11C8F=0+3000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C71:[u11C71=0+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11CB5:[u11C8A=0+2000|u11CB5=0@-2000,0+0]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C84,U+11C71:[u11C84=0+2200|u11C71=1+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7E,U+11C8A:[u11C7E=0+2600|u11C8A=1+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11C92,U+11CA9:[u11C8A.11C92.11CA9=0+2600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11C94,U+11CA9:[u11C8A.11C94.11CA9=0+2600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C92,U+11CA9:[u11C8D.11C92.11CA9=0+2600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C94,U+11CA9:[u11C8D.11C94.11CA9=0+2600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9E,U+11CA9:[u11C8D.11C9E.11CA9=0+3200]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA0,U+11CA9:[u11C8D.11CA0.11CA9=0+3000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C92,U+11CAA:[u11C8D.11C92.11CAA=0+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C94,U+11CAA:[u11C8D.11C94.11CAA=0+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9D,U+11CAA:[u11C8D.11C9D.11CAA=0+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11C9E,U+11CAA:[u11C8D.11C9E.11CAA=0+2600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA0,U+11CAA:[u11C8D.11CA0.11CAA=0+2400]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C72,U+11CAA:[u11C80=0+2400|u11C72.11CAA=1+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8C,U+11CB1,U+11C8D:[u11C8C.11CB1=0+2793|u11C8D=2+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C7C,U+11CB3:[u11C80=0+2400|u11C7C.11CB3=1+2200]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7F,U+11CB2,U+11C7D:[u11C7F.11CB2=0+2400|u11C7D=2+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CB2,U+11C81:[u11C8D.11CB2=0+2000|u11C81=2+2400]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8C,U+11CB4,U+11C74:[u11C8C.11CB4=0+2800|u11C74=2+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8A,U+11CA1,U+11CA9,U+11C71:[u11C8A.11CA1.11CA9=0+3000|u11C71=3+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA1,U+11CA9,U+11C71:[u11C8D.11CA1.11CA9=0+3000|u11C71=3+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8D,U+11CA1,U+11CAA,U+11C71:[u11C8D.11CA1.11CAA=0+2400|u11C71=3+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8F,U+11CB0,U+11CB4,U+11CB6:[u11C8F.11CB0.11CB4=0+3600|u11CB6=0@-3200,0+0]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8E,U+11CB0,U+11CB2,U+11CB5:[u11C8E.11CB0.11CB2=0+2000|u11CB5=0@-2000,0+0]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C74,U+11C89,U+11CB2,U+11C75:[u11C74=0+2000|u11C89.11CB2=1+2000|u11C75=3+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C7C,U+11CAA,U+11CB2,U+11C75:[u11C7C.11CAA.11CB2=0+2200|u11C75=3+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C81,U+11C74,U+11CB2,U+11C8B:[u11C81=0+2400|u11C74.11CB2=1+2000|u11C8B=3+2400]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8B,U+11CB3,U+11C74,U+11C8D:[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C83,U+11CB4,U+11C74,U+11C8D:[u11C83.11CB4=0+2800|u11C74=2+2000|u11C8D=3+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C8B,U+11CB3,U+11C74,U+11C8D,U+11C71:[u11C8B.11CB3=0+2400|u11C74=2+2000|u11C8D=3+2000|u11C71=4+1600]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C76,U+11CB1,U+11C75,U+11C8D:[u11C80=0+2400|u11C76.11CB1=1+3200|u11C75=3+2000|u11C8D=4+2000]
-../fonts/85414f2552b654585b7a8d13dcc3e8fd9f7970a3.ttf::U+11C80,U+11C8D,U+11C94,U+11CAA,U+11CB1,U+11C74,U+11C8D:[u11C80=0+2400|u11C8D.11C94.11CAA.11CB1.shorti=1+2600|u11C74=5+2000|u11C8D=6+2000]
diff --git a/test/shaping/data/in-house/tests/use-syllable.tests b/test/shaping/data/in-house/tests/use-syllable.tests
deleted file mode 100644
index 9056008..0000000
--- a/test/shaping/data/in-house/tests/use-syllable.tests
+++ /dev/null
@@ -1,16 +0,0 @@
-../fonts/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf::U+AA00,U+AA2D,U+AA29:[a_cham=0+1121|uSign_cham=0@14,0+0|.notdef=0+600]
-../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf::U+AA00,U+AA34,U+AA36:[raMedial_cham_pre=0+400|a_cham=0+1121|waMedial_cham=0@-32,0+0]
-../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/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]
-../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11042,U+11046:[brm_KA=0+754|brm_vowelEE=0@-383,0+0|brm_virama=0@-524,0+0]
-../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11044,U+11046:[brm_KA=0+754|brm_vowelOO=0@-647,0+0|brm_virama=0@-524,0+0]
-../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+1103C:[brm_KA=0+754|brm_vowelU=0@-403,0+0]
-../fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf::U+111C8,U+111C9,U+111C9:[u111C8=0+500|u111C9=0@-500,0+0|u111C9=0@-500,0+0]
-../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A5A,U+1A63:[uni1A3D=0+250|uni1A5A=0+0|uni1A63=0+250]
-../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A59:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A59=5+0]
-../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A5A:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni25CC=5+250|uni1A5A=5+0]
-../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A60:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A60=5+0]
diff --git a/test/shaping/data/in-house/tests/use-vowel-letter-spoofing.tests b/test/shaping/data/in-house/tests/use-vowel-letter-spoofing.tests
deleted file mode 100644
index 45cf80e..0000000
--- a/test/shaping/data/in-house/tests/use-vowel-letter-spoofing.tests
+++ /dev/null
@@ -1,94 +0,0 @@
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093A:[uni0905=0+500|uni25CC=0+500|uni093A=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093B:[uni0905=0+500|uni25CC=0+500|uni093B=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093E:[uni0905=0+500|uni25CC=0+500|uni093E=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0945:[uni0905=0+500|uni25CC=0+500|uni0945=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0946:[uni0905=0+500|uni25CC=0+500|uni0946=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0949:[uni0905=0+500|uni25CC=0+500|uni0949=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094A:[uni0905=0+500|uni25CC=0+500|uni094A=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094B:[uni0905=0+500|uni25CC=0+500|uni094B=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094C:[uni0905=0+500|uni25CC=0+500|uni094C=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094F:[uni0905=0+500|uni25CC=0+500|uni094F=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0956:[uni0905=0+500|uni25CC=0+500|uni0956=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0957:[uni0905=0+500|uni25CC=0+500|uni0957=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+093A:[uni0906=0+500|uni25CC=0+500|uni093A=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0945:[uni0906=0+500|uni25CC=0+500|uni0945=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0946:[uni0906=0+500|uni25CC=0+500|uni0946=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0947:[uni0906=0+500|uni25CC=0+500|uni0947=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0948:[uni0906=0+500|uni25CC=0+500|uni0948=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0909,U+0941:[uni0909=0+500|uni25CC=0+500|uni0941=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0945:[uni090F=0+500|uni25CC=0+500|uni0945=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0946:[uni090F=0+500|uni25CC=0+500|uni0946=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0947:[uni090F=0+500|uni25CC=0+500|uni0947=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0930,U+094D,U+0907:[uni0930=0+500|uni094D=0+500|uni25CC=2+500|uni0907=2+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0985,U+09BE:[uni0985=0+500|uni25CC=0+500|.notdef=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+098B,U+09C3:[uni098B=0+500|uni25CC=0+500|uni09C3=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+098C,U+09E2:[uni098C=0+500|uni25CC=0+500|uni09E2=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A3E:[uni0A05=0+500|uni25CC=0+500|uni0A3E=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A48:[uni0A05=0+500|uni25CC=0+500|uni0A48=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A4C:[uni0A05=0+500|uni25CC=0+500|uni0A4C=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A3F:[uni0A72=0+500|uni0A3F=0+500|uni25CC=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A40:[uni0A72=0+500|uni25CC=0+500|uni0A40=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A47:[uni0A72=0+500|uni25CC=0+500|uni0A47=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A41:[uni0A73=0+500|uni25CC=0+500|uni0A41=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A42:[uni0A73=0+500|uni25CC=0+500|uni0A42=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A4B:[uni0A73=0+500|uni25CC=0+500|uni0A4B=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE,U+0AC5:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC5=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE,U+0AC8:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC8=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC5:[uni0A85=0+500|uni25CC=0+500|uni0AC5=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC7:[uni0A85=0+500|uni25CC=0+500|uni0AC7=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC8:[uni0A85=0+500|uni25CC=0+500|uni0AC8=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC9:[uni0A85=0+500|uni25CC=0+500|uni0AC9=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ACB:[uni0A85=0+500|uni25CC=0+500|uni0ACB=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ACC:[uni0A85=0+500|uni25CC=0+500|uni0ACC=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0AC5,U+0ABE:[uni25CC=0+500|uni0AC5=0+500|uni25CC=0+500|uni0ABE=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B05,U+0B3E:[uni0B05=0+500|uni25CC=0+500|uni0B3E=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B0F,U+0B57:[uni0B0F=0+500|uni25CC=0+500|uni0B57=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B13,U+0B57:[uni0B13=0+500|uni25CC=0+500|uni0B57=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C12,U+0C4C:[uni0C12=0+500|uni25CC=0+500|uni0C4C=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C12,U+0C55:[uni0C12=0+500|uni25CC=0+500|uni0C55=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C3F,U+0C55:[uni25CC=0+500|uni0C3F=0+500|uni25CC=0+500|uni0C55=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C46,U+0C55:[uni25CC=0+500|uni0C46=0+500|uni25CC=0+500|uni0C55=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C4A,U+0C55:[uni25CC=0+500|uni0C4A=0+500|uni25CC=0+500|uni0C55=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C89,U+0CBE:[uni0C89=0+500|uni25CC=0+500|uni0CBE=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C8B,U+0CBE:[uni0C8B=0+500|uni25CC=0+500|uni0CBE=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C92,U+0CCC:[uni0C92=0+500|uni25CC=0+500|uni0CCC=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D07,U+0D57:[uni0D07=0+500|uni25CC=0+500|uni0D57=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D09,U+0D57:[uni0D09=0+500|uni25CC=0+500|uni0D57=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D0E,U+0D46:[uni0D0E=0+500|uni0D46=0+500|uni25CC=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D12,U+0D3E:[uni0D12=0+500|uni25CC=0+500|uni0D3E=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D12,U+0D57:[uni0D12=0+500|uni25CC=0+500|uni0D57=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DCF:[uni0D85=0+500|uni25CC=0+500|uni0DCF=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DD0:[uni0D85=0+500|uni25CC=0+500|uni0DD0=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DD1:[uni0D85=0+500|uni25CC=0+500|uni0DD1=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8B,U+0DDF:[uni0D8B=0+500|uni25CC=0+500|uni0DDF=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8D,U+0DD8:[uni0D8D=0+500|uni25CC=0+500|uni0DD8=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8F,U+0DDF:[uni0D8F=0+500|uni25CC=0+500|uni0DDF=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DCA:[uni0D91=0+500|uni25CC=0+500|uni0DCA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DD9:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDA:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDC:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDD:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDD:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D94,U+0DDF:[uni0D94=0+500|uni25CC=0+500|uni0DDF=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11005,U+11038:[u11005=0+500|uni25CC=0+500|u11038=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1100B,U+1103E:[u1100B=0+500|uni25CC=0+500|u1103E=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1100F,U+11042:[u1100F=0+500|uni25CC=0+500|u11042=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E0:[u112B0=0+500|uni25CC=0+500|u112E0=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E5:[u112B0=0+500|uni25CC=0+500|u112E5=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E6:[u112B0=0+500|uni25CC=0+500|u112E6=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E7:[u112B0=0+500|uni25CC=0+500|u112E7=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E8:[u112B0=0+500|uni25CC=0+500|u112E8=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11481,U+114B0:[u11481=0+500|uni25CC=0+500|u114B0=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1148B,U+114BA:[u1148B=0+500|uni25CC=0+500|u114BA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1148D,U+114BA:[u1148D=0+500|uni25CC=0+500|u114BA=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+114AA,U+114B5:[u114AA=0+500|uni25CC=0+500|u114B5=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+114AA,U+114B6:[u114AA=0+500|uni25CC=0+500|u114B6=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11600,U+11639:[u11600=0+500|uni25CC=0+500|u11639=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11600,U+1163A:[u11600=0+500|uni25CC=0+500|u1163A=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11601,U+11639:[u11601=0+500|uni25CC=0+500|u11639=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11601,U+1163A:[u11601=0+500|uni25CC=0+500|u1163A=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116AD:[u11680=0+500|uni25CC=0+500|u116AD=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116B4:[u11680=0+500|uni25CC=0+500|u116B4=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116B5:[u11680=0+500|uni25CC=0+500|u116B5=0+500]
-../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11686,U+116B2:[u11686=0+500|uni25CC=0+500|u116B2=0+500]
diff --git a/test/shaping/data/in-house/tests/use.tests b/test/shaping/data/in-house/tests/use.tests
deleted file mode 100644
index dd2a3a2..0000000
--- a/test/shaping/data/in-house/tests/use.tests
+++ /dev/null
@@ -1,14 +0,0 @@
-../fonts/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf::U+1B1B,U+1B44,U+1B13,U+1B3E:[gid3=0+990|gid7=0+2473|gid5=0@-293,-400+0]
-../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/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.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+1211|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
-../fonts/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf:--font-funcs=ot:U+11103,U+11128:[u11103=0+837|u11128=0+0]
-../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+1112E:[u11124=0+514|u11131=0+0|u11127=0+0]
-../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11127:[u11124=0+514|u11131=0+0|u11127=0+0]
-../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11127,U+11131:[u11124=0+514|u11127=0+0|uni25CC=0+547|u11131=0+0]
-../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11134,U+11131:[u11124=0+514|u11134=0+0|u11131=0+0]
-../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11134:[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0]
-../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft: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/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]
diff --git a/test/shaping/data/in-house/tests/variations-rvrn.tests b/test/shaping/data/in-house/tests/variations-rvrn.tests
deleted file mode 100644
index 78ebb92..0000000
--- a/test/shaping/data/in-house/tests/variations-rvrn.tests
+++ /dev/null
@@ -1,100 +0,0 @@
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=1:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=11:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=21:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=31:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=41:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=51:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=61:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=71:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=81:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=91:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=101:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=111:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=121:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=131:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=141:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=151:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=161:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=171:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=181:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=191:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=201:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=211:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=221:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=231:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=241:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=251:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=261:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=271:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=281:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=291:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=301:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=311:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=321:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=331:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=341:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=351:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=361:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=371:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=381:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=391:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=401:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=411:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=421:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=431:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=441:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=451:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=461:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=471:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=481:U+0072:[rvrn_base=0+1529]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=491:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=501:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=511:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=521:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=531:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=541:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=551:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=561:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=571:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=581:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=591:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=601:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=611:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=621:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=631:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=641:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=651:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=661:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=671:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=681:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=691:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=701:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=711:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=721:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=731:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=741:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=751:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=761:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=771:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=781:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=791:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=801:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=811:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=821:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=831:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=841:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=851:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=861:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=871:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=881:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=891:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=901:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=911:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=921:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=931:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=941:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=951:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=961:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=971:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=981:U+0072:[rvrn_subst=0+1825]
-../fonts/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=991:U+0072:[rvrn_subst=0+1825]
diff --git a/test/shaping/data/in-house/tests/vertical.tests b/test/shaping/data/in-house/tests/vertical.tests
deleted file mode 100644
index 3958813..0000000
--- a/test/shaping/data/in-house/tests/vertical.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../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/4cbbc461be066fccc611dcc634af6e8cb2705537.ttf:--direction=t --font-funcs=ot:U+FF38:[gid2=0@-500,-867+0,-1000]
diff --git a/test/shaping/data/in-house/tests/zero-width-marks.tests b/test/shaping/data/in-house/tests/zero-width-marks.tests
deleted file mode 100644
index 1a3474a..0000000
--- a/test/shaping/data/in-house/tests/zero-width-marks.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/bb9473d2403488714043bcfb946c9f78b86ad627.ttf::U+1030:[circledash=0+636|u1030.med=0@-162,0+0]
-../fonts/8454d22037f892e76614e1645d066689a0200e61.ttf::U+05E0,U+05B8,U+0591,U+05DA,U+05B0:[uni05DA05B0=3+991|uni2009=0+200|uni0591=0@75,0+0|uni05B8=0@495,0+0|uni05E0=0+683]
-../fonts/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0@20,0+0|gid1=2+1264]
-../fonts/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0@20,0+1000|gid1=2+1264]
-../fonts/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0+0|gid1=2+1264]
-../fonts/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0+0|gid1=2+1264]
-../fonts/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
-../fonts/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+1200|gid3=2+1083|gid6=2@-992,0+1200|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+1200|gid5=8+528|gid6=8@-693,0+1200|gid2=10+528|gid2=11+528]
-../fonts/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0+0|gid3=2+1083|gid6=2+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6+0|gid5=8+528|gid6=8+0|gid2=10+528|gid2=11+528]
-../fonts/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
-../fonts/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf::U+0041,U+0042,U+0041:[A=0+1368|B=1+0|A=2+1368]
diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED
deleted file mode 100644
index 8539c0e..0000000
--- a/test/shaping/data/text-rendering-tests/DISABLED
+++ /dev/null
@@ -1,9 +0,0 @@
-# Non-Unicode cmap
-tests/CMAP-3.tests
-
-# Rounding differences
-tests/SHARAN-1.tests
-tests/SHBALI-1.tests
-tests/SHBALI-2.tests
-tests/SHKNDA-2.tests
-tests/SHKNDA-3.tests
diff --git a/test/shaping/data/text-rendering-tests/Makefile.am b/test/shaping/data/text-rendering-tests/Makefile.am
deleted file mode 100644
index cad0358..0000000
--- a/test/shaping/data/text-rendering-tests/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-# Process this file with automake to produce Makefile.in
-
-NULL =
-
-# Convenience targets:
-lib:
-	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-
-update:
-	(cd $(srcdir) && ./update.sh)
-
-EXTRA_DIST = \
-	README \
-	COPYING \
-	update.sh \
-	extract-tests.py \
-	fonts \
-	$(TESTS) \
-	$(NULL)
-
-TEST_EXTENSIONS = .tests
-TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT)
-
-include Makefile.sources
-
--include $(top_srcdir)/git.mk
diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources
deleted file mode 100644
index ccbbb37..0000000
--- a/test/shaping/data/text-rendering-tests/Makefile.sources
+++ /dev/null
@@ -1,85 +0,0 @@
-TESTS = \
-	tests/AVAR-1.tests \
-	tests/CFF-1.tests \
-	tests/CFF2-1.tests \
-	tests/CFF-2.tests \
-	tests/CMAP-1.tests \
-	tests/CMAP-2.tests \
-	tests/CVAR-1.tests \
-	tests/CVAR-2.tests \
-	tests/GLYF-1.tests \
-	tests/GPOS-1.tests \
-	tests/GPOS-2.tests \
-	tests/GPOS-3.tests \
-	tests/GPOS-4.tests \
-	tests/GPOS-5.tests \
-	tests/GSUB-1.tests \
-	tests/GSUB-2.tests \
-	tests/GSUB-3.tests \
-	tests/GVAR-1.tests \
-	tests/GVAR-2.tests \
-	tests/GVAR-3.tests \
-	tests/GVAR-4.tests \
-	tests/GVAR-5.tests \
-	tests/GVAR-6.tests \
-	tests/GVAR-7.tests \
-	tests/GVAR-8.tests \
-	tests/GVAR-9.tests \
-	tests/HVAR-1.tests \
-	tests/HVAR-2.tests \
-	tests/KERN-1.tests \
-	tests/KERN-2.tests \
-	tests/MORX-10.tests \
-	tests/MORX-11.tests \
-	tests/MORX-12.tests \
-	tests/MORX-13.tests \
-	tests/MORX-14.tests \
-	tests/MORX-16.tests \
-	tests/MORX-17.tests \
-	tests/MORX-18.tests \
-	tests/MORX-19.tests \
-	tests/MORX-1.tests \
-	tests/MORX-20.tests \
-	tests/MORX-21.tests \
-	tests/MORX-22.tests \
-	tests/MORX-23.tests \
-	tests/MORX-24.tests \
-	tests/MORX-25.tests \
-	tests/MORX-26.tests \
-	tests/MORX-27.tests \
-	tests/MORX-28.tests \
-	tests/MORX-29.tests \
-	tests/MORX-2.tests \
-	tests/MORX-30.tests \
-	tests/MORX-31.tests \
-	tests/MORX-32.tests \
-	tests/MORX-33.tests \
-	tests/MORX-34.tests \
-	tests/MORX-35.tests \
-	tests/MORX-36.tests \
-	tests/MORX-37.tests \
-	tests/MORX-38.tests \
-	tests/MORX-39.tests \
-	tests/MORX-3.tests \
-	tests/MORX-40.tests \
-	tests/MORX-41.tests \
-	tests/MORX-4.tests \
-	tests/MORX-5.tests \
-	tests/MORX-6.tests \
-	tests/MORX-7.tests \
-	tests/MORX-8.tests \
-	tests/MORX-9.tests \
-	tests/SHBALI-3.tests \
-	tests/SHKNDA-1.tests \
-	$(NULL)
-
-DISBALED_TESTS = \
-	tests/CMAP-3.tests \
-	tests/MORX-31.tests \
-	tests/MORX-41.tests \
-	tests/SHARAN-1.tests \
-	tests/SHBALI-1.tests \
-	tests/SHBALI-2.tests \
-	tests/SHKNDA-2.tests \
-	tests/SHKNDA-3.tests \
-	$(NULL)
diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py
deleted file mode 100755
index f1722b5..0000000
--- a/test/shaping/data/text-rendering-tests/extract-tests.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function, division, absolute_import
-
-import sys
-import xml.etree.ElementTree as ET
-
-# Can we extract this from HTML element itself? I couldn't.
-namespaces = {
-	'ft': 'https://github.com/OpenType/fonttest',
-	'xlink': 'http://www.w3.org/1999/xlink',
-}
-def ns(s):
-	ns,s = s.split(':')
-	return '{%s}%s' % (namespaces[ns], s)
-
-def unistr(s):
-	return ','.join('U+%04X' % ord(c) for c in s)
-
-def glyphstr(glyphs):
-	out = []
-	for glyphname,x,y in glyphs:
-		if x or y:
-			out.append('%s@%d,%d' % (glyphname, x, y))
-		else:
-			out.append(glyphname)
-	return '['+'|'.join(out)+']'
-
-html = ET.fromstring(sys.stdin.read())
-found = False
-
-for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
-	found = True
-	name = elt.get(ns('ft:id'))
-	text = elt.get(ns('ft:render'))
-	font = elt.get(ns('ft:font'))
-	variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
-	glyphs = []
-	for use in elt.findall(".//use"):
-		x = int(use.get('x'))
-		y = int(use.get('y'))
-		href = use.get(ns('xlink:href'))
-		assert href[0] == '#'
-		glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:])
-		glyphs.append((glyphname, x, y))
-	opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft'
-	if variations:
-		opts = opts + ' --variations=%s' % variations
-	print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
-
-for elt in html.findall(".//*[@class='expected-no-crash'][@ft:id]", namespaces):
-	found = True
-	name = elt.get(ns('ft:id'))
-	text = elt.get(ns('ft:render'))
-	font = elt.get(ns('ft:font'))
-	variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
-	opts = ''
-	if variations:
-		opts = '--variations=%s' % variations
-	print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text)))
-
-sys.exit(0 if found else 1)
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf b/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf
deleted file mode 100644
index 5df9867..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf b/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf
deleted file mode 100644
index da485d9..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf
deleted file mode 100644
index 158a77a..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf b/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf
deleted file mode 100644
index 76d04eb..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf
deleted file mode 100644
index 8fce4ac..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf
deleted file mode 100644
index 0ecd326..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf b/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf
deleted file mode 100644
index a87395c..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf b/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf
deleted file mode 100644
index 35369d1..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf
deleted file mode 100644
index 9255e99..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf
deleted file mode 100644
index 91c364f..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf
deleted file mode 100644
index 92b889c..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf
deleted file mode 100644
index 37d0b63..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf
deleted file mode 100644
index 0028972..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf
deleted file mode 100644
index 31c30c0..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
deleted file mode 100644
index 98ebe33..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf
deleted file mode 100644
index 4371df4..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf
deleted file mode 100644
index 88b8dec..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf
deleted file mode 100644
index 9dd3a84..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf
deleted file mode 100644
index e34e1fe..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf
deleted file mode 100644
index 5827ec5..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf
deleted file mode 100644
index f3c6f0f..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
deleted file mode 100644
index 29a41d0..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
deleted file mode 100644
index f157063..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
deleted file mode 100644
index a70dadc..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
deleted file mode 100644
index c106ae9..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
deleted file mode 100644
index c64c12c..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
deleted file mode 100644
index 22057f1..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
deleted file mode 100644
index 6676e52..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
deleted file mode 100644
index 5cab73e..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
deleted file mode 100644
index 07ed76c..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf
deleted file mode 100644
index 56984f2..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf
deleted file mode 100644
index b1e4bc4..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf
deleted file mode 100644
index 769e29b..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf
deleted file mode 100644
index edabb43..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf
deleted file mode 100644
index e3fadf5..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
deleted file mode 100644
index 271dddb..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
deleted file mode 100644
index 9f015ca..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf
deleted file mode 100644
index 4101680..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf
deleted file mode 100644
index 960b4cf..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf
deleted file mode 100644
index 603b1c6..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf
deleted file mode 100644
index df34912..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf
deleted file mode 100644
index 4459e8a..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf
deleted file mode 100644
index 39f2db5..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf b/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf
deleted file mode 100644
index 425bce6..0000000
--- a/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/tests/AVAR-1.tests b/test/shaping/data/text-rendering-tests/tests/AVAR-1.tests
deleted file mode 100644
index 19223eb..0000000
--- a/test/shaping/data/text-rendering-tests/tests/AVAR-1.tests
+++ /dev/null
@@ -1,17 +0,0 @@
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=100:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=150:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=200:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=250:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=300:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=350:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=400:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=450:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=500:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=550:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=600:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=650:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=700:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=750:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=800:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=850:U+2A01:[gid1]
-../fonts/TestAVAR.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=900:U+2A01:[gid1]
diff --git a/test/shaping/data/text-rendering-tests/tests/CFF-1.tests b/test/shaping/data/text-rendering-tests/tests/CFF-1.tests
deleted file mode 100644
index 6788253..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CFF-1.tests
+++ /dev/null
@@ -1,13 +0,0 @@
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[gid66]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+211D:[gid30]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+24EA:[gid235]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2460:[gid97]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2461:[gid98]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+4EFF:[gid256]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+FF21:[gid34]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+10133:[gid52]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1D4D0:[gid209]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F33A:[gid59]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F33B:[gid60]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F4A7:[gid168]
-../fonts/FDArrayTest257.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F95D:[gid94]
diff --git a/test/shaping/data/text-rendering-tests/tests/CFF-2.tests b/test/shaping/data/text-rendering-tests/tests/CFF-2.tests
deleted file mode 100644
index 6f190a8..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CFF-2.tests
+++ /dev/null
@@ -1,13 +0,0 @@
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[gid66]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+211D:[gid8478]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+24EA:[gid9451]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2460:[gid9313]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2461:[gid9314]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+4EFF:[gid20224]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+FF21:[gid65314]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+10133:[gid308]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1D4D0:[gid54481]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F33A:[gid62267]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F33B:[gid62268]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F4A7:[gid62632]
-../fonts/FDArrayTest65535.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1F95D:[gid63838]
diff --git a/test/shaping/data/text-rendering-tests/tests/CFF2-1.tests b/test/shaping/data/text-rendering-tests/tests/CFF2-1.tests
deleted file mode 100644
index 84cb14d..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CFF2-1.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=100:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700:U+0024:[dollar]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800:U+0024:[dollar.nostroke]
-../fonts/AdobeVFPrototype-Subset.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=900:U+0024:[dollar.nostroke]
diff --git a/test/shaping/data/text-rendering-tests/tests/CMAP-1.tests b/test/shaping/data/text-rendering-tests/tests/CMAP-1.tests
deleted file mode 100644
index 337b9f8..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CMAP-1.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+82A6:[uni82A6_uE0100]
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+82A6,U+E0100:[uni82A6_uE0100]
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+82A6,U+E0101:[uni82A6_uE0101]
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+82A6,U+E0102:[uni82A6_uE0100]
diff --git a/test/shaping/data/text-rendering-tests/tests/CMAP-2.tests b/test/shaping/data/text-rendering-tests/tests/CMAP-2.tests
deleted file mode 100644
index 861f2e4..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CMAP-2.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2269:[uni2269]
-../fonts/TestCMAP14.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+2269,U+FE00:[uni2269FE00]
diff --git a/test/shaping/data/text-rendering-tests/tests/CMAP-3.tests b/test/shaping/data/text-rendering-tests/tests/CMAP-3.tests
deleted file mode 100644
index d8758d3..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CMAP-3.tests
+++ /dev/null
@@ -1,20 +0,0 @@
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+201C:[gid200]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[gid34]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[gid35]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00C7:[gid126]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+011E:[gid176]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0049:[gid42]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0130:[gid178]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00D6:[gid140]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+015E:[gid181]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00DC:[gid145]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+201D:[gid201]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061:[gid66]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062:[gid67]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00E7:[gid154]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+011F:[gid177]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0131:[gid222]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0069:[gid74]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00F6:[gid168]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+015F:[gid182]
-../fonts/TestCMAPMacTurkish.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+00FC:[gid174]
diff --git a/test/shaping/data/text-rendering-tests/tests/CVAR-1.tests b/test/shaping/data/text-rendering-tests/tests/CVAR-1.tests
deleted file mode 100644
index c874a14..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CVAR-1.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestCVARGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=28,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@595,0|uni006E@1126,0]
-../fonts/TestCVARGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=94,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@635,0|uni006E@1212,0]
-../fonts/TestCVARGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=194,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@691,0|uni006E@1331,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/CVAR-2.tests b/test/shaping/data/text-rendering-tests/tests/CVAR-2.tests
deleted file mode 100644
index 6bd42e1..0000000
--- a/test/shaping/data/text-rendering-tests/tests/CVAR-2.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestCVARGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=28,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@595,0|uni006E@1126,0]
-../fonts/TestCVARGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=94,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@635,0|uni006E@1212,0]
-../fonts/TestCVARGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=194,wdth=100,opsz=72:U+0068,U+006F,U+006E:[uni0068|uni006F@691,0|uni006E@1331,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GLYF-1.tests b/test/shaping/data/text-rendering-tests/tests/GLYF-1.tests
deleted file mode 100644
index bdc0346..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GLYF-1.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestGLYFOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0123:[gcommaabove]
diff --git a/test/shaping/data/text-rendering-tests/tests/GPOS-1.tests b/test/shaping/data/text-rendering-tests/tests/GPOS-1.tests
deleted file mode 100644
index 221d16b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GPOS-1.tests
+++ /dev/null
@@ -1,19 +0,0 @@
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0104,U+004A:[Aogonek|J@732,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0104,U+0067:[Aogonek|g@692,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0104,U+0123:[Aogonek|gcommaabove@692,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0104,U+006A:[Aogonek|j@752,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0104,U+0237:[Aogonek|dotlessj@752,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0051,U+0237:[Q|dotlessj@734,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0105,U+006A:[aogonek|j@588,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0105,U+0237:[aogonek|dotlessj@588,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0067,U+0237:[g|dotlessj@563,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0123,U+0237:[gcommaabove|dotlessj@563,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0131,U+0237:[dotlessi|dotlessj@334,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0173,U+0237:[uogonek|dotlessj@656,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0076,U+0237:[v|dotlessj@587,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+0061:[V|a@594,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+00E1:[V|aacute@594,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+0105:[V|aogonek@594,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+0066:[V|f@634,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+FB02:[V|fl@634,0]
-../fonts/TestGPOSOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0056,U+002E:[V|period@504,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GPOS-2.tests b/test/shaping/data/text-rendering-tests/tests/GPOS-2.tests
deleted file mode 100644
index 03fcc36..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GPOS-2.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestGPOSTwo.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+25EF:[uni25EF]
-../fonts/TestGPOSTwo.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+263C:[sun]
-../fonts/TestGPOSTwo.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+25EF,U+263C:[uni25EF|sun]
diff --git a/test/shaping/data/text-rendering-tests/tests/GPOS-3.tests b/test/shaping/data/text-rendering-tests/tests/GPOS-3.tests
deleted file mode 100644
index 32aeb6e..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GPOS-3.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1208:[uni1208]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1208,U+135E:[uni1208|uni135E@303,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1208,U+135F:[uni1208|uni135F@303,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1208,U+135D:[uni1208|uni135D@303,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GPOS-4.tests b/test/shaping/data/text-rendering-tests/tests/GPOS-4.tests
deleted file mode 100644
index fd77542..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GPOS-4.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestGPOSThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0075,U+0308,U+0301:[u|uni0308@529,-31|acutecomb@537,138]
-../fonts/TestGPOSThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0075,U+0308,U+0304:[u|uni0308@529,-31|uni0304@526,138]
-../fonts/TestGPOSThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0075,U+0308,U+0308:[u|uni0308@529,-31|uni0308@529,138]
-../fonts/TestGPOSThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0075,U+0308,U+0308,U+0308:[u|uni0308@529,-31|uni0308@529,138|uni0308@529,307]
diff --git a/test/shaping/data/text-rendering-tests/tests/GPOS-5.tests b/test/shaping/data/text-rendering-tests/tests/GPOS-5.tests
deleted file mode 100644
index 2d7ce14..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GPOS-5.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/TestGPOSFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=100:U+0634,U+0652:[uni0652@663,144|uni0634]
-../fonts/TestGPOSFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+0634,U+0652:[uni0652@680,165|uni0634]
-../fonts/TestGPOSFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+0634,U+0652:[uni0652@730,246|uni0634]
-../fonts/TestGPOSFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700:U+0634,U+0652:[uni0652@750,282|uni0634]
-../fonts/TestGPOSFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=900:U+0634,U+0652:[uni0652@784,351|uni0634]
diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-1.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-1.tests
deleted file mode 100644
index e33a6f1..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GSUB-1.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestGSUBOne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0020,U+0061:[a.alt|space@500,0|a@1000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-2.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-2.tests
deleted file mode 100644
index 34c8deb..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GSUB-2.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1373:[uni1373]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+136B:[uni136B]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1375:[uni1375]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+136D:[uni136D]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1373,U+136B:[uni1373.init|uni136B.fina@621,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1375,U+136D:[uni1375.init|uni136D.fina@662,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+137B:[uni137B]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1373,U+136B,U+137B:[uni1373.init|uni136B.medi@621,0|uni137B.fina@1102,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1373,U+136B,U+137B,U+1373,U+136B:[uni1373.init|uni136B.medi@621,0|uni137B.medi@1102,0|uni1373.medi@1489,0|uni136B.fina@2110,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1373,U+136B,U+137B,U+1375,U+136D:[uni1373.init|uni136B.medi@621,0|uni137B.medi@1102,0|uni1375.medi@1489,0|uni136D.fina@2157,0]
-../fonts/TestShapeEthi.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1375,U+136D,U+137B,U+1373,U+136B:[uni1375.init|uni136D.medi@662,0|uni137B.medi@1203,0|uni1373.medi@1590,0|uni136B.fina@2211,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests
deleted file mode 100644
index c2f7e6e..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestGSUBThree.ttf::U+006C,U+006F,U+006C:*
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-1.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-1.tests
deleted file mode 100644
index fc00a4e..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-1.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650:U+5F4C:[gid2]
-../fonts/TestGVAROne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700:U+5F4C:[gid2]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-2.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-2.tests
deleted file mode 100644
index 10e22e4..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-2.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650:U+5F4C:[gid2]
-../fonts/TestGVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700:U+5F4C:[gid2]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-3.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-3.tests
deleted file mode 100644
index c3b8049..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-3.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=500:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=550:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=650:U+5F4C:[gid2]
-../fonts/TestGVARThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=700:U+5F4C:[gid2]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-4.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-4.tests
deleted file mode 100644
index 1c0964d..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-4.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-1.0,T1=0.0:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.8,T1=0.1:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.6,T1=0.2:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.4,T1=0.3:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.2,T1=0.4:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.0,T1=0.5:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.2,T1=0.6:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.4,T1=0.7:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.6,T1=0.8:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.8,T1=0.9:U+1F98E:[gid5]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=1.0,T1=1.0:U+1F98E:[gid5]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-5.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-5.tests
deleted file mode 100644
index b2ff710..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-5.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-1.0:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.8:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.6:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.4:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=-0.2:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.0:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.2:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.4:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.6:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=0.8:U+1F31D:[gid15]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=M1=1.0:U+1F31D:[gid15]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-6.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-6.tests
deleted file mode 100644
index f96292b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-6.tests
+++ /dev/null
@@ -1,11 +0,0 @@
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.0:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.1:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.2:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.3:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.4:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.5:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.6:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.7:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.8:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=0.9:U+1F422:[gid12]
-../fonts/Zycon.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=T1=1.0:U+1F422:[gid12]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-7.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-7.tests
deleted file mode 100644
index 594da3b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-7.tests
+++ /dev/null
@@ -1,7 +0,0 @@
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=150:U+004F,U+0049,U+004F:[uni004F|uni0049@706,0|uni004F@1072,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200:U+004F,U+0049,U+004F:[uni004F|uni0049@707,0|uni004F@1074,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=250:U+004F,U+0049,U+004F:[uni004F|uni0049@707,0|uni004F@1075,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=300:U+004F,U+0049,U+004F:[uni004F|uni0049@707,0|uni004F@1076,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=350:U+004F,U+0049,U+004F:[uni004F|uni0049@707,0|uni004F@1077,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+004F,U+0049,U+004F:[uni004F|uni0049@707,0|uni004F@1078,0]
-../fonts/TestGVARFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=450:U+004F,U+0049,U+004F:[uni004F|uni0049@706,0|uni004F@1079,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-8.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-8.tests
deleted file mode 100644
index e5c8209..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-8.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=0.0:U+0048:[H]
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.2:U+0048:[H]
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.4:U+0048:[H]
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.6:U+0048:[H]
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-0.8:U+0048:[H]
-../fonts/TestGVAREight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=HV=-1.0:U+0048:[H]
diff --git a/test/shaping/data/text-rendering-tests/tests/GVAR-9.tests b/test/shaping/data/text-rendering-tests/tests/GVAR-9.tests
deleted file mode 100644
index 19e2ed8..0000000
--- a/test/shaping/data/text-rendering-tests/tests/GVAR-9.tests
+++ /dev/null
@@ -1,10 +0,0 @@
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=-1.0:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=-0.5:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.0:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.5:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.6:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.7:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.8:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.9:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=0.944444:U+0041:[A]
-../fonts/TestGVARNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=TEST=1.0:U+0041:[A]
diff --git a/test/shaping/data/text-rendering-tests/tests/HVAR-1.tests b/test/shaping/data/text-rendering-tests/tests/HVAR-1.tests
deleted file mode 100644
index 189d9f0..0000000
--- a/test/shaping/data/text-rendering-tests/tests/HVAR-1.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=0:U+0041,U+0042,U+0043:[A|B@520,0|C@1094,0]
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200:U+0041,U+0042,U+0043:[A|B@533,0|C@1115,0]
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+0041,U+0042,U+0043:[A|B@546,0|C@1135,0]
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+0041,U+0042,U+0043:[A|B@558,0|C@1155,0]
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800:U+0041,U+0042,U+0043:[A|B@571,0|C@1175,0]
-../fonts/TestHVAROne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=1000:U+0041,U+0042,U+0043:[A|B@584,0|C@1196,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/HVAR-2.tests b/test/shaping/data/text-rendering-tests/tests/HVAR-2.tests
deleted file mode 100644
index db93be9..0000000
--- a/test/shaping/data/text-rendering-tests/tests/HVAR-2.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=0:U+0041,U+0042:[uni0041|uni0042@450,0]
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=200:U+0041,U+0042:[uni0041|uni0042@515,0]
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=400:U+0041,U+0042:[uni0041|uni0042@584,0]
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=600:U+0041,U+0042:[uni0041|uni0042@673,0]
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=800:U+0041,U+0042:[uni0041|uni0042@761,0]
-../fonts/TestHVARTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft --variations=wght=1000:U+0041,U+0042:[uni0041|uni0042@850,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/KERN-1.tests b/test/shaping/data/text-rendering-tests/tests/KERN-1.tests
deleted file mode 100644
index f0c0214..0000000
--- a/test/shaping/data/text-rendering-tests/tests/KERN-1.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestKERNOne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0131,U+0054,U+0075,U+0054,U+0075,U+0054,U+0131:[dotlessi|T|u@400,0|T@600,0|u@1000,0|T@1200,0|dotlessi@1600,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/KERN-2.tests b/test/shaping/data/text-rendering-tests/tests/KERN-2.tests
deleted file mode 100644
index fdffa4a..0000000
--- a/test/shaping/data/text-rendering-tests/tests/KERN-2.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestKERNOne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0075,U+0131,U+0131,U+0054,U+0131,U+0131,U+0054,U+0131,U+0131,U+0075:[u|dotlessi@400,0|dotlessi@1100,0|T@1100,0|dotlessi@1500,0|dotlessi@2200,0|T@2200,0|dotlessi@2600,0|dotlessi@3300,0|u@3500,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-1.tests b/test/shaping/data/text-rendering-tests/tests/MORX-1.tests
deleted file mode 100644
index 794b01b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-1.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXOne.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043:[A.alt|B@1000,0|C.alt@2000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-10.tests b/test/shaping/data/text-rendering-tests/tests/MORX-10.tests
deleted file mode 100644
index a6a5444..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-10.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0041,U+0042,U+0041,U+0042:[A|B@638,0|A@1288,0|B@1926,0|B@2576,0|A@3226,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-11.tests b/test/shaping/data/text-rendering-tests/tests/MORX-11.tests
deleted file mode 100644
index 1fce69b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-11.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXEleven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041,U+0042,U+0042,U+0041,U+0041,U+0042,U+0058:[B|A@650,0|B@1288,0|B@1938,0|A@2588,0|X@3226,0|A@3812,0|B@4450,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-12.tests b/test/shaping/data/text-rendering-tests/tests/MORX-12.tests
deleted file mode 100644
index 8b9886f..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-12.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestMORXTwelve.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0042,U+0043,U+0058,U+0031:[X|C@598,0|A@1230,0|B@1868,0|X@2518,0|one@3116,0]
-../fonts/TestMORXTwelve.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0042,U+0043,U+0058,U+0032:[X|C@598,0|A@1230,0|B@1868,0|X@2518,0|two@3116,0]
-../fonts/TestMORXTwelve.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0042,U+0043,U+0058,U+0033:[X|B@598,0|C@1248,0|A@1880,0|X@2518,0|three@3116,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-13.tests b/test/shaping/data/text-rendering-tests/tests/MORX-13.tests
deleted file mode 100644
index 42d8107..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-13.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXThirteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests b/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
deleted file mode 100644
index d01f2e9..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/TestMORXFourteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
-../fonts/TestMORXFourteen.ttf::U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-16.tests b/test/shaping/data/text-rendering-tests/tests/MORX-16.tests
deleted file mode 100644
index ce0d5b2..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-16.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXSixteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-17.tests b/test/shaping/data/text-rendering-tests/tests/MORX-17.tests
deleted file mode 100644
index 6e1c94c..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-17.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXSeventeen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[B|A@626,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-18.tests b/test/shaping/data/text-rendering-tests/tests/MORX-18.tests
deleted file mode 100644
index b032a76..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-18.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[A|B.alt@639,0|C@1639,0|D.alt1@2235,0|E@3235,0]
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0042,U+0042,U+0044,U+0045:[A|B@639,0|B@1265,0|B.alt@1891,0|D.alt1@2891,0|E@3891,0]
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0044,U+0045:[A|B.alt@639,0|D.alt1@1639,0|E@2639,0]
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0045:[A|B@639,0|E@1265,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-19.tests b/test/shaping/data/text-rendering-tests/tests/MORX-19.tests
deleted file mode 100644
index e9b9dc4..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-19.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0043,U+0044,U+0045:[A.alt|C@1000,0|D.alt1@1596,0|E@2596,0]
-../fonts/TestMORXEighteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0044:[D.alt]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-2.tests b/test/shaping/data/text-rendering-tests/tests/MORX-2.tests
deleted file mode 100644
index 3e64d23..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-2.tests
+++ /dev/null
@@ -1,16 +0,0 @@
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24FF:[O|O@418,0|O@836,0|A@1254,0|B@2084,0|X@2914,0|Y@3744,0|Z@4574,0|C@5404,0|D@6234,0|O@7064,0|O@7482,0|O@7900,0|zero@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+278A:[O|O@418,0|O@836,0|B@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|D@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+278B:[O|O@418,0|O@836,0|D@1254,0|A@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|C@6234,0|O@7064,0|O@7482,0|O@7900,0|two@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0033:[O|O@418,0|O@836,0|D@1254,0|B@2084,0|X@2914,0|Y@3744,0|Z@4574,0|C@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|three@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0034:[O|O@418,0|O@836,0|X@1254,0|Y@2084,0|Z@2914,0|C@3744,0|D@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|four@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0035:[O|O@418,0|O@836,0|X@1254,0|Y@2084,0|Z@2914,0|C@3744,0|D@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|five@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0036:[O|O@418,0|O@836,0|C@1254,0|D@2084,0|A@2914,0|B@3744,0|X@4574,0|Y@5404,0|Z@6234,0|O@7064,0|O@7482,0|O@7900,0|six@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0037:[O|O@418,0|O@836,0|D@1254,0|C@2084,0|A@2914,0|B@3744,0|X@4574,0|Y@5404,0|Z@6234,0|O@7064,0|O@7482,0|O@7900,0|seven@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0038:[O|O@418,0|O@836,0|C@1254,0|D@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|eight@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+0039:[O|O@418,0|O@836,0|D@1254,0|C@2084,0|B@2914,0|X@3744,0|Y@4574,0|Z@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|nine@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+2793:[O|O@418,0|O@836,0|D@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_zero@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EB:[O|O@418,0|O@836,0|D@1254,0|X@2084,0|Y@2914,0|Z@3744,0|C@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_one@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EC:[O|O@418,0|O@836,0|C@1254,0|D@2084,0|X@2914,0|Y@3744,0|Z@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_two@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24ED:[O|O@418,0|O@836,0|C@1254,0|D@2084,0|X@2914,0|Y@3744,0|Z@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_three@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EE:[O|O@418,0|O@836,0|D@1254,0|C@2084,0|X@2914,0|Y@3744,0|Z@4574,0|A@5404,0|B@6234,0|O@7064,0|O@7482,0|O@7900,0|one_four@8318,0]
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0058,U+0059,U+005A,U+0043,U+0044,U+004F,U+004F,U+004F,U+24EF:[O|O@418,0|O@836,0|D@1254,0|C@2084,0|X@2914,0|Y@3744,0|Z@4574,0|B@5404,0|A@6234,0|O@7064,0|O@7482,0|O@7900,0|one_five@8318,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-20.tests b/test/shaping/data/text-rendering-tests/tests/MORX-20.tests
deleted file mode 100644
index 8d04192..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-20.tests
+++ /dev/null
@@ -1,7 +0,0 @@
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[A|B@639,0|C.alt@1265,0|D@2265,0|E.alt1@2939,0]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043:[A|B@639,0|C.alt@1265,0]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0045:[A|B.alt@639,0|E.alt1@1639,0]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045:[A.alt|E.alt1@1000,0]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0045,U+0045:[E|E@556,0]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A.alt]
-../fonts/TestMORXTwenty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0045:[E]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-21.tests b/test/shaping/data/text-rendering-tests/tests/MORX-21.tests
deleted file mode 100644
index a608755..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-21.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwentyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[A|B.alt@639,0|C@1639,0|D@2235,0|E@2909,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-22.tests b/test/shaping/data/text-rendering-tests/tests/MORX-22.tests
deleted file mode 100644
index 960874c..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-22.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwentytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[C]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-23.tests b/test/shaping/data/text-rendering-tests/tests/MORX-23.tests
deleted file mode 100644
index 9575a80..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-23.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwentythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[E|E@556,0|E@1112,0|E@1668,0|E@2224,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-24.tests b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests
deleted file mode 100644
index 79a3d7b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-24.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwentyfour.ttf::U+0041,U+0042,U+0043,U+0044,U+0045:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-25.tests b/test/shaping/data/text-rendering-tests/tests/MORX-25.tests
deleted file mode 100644
index ccd0563..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-25.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[A.alt|B.alt@1000,0|C.alt@2000,0|D.alt@3000,0|E.alt@4000,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0045,U+0042,U+0043,U+0044,U+0041:[E|B@556,0|C@1182,0|D@1778,0|A@2452,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0043,U+0042,U+0041,U+0042,U+0043:[C|B@596,0|A.alt@1222,0|B.alt@2222,0|C.alt@3222,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043:[A.alt|B.alt@1000,0|C.alt@2000,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0043,U+0042,U+0041:[C|B@596,0|A@1222,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@626,0]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
-../fonts/TestMORXTwentyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-26.tests b/test/shaping/data/text-rendering-tests/tests/MORX-26.tests
deleted file mode 100644
index bebae60..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-26.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/TestMORXTwentysix.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0]
-../fonts/TestMORXTwentysix.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B.alt]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-27.tests b/test/shaping/data/text-rendering-tests/tests/MORX-27.tests
deleted file mode 100644
index 1ec96a2..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-27.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestMORXTwentyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045,U+0042:[A_E_B]
-../fonts/TestMORXTwentyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045,U+0043:[A_E_C]
-../fonts/TestMORXTwentyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045,U+0044:[A_E_D]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-28.tests b/test/shaping/data/text-rendering-tests/tests/MORX-28.tests
deleted file mode 100644
index 59f5d25..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-28.tests
+++ /dev/null
@@ -1,5 +0,0 @@
-../fonts/TestMORXTwentyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045,U+0044:[A_E_D]
-../fonts/TestMORXTwentyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0078,U+0045,U+0044:[A_E_D|x@1394,0]
-../fonts/TestMORXTwentyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0045,U+0079,U+0044:[A_E_D|y@1394,0]
-../fonts/TestMORXTwentyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0078,U+0045,U+0079,U+0044:[A_E_D|x@1394,0|y@1923,0]
-../fonts/TestMORXTwentyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0078,U+0078,U+0078,U+0045,U+0079,U+0079,U+0079,U+0044:[A_E_D|x@1394,0|x@1923,0|x@2452,0|y@2981,0|y@3491,0|y@4001,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-29.tests b/test/shaping/data/text-rendering-tests/tests/MORX-29.tests
deleted file mode 100644
index 82fd963..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-29.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|I@4268,0|N@5098,0|S@5928,0|M@6758,0|Y@7588,0|Y@7920,0|A@8252,0|Z@9082,0|Z@9404,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|I@5098,0|N@5928,0|S@6758,0|Y@7588,0|Y@7920,0|B@8252,0|Z@9082,0|Z@9404,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0043,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|I@5762,0|N@6592,0|S@7422,0|C@8252,0|Z@9082,0|Z@9404,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0044,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|D@5762,0|I@6592,0|N@7422,0|S@8252,0|Z@9082,0|Z@9404,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-3.tests b/test/shaping/data/text-rendering-tests/tests/MORX-3.tests
deleted file mode 100644
index fc7fe94..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-3.tests
+++ /dev/null
@@ -1,16 +0,0 @@
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0030:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|zero@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0031:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0032:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|two@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0033:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|three@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0034:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|four@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0035:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|five@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0036:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|six@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0037:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|seven@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0038:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|eight@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+0039:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|nine@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+2793:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_zero@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+24EB:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_one@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+24EC:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_two@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+24ED:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_three@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+24EE:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_four@1793,0]
-../fonts/TestMORXThree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0043,U+0044,U+24EF:[A|B@363,0|X@722,0|C@1086,0|D@1402,0|one_five@1793,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-30.tests b/test/shaping/data/text-rendering-tests/tests/MORX-30.tests
deleted file mode 100644
index ad4ab21..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-30.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|I@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|I@2710,0|N@3540,0|S@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|M@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
-../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|I@2710,0|N@3540,0|S@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-31.tests b/test/shaping/data/text-rendering-tests/tests/MORX-31.tests
deleted file mode 100644
index ac09e27..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-31.tests
+++ /dev/null
@@ -1,8 +0,0 @@
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[I|N@830,0|I@1660,0|N@2490,0|S@3320,0|S@4150,0|X@4980,0|X@5344,0|A@5708,0|Y@6538,0|Y@6870,0|A@7202,0|Z@8032,0|Z@8354,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+0059,U+0059:[I|N@830,0|S@1660,0|I@2490,0|N@3320,0|S@4150,0|X@4980,0|X@5344,0|A@5708,0|Y@6538,0|Y@6870,0|B@7202,0|Y@8032,0|Y@8364,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[X|I@364,0|I@1194,0|N@2024,0|S@2854,0|N@3684,0|S@4514,0|X@5344,0|B@5708,0|Y@6538,0|Y@6870,0|A@7202,0|Z@8032,0|Z@8354,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[X|I@364,0|N@1194,0|I@2024,0|N@2854,0|S@3684,0|S@4514,0|X@5344,0|B@5708,0|Y@6538,0|Y@6870,0|B@7202,0|Z@8032,0|Z@8354,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0041:[I|N@830,0|S@1660,0|M@2490,0|I@3320,0|N@4150,0|S@4980,0|P@5810,0|Q@6143,0|R@6509,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0042:[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|I@3653,0|N@4483,0|S@5313,0|Q@6143,0|R@6509,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0041:[M|I@830,0|N@1660,0|S@2490,0|I@3320,0|N@4150,0|S@4980,0|P@5810,0|Q@6143,0|R@6509,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
-../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0042:[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|I@3653,0|N@4483,0|S@5313,0|Q@6143,0|R@6509,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
deleted file mode 100644
index 6f3ae88..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[I|N@830,0|S@1660,0|A@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B|I@830,0|N@1660,0|S@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-33.tests b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests
deleted file mode 100644
index 17d080a..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-33.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0]
-../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061,U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0]
-../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0068:[a|h@561,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-34.tests b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests
deleted file mode 100644
index 8c309df..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-34.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXThirtyfour.ttf::U+0068,U+0061:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-35.tests b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests
deleted file mode 100644
index a033185..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-35.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A|B@639,0|C@1265,0|E@1861,0]
-../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-36.tests b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests
deleted file mode 100644
index 6b2340e..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-36.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXThirtysix.ttf::U+0041:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-37.tests b/test/shaping/data/text-rendering-tests/tests/MORX-37.tests
deleted file mode 100644
index f28c5e2..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-37.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0]
-../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0]
-../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0]
-../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-38.tests b/test/shaping/data/text-rendering-tests/tests/MORX-38.tests
deleted file mode 100644
index abefe29..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-38.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0]
-../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0]
-../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0]
-../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-39.tests b/test/shaping/data/text-rendering-tests/tests/MORX-39.tests
deleted file mode 100644
index 83bfa52..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-39.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0]
-../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0]
-../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0]
-../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-4.tests b/test/shaping/data/text-rendering-tests/tests/MORX-4.tests
deleted file mode 100644
index cbb1ce8..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-4.tests
+++ /dev/null
@@ -1,15 +0,0 @@
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0031:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0032:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|two@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0044,U+0058,U+0059,U+005A,U+0033:[P|Q@333,0|R@699,0|D@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|three@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0034:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|four@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0035:[P|Q@333,0|R@699,0|B@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|five@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0036:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|six@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0037:[P|Q@333,0|R@699,0|B@1050,0|A@1880,0|X@2710,0|Y@3074,0|Z@3406,0|seven@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0043,U+0044,U+0058,U+0059,U+005A,U+0038:[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|eight@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0043,U+0044,U+0058,U+0059,U+005A,U+0039:[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|nine@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0044,U+0058,U+0059,U+005A,U+2793:[P|Q@333,0|R@699,0|D@1050,0|A@1880,0|B@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_zero@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0044,U+0058,U+0059,U+005A,U+24EB:[P|Q@333,0|R@699,0|D@1050,0|B@1880,0|A@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_one@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EC:[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|A@2710,0|B@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_two@5388,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24ED:[P|Q@333,0|R@699,0|C@1050,0|D@1880,0|B@2710,0|A@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_three@5388,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EE:[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|A@2710,0|B@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_four@5388,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0044,U+0058,U+0059,U+005A,U+24EF:[P|Q@333,0|R@699,0|D@1050,0|C@1880,0|B@2710,0|A@3540,0|X@4370,0|Y@4734,0|Z@5066,0|one_five@5388,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-40.tests b/test/shaping/data/text-rendering-tests/tests/MORX-40.tests
deleted file mode 100644
index c99155e..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-40.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0]
-../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0]
-../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0]
-../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
deleted file mode 100644
index 815bebe..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
+++ /dev/null
@@ -1,4 +0,0 @@
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0063:[a_c]
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062,U+0063:[b_c]
-../fonts/TestMORXFourtyone.ttf::U+0063,U+0063:*
-../fonts/TestMORXFourtyone.ttf::U+0061,U+0062,U+0063,U+0063:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-5.tests b/test/shaping/data/text-rendering-tests/tests/MORX-5.tests
deleted file mode 100644
index ca8d086..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-5.tests
+++ /dev/null
@@ -1,25 +0,0 @@
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0033:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|three@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0034:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|four@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0035:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|five@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0036:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|six@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0037:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|seven@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0038:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|eight@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0038:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|eight@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0039:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|nine@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+0039:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|nine@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+2793:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_zero@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+2793:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_zero@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EB:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_one@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EB:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_one@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EC:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_two@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EC:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_two@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EC:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_two@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24ED:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_three@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24ED:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_three@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24ED:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_three@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EE:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_four@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EE:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_four@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EE:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_four@4558,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+24EF:[P|Q@333,0|R@699,0|A@1050,0|X@1880,0|Y@2244,0|Z@2576,0|one_five@2898,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0058,U+0059,U+005A,U+24EF:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|X@2710,0|Y@3074,0|Z@3406,0|one_five@3728,0]
-../fonts/TestMORXFour.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+0041,U+0042,U+0043,U+0058,U+0059,U+005A,U+24EF:[P|Q@333,0|R@699,0|A@1050,0|B@1880,0|C@2710,0|X@3540,0|Y@3904,0|Z@4236,0|one_five@4558,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-6.tests b/test/shaping/data/text-rendering-tests/tests/MORX-6.tests
deleted file mode 100644
index ff9c061..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-6.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+004F,U+004F,U+0041,U+0042,U+0043,U+0044,U+0045,U+0046,U+0047,U+004F,U+004F,U+004F,U+0033,U+0031,U+0034,U+0031:[O|O@418,0|O@836,0|E@1254,0|F@2084,0|A@2914,0|G@3744,0|B@4574,0|C@5404,0|D@6234,0|O@7064,0|O@7482,0|O@7900,0|three@8318,0|one@9168,0|four@10018,0|one@10868,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-7.tests b/test/shaping/data/text-rendering-tests/tests/MORX-7.tests
deleted file mode 100644
index f250848..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-7.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004F,U+0042,U+0043,U+0044,U+0031:[B|C@830,0|D@1660,0|O@2490,0|one@2908,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-8.tests b/test/shaping/data/text-rendering-tests/tests/MORX-8.tests
deleted file mode 100644
index aa0d28b..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-8.tests
+++ /dev/null
@@ -1,3 +0,0 @@
-../fonts/TestMORXEight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0030,U+0041,U+0042,U+0043:[zero|A@914,0|B@1552,0|C@2202,0]
-../fonts/TestMORXEight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0031,U+0041,U+0042,U+0043:[one|B@914,0|C@1564,0|A@2196,0]
-../fonts/TestMORXEight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0032,U+0041,U+0042,U+0043:[two|C@914,0|A@1546,0|B@2184,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-9.tests b/test/shaping/data/text-rendering-tests/tests/MORX-9.tests
deleted file mode 100644
index a899908..0000000
--- a/test/shaping/data/text-rendering-tests/tests/MORX-9.tests
+++ /dev/null
@@ -1 +0,0 @@
-../fonts/TestMORXNine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0058,U+0041,U+0042:[B|A@650,0|X@1288,0|A@1874,0|B@2512,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHARAN-1.tests b/test/shaping/data/text-rendering-tests/tests/SHARAN-1.tests
deleted file mode 100644
index 56e83ab..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHARAN-1.tests
+++ /dev/null
@@ -1,6 +0,0 @@
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0644,U+0633,U+0627,U+0646:[OneDotEnclNS@398,-1|NoonxSep|AlefFin@861,0|SeenMed.inT2outT1@1125,0|sp0@1664,0|LamIni.outT2@1664,223]
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+06CC,U+0648,U+0646,U+06CC,U+06A9,U+0648,U+0688:[TahSmallNS@118,-213|DalSep|WawFin.cut@300,0|KafMed.outT3@573,206|TwoDotsBelowNS@1115,220|BehxMed.inT2outT1@903,304|OneDotAboveNS@1271,-71|sp1@1170,0|BehxIni.outT2@1170,449|WawFin.inD2@1387,0|TwoDotsBelowNS@1867,1|sp0@1758,0|BehxIni.outD2WQ@1758,323]
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0641,U+0648,U+0646,U+0679:[TahSmallNS@595,-331|BehxFin.soft|OneDotAboveNS@1163,-182|sp0@1184,0|BehxIni.outT2B@1184,300|WawFin.inD2alt@1340,0|OneDotAboveNS@1784,108|sp0@1599,0|FehxIni.outD2WQ@1599,237]
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0679,U+0627,U+0626,U+067E,U+0020,U+0641,U+06CC,U+0633:[SeenFin|TwoDotsBelowNS@1216,269|BehxMed.inT1outT2SeenWide@1041,455|OneDotAboveNS@1454,224|sp0@1271,0|FehxIni@1271,490|space@1584,0|ThreeDotsDownBelowNS@2290,-159|BehxFin.soft@1715,0|HamzaAboveNS@2878,-201|sp0@2899,0|BehxIni.outT2B@2899,300|AlefFin.narrow@3056,0|TahSmallNS@3442,-420|sp0@3295,0|BehxIni.A@3295,0]
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0641,U+0646,U+0020,U+062E,U+0637,U+0627,U+0637,U+06CC:[YehxFin|sp0@521,0|TahIni.outD2@521,380|AlefFin@1119,0|TahMed.inD1outT1@1382,0|OneDotAboveNS@2081,-47|sp0@1451,0|HahIni.outD1@1451,36|space@2326,0|OneDotEnclNS@2855,-2|NoonxFin@2458,0|OneDotAboveNS@3361,188|sp0@3208,0|FehxIni.outT2N@3208,336]
-../fonts/TestShapeAran.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0646,U+0633,U+062A,U+0639,U+0644,U+06CC,U+0642:[TwoDotsAboveNS@519,-199|QafxFin.cut|TwoDotsBelowNS@977,141|BehxMed.inT2outD2WQ@692,272|LamMed.outT2@1023,434|AinMed.inT3outT1@1301,507|TwoDotsAboveNS@1785,209|BehxMed.inT2outT3@1563,603|SeenMed.inT2outT2@1865,735|OneDotAboveNS@2574,670|sp0@2434,0|BehxIni.outT2tall@2434,952]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHBALI-1.tests b/test/shaping/data/text-rendering-tests/tests/SHBALI-1.tests
deleted file mode 100644
index 4c727b0..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHBALI-1.tests
+++ /dev/null
@@ -1,22 +0,0 @@
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B38,U+1B00:[gid23|gid60@1113,0|gid4@1064,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B15,U+1B44,U+1B16,U+1B02:[gid25|gid132@1092,0|gid6@942,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B18,U+1B3B:[gid28|gid62@796,0|gid57@794,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B19,U+1B40:[gid66|gid29@483,0|gid57@1536,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B1A,U+1B3F:[gid67|gid30@483,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B14,U+1B36:[gid24|gid58@828,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B13,U+1B01:[gid23|gid129@1111,0|gid5@1064,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B1B,U+1B01:[gid23|gid137@1111,0|gid5@1379,181]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B26,U+1B03:[gid23|gid148@1111,0|gid7@991,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B13,U+1B38:[gid23|gid129@1111,0|gid60@1111,-488]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B13,U+1B3C:[gid23|gid129@1111,0|gid70@1128,0|gid170@1113,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B13,U+1B3D:[gid23|gid129@1111,0|gid70@1128,0|gid170@1113,0|gid57@1111,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B3E:[gid66|gid23@483,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B36,U+1B3E:[gid23|gid58@1064,0|gid66@1111,0|gid128@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B38,U+1B3E:[gid23|gid60@1113,0|gid66@1111,0|gid128@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B15,U+1B3E:[gid66|gid23@483,0|gid131@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B40:[gid66|gid23@483,0|gid57@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B3E:[gid66|gid23@483,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B3E,U+1B36:[gid66|gid23@483,0|gid58@1548,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B3E,U+1B38:[gid66|gid23@483,0|gid60@1597,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B15,U+1B3E:[gid66|gid23@483,0|gid131@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B40:[gid66|gid23@483,0|gid57@1594,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHBALI-2.tests b/test/shaping/data/text-rendering-tests/tests/SHBALI-2.tests
deleted file mode 100644
index 3878fcc..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHBALI-2.tests
+++ /dev/null
@@ -1,12 +0,0 @@
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B27,U+1B3E:[gid66|gid23@483,0|gid149@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B28,U+1B3F:[gid67|gid23@483,0|gid150@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B31,U+1B3E:[gid66|gid23@483,0|gid159@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B32,U+1B3E:[gid66|gid23@483,0|gid60@1597,0|gid149@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B4A,U+1B3E:[gid66|gid23@483,0|gid60@1597,0|gid165@1594,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B1B,U+1B44,U+1B13:[gid181|gid129@1064,-195]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B1B,U+1B44,U+1B13,U+1B3E:[gid66|gid181@483,0|gid129@1548,-195]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B1B,U+1B44,U+1B13,U+1B38,U+1B00:[gid181|gid129@1064,-195|gid60@1064,-684|gid4@855,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B13,U+1B38:[gid23|gid129@1111,0|gid60@1111,-488]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B1B,U+1B39:[gid23|gid137@1111,0|gid61@1261,-488]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B31,U+1B3A:[gid23|gid159@1111,0|gid62@1753,0]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B13,U+1B44,U+1B45,U+1B38:[gid23|gid162@1111,0|gid60@1111,-488]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHBALI-3.tests b/test/shaping/data/text-rendering-tests/tests/SHBALI-3.tests
deleted file mode 100644
index a0f3a32..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHBALI-3.tests
+++ /dev/null
@@ -1,9 +0,0 @@
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B6B:[gid102|gid107@560,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B6C:[gid102|gid108@573,49]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B6D:[gid102|gid109@652,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B6E:[gid102|gid110@652,-98]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B6F:[gid102|gid111@667,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B70:[gid102|gid112@667,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B71:[gid102|gid113@667,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B72:[gid102|gid114@667,-10]
-../fonts/NotoSansBalinese-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1B66,U+1B73:[gid102|gid115@599,-10]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHKNDA-1.tests b/test/shaping/data/text-rendering-tests/tests/SHKNDA-1.tests
deleted file mode 100644
index adb5aa7..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHKNDA-1.tests
+++ /dev/null
@@ -1,34 +0,0 @@
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB2,U+0CCD,U+0CB2,U+0CBF:[knLI|knLAc2@757,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9F,U+0CCD,U+0CB8,U+0CCD:[knTT|knSAc2@1021,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB3,U+0CBF:[knLLI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA1,U+0CBF:[knDDI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAE,U+0CC6:[knME]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB0,U+0CBF:[knRI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C96,U+0CCD,U+0CAF,U+0CC6:[knKHE|knYAc2@846,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAB,U+0CCD,U+0CB0,U+0CBF:[knPHI|knRAc2@735,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CC6:[knNE]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C97,U+0CBF:[knGI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB7,U+0CCD,U+0C9F,U+0CBF:[knSSI|knTTAc2@746,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAF,U+0CBF,U+0C82:[knYI|knAnusvara@1252,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9A,U+0CC0:[knCI|knLengthmark@766,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CBF:[knNI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C97,U+0CCD,U+0CB2,U+0CBF:[knGI|knLAc2@621,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB7,U+0CBF:[knSSI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C97,U+0CC6:[knGE]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA6,U+0CCD,U+0CB5,U+0CBF:[knDI|knVAc2@740,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA4,U+0CC0:[knTI|knLengthmark@613,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAE,U+0CBF:[knMI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB2,U+0CBF:[knLI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C97,U+0CBF:[knGI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CCD:[knN]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAC,U+0CBF:[knBI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB2,U+0CBF:[knLI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CCD,U+0CA8,U+0CBF,U+0C82:[knNI|knNAc2@678,0|knAnusvara@755,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB2,U+0CCD,U+0CB2,U+0CBF:[knLI|knLAc2@757,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA7,U+0CBF:[knDHI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAA,U+0CCC:[knPA.base|knmAU@739,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB5,U+0CBF,U+0C82:[knVI|knAnusvara@749,0]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA1,U+0CBF:[knDDI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9F,U+0CBF:[knTTI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CBF:[knNI]
-../fonts/NotoSerifKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA7,U+0CBF:[knDHI]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHKNDA-2.tests b/test/shaping/data/text-rendering-tests/tests/SHKNDA-2.tests
deleted file mode 100644
index 7936308..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHKNDA-2.tests
+++ /dev/null
@@ -1,16 +0,0 @@
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CCD,U+0CA8,U+0CBE:[gid150|gid57@711,0|gid116@1160,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CCD,U+0CA8,U+0CBE:[gid150|gid57@711,0|gid116@1160,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA4,U+0CCD,U+0CA4,U+0CBE:[gid146|gid57@623,0|gid112@1071,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9F,U+0CCD,U+0C9F,U+0CBE:[gid141|gid57@815,0|gid107@1264,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA1,U+0CCB,U+0C82,U+0C97,U+0CBF:[gid249|gid61@768,0|gid71@1513,0|gid4@1925,0|gid207@2475,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9C,U+0CBF,U+0CBC,U+0CD5,U+0CAC,U+0CC6,U+0CA8,U+0CCD:[gid211|gid55@652,0|gid71@776,0|gid259@1188,0|gid186@1994,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9C,U+0CBE,U+0CBC,U+0C95,U+0CBF,U+0CB0,U+0CCD:[gid139|gid57@776,0|gid55@652,0|gid205@1225,0|gid193@1799,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C87,U+0CA8,U+0CCD,U+0CAB,U+0CCD,U+0CB2,U+0CC6,U+0C95,U+0CCD,U+0CB7,U+0CA8,U+0CB2,U+0CCD:[gid8|gid256@711,0|gid118@1422,0|gid335@1591,0|gid282@1978,0|gid39@2552,0|gid195@3263,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C87,U+0CA8,U+0CCD,U+0CAB,U+0CCD,U+0CB2,U+0CC6,U+0C95,U+0CCD,U+0CB7,U+0CA8,U+0CCD:[gid8|gid256@711,0|gid118@1422,0|gid335@1591,0|gid282@1978,0|gid186@2552,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA6,U+0C9F,U+0CCD,U+0CB8,U+0CCD:[gid37|gid177@765,0|gid130@1814,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C8E,U+0C95,U+0CCD,U+0CB8,U+0CCD:[gid14|gid167@787,0|gid130@1596,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAE,U+0CBE,U+0CB0,U+0CCD,U+0C9A,U+0CCD:[gid155|gid57@1156,0|gid172@1605,0|gid94@2718,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9F,U+0CC6,U+0C95,U+0CCD,U+0CB8,U+0CCD,U+0C9F,U+0CCD:[gid247|gid167@815,0|gid130@1624,0|gid317@1792,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAC,U+0CC1,U+0C95,U+0CCD,U+0CB8,U+0CCD:[gid42|gid60@801,0|gid167@1165,0|gid130@1974,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB8,U+0CBE,U+0CAB,U+0CCD,U+0C9F,U+0CCD:[gid163|gid57@709,0|gid188@1158,0|gid107@2184,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9C,U+0CB8,U+0CCD,U+0C9F,U+0CCD:[gid27|gid200@776,0|gid107@1720,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/SHKNDA-3.tests b/test/shaping/data/text-rendering-tests/tests/SHKNDA-3.tests
deleted file mode 100644
index 460ff0f..0000000
--- a/test/shaping/data/text-rendering-tests/tests/SHKNDA-3.tests
+++ /dev/null
@@ -1,31 +0,0 @@
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C95,U+0CCB,U+0C82:[gid239|gid61@574,0|gid71@1319,0|gid4@1731,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C96,U+0CCB,U+0C82:[gid240|gid61@865,0|gid71@1610,0|gid4@2022,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C97,U+0CCB,U+0C82:[gid241|gid61@648,0|gid71@1393,0|gid4@1805,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C98,U+0CCB,U+0C82:[gid242|gid279@997,0|gid71@1742,0|gid4@2153,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C99,U+0CCB,U+0C82:[gid24|gid67@737,0|gid71@1718,0|gid4@2130,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9A,U+0CCB,U+0C82:[gid243|gid61@795,0|gid71@1540,0|gid4@1952,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9B,U+0CCB,U+0C82:[gid244|gid61@843,0|gid71@1588,0|gid4@2000,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9C,U+0CCB,U+0C82:[gid245|gid61@776,0|gid71@1522,0|gid4@1933,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9D,U+0CCB,U+0C82:[gid246|gid61@1379,0|gid71@2124,0|gid4@2536,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9E,U+0CCB,U+0C82:[gid29|gid67@968,0|gid71@1949,0|gid4@2360,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C9F,U+0CCB,U+0C82:[gid247|gid61@815,0|gid71@1560,0|gid4@1972,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA0,U+0CCB,U+0C82:[gid248|gid61@651,0|gid71@1397,0|gid4@1808,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA1,U+0CCB,U+0C82:[gid249|gid61@768,0|gid71@1513,0|gid4@1925,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA2,U+0CCB,U+0C82:[gid250|gid61@768,0|gid71@1513,0|gid4@1925,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA3,U+0CCB,U+0C82:[gid251|gid61@867,0|gid71@1612,0|gid4@2023,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA4,U+0CCB,U+0C82:[gid252|gid61@623,0|gid71@1368,0|gid4@1779,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA5,U+0CCB,U+0C82:[gid253|gid61@765,0|gid71@1510,0|gid4@1921,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA6,U+0CCB,U+0C82:[gid254|gid61@765,0|gid71@1510,0|gid4@1921,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA7,U+0CCB,U+0C82,U+0020:[gid255|gid61@765,0|gid71@1510,0|gid4@1921,0|gid3@2472,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CA8,U+0CCB,U+0C82:[gid256|gid61@711,0|gid71@1456,0|gid4@1868,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAA,U+0CCB,U+0C82:[gid257|gid275@792,0|gid71@1434,0|gid4@1846,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAB,U+0CCB,U+0C82:[gid258|gid277@792,0|gid71@1434,0|gid4@1846,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAC,U+0CCB,U+0C82:[gid259|gid61@806,0|gid71@1551,0|gid4@1963,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAD,U+0CCB,U+0C82:[gid260|gid61@806,0|gid71@1551,0|gid4@1963,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAE,U+0CCB,U+0C82:[gid280|gid71@1539,0|gid4@1951,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CAF,U+0CCB,U+0C82:[gid281|gid71@1712,0|gid4@2124,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB0,U+0CCB,U+0C82:[gid263|gid61@651,0|gid71@1397,0|gid4@1808,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB1,U+0CCB,U+0C82:[gid47|gid67@831,0|gid71@1812,0|gid4@2223,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB2,U+0CCB,U+0C82:[gid264|gid61@769,0|gid71@1514,0|gid4@1925,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0CB5,U+0CCB,U+0C82:[gid266|gid275@794,0|gid71@1437,0|gid4@1848,0]
-../fonts/NotoSansKannada-Regular.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0C86,U+0CCD,U+0CAF,U+0C95,U+0CCD,U+0CB7,U+0CBF,U+0CB8,U+0CCD,U+200C:[gid7|gid122@838,0|gid285@1098,0|gid200@1672,0|gid3@2694,0]
diff --git a/test/shaping/data/text-rendering-tests/update.sh b/test/shaping/data/text-rendering-tests/update.sh
deleted file mode 100755
index 47545bc..0000000
--- a/test/shaping/data/text-rendering-tests/update.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-dir=`dirname "$0"`
-
-set -ex
-if test -d text-rendering-tests; then
-	cd text-rendering-tests
-	git pull
-	cd ..
-else
-	git clone https://github.com/unicode-org/text-rendering-tests
-fi
-
-test -d fonts && git rm -rf fonts
-test -d fonts && (echo "fonts/ dir not empty; investigate."; false)
-cp -a text-rendering-tests/fonts .
-git add fonts
-
-rmdir tests || true
-test -d tests && git rm -rf tests || true
-test -d tests && (echo "tests/ dir not empty; investigate."; false)
-mkdir tests
-
-echo "TESTS = \\" > Makefile.sources
-
-DISABLED="DISBALED_TESTS = \\"
-for x in text-rendering-tests/testcases/*.html; do
-	test "x$x" = xtext-rendering-tests/testcases/index.html && continue
-	out=tests/`basename "$x" .html`.tests
-	"$dir"/extract-tests.py < "$x" > "$out"
-	if grep -q "^$out$" DISABLED; then
-		DISABLED="$DISABLED
-	$out \\"
-	else
-		echo "	$out \\" >> Makefile.sources
-	fi
-done
-git add tests
-
-echo '	$(NULL)' >> Makefile.sources
-echo >> Makefile.sources
-echo "$DISABLED" >> Makefile.sources
-echo '	$(NULL)' >> Makefile.sources
-git add Makefile.sources
-
-git commit -e -m "[test/text-rendering-tests] Update from upstream"
diff --git a/test/shaping/hb-diff b/test/shaping/hb-diff
deleted file mode 100755
index 3705de7..0000000
--- a/test/shaping/hb-diff
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-import sys, os
-
-if len (sys.argv) < 2:
-	print "usage: %s FILES..." % sys.argv[0]
-	sys.exit (1)
-
-ZipDiffer.diff_files (FileHelpers.open_file_or_stdin (f) for f in sys.argv[1:])
diff --git a/test/shaping/hb-diff-colorize b/test/shaping/hb-diff-colorize
deleted file mode 100755
index 1fdae8a..0000000
--- a/test/shaping/hb-diff-colorize
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-formatter = ColorFormatter.Auto (sys.argv)
-colorizer = DiffColorizer (formatter=formatter)
-UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (colorizer.colorize_diff))
diff --git a/test/shaping/hb-diff-filter-failures b/test/shaping/hb-diff-filter-failures
deleted file mode 100755
index 34b76de..0000000
--- a/test/shaping/hb-diff-filter-failures
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (DiffFilters.filter_failures))
diff --git a/test/shaping/hb-diff-stat b/test/shaping/hb-diff-stat
deleted file mode 100755
index 12ee8f0..0000000
--- a/test/shaping/hb-diff-stat
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-UtilMains.process_multiple_files (DiffSinks.print_stat)
diff --git a/test/shaping/hb-unicode-decode b/test/shaping/hb-unicode-decode
deleted file mode 100755
index 9ac5ed6..0000000
--- a/test/shaping/hb-unicode-decode
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-UtilMains.filter_multiple_strings_or_stdin (Unicode.decode, "UNICODE_STRING")
diff --git a/test/shaping/hb-unicode-encode b/test/shaping/hb-unicode-encode
deleted file mode 100755
index 5889807..0000000
--- a/test/shaping/hb-unicode-encode
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-UtilMains.filter_multiple_strings_or_stdin (Unicode.encode, "UNICODE_STRING", '')
diff --git a/test/shaping/hb-unicode-prettyname b/test/shaping/hb-unicode-prettyname
deleted file mode 100755
index 1d004c0..0000000
--- a/test/shaping/hb-unicode-prettyname
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-from hb_test_tools import *
-
-UtilMains.filter_multiple_strings_or_stdin (Unicode.pretty_names, "UNICODE_CODEPOINTS", \
-					    concat_separator = ' ')
diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
deleted file mode 100644
index feff70a..0000000
--- a/test/shaping/hb_test_tools.py
+++ /dev/null
@@ -1,576 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function, division, absolute_import
-
-import sys, os, re, difflib, unicodedata, errno, cgi
-from itertools import *
-try:
-	import unicodedata2 as unicodedata
-except Exception:
-	pass
-
-diff_symbols = "-+=*&^%$#@!~/"
-diff_colors = ['red', 'green', 'blue']
-
-def codepoints(s):
-	return (ord (u) for u in s)
-
-try:
-	unichr = unichr
-
-	if sys.maxunicode < 0x10FFFF:
-		# workarounds for Python 2 "narrow" builds with UCS2-only support.
-
-		_narrow_unichr = unichr
-
-		def unichr(i):
-			"""
-			Return the unicode character whose Unicode code is the integer 'i'.
-			The valid range is 0 to 0x10FFFF inclusive.
-
-			>>> _narrow_unichr(0xFFFF + 1)
-			Traceback (most recent call last):
-			  File "<stdin>", line 1, in ?
-			ValueError: unichr() arg not in range(0x10000) (narrow Python build)
-			>>> unichr(0xFFFF + 1) == u'\U00010000'
-			True
-			>>> unichr(1114111) == u'\U0010FFFF'
-			True
-			>>> unichr(0x10FFFF + 1)
-			Traceback (most recent call last):
-			  File "<stdin>", line 1, in ?
-			ValueError: unichr() arg not in range(0x110000)
-			"""
-			try:
-				return _narrow_unichr(i)
-			except ValueError:
-				try:
-					padded_hex_str = hex(i)[2:].zfill(8)
-					escape_str = "\\U" + padded_hex_str
-					return escape_str.decode("unicode-escape")
-				except UnicodeDecodeError:
-					raise ValueError('unichr() arg not in range(0x110000)')
-
-		def codepoints(s):
-			high_surrogate = None
-			for u in s:
-				cp = ord (u)
-				if 0xDC00 <= cp <= 0xDFFF:
-					if high_surrogate:
-						yield 0x10000 + (high_surrogate - 0xD800) * 0x400 + (cp - 0xDC00)
-						high_surrogate = None
-					else:
-						yield 0xFFFD
-				else:
-					if high_surrogate:
-						yield 0xFFFD
-						high_surrogate = None
-					if 0xD800 <= cp <= 0xDBFF:
-						high_surrogate = cp
-					else:
-						yield cp
-						high_surrogate = None
-			if high_surrogate:
-				yield 0xFFFD
-
-except NameError:
-	unichr = chr
-
-try:
-	unicode = unicode
-except NameError:
-	unicode = str
-
-def tounicode(s, encoding='ascii', errors='strict'):
-	if not isinstance(s, unicode):
-		return s.decode(encoding, errors)
-	else:
-		return s
-
-class ColorFormatter:
-
-	class Null:
-		@staticmethod
-		def start_color (c): return ''
-		@staticmethod
-		def end_color (): return ''
-		@staticmethod
-		def escape (s): return s
-		@staticmethod
-		def newline (): return '\n'
-
-	class ANSI:
-		@staticmethod
-		def start_color (c):
-			return {
-				'red': '\033[41;37;1m',
-				'green': '\033[42;37;1m',
-				'blue': '\033[44;37;1m',
-			}[c]
-		@staticmethod
-		def end_color ():
-			return '\033[m'
-		@staticmethod
-		def escape (s): return s
-		@staticmethod
-		def newline (): return '\n'
-
-	class HTML:
-		@staticmethod
-		def start_color (c):
-			return '<span style="background:%s">' % c
-		@staticmethod
-		def end_color ():
-			return '</span>'
-		@staticmethod
-		def escape (s): return cgi.escape (s)
-		@staticmethod
-		def newline (): return '<br/>\n'
-
-	@staticmethod
-	def Auto (argv = [], out = sys.stdout):
-		format = ColorFormatter.ANSI
-		if "--format" in argv:
-			argv.remove ("--format")
-			format = ColorFormatter.ANSI
-		if "--format=ansi" in argv:
-			argv.remove ("--format=ansi")
-			format = ColorFormatter.ANSI
-		if "--format=html" in argv:
-			argv.remove ("--format=html")
-			format = ColorFormatter.HTML
-		if "--no-format" in argv:
-			argv.remove ("--no-format")
-			format = ColorFormatter.Null
-		return format
-
-
-class DiffColorizer:
-
-	diff_regex = re.compile ('([a-za-z0-9_]*)([^a-za-z0-9_]?)')
-
-	def __init__ (self, formatter, colors=diff_colors, symbols=diff_symbols):
-		self.formatter = formatter
-		self.colors = colors
-		self.symbols = symbols
-
-	def colorize_lines (self, lines):
-		lines = (l if l else '' for l in lines)
-		ss = [self.diff_regex.sub (r'\1\n\2\n', l).splitlines (True) for l in lines]
-		oo = ["",""]
-		st = [False, False]
-		for l in difflib.Differ().compare (*ss):
-			if l[0] == '?':
-				continue
-			if l[0] == ' ':
-				for i in range(2):
-					if st[i]:
-						oo[i] += self.formatter.end_color ()
-						st[i] = False
-				oo = [o + self.formatter.escape (l[2:]) for o in oo]
-				continue
-			if l[0] in self.symbols:
-				i = self.symbols.index (l[0])
-				if not st[i]:
-					oo[i] += self.formatter.start_color (self.colors[i])
-					st[i] = True
-				oo[i] += self.formatter.escape (l[2:])
-				continue
-		for i in range(2):
-			if st[i]:
-				oo[i] += self.formatter.end_color ()
-				st[i] = False
-		oo = [o.replace ('\n', '') for o in oo]
-		return [s1+s2+self.formatter.newline () for (s1,s2) in zip (self.symbols, oo) if s2]
-
-	def colorize_diff (self, f):
-		lines = [None, None]
-		for l in f:
-			if l[0] not in self.symbols:
-				yield self.formatter.escape (l).replace ('\n', self.formatter.newline ())
-				continue
-			i = self.symbols.index (l[0])
-			if lines[i]:
-				# Flush
-				for line in self.colorize_lines (lines):
-					yield line
-				lines = [None, None]
-			lines[i] = l[1:]
-			if (all (lines)):
-				# Flush
-				for line in self.colorize_lines (lines):
-					yield line
-				lines = [None, None]
-		if (any (lines)):
-			# Flush
-			for line in self.colorize_lines (lines):
-				yield line
-
-
-class ZipDiffer:
-
-	@staticmethod
-	def diff_files (files, symbols=diff_symbols):
-		files = tuple (files) # in case it's a generator, copy it
-		try:
-			for lines in izip_longest (*files):
-				if all (lines[0] == line for line in lines[1:]):
-					sys.stdout.writelines ([" ", lines[0]])
-					continue
-
-				for i, l in enumerate (lines):
-					if l:
-						sys.stdout.writelines ([symbols[i], l])
-		except IOError as e:
-			if e.errno != errno.EPIPE:
-				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
-				sys.exit (1)
-
-
-class DiffFilters:
-
-	@staticmethod
-	def filter_failures (f):
-		for key, lines in DiffHelpers.separate_test_cases (f):
-			lines = list (lines)
-			if not DiffHelpers.test_passed (lines):
-				for l in lines: yield l
-
-class Stat:
-
-	def __init__ (self):
-		self.count = 0
-		self.freq = 0
-
-	def add (self, test):
-		self.count += 1
-		self.freq += test.freq
-
-class Stats:
-
-	def __init__ (self):
-		self.passed = Stat ()
-		self.failed = Stat ()
-		self.total  = Stat ()
-
-	def add (self, test):
-		self.total.add (test)
-		if test.passed:
-			self.passed.add (test)
-		else:
-			self.failed.add (test)
-
-	def mean (self):
-		return float (self.passed.count) / self.total.count
-
-	def variance (self):
-		return (float (self.passed.count) / self.total.count) * \
-		       (float (self.failed.count) / self.total.count)
-
-	def stddev (self):
-		return self.variance () ** .5
-
-	def zscore (self, population):
-		"""Calculate the standard score.
-		   Population is the Stats for population.
-		   Self is Stats for sample.
-		   Returns larger absolute value if sample is highly unlikely to be random.
-		   Anything outside of -3..+3 is very unlikely to be random.
-		   See: http://en.wikipedia.org/wiki/Standard_score"""
-
-		return (self.mean () - population.mean ()) / population.stddev ()
-
-
-
-
-class DiffSinks:
-
-	@staticmethod
-	def print_stat (f):
-		passed = 0
-		failed = 0
-		# XXX port to Stats, but that would really slow us down here
-		for key, lines in DiffHelpers.separate_test_cases (f):
-			if DiffHelpers.test_passed (lines):
-				passed += 1
-			else:
-				failed += 1
-		total = passed + failed
-		print ("%d out of %d tests passed.  %d failed (%g%%)" % (passed, total, failed, 100. * failed / total))
-
-
-class Test:
-
-	def __init__ (self, lines):
-		self.freq = 1
-		self.passed = True
-		self.identifier = None
-		self.text = None
-		self.unicodes = None
-		self.glyphs = None
-		for l in lines:
-			symbol = l[0]
-			if symbol != ' ':
-				self.passed = False
-			i = 1
-			if ':' in l:
-				i = l.index (':')
-				if not self.identifier:
-					self.identifier = l[1:i]
-				i = i + 2 # Skip colon and space
-			j = -1
-			if l[j] == '\n':
-				j -= 1
-			brackets = l[i] + l[j]
-			l = l[i+1:-2]
-			if brackets == '()':
-				self.text = l
-			elif brackets == '<>':
-				self.unicodes = Unicode.parse (l)
-			elif brackets == '[]':
-				# XXX we don't handle failed tests here
-				self.glyphs = l
-
-
-class DiffHelpers:
-
-	@staticmethod
-	def separate_test_cases (f):
-		'''Reads lines from f, and if the lines have identifiers, ie.
-		   have a colon character, groups them by identifier,
-		   yielding lists of all lines with the same identifier.'''
-
-		def identifier (l):
-			if ':' in l[1:]:
-				return l[1:l.index (':')]
-			return l
-		return groupby (f, key=identifier)
-
-	@staticmethod
-	def test_passed (lines):
-		lines = list (lines)
-		# XXX This is a hack, but does the job for now.
-		if any (l.find("space+0|space+0") >= 0 for l in lines if l[0] == '+'): return True
-		if any (l.find("uni25CC") >= 0 for l in lines if l[0] == '+'): return True
-		if any (l.find("dottedcircle") >= 0 for l in lines if l[0] == '+'): return True
-		if any (l.find("glyph0") >= 0 for l in lines if l[0] == '+'): return True
-		if any (l.find("gid0") >= 0 for l in lines if l[0] == '+'): return True
-		if any (l.find("notdef") >= 0 for l in lines if l[0] == '+'): return True
-		return all (l[0] == ' ' for l in lines)
-
-
-class FilterHelpers:
-
-	@staticmethod
-	def filter_printer_function (filter_callback):
-		def printer (f):
-			for line in filter_callback (f):
-				print (line)
-		return printer
-
-	@staticmethod
-	def filter_printer_function_no_newline (filter_callback):
-		def printer (f):
-			for line in filter_callback (f):
-				sys.stdout.writelines ([line])
-		return printer
-
-
-class Ngram:
-
-	@staticmethod
-	def generator (n):
-
-		def gen (f):
-			l = []
-			for x in f:
-				l.append (x)
-				if len (l) == n:
-					yield tuple (l)
-					l[:1] = []
-
-		gen.n = n
-		return gen
-
-
-class UtilMains:
-
-	@staticmethod
-	def process_multiple_files (callback, mnemonic = "FILE"):
-
-		if "--help" in sys.argv:
-			print ("Usage: %s %s..." % (sys.argv[0], mnemonic))
-			sys.exit (1)
-
-		try:
-			files = sys.argv[1:] if len (sys.argv) > 1 else ['-']
-			for s in files:
-				callback (FileHelpers.open_file_or_stdin (s))
-		except IOError as e:
-			if e.errno != errno.EPIPE:
-				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
-				sys.exit (1)
-
-	@staticmethod
-	def process_multiple_args (callback, mnemonic):
-
-		if len (sys.argv) == 1 or "--help" in sys.argv:
-			print ("Usage: %s %s..." % (sys.argv[0], mnemonic))
-			sys.exit (1)
-
-		try:
-			for s in sys.argv[1:]:
-				callback (s)
-		except IOError as e:
-			if e.errno != errno.EPIPE:
-				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
-				sys.exit (1)
-
-	@staticmethod
-	def filter_multiple_strings_or_stdin (callback, mnemonic, \
-					      separator = " ", \
-					      concat_separator = False):
-
-		if "--help" in sys.argv:
-			print ("Usage:\n  %s %s...\nor:\n  %s\n\nWhen called with no arguments, input is read from standard input." \
-			      % (sys.argv[0], mnemonic, sys.argv[0]))
-			sys.exit (1)
-
-		try:
-			if len (sys.argv) == 1:
-				while (1):
-					line = sys.stdin.readline ()
-					if not len (line):
-						break
-					if line[-1] == '\n':
-						line = line[:-1]
-					print (callback (line))
-			else:
-				args = sys.argv[1:]
-				if concat_separator != False:
-					args = [concat_separator.join (args)]
-				print (separator.join (callback (x) for x in (args)))
-		except IOError as e:
-			if e.errno != errno.EPIPE:
-				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
-				sys.exit (1)
-
-
-class Unicode:
-
-	@staticmethod
-	def decode (s):
-		return u','.join ("U+%04X" % cp for cp in codepoints (tounicode (s, 'utf-8')))
-
-	@staticmethod
-	def parse (s):
-		s = re.sub (r"0[xX]", " ", s)
-		s = re.sub (r"[<+>{},;&#\\xXuUnNiI\n\t]", " ", s)
-		return [int (x, 16) for x in s.split ()]
-
-	@staticmethod
-	def encode (s):
-		s = u''.join (unichr (x) for x in Unicode.parse (s))
-		if sys.version_info[0] == 2: s = s.encode ('utf-8')
-		return s
-
-	shorthands = {
-		"ZERO WIDTH NON-JOINER": "ZWNJ",
-		"ZERO WIDTH JOINER": "ZWJ",
-		"NARROW NO-BREAK SPACE": "NNBSP",
-		"COMBINING GRAPHEME JOINER": "CGJ",
-		"LEFT-TO-RIGHT MARK": "LRM",
-		"RIGHT-TO-LEFT MARK": "RLM",
-		"LEFT-TO-RIGHT EMBEDDING": "LRE",
-		"RIGHT-TO-LEFT EMBEDDING": "RLE",
-		"POP DIRECTIONAL FORMATTING": "PDF",
-		"LEFT-TO-RIGHT OVERRIDE": "LRO",
-		"RIGHT-TO-LEFT OVERRIDE": "RLO",
-	}
-
-	@staticmethod
-	def pretty_name (u):
-		try:
-			s = unicodedata.name (u)
-		except ValueError:
-			return "XXX"
-		s = re.sub (".* LETTER ", "", s)
-		s = re.sub (".* VOWEL SIGN (.*)", r"\1-MATRA", s)
-		s = re.sub (".* SIGN ", "", s)
-		s = re.sub (".* COMBINING ", "", s)
-		if re.match (".* VIRAMA", s):
-			s = "HALANT"
-		if s in Unicode.shorthands:
-			s = Unicode.shorthands[s]
-		return s
-
-	@staticmethod
-	def pretty_names (s):
-		s = re.sub (r"[<+>\\uU]", " ", s)
-		s = re.sub (r"0[xX]", " ", s)
-		s = [unichr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)]
-		return u' + '.join (Unicode.pretty_name (x) for x in s).encode ('utf-8')
-
-
-class FileHelpers:
-
-	@staticmethod
-	def open_file_or_stdin (f):
-		if f == '-':
-			return sys.stdin
-		return open (f)
-
-
-class Manifest:
-
-	@staticmethod
-	def read (s, strict = True):
-
-		if not os.path.exists (s):
-			if strict:
-				print ("%s: %s does not exist" % (sys.argv[0], s), file=sys.stderr)
-				sys.exit (1)
-			return
-
-		s = os.path.normpath (s)
-
-		if os.path.isdir (s):
-
-			try:
-				m = open (os.path.join (s, "MANIFEST"))
-				items = [x.strip () for x in m.readlines ()]
-				for f in items:
-					for p in Manifest.read (os.path.join (s, f)):
-						yield p
-			except IOError:
-				if strict:
-					print ("%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST")), file=sys.stderr)
-					sys.exit (1)
-				return
-		else:
-			yield s
-
-	@staticmethod
-	def update_recursive (s):
-
-		for dirpath, dirnames, filenames in os.walk (s, followlinks=True):
-
-			for f in ["MANIFEST", "README", "LICENSE", "COPYING", "AUTHORS", "SOURCES", "ChangeLog"]:
-				if f in dirnames:
-					dirnames.remove (f)
-				if f in filenames:
-					filenames.remove (f)
-			dirnames.sort ()
-			filenames.sort ()
-			ms = os.path.join (dirpath, "MANIFEST")
-			print ("  GEN    %s" % ms)
-			m = open (ms, "w")
-			for f in filenames:
-				print (f, file=m)
-			for f in dirnames:
-				print (f, file=m)
-			for f in dirnames:
-				Manifest.update_recursive (os.path.join (dirpath, f))
-
-if __name__ == '__main__':
-	pass
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
deleted file mode 100755
index 7f24354..0000000
--- a/test/shaping/record-test.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/bash
-
-dir=`mktemp -d`
-
-if which sha1sum 2>/dev/null >/dev/null; then
-	SHA1SUM=sha1sum
-elif which shasum 2>/dev/null >/dev/null; then
-	SHA1SUM='shasum -a 1'
-elif which digest 2>/dev/null >/dev/null; then
-	SHA1SUM='digest -a sha1'
-else
-	echo "'sha1sum' not found"
-	exit 2
-fi
-
-out=/dev/stdout
-if test "x$1" == 'x-o'; then
-	shift
-	out=$1
-	shift
-fi
-hb_shape=$1
-shift
-fontfile=$1
-if test "x${fontfile:0:1}" == 'x-'; then
-	echo "Specify font file before other options." >&2
-	exit 1
-fi
-shift
-if ! echo "$hb_shape" | grep -q 'hb-shape'; then
-	echo "Specify hb-shape (not hb-view, etc): got "$hb_shape"." >&2
-	exit 1
-fi
-options=
-have_text=false
-for arg in "$@"; do
-	if test "x${arg:0:1}" == 'x-'; then
-		if echo "$arg" | grep -q ' '; then
-			echo "Space in argument is not supported: '$arg'." >&2
-			exit 1
-		fi
-		options="$options${options:+ }$arg"
-		continue
-	fi
-	if $have_text; then
-		echo "Too many arguments found...  Use '=' notation for options: '$arg'" >&2
-		exit 1;
-	fi
-	text="$arg"
-	have_text=true
-done
-if ! $have_text; then
-	text=`cat`
-fi
-unicodes=`echo "$text" | ./hb-unicode-decode`
-glyphs=`echo "$text" | $hb_shape $options "$fontfile"`
-if test $? != 0; then
-	echo "hb-shape failed." >&2
-	exit 2
-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 \
-	--glyph-names \
-	--no-hinting \
-	--layout-features='*' \
-	"$dir/font.ttf" \
-	--gids="$glyph_ids" \
-	--text="$text"
-fonttools subset \
-	--glyph-names \
-	--no-hinting \
-	--layout-features='*' \
-	"$dir/font.ttf" \
-	--gids="$glyph_ids" \
-	--text="$text"
-if ! test -s "$dir/font.subset.ttf"; then
-	echo "Subsetter didn't produce nonempty subset font in $dir/font.subset.ttf" >&2
-	exit 2
-fi
-
-# Verify that subset font produces same glyphs!
-glyphs_subset=`echo "$text" | $hb_shape $options "$dir/font.subset.ttf"`
-
-if ! test "x$glyphs" = "x$glyphs_subset"; then
-	echo "Subset font produced different glyphs!" >&2
-	echo "Perhaps font doesn't have glyph names; checking visually..." >&2
-	hb_view=${hb_shape/shape/view}
-	echo "$text" | $hb_view $options "$dir/font.ttf" --output-format=png --output-file="$dir/orig.png"
-	echo "$text" | $hb_view $options "$dir/font.subset.ttf" --output-format=png --output-file="$dir/subset.png"
-	if ! cmp "$dir/orig.png" "$dir/subset.png"; then
-		echo "Images differ.  Please inspect $dir/*.png." >&2
-		echo "$glyphs" >> "$out"
-		echo "$glyphs_subset" >> "$out"
-		exit 2
-	fi
-	echo "Yep; all good." >&2
-	rm -f "$dir/orig.png"
-	rm -f "$dir/subset.png"
-	glyphs=$glyphs_subset
-fi
-
-sha1sum=`$SHA1SUM "$dir/font.subset.ttf" | cut -d' ' -f1`
-subset="data/in-house/fonts/$sha1sum.ttf"
-mv "$dir/font.subset.ttf" "$subset"
-
-# There ought to be an easier way to do this, but it escapes me...
-unicodes_file=`mktemp`
-glyphs_file=`mktemp`
-echo "$unicodes" > "$unicodes_file"
-echo "$glyphs" > "$glyphs_file"
-# Open the "file"s
-exec 3<"$unicodes_file"
-exec 4<"$glyphs_file"
-relative_subset="$subset"
-if test "$out" != "/dev/stdout"; then
-	relative_subset="$(/usr/bin/python -c 'import os, sys; print (os.path.relpath (sys.argv[1], sys.argv[2]))' "$subset" "$(dirname "$out")")"
-fi
-while read uline <&3 && read gline <&4; do
-	echo "$relative_subset:$options:$uline:$gline" >> "$out"
-done
-
-
-rm -f "$dir/font.ttf"
-rmdir "$dir"
diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py
deleted file mode 100755
index 26853e4..0000000
--- a/test/shaping/run-tests.py
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function, division, absolute_import
-
-import sys, os, subprocess, hashlib, tempfile, shutil
-
-def cmd(command):
-	global process
-	process.stdin.write ((' '.join (command) + '\n').encode ("utf-8"))
-	process.stdin.flush ()
-	return process.stdout.readline().decode ("utf-8").strip ()
-
-args = sys.argv[1:]
-
-reference = False
-if len (args) and args[0] == "--reference":
-	reference = True
-	args = args[1:]
-
-if not args or args[0].find('hb-shape') == -1 or not os.path.exists (args[0]):
-	print ("""First argument does not seem to point to usable hb-shape.""")
-	sys.exit (1)
-hb_shape, args = args[0], args[1:]
-
-process = subprocess.Popen ([hb_shape, '--batch'],
-			    stdin=subprocess.PIPE,
-			    stdout=subprocess.PIPE,
-			    stderr=sys.stdout)
-
-passes = 0
-fails = 0
-skips = 0
-
-if not len (args):
-	args = ['-']
-
-for filename in args:
-	if not reference:
-		if filename == '-':
-			print ("Running tests from standard input")
-		else:
-			print ("Running tests in " + filename)
-
-	if filename == '-':
-		f = sys.stdin
-	else:
-		f = open (filename)
-
-	for line in f:
-		comment = False
-		if line.startswith ("#"):
-			comment = True
-			line = line[1:]
-
-			if line.startswith (' '):
-				if not reference:
-					print ("#%s" % line)
-				continue
-
-		line = line.strip ()
-		if not line:
-			continue
-
-		fontfile, options, unicodes, glyphs_expected = line.split (":")
-		if fontfile.startswith ('/') or fontfile.startswith ('"/'):
-			fontfile, expected_hash = fontfile.split('@')
-
-			try:
-				with open (fontfile, 'rb') as ff:
-					actual_hash = hashlib.sha1 (ff.read()).hexdigest ().strip ()
-					if actual_hash != expected_hash:
-						print ('different version of %s found; Expected hash %s, got %s; skipping.' %
-							   (fontfile, expected_hash, actual_hash))
-						skips += 1
-						continue
-			except:
-				print ('%s not found, skip.' % fontfile)
-				skips += 1
-				continue
-		else:
-			cwd = os.path.dirname(filename)
-			fontfile = os.path.normpath (os.path.join (cwd, fontfile))
-
-		extra_options = ["--shaper=ot"]
-		if glyphs_expected != '*':
-			extra_options.append("--verify")
-
-		if comment:
-			if not reference:
-				print ('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
-			continue
-
-		if not reference:
-			print ('%s "%s" %s %s --unicodes %s' %
-					 (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
-
-		# hack to support fonts with space on run-tests.py, after several other tries...
-		if ' ' in fontfile:
-			new_fontfile = os.path.join (tempfile.gettempdir (), 'tmpfile')
-			shutil.copyfile(fontfile, new_fontfile)
-			fontfile = new_fontfile
-
-		glyphs1 = cmd ([hb_shape, "--font-funcs=ft",
-			fontfile] + extra_options + ["--unicodes",
-			unicodes] + (options.split (' ') if options else []))
-
-		glyphs2 = cmd ([hb_shape, "--font-funcs=ot",
-			fontfile] + extra_options + ["--unicodes",
-			unicodes] + (options.split (' ') if options else []))
-
-		if glyphs1 != glyphs2 and glyphs_expected != '*':
-			print ("FT funcs: " + glyphs1) # file=sys.stderr
-			print ("OT funcs: " + glyphs2) # file=sys.stderr
-			fails += 1
-		else:
-			passes += 1
-
-		if reference:
-			print (":".join ([fontfile, options, unicodes, glyphs1]))
-			continue
-
-		if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
-			print ("Actual:   " + glyphs1) # file=sys.stderr
-			print ("Expected: " + glyphs_expected) # file=sys.stderr
-			fails += 1
-		else:
-			passes += 1
-
-if not reference:
-	print ("%d tests passed; %d failed; %d skipped." % (passes, fails, skips)) # file=sys.stderr
-	if not (fails + passes):
-		print ("No tests ran.")
-	elif not (fails + skips):
-		print ("All tests passed.")
-
-if fails:
-	sys.exit (1)
-elif passes:
-	sys.exit (0)
-else:
-	sys.exit (77)
diff --git a/test/subset/CMakeLists.txt b/test/subset/CMakeLists.txt
deleted file mode 100644
index af2b41a..0000000
--- a/test/subset/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-if (HB_BUILD_UTILS)
-  file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/Makefile.sources" SOURCES)
-  extract_make_variable (TESTS ${SOURCES})
-  foreach (test IN ITEMS ${TESTS})
-    add_test (NAME ${test}
-      COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $<TARGET_FILE:hb-subset> "data/${test}"
-      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-    set_property(TEST ${test} PROPERTY SKIP_RETURN_CODE 77)
-  endforeach ()
-endif ()
diff --git a/test/subset/Makefile.am b/test/subset/Makefile.am
index da4b3d4..cfd739b 100644
--- a/test/subset/Makefile.am
+++ b/test/subset/Makefile.am
@@ -11,9 +11,11 @@
 	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
 
 EXTRA_DIST += \
-	CMakeLists.txt \
+	meson.build \
 	run-tests.py \
+	run-repack-tests.py \
 	subset_test_suite.py \
+	repack_test.py \
 	$(NULL)
 
 CLEANFILES += \
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index 4508fcd..a69005a 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -3,25 +3,60 @@
 NULL =
 EXTRA_DIST =
 CLEANFILES =
-SUBDIRS =
+SUBDIRS = repack_tests
 
 EXTRA_DIST += \
 	$(TESTS) \
 	expected/basics \
 	expected/full-font \
+	expected/glyf_bug_3131 \
 	expected/cff-full-font \
 	expected/japanese \
 	expected/cff-japanese \
+	expected/cff.notoserifmyanmar \
 	expected/layout \
 	expected/layout.gpos \
 	expected/layout.gpos2 \
 	expected/layout.gpos3 \
+	expected/layout.gpos4 \
+	expected/layout.gpos5 \
+	expected/layout.gpos6 \
+	expected/layout.gpos8 \
+	expected/layout.gpos8.amiri \
+	expected/layout.gpos9 \
+	expected/layout.gsub3 \
+	expected/layout.gsub5 \
+	expected/layout.gsub5_format2 \
 	expected/layout.gsub6 \
+	expected/layout.gsub8 \
+	expected/layout.khmer \
+	expected/layout.gdef \
+	expected/layout.gdef.glyphset \
+	expected/layout.context \
+	expected/layout.gdef-varstore \
+	expected/layout.gdef-attachlist \
+	expected/layout.notonastaliqurdu \
+	expected/layout.tinos \
+	expected/layout.duplicate_features \
+	expected/layout.unsorted_featurelist \
+	expected/cmap \
 	expected/cmap14 \
+	expected/sbix \
+	expected/colr \
+	expected/colrv1 \
+	expected/colr_with_components \
+	expected/cbdt \
+	expected/variable \
+	expected/glyph_names \
+	expected/math \
 	fonts \
 	profiles \
 	$(NULL)
 
+# TODO: re-able once colrv1 subsetting is stabilized.
+#      	expected/colrv1
+#   	expected/colrv1.notoemoji
+
 # Convenience targets:
 lib:
 	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index 5b93f27..c1a70ba 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -1,17 +1,53 @@
 TESTS = \
 	tests/basics.tests \
-	tests/full-font.tests \
+	tests/cbdt.tests \
 	tests/cff-full-font.tests \
-	tests/japanese.tests \
 	tests/cff-japanese.tests \
-	tests/layout.tests \
+	tests/cff.notoserifmyanmar.tests \
+	tests/cmap.tests \
+	tests/cmap14.tests \
+	tests/colr.tests \
+	tests/colrv1.tests \
+	tests/colr_with_components.tests \
+	tests/full-font.tests \
+	tests/glyf_bug_3131.tests \
+	tests/japanese.tests \
+	tests/layout.context.tests \
+	tests/layout.gdef-attachlist.tests \
+	tests/layout.gdef-varstore.tests \
+	tests/layout.gdef.tests \
+	tests/layout.gdef.glyphset.tests \
 	tests/layout.gpos.tests \
 	tests/layout.gpos2.tests \
 	tests/layout.gpos3.tests \
+	tests/layout.gpos4.tests \
+	tests/layout.gpos5.tests \
+	tests/layout.gpos6.tests \
+	tests/layout.gpos8.tests \
+	tests/layout.gpos8.amiri.tests \
+	tests/layout.gpos9.tests \
+	tests/layout.gsub3.tests \
+	tests/layout.gsub5.tests \
+	tests/layout.gsub5_format2.tests \
 	tests/layout.gsub6.tests \
-	tests/cmap14.tests \
+	tests/layout.gsub8.tests \
+	tests/layout.khmer.tests \
+	tests/layout.notonastaliqurdu.tests \
+	tests/layout.tests \
+	tests/layout.tinos.tests \
+	tests/layout.duplicate_features.tests \
+	tests/layout.unsorted_featurelist.tests \
+	tests/sbix.tests \
+	tests/variable.tests \
+	tests/glyph_names.tests \
+	tests/math.tests \
 	$(NULL)
 
+# TODO: re-enable once colrv1 subsetting is stabilized.
+#	tests/colrv1.notoemoji.tests
+#	tests/colrv1.tests
+
+
 XFAIL_TESTS = \
 	$(NULL)
 
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
index efe5bcb..61564e1 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
index 8e12241..c5d1ca5 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
index bd802a5..2fa7d5d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
index 9fbebb5..210d224 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
index 7391741..9f840d0 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
index 5de8d89..f80bdd4 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
index 05d83d8..5b5033d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
index f47887e..29b2dc9 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
index bfa9267..ac14d56 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
index 8c12158..eae3a89 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
index 6a47c39..63690d0 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
index e3c0727..37ea7b8 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
index 36a4b9a..f9a7acb 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
index 251794c..3bba719 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
index 9e65c83..1759c85 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
index ada1649..7accc1d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
index 6b0dc6c..02fc4c5 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
index 6425ecf..7e54891 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf
new file mode 100644
index 0000000..a12408b
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf
new file mode 100644
index 0000000..ae965b8
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf
new file mode 100644
index 0000000..2bc4119
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf
new file mode 100644
index 0000000..045a564
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf
new file mode 100644
index 0000000..127a085
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f80bdd4
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf
new file mode 100644
index 0000000..50d5176
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf
new file mode 100644
index 0000000..8389377
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf
new file mode 100644
index 0000000..6de5862
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf
new file mode 100644
index 0000000..86e9c79
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf
new file mode 100644
index 0000000..c50cb5b
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..d27fcd4
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf
new file mode 100644
index 0000000..f86a38f
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf
new file mode 100644
index 0000000..8a8dfab
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf
new file mode 100644
index 0000000..c2ac34c
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf
new file mode 100644
index 0000000..210d224
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf
new file mode 100644
index 0000000..9f840d0
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..0d79f43
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.keep-all-layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf
new file mode 100644
index 0000000..61564e1
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf
new file mode 100644
index 0000000..c5d1ca5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf
new file mode 100644
index 0000000..2fa7d5d
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf
new file mode 100644
index 0000000..210d224
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf
new file mode 100644
index 0000000..9f840d0
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..686180c
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
index 90e49be..edc2749 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
index 5277d15..7f21708 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
index de06660..b5167c9 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
index effad7b..4240265 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
index 21c8205..f7ae43d 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
index fbb8c33..c09fca4 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf
new file mode 100644
index 0000000..61564e1
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf
new file mode 100644
index 0000000..c5d1ca5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf
new file mode 100644
index 0000000..2fa7d5d
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf
new file mode 100644
index 0000000..210d224
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf
new file mode 100644
index 0000000..9f840d0
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f80bdd4
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf
new file mode 100644
index 0000000..61564e1
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf
new file mode 100644
index 0000000..c5d1ca5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf
new file mode 100644
index 0000000..2fa7d5d
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf
new file mode 100644
index 0000000..210d224
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf
new file mode 100644
index 0000000..9f840d0
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f80bdd4
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf
new file mode 100644
index 0000000..47315bd
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf
new file mode 100644
index 0000000..807f21d
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf
new file mode 100644
index 0000000..8de6489
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf
new file mode 100644
index 0000000..09396e2
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf
new file mode 100644
index 0000000..1a62c02
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f80bdd4
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.no-prune-unicode-ranges.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf
new file mode 100644
index 0000000..876398a
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf
new file mode 100644
index 0000000..c1ffb6f
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf
new file mode 100644
index 0000000..daba7e3
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf
new file mode 100644
index 0000000..30087b5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf
new file mode 100644
index 0000000..1a084d5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cac5bbd
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
index 3c0f4cd..727239c 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
index a5ce9e0..02d67aa 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
index 1b84335..4eda654 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
index 97eaa26..cd321b7 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
index f42edb7..7b88b55 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
index cc2805a..441646a 100644
--- a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..f07052a
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf
new file mode 100644
index 0000000..3d67628
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf
new file mode 100644
index 0000000..15dfc01
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf
new file mode 100644
index 0000000..f5d668e
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf
new file mode 100644
index 0000000..1298f53
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..b3d2945
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf
new file mode 100644
index 0000000..f07052a
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf
new file mode 100644
index 0000000..0bfa6ca
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf
new file mode 100644
index 0000000..15dfc01
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf
new file mode 100644
index 0000000..7358857
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf
new file mode 100644
index 0000000..245b20f
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..b3d2945
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.keep-all-layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf
new file mode 100644
index 0000000..a9ab96e
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf
new file mode 100644
index 0000000..a7b8d17
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf
new file mode 100644
index 0000000..69c51c3
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf
new file mode 100644
index 0000000..b3dce53
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf
new file mode 100644
index 0000000..afc5a93
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..262804c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf
new file mode 100644
index 0000000..414c962
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf
new file mode 100644
index 0000000..6759ce3
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf
new file mode 100644
index 0000000..d185267
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf
new file mode 100644
index 0000000..a7a9c05
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf
new file mode 100644
index 0000000..30aa18c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf
new file mode 100644
index 0000000..23feb15
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf
new file mode 100644
index 0000000..9854d47
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf
new file mode 100644
index 0000000..c33b4cb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf
new file mode 100644
index 0000000..fefbfaf
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf
new file mode 100644
index 0000000..a951a4c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf
new file mode 100644
index 0000000..349899d
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.no-prune-unicode-ranges.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,63.ttf
new file mode 100644
index 0000000..d2a94dd
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.62.ttf
new file mode 100644
index 0000000..6637064
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.63.ttf
new file mode 100644
index 0000000..8efd69b
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..5f0d98c
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf
new file mode 100644
index 0000000..e8b3955
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf
new file mode 100644
index 0000000..e5f08c7
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf
new file mode 100644
index 0000000..c329cea
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf
new file mode 100644
index 0000000..6e399ee
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f17e9fb
--- /dev/null
+++ b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
index 1af233f..1f017da 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
index a699eea..d35619a 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
index 52706dc..5d73ef6 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
index 3de7c77..b384aed 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
index 52dc474..508510c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
index d6c516e..b59987e 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
index 128eae0..36dd105 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
index 2d2b65b..8d9ffa4 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
index ac735b3..3bc6e78 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
index 52dc474..508510c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
index 52dc474..508510c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
index 1873672..ac634f8 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
index 128eae0..36dd105 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
index 122b109..8d0d8dd 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
index 381e97e..54cd503 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
index 52dc474..508510c 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.keep-all-layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.layout-features.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
index 1af233f..1f017da 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
index a699eea..d35619a 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
index 52706dc..5d73ef6 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
index 3de7c77..b384aed 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf
new file mode 100644
index 0000000..617e9fd
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf
new file mode 100644
index 0000000..91d71fd
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf
new file mode 100644
index 0000000..c66b0b2
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.no-prune-unicode-ranges.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf
new file mode 100644
index 0000000..1f017da
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf
new file mode 100644
index 0000000..d35619a
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf
new file mode 100644
index 0000000..5d73ef6
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf
new file mode 100644
index 0000000..b384aed
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8b2c634
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
index f545375..accefc9 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
index a699eea..d35619a 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
index eb84f9c..d4e5508 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
index efd7c16..350b166 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
index 12d9208..8b2c634 100644
--- a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf
new file mode 100644
index 0000000..fdd7aed
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf
new file mode 100644
index 0000000..80bba05
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf
new file mode 100644
index 0000000..860a9de
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..f9521e1
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf
new file mode 100644
index 0000000..2129fde
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf
new file mode 100644
index 0000000..5b78e35
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf
new file mode 100644
index 0000000..2402c69
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf
new file mode 100644
index 0000000..ecc75f2
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf
new file mode 100644
index 0000000..9be8e29
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..7161196
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..77e275b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..262dfcf
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf
new file mode 100644
index 0000000..b7bd7d9
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf
new file mode 100644
index 0000000..9cf2a3f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf
new file mode 100644
index 0000000..2db03c9
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf
new file mode 100644
index 0000000..0c7e212
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf
new file mode 100644
index 0000000..b330fd1
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..77e275b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf
new file mode 100644
index 0000000..efdc225
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf
new file mode 100644
index 0000000..e601a06
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf
new file mode 100644
index 0000000..16ebd04
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf
new file mode 100644
index 0000000..947c5ee
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf
new file mode 100644
index 0000000..7754895
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf
new file mode 100644
index 0000000..18c7138
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..3e65d5c
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf
new file mode 100644
index 0000000..f7e0d96
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf
new file mode 100644
index 0000000..d59b841
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf
new file mode 100644
index 0000000..7f54597
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf
new file mode 100644
index 0000000..5d989cb
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf
new file mode 100644
index 0000000..b574032
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..8245fa3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..9c7b087
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..6f3eb6c
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf
new file mode 100644
index 0000000..3b5140d
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf
new file mode 100644
index 0000000..0008afd
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf
new file mode 100644
index 0000000..f00ff0f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf
new file mode 100644
index 0000000..a4b45e0
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf
new file mode 100644
index 0000000..0743e25
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..9c7b087
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf
new file mode 100644
index 0000000..ac7e339
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf
new file mode 100644
index 0000000..38b7934
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf
new file mode 100644
index 0000000..ef84731
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf
new file mode 100644
index 0000000..ff4acba
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf
new file mode 100644
index 0000000..5ebeb2b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..24bdc31
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..3e65d5c
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..768acab
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf
new file mode 100644
index 0000000..b0b9bf9
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf
new file mode 100644
index 0000000..dd378c3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf
new file mode 100644
index 0000000..0b4f45a
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf
new file mode 100644
index 0000000..ce7fda2
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf
new file mode 100644
index 0000000..716db34
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..2151697
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf
new file mode 100644
index 0000000..5dc41bb
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf
new file mode 100644
index 0000000..7a57b83
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf
new file mode 100644
index 0000000..25cc44e
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf
new file mode 100644
index 0000000..ad359c3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf
new file mode 100644
index 0000000..1970859
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..79b338b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..46ffded
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..0934fec
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf
new file mode 100644
index 0000000..2630dfb
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf
new file mode 100644
index 0000000..68574c3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf
new file mode 100644
index 0000000..1052bd3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf
new file mode 100644
index 0000000..ad1aa83
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf
new file mode 100644
index 0000000..d2d389f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..46ffded
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf
new file mode 100644
index 0000000..db416ff
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf
new file mode 100644
index 0000000..81b0b43
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf
new file mode 100644
index 0000000..bcd08f1
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf
new file mode 100644
index 0000000..abefa6b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf
new file mode 100644
index 0000000..94c2d0a
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..8dba70f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..2151697
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..f4eb909
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf
new file mode 100644
index 0000000..5e595a6
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf
new file mode 100644
index 0000000..29348ac
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf
new file mode 100644
index 0000000..f050646
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf
new file mode 100644
index 0000000..740ea15
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf
new file mode 100644
index 0000000..9f2baca
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..661ce52
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf
new file mode 100644
index 0000000..3ce9056
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf
new file mode 100644
index 0000000..3ac9fe2
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf
new file mode 100644
index 0000000..56ba35f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf
new file mode 100644
index 0000000..265df72
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf
new file mode 100644
index 0000000..0c2f8da
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..d0e194b
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..2864095
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..41efe9d
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf
new file mode 100644
index 0000000..aab2fc7
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf
new file mode 100644
index 0000000..19ebe2e
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf
new file mode 100644
index 0000000..58c0225
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf
new file mode 100644
index 0000000..925d61e
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf
new file mode 100644
index 0000000..310748e
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..2864095
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf
new file mode 100644
index 0000000..b1c64b3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf
new file mode 100644
index 0000000..f4f76b6
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf
new file mode 100644
index 0000000..69fcb6c
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf
new file mode 100644
index 0000000..bce746f
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf
new file mode 100644
index 0000000..8c64701
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..7cfc9c2
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..661ce52
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..c23b53d
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf
new file mode 100644
index 0000000..3754c86
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf
new file mode 100644
index 0000000..b62b7c6
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf
new file mode 100644
index 0000000..9ae2122
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf
new file mode 100644
index 0000000..a16c8f3
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf
new file mode 100644
index 0000000..7b52513
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf
new file mode 100644
index 0000000..f9521e1
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf
new file mode 100644
index 0000000..b78fd9c
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf
new file mode 100644
index 0000000..34a9750
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf
Binary files differ
diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf
new file mode 100644
index 0000000..6288dd4
--- /dev/null
+++ b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
deleted file mode 100644
index f0ea3ca..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf
deleted file mode 100644
index 7ea55a2..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 07b9aa2..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 2811017..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf
deleted file mode 100644
index 98bbf38..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 2d88e57..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
deleted file mode 100644
index cf0fbf6..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
deleted file mode 100644
index 8ab8294..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index de475e6..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
deleted file mode 100644
index e5775fd..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf
deleted file mode 100644
index 572ea74..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 376f658..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
deleted file mode 100644
index cf3228d..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf
deleted file mode 100644
index 1bafff1..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 34303e7..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf
deleted file mode 100644
index e23e37f..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf
deleted file mode 100644
index b5a565e..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 6045b4c..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 112dec7..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
deleted file mode 100644
index 929c4e2..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 939a565..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..a06d900
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..1af511d
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..48ec219
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..179fc28
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf
new file mode 100644
index 0000000..7a5e3ba
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..61999cb
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..7b881e0
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..59be7c3
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..4b0aeeb
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..b60efdc
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf
new file mode 100644
index 0000000..a2a8d1a
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..895b69d
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..4024ffa
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..514ec3c
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..f6d838c
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..3c66f6d
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf
new file mode 100644
index 0000000..4308642
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..54dbd8f
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-drop-hints.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..268cefd
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..88c7b33
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..dd85287
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..d5992f7
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf
new file mode 100644
index 0000000..de13277
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..90fdd95
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.notdef-outline.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf
deleted file mode 100644
index e1613ac..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf
deleted file mode 100644
index 479c5e0..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 95149dc..0000000
--- a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
index 6065be4..028434d 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
index cee7584..73b2f01 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
index 0f13fa5..3c99fb5 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
index 6db56f4..f803b3e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
index 1b216cc..d3b97c1 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
index 690fe90..2fd4d01 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index f1f0cb1..8104df8 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
index b353d43..2eaaff3 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 7d96667..02b738b 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
index afd9c33..2e1aafe 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
index 1a47c85..e377284 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
index b69448b..0e613b7 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
index 3682a0d..d6a6ae7 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
index 6f98c8f..839a963 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
index 1497979..71d39df 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
index c728315..4c48a5a 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 9a0e726..4e7e817 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
index 513d47e..093927c 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index b10526d..4471395 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
index 2684381..0ca639a 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
index 68a254e..ddd99b8 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
index b900d92..af0b861 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
index 6b7cc2e..5aa7cc0 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
index 69b6b2e..47e085e 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
index 460bace..7112ccc 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
index ecdd5d6..edd4687 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 77b1f95..9c4a8f5 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
index 8a1bc96..81e2f2f 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 7d943fd..165e7f5 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
index eb01e55..b3f7767 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
index 19c8ed8..ad18ccc 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
index 5c7ac1a..e8df0b0 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
index abac3dd..7de6715 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
index e593d6d..db8db37 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
index e586904..d896e2f 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
index 75f1613..24d8fae 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
index 6f3794c..47af163 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
index 7c5f648..1503185 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
index 2dcd75b..4b08011 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
index a5d40d0..40ef924 100644
--- a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf b/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf
new file mode 100644
index 0000000..5935868
--- /dev/null
+++ b/test/subset/data/expected/cff.notoserifmyanmar/NotoSerifMyanmar-Regular.notdef-outline.1092.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf
new file mode 100644
index 0000000..6c594ee
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf
new file mode 100644
index 0000000..6738685
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf
new file mode 100644
index 0000000..7a49c16
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf
new file mode 100644
index 0000000..120ea52
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf
new file mode 100644
index 0000000..f38f951
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf
new file mode 100644
index 0000000..1f39a65
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf
new file mode 100644
index 0000000..45a872c
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf
new file mode 100644
index 0000000..2a9054f
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf
new file mode 100644
index 0000000..c7d4754
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf
new file mode 100644
index 0000000..acad1db
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf
new file mode 100644
index 0000000..a8f0daa
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf
new file mode 100644
index 0000000..373027a
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf
new file mode 100644
index 0000000..dedad90
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf
new file mode 100644
index 0000000..955e4c0
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf
new file mode 100644
index 0000000..67f2473
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf
new file mode 100644
index 0000000..7fed7b2
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf
new file mode 100644
index 0000000..d94e366
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf
new file mode 100644
index 0000000..2f52892
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf
new file mode 100644
index 0000000..211b26d
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf
new file mode 100644
index 0000000..feb7d5c
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf
new file mode 100644
index 0000000..cdab53e
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf
new file mode 100644
index 0000000..1d35e58
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf
new file mode 100644
index 0000000..7ad50fc
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf
new file mode 100644
index 0000000..762e33d
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf
new file mode 100644
index 0000000..6b2570d
--- /dev/null
+++ b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf
deleted file mode 100644
index fb41408..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf
deleted file mode 100644
index e50256d..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf
deleted file mode 100644
index 24f3871..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf
deleted file mode 100644
index 38672ba..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf
deleted file mode 100644
index c5f898e..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf
deleted file mode 100644
index 03cae07..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf
deleted file mode 100644
index 2506a41..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf
deleted file mode 100644
index e8ebeb4..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf
deleted file mode 100644
index 910cc0f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf
deleted file mode 100644
index d7d6972..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf
deleted file mode 100644
index a1c001c..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf
deleted file mode 100644
index 5b41802..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf
deleted file mode 100644
index b88e288..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf
deleted file mode 100644
index 6d95272..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf
deleted file mode 100644
index 251568f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf
deleted file mode 100644
index 2b1d7a7..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
deleted file mode 100644
index dce7f14..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf
deleted file mode 100644
index e1e2245..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf
deleted file mode 100644
index f72cdc9..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 4efa2e2..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf
deleted file mode 100644
index a440b96..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf
deleted file mode 100644
index c503e38..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf
deleted file mode 100644
index d36d155..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf
deleted file mode 100644
index 34a8469..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf
deleted file mode 100644
index d695329..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf
deleted file mode 100644
index 1c4d2b5..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf
deleted file mode 100644
index e5981f0..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf
deleted file mode 100644
index 4b76f1c..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf
deleted file mode 100644
index cf60215..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf
deleted file mode 100644
index bf353ed..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf
deleted file mode 100644
index a7b67bf..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf
deleted file mode 100644
index 7c6805d..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf
deleted file mode 100644
index b1876b6..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf
deleted file mode 100644
index b07778f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf
deleted file mode 100644
index fb77632..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf
deleted file mode 100644
index 4ec322c..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf
deleted file mode 100644
index ec20755..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf
deleted file mode 100644
index bf2c086..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf
deleted file mode 100644
index 0a3721e..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf
deleted file mode 100644
index eaaa56d..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..9a7689e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..0e41c75
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..5830ba8
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..2b59c26
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf
new file mode 100644
index 0000000..7883f60
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf
new file mode 100644
index 0000000..0c61722
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..6be7ed3
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..7ff9072
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf
new file mode 100644
index 0000000..4aac45a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..0c8bdd4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..bc44565
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf
new file mode 100644
index 0000000..095724d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..8deb80f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..e03436c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf
new file mode 100644
index 0000000..6042d7e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf
new file mode 100644
index 0000000..e49657f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..e4e2ad6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf
new file mode 100644
index 0000000..0187125
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf
new file mode 100644
index 0000000..97cbc62
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf
new file mode 100644
index 0000000..eda7a1f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-drop-hints.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..21cfd22
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf
new file mode 100644
index 0000000..7bda9a9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..7557554
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..4dc196a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf
new file mode 100644
index 0000000..bc54e22
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf
new file mode 100644
index 0000000..c1de48f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..d8d6f58
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf
new file mode 100644
index 0000000..094a965
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf
new file mode 100644
index 0000000..7128ec4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..89866d8
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..8d49034
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf
new file mode 100644
index 0000000..10e0362
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..1e91545
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..0c60f01
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf
new file mode 100644
index 0000000..ce7842c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf
new file mode 100644
index 0000000..da265e6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..52018d6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf
new file mode 100644
index 0000000..0ba8353
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf
new file mode 100644
index 0000000..4db7283
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf
new file mode 100644
index 0000000..803cbb6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-name-ids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..62c8632
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..1daaef8
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..59f3b72
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..1827c3f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf
new file mode 100644
index 0000000..3e8d1d3
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf
new file mode 100644
index 0000000..ba0dbd2
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..dafe03c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..e779116
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf
new file mode 100644
index 0000000..7497dae
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..22c1ca8
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..159a573
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf
new file mode 100644
index 0000000..e21ca4f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..fbd6256
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..1dc8d26
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf
new file mode 100644
index 0000000..82fc8b4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf
new file mode 100644
index 0000000..b3f15b5
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..b9ef00e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf
new file mode 100644
index 0000000..77955aa
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf
new file mode 100644
index 0000000..5b4433e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf
new file mode 100644
index 0000000..b6a6e84
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.notdef-outline.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf
deleted file mode 100644
index 5c5ce5c..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf
deleted file mode 100644
index 3b87f54..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf
deleted file mode 100644
index e06a24d..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf
deleted file mode 100644
index aabdc5e..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf
deleted file mode 100644
index 4183c9f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf
deleted file mode 100644
index 66ef901..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf
deleted file mode 100644
index 4bee46f..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf
deleted file mode 100644
index 6e8baa9..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf
deleted file mode 100644
index f6191da..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index bf2746b..0000000
--- a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..b63b9e2
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..15818ed
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..74e2804
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..b7e6b17
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf
new file mode 100644
index 0000000..a342c31
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf
new file mode 100644
index 0000000..e4fcb04
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..04312b7
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..3b7cf7a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf
new file mode 100644
index 0000000..fdd065b
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..1cfbc63
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..27805f7
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf
new file mode 100644
index 0000000..c54052f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..ea4ea20
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..6e74624
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf
new file mode 100644
index 0000000..e7992bf
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf
new file mode 100644
index 0000000..f31ed37
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..6c3b011
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf
new file mode 100644
index 0000000..dc5c3f7
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf
new file mode 100644
index 0000000..516dd0e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf
new file mode 100644
index 0000000..31a1023
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-drop-hints.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..3dcee76
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf
new file mode 100644
index 0000000..8ce23a5
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..e2b6cf9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..7aea89a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf
new file mode 100644
index 0000000..6156ca9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf
new file mode 100644
index 0000000..eb132d1
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..434d6d6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf
new file mode 100644
index 0000000..0dfaad4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf
new file mode 100644
index 0000000..6d72bbd
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..76ecdba
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..387a7cc
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf
new file mode 100644
index 0000000..c232dec
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..35b2f8d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..b043082
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf
new file mode 100644
index 0000000..3df697a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf
new file mode 100644
index 0000000..5719734
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..a15a74a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf
new file mode 100644
index 0000000..05bc0fb
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf
new file mode 100644
index 0000000..26d7721
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf
new file mode 100644
index 0000000..7294e69
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-name-ids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..908dfd6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..4da6787
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..dad8165
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..7788698
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf
new file mode 100644
index 0000000..85c157f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf
new file mode 100644
index 0000000..8ffddaa
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..1fb7a4c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..f446067
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf
new file mode 100644
index 0000000..7c2ea2e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..10e5374
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..e4d4b36
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf
new file mode 100644
index 0000000..31dbcd9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..8a708ba
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..dee6213
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf
new file mode 100644
index 0000000..b8d991e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf
new file mode 100644
index 0000000..a939f5a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..ef379a0
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf
new file mode 100644
index 0000000..aac127a
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf
new file mode 100644
index 0000000..b4461a4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf
new file mode 100644
index 0000000..2c3cfd4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font2.notdef-outline.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf
new file mode 100644
index 0000000..5045cb3
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf
new file mode 100644
index 0000000..f911e0e
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf
new file mode 100644
index 0000000..ea7411a
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf
new file mode 100644
index 0000000..9ac8407
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf
new file mode 100644
index 0000000..d3fc1d2
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf
new file mode 100644
index 0000000..7119a37
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf
new file mode 100644
index 0000000..98a36ef
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf
new file mode 100644
index 0000000..65547c3
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf
new file mode 100644
index 0000000..00eb43e
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf
new file mode 100644
index 0000000..7d6e3c0
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf
new file mode 100644
index 0000000..81e540e
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf
new file mode 100644
index 0000000..7e87237
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf
new file mode 100644
index 0000000..b1c100e
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf
new file mode 100644
index 0000000..1e63412
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf
new file mode 100644
index 0000000..65547c3
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf
new file mode 100644
index 0000000..7cc71b1
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf
new file mode 100644
index 0000000..2c5d33c
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf
new file mode 100644
index 0000000..81e540e
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf
new file mode 100644
index 0000000..275d198
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf
new file mode 100644
index 0000000..73e6b97
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf
new file mode 100644
index 0000000..30ed3b8
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf
new file mode 100644
index 0000000..5045cb3
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf
new file mode 100644
index 0000000..1fad08b
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf
new file mode 100644
index 0000000..adb431c
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf
new file mode 100644
index 0000000..9ac8407
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf
new file mode 100644
index 0000000..3d01daa
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf
new file mode 100644
index 0000000..7823ed8
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf
new file mode 100644
index 0000000..c8d4ccd
--- /dev/null
+++ b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
new file mode 100644
index 0000000..67020e2
--- /dev/null
+++ b/test/subset/data/expected/colr_with_components/colr-table.default.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
new file mode 100644
index 0000000..a2be484
--- /dev/null
+++ b/test/subset/data/expected/colr_with_components/colr-table.drop-hints-retain-gids.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
new file mode 100644
index 0000000..67020e2
--- /dev/null
+++ b/test/subset/data/expected/colr_with_components/colr-table.drop-hints.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf b/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
new file mode 100644
index 0000000..a2be484
--- /dev/null
+++ b/test/subset/data/expected/colr_with_components/colr-table.retain-gids.6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002,E003.ttf
new file mode 100644
index 0000000..c7fafc1
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002.ttf
new file mode 100644
index 0000000..78634bb
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001,E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001.ttf
new file mode 100644
index 0000000..7a490cb
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf
new file mode 100644
index 0000000..bab0b4f
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E000.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000.ttf
new file mode 100644
index 0000000..764be9b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E000.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E001.ttf
new file mode 100644
index 0000000..0a381b7
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf
new file mode 100644
index 0000000..7d094e0
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003.ttf
new file mode 100644
index 0000000..82dd4b9
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002.ttf
new file mode 100644
index 0000000..c2e76cc
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf
new file mode 100644
index 0000000..af8c79b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003.ttf
new file mode 100644
index 0000000..2ea7578
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.E004.ttf
new file mode 100644
index 0000000..d547667
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..b0e9865
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002,E003.ttf
new file mode 100644
index 0000000..929a9ed
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002.ttf
new file mode 100644
index 0000000..5516df3
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001,E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001.ttf
new file mode 100644
index 0000000..d529046
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf
new file mode 100644
index 0000000..3e9abac
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000.ttf
new file mode 100644
index 0000000..f5f0e0b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E000.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E001.ttf
new file mode 100644
index 0000000..a98ed2e
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf
new file mode 100644
index 0000000..25b5aed
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003.ttf
new file mode 100644
index 0000000..b8b3e90
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002.ttf
new file mode 100644
index 0000000..85e2f68
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf
new file mode 100644
index 0000000..f983408
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003.ttf
new file mode 100644
index 0000000..907da5f
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E004.ttf
new file mode 100644
index 0000000..66528df
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..ec3ddec
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002,E003.ttf
new file mode 100644
index 0000000..714c9c8
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002.ttf
new file mode 100644
index 0000000..437a67d
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001,E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001.ttf
new file mode 100644
index 0000000..2729c8d
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf
new file mode 100644
index 0000000..2c87b3d
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000.ttf
new file mode 100644
index 0000000..56e3835
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E000.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E001.ttf
new file mode 100644
index 0000000..80d281f
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf
new file mode 100644
index 0000000..dde87f7
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003.ttf
new file mode 100644
index 0000000..b06cf18
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002.ttf
new file mode 100644
index 0000000..89520f0
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf
new file mode 100644
index 0000000..50be561
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003.ttf
new file mode 100644
index 0000000..b05b82b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E004.ttf
new file mode 100644
index 0000000..f6a12e2
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..ec3ddec
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002,E003.ttf
new file mode 100644
index 0000000..ff537f1
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002.ttf
new file mode 100644
index 0000000..e548a8b
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001,E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001.ttf
new file mode 100644
index 0000000..cb5a94d
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf
new file mode 100644
index 0000000..5d72345
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000.ttf
new file mode 100644
index 0000000..fe1a85c
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E000.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E001.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E001.ttf
new file mode 100644
index 0000000..f25586a
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E001.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf
new file mode 100644
index 0000000..549b52d
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003.ttf
new file mode 100644
index 0000000..bc43627
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002,E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002.ttf
new file mode 100644
index 0000000..f99b3dd
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E002.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf
new file mode 100644
index 0000000..ec25389
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003,E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003.ttf
new file mode 100644
index 0000000..4e6ef19
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E003.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E004.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E004.ttf
new file mode 100644
index 0000000..756ea5f
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.E004.ttf
Binary files differ
diff --git a/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..b0e9865
--- /dev/null
+++ b/test/subset/data/expected/colrv1/TestCOLRv1.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
index e8b7b37..95852e3 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
index 912e1fb..e2fe6e6 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
index 6f19df6..372c13b 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
index 9ea42ab..d1fd6d5 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
index 4d12593..429e4ce 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
index 281b475..6f7c0c1 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf
new file mode 100644
index 0000000..43edc2c
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf
new file mode 100644
index 0000000..d049757
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 0000000..205e9a8
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
new file mode 100644
index 0000000..930d871
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf
new file mode 100644
index 0000000..d049757
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf
new file mode 100644
index 0000000..205e9a8
--- /dev/null
+++ b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.63,64,65,6F,70,71,72.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.63,64,65,6F,70,71,72.ttf
new file mode 100644
index 0000000..8ba3b02
--- /dev/null
+++ b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.63,64,65,6F,70,71,72.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..8ba3b02
--- /dev/null
+++ b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.63,64,65,6F,70,71,72.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.63,64,65,6F,70,71,72.ttf
new file mode 100644
index 0000000..cc0e68f
--- /dev/null
+++ b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.63,64,65,6F,70,71,72.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cc0e68f
--- /dev/null
+++ b/test/subset/data/expected/glyf_bug_3131/glyf_bug_3131.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.0x0,0x8,0x9,0x1d,0x20,0xb7.ttf b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.0x0,0x8,0x9,0x1d,0x20,0xb7.ttf
new file mode 100644
index 0000000..dd2bf2c
--- /dev/null
+++ b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.0x0,0x8,0x9,0x1d,0x20,0xb7.ttf
Binary files differ
diff --git a/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..d45c856
--- /dev/null
+++ b/test/subset/data/expected/glyph_names/Ubuntu-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf
new file mode 100644
index 0000000..5b6005d
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf
new file mode 100644
index 0000000..c8cefe9
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
index 6770dac..b009502 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
index 0c66219..5fda0ef 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
index 4a5a6f8..76e7dd9 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
index 465ce34..6ce2200 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
index 28f3c37..722d033 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf
new file mode 100644
index 0000000..a6685d8
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf
new file mode 100644
index 0000000..5e28a0d
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
index 1bebda7..f9d7a81 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
index a43998d..d4c020c 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
index 34c7788..5a8a939 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
index 92ec10b..7074f54 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
index b9bb539..54baae4 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf
new file mode 100644
index 0000000..5b6005d
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf
new file mode 100644
index 0000000..c8cefe9
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf
new file mode 100644
index 0000000..b009502
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf
new file mode 100644
index 0000000..5fda0ef
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf
new file mode 100644
index 0000000..76e7dd9
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf
new file mode 100644
index 0000000..6ce2200
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf
new file mode 100644
index 0000000..722d033
--- /dev/null
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..ca18f67
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..5fe0af5
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..29e9b9c
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..cecfb20
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..d2507fa
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..dcc3e3f
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf
new file mode 100644
index 0000000..801a547
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf
new file mode 100644
index 0000000..ccc8d06
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf
new file mode 100644
index 0000000..2045896
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..d2507fa
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..70dd0fd
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..f9349f6
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..0ec5c0b
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..531d6e2
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..07e6ad5
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..070f9ec
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
new file mode 100644
index 0000000..60fd45c
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf
new file mode 100644
index 0000000..0ff1503
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf
new file mode 100644
index 0000000..b3b1e4b
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..07e6ad5
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..8ecfac1
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..9969bd5
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..1072cdc
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..3a8173b
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..fc0dcbb
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..51340dd
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf
new file mode 100644
index 0000000..72cf50c
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf
new file mode 100644
index 0000000..157c302
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf
new file mode 100644
index 0000000..662a36f
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..fc0dcbb
--- /dev/null
+++ b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
new file mode 100644
index 0000000..d53abcb
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cdd6bc7
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
new file mode 100644
index 0000000..f3ca7d8
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..0de5e98
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
new file mode 100644
index 0000000..d53abcb
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.20,2f,38,49,4c,51,53,66,67,6f,b4,2044.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cdd6bc7
--- /dev/null
+++ b/test/subset/data/expected/layout.duplicate_features/AlegreyaSans-BlackItalic.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf
new file mode 100644
index 0000000..de9a5ee
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf
new file mode 100644
index 0000000..af784fe
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf
new file mode 100644
index 0000000..3ee2ab5
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..ab0c1d1
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf
new file mode 100644
index 0000000..4e138dd
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf
new file mode 100644
index 0000000..ac0c32d
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf
new file mode 100644
index 0000000..00abf00
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..2306381
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf
new file mode 100644
index 0000000..de9a5ee
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf
new file mode 100644
index 0000000..af784fe
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf
new file mode 100644
index 0000000..3ee2ab5
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
new file mode 100644
index 0000000..ab0c1d1
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
new file mode 100644
index 0000000..e939b0b
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..798b856
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..a0d7fee
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
new file mode 100644
index 0000000..68654ea
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41,56,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..6e0aa21
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
new file mode 100644
index 0000000..600edf9
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test-retain-gids.42,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
new file mode 100644
index 0000000..0606b02
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
new file mode 100644
index 0000000..76fb186
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
new file mode 100644
index 0000000..13437bc
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
new file mode 100644
index 0000000..64e299a
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41,56,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
new file mode 100644
index 0000000..ada8cb6
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
new file mode 100644
index 0000000..e38300e
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.layout-test.42,57.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.9dd.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.9dd.ttf
new file mode 100644
index 0000000..3110b2e
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.9dd.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..7f9a3b1
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.9dd.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.9dd.ttf
new file mode 100644
index 0000000..731dae6
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.9dd.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..148b318
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.9dd.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.9dd.ttf
new file mode 100644
index 0000000..16355fe
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.9dd.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..80a1439
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef.glyphset/IndicTestHowrah-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf
new file mode 100644
index 0000000..863fce8
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf
new file mode 100644
index 0000000..efc3e47
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf
new file mode 100644
index 0000000..9d794ef
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf
new file mode 100644
index 0000000..e1d1605
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf
new file mode 100644
index 0000000..1f5721d
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf
new file mode 100644
index 0000000..0a8dcb0
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf
new file mode 100644
index 0000000..b3fc9df
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf
new file mode 100644
index 0000000..d553a87
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf
new file mode 100644
index 0000000..edaadc5
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf
new file mode 100644
index 0000000..7098c08
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf
new file mode 100644
index 0000000..863fce8
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf
new file mode 100644
index 0000000..efc3e47
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf
new file mode 100644
index 0000000..9d794ef
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf
new file mode 100644
index 0000000..e1d1605
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf
new file mode 100644
index 0000000..1f5721d
--- /dev/null
+++ b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf
deleted file mode 100644
index 6b2879f..0000000
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf
deleted file mode 100644
index eebb3e1..0000000
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf
deleted file mode 100644
index c271bde..0000000
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 2d6962b..0000000
--- a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..1e59c75
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf
new file mode 100644
index 0000000..67d882b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..77ab03a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf
new file mode 100644
index 0000000..35f81e5
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf
new file mode 100644
index 0000000..148c9ca
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.43,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..24f1c46
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf
new file mode 100644
index 0000000..21a9b63
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf
new file mode 100644
index 0000000..78e4ab8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf
new file mode 100644
index 0000000..8a17ae6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf
new file mode 100644
index 0000000..6bb5293
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf
new file mode 100644
index 0000000..354ace8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.43,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..24f1c46
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf
deleted file mode 100644
index 49039fe..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf
deleted file mode 100644
index 68cb0ec..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 8f18b89..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf
deleted file mode 100644
index 47fea1a..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf
deleted file mode 100644
index 99e813f..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index 8f18b89..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf
new file mode 100644
index 0000000..e56914e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf
new file mode 100644
index 0000000..3c6c260
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf
new file mode 100644
index 0000000..2250037
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..e32d342
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..a047174
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf
new file mode 100644
index 0000000..99f8761
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf
new file mode 100644
index 0000000..2fc6e5f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf
new file mode 100644
index 0000000..e7dead8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf
new file mode 100644
index 0000000..969d156
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..a047174
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf
deleted file mode 100644
index b34a49f..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf
deleted file mode 100644
index 2ad1d29..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 88e6046..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf
deleted file mode 100644
index 195c8dc..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf
deleted file mode 100644
index d10d362..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index 88e6046..0000000
--- a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf
new file mode 100644
index 0000000..2c67f99
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf
new file mode 100644
index 0000000..267bec4
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf
new file mode 100644
index 0000000..ee13a7f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..b2ec05c
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..b9c03f0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf
new file mode 100644
index 0000000..693e784
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf
new file mode 100644
index 0000000..2c0626a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf
new file mode 100644
index 0000000..bac77bb
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.2E,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf
new file mode 100644
index 0000000..82d4b3a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..b9c03f0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf
deleted file mode 100644
index 17aa6d8..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf
deleted file mode 100644
index 9e6f2eb..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf
deleted file mode 100644
index 0187ed7..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index d9b5dfb..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf
deleted file mode 100644
index f3ca19a..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf
deleted file mode 100644
index 2a8114a..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf
deleted file mode 100644
index 1426d50..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index d9b5dfb..0000000
--- a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf
new file mode 100644
index 0000000..4784f61
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf
new file mode 100644
index 0000000..25ab8a0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf
new file mode 100644
index 0000000..f6225b2
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..2742c80
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..308dcb8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf
new file mode 100644
index 0000000..1111175
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf
new file mode 100644
index 0000000..a0f56c9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf
new file mode 100644
index 0000000..9e882c1
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf
new file mode 100644
index 0000000..c7a4eb4
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..308dcb8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf
new file mode 100644
index 0000000..af2af9f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf
new file mode 100644
index 0000000..9a74dd1
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..2c72bad
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..dab6fdd
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf
new file mode 100644
index 0000000..9c0853b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf
new file mode 100644
index 0000000..5f57975
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf
new file mode 100644
index 0000000..3dcc084
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..ada1a54
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..656c6e3
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..8dd5444
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf
new file mode 100644
index 0000000..58889d6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf
new file mode 100644
index 0000000..8c0c211
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..3aff353
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf
new file mode 100644
index 0000000..cb75819
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf
new file mode 100644
index 0000000..9776758
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf
new file mode 100644
index 0000000..bc06070
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf
new file mode 100644
index 0000000..3d87498
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf
new file mode 100644
index 0000000..fc99dd8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf
new file mode 100644
index 0000000..6395a87
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..8dd5444
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf
new file mode 100644
index 0000000..0313313
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf
new file mode 100644
index 0000000..99116b4
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..564d0c5
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf
new file mode 100644
index 0000000..1dcc5bd
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf
new file mode 100644
index 0000000..9c330c7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..1965933
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..8ee98e9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..10c7629
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf
new file mode 100644
index 0000000..f7e92d6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..32ffff9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf
new file mode 100644
index 0000000..6ff7711
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf
new file mode 100644
index 0000000..bf8265e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..8f41e96
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf
new file mode 100644
index 0000000..63d5b1a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf
new file mode 100644
index 0000000..2d5de06
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf
new file mode 100644
index 0000000..aecd96a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf
new file mode 100644
index 0000000..19b6c7b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf
new file mode 100644
index 0000000..81b6196
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf
new file mode 100644
index 0000000..4ac9a09
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..32ffff9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos5/gpos5_font1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf
new file mode 100644
index 0000000..8f46239
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf
new file mode 100644
index 0000000..e1ae2bc
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..42b332e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..8028c9d
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf
new file mode 100644
index 0000000..3e9f1e7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf
new file mode 100644
index 0000000..ea47831
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf
new file mode 100644
index 0000000..79206e8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..db066b7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..7019ee3
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..59c911d
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf
new file mode 100644
index 0000000..b4d50a9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf
new file mode 100644
index 0000000..e39e1b9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..a328c7e
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf
new file mode 100644
index 0000000..5b6424a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf
new file mode 100644
index 0000000..21b1983
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf
new file mode 100644
index 0000000..c23f81b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,44.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf
new file mode 100644
index 0000000..69b2e46
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43,45.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf
new file mode 100644
index 0000000..d533fa0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf
new file mode 100644
index 0000000..3cbf9fd
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..59c911d
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos6/gpos6_font1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 0000000..8c905f6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf
new file mode 100644
index 0000000..b286e53
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf
new file mode 100644
index 0000000..dd9e475
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf
new file mode 100644
index 0000000..6c8c557
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf
new file mode 100644
index 0000000..f04f721
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 0000000..c37f0b6
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf
new file mode 100644
index 0000000..5559015
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf
new file mode 100644
index 0000000..c1c9fa3
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf
new file mode 100644
index 0000000..fd99ae3
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf
new file mode 100644
index 0000000..b5a7b43
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..445f567
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..456575a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..f1d3e43
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..bc47f58
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..babb9d5
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..f1d3e43
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..77f9ce0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..60bf6f0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..7d4dea0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..e57101a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..41bc343
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..7d4dea0
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..09452d9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..66edc45
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..554fb54
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..f72d0cc
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..33abe62
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..554fb54
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..c382ed2
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..0ff63b9
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf
new file mode 100644
index 0000000..7981553
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test-retain-gids.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf
new file mode 100644
index 0000000..f2406c5
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf
new file mode 100644
index 0000000..32f8025
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf
new file mode 100644
index 0000000..da45812
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos9/gpos9_font2.layout-test.42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf
new file mode 100644
index 0000000..9a58fee
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9,53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf
new file mode 100644
index 0000000..c5c9146
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53A9.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf
new file mode 100644
index 0000000..1b11e10
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..7249c5a
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf
new file mode 100644
index 0000000..91357c9
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9,53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf
new file mode 100644
index 0000000..df08b73
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53A9.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf
new file mode 100644
index 0000000..39da89b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.53F1.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..51afa40
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..ed8a98b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..33c8824
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..8148021
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..24e6b78
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..0ff250b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf
new file mode 100644
index 0000000..bde0da1
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf
new file mode 100644
index 0000000..d34cc87
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf
new file mode 100644
index 0000000..e62f795
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf
new file mode 100644
index 0000000..649e446
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..0ff250b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..1d3f3cd
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..5a0d0c4
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..27b29e5
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..f4fa0e9
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..b3d6ae9
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
new file mode 100644
index 0000000..0a693c6
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
new file mode 100644
index 0000000..128c1d4
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf
new file mode 100644
index 0000000..f4a46ef
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf
new file mode 100644
index 0000000..00d4707
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..b3d6ae9
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..bfe6624
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf
new file mode 100644
index 0000000..808ba68
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf
new file mode 100644
index 0000000..5bb167e
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..8844949
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..a012ff1
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..a00ab82
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf
new file mode 100644
index 0000000..0cfcad6
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,42.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf
new file mode 100644
index 0000000..3d96d48
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf
new file mode 100644
index 0000000..51c6316
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..a012ff1
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.268,301,302,324.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.268,301,302,324.ttf
new file mode 100644
index 0000000..82cc953
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.268,301,302,324.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..06d1fad
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.268,301,302,324.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.268,301,302,324.ttf
new file mode 100644
index 0000000..ceafb38
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.268,301,302,324.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.retain-all-codepoint.ttf
new file mode 100644
index 0000000..895a035
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub5_format2/Molengo-Regular.layout-test.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
deleted file mode 100644
index e10d863..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 1f90754..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf
deleted file mode 100644
index bdaa805..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index 1f90754..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..c38bb18
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..ea05697
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..be5c742
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..9c6cf18
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..e5e4cfb
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..be5c742
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
deleted file mode 100644
index 856249e..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index e764393..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf
deleted file mode 100644
index a53b114..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index e764393..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..e5b9d6e
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..dcf5a16
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..3072df6
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..ef1bc2d
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
new file mode 100644
index 0000000..f89f5b8
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..3072df6
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf
deleted file mode 100644
index 2d08eb0..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf
deleted file mode 100644
index 737f85a..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf
deleted file mode 100644
index fbd9a44..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf
deleted file mode 100644
index 737f85a..0000000
--- a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..eb573b0
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..f5dd384
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..73d92d4
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf
new file mode 100644
index 0000000..16d2b34
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf
new file mode 100644
index 0000000..6623508
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..73d92d4
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf
new file mode 100644
index 0000000..4e0b307
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47,48,49.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf
new file mode 100644
index 0000000..28bc409
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,47.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf
new file mode 100644
index 0000000..90e1cdf
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,4D.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf
new file mode 100644
index 0000000..1b07a7a
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46,51.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf
new file mode 100644
index 0000000..ef2bd57
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf
new file mode 100644
index 0000000..ecc3c41
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf
new file mode 100644
index 0000000..eb60c6b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf
new file mode 100644
index 0000000..275b11b
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.61.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..d29304c
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf
new file mode 100644
index 0000000..f149bbf
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47,48,49.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf
new file mode 100644
index 0000000..3475f4e
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,47.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf
new file mode 100644
index 0000000..8e8c4de
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,4D.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf
new file mode 100644
index 0000000..cd519a5
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46,51.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf
new file mode 100644
index 0000000..063ac99
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43,44,45,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf
new file mode 100644
index 0000000..9ee6ccf
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41,42,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf
new file mode 100644
index 0000000..0cb632a
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.41.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf
new file mode 100644
index 0000000..ec09bf0
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.61.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf
new file mode 100644
index 0000000..d29304c
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.layout-test.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf
new file mode 100644
index 0000000..d6544fb
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf
new file mode 100644
index 0000000..65c84c3
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf
new file mode 100644
index 0000000..4a6b93d
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf
new file mode 100644
index 0000000..7d1c5ec
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf
new file mode 100644
index 0000000..07c8389
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf
new file mode 100644
index 0000000..0c03905
--- /dev/null
+++ b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 0000000..e6c8b6f
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf
new file mode 100644
index 0000000..bf2ff01
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf
new file mode 100644
index 0000000..1c0f0e9
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf
new file mode 100644
index 0000000..9424060
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf
new file mode 100644
index 0000000..fdd0b84
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf
new file mode 100644
index 0000000..6580937
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,623,62D,644,627,645,2E.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf
new file mode 100644
index 0000000..64d8565
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D,628.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf
new file mode 100644
index 0000000..cb2e429
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf
new file mode 100644
index 0000000..be237a7
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.633,645,627,621,20,644,627.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf
new file mode 100644
index 0000000..d69ba99
--- /dev/null
+++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
new file mode 100644
index 0000000..d289df2
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..5e7157d
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
new file mode 100644
index 0000000..31b87ec
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..e7b13f2
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
new file mode 100644
index 0000000..d289df2
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..5e7157d
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
new file mode 100644
index 0000000..6c9e2d3
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.5bf,5f0,5f1,5f2,fb21,fb22,fb23,fb24,fb25,fb26,fb27,fb28.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..401187c
--- /dev/null
+++ b/test/subset/data/expected/layout.tinos/Tinos-Italic.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf
new file mode 100644
index 0000000..3fb42c6
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..376ecc8
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf
new file mode 100644
index 0000000..a0b6145
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
new file mode 100644
index 0000000..b299db7
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.layout-test.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf
new file mode 100644
index 0000000..012bb16
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.392,3a7,3b2,3c7.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..f3f6f4a
--- /dev/null
+++ b/test/subset/data/expected/layout.unsorted_featurelist/NotoIKEAHebrewLatin-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf
new file mode 100644
index 0000000..908d200
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf
new file mode 100644
index 0000000..483e409
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf
new file mode 100644
index 0000000..f3685e4
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf
new file mode 100644
index 0000000..b33c28f
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf
new file mode 100644
index 0000000..c6098b2
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf
deleted file mode 100644
index aa007ba..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf
deleted file mode 100644
index f3be30c..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf
deleted file mode 100644
index 44c329e..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf
deleted file mode 100644
index b0a1ea3..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf
deleted file mode 100644
index 16ad9d5..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf
deleted file mode 100644
index d0d9d5a..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf
deleted file mode 100644
index f4d881f..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf
deleted file mode 100644
index 9e6dd28..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf
deleted file mode 100644
index 50260c5..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf
deleted file mode 100644
index 22d5b61..0000000
--- a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf
new file mode 100644
index 0000000..fb0bbad
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf
new file mode 100644
index 0000000..6d30e6d
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf
new file mode 100644
index 0000000..24bfcaf
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf
new file mode 100644
index 0000000..37b6cee
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf
new file mode 100644
index 0000000..0445fd8
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.default.2f,7c,305.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.default.2f,7c,305.ttf
new file mode 100644
index 0000000..e662f4c
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.default.2f,7c,305.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..3c2434d
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.2f,7c,305.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.2f,7c,305.ttf
new file mode 100644
index 0000000..b757c5c
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.2f,7c,305.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
new file mode 100644
index 0000000..7ff30bb
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.glyph-names.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.2f,7c,305.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.2f,7c,305.ttf
new file mode 100644
index 0000000..a93fdbb
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.2f,7c,305.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
new file mode 100644
index 0000000..db3f9a1
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.notdef-outline.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.2f,7c,305.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.2f,7c,305.ttf
new file mode 100644
index 0000000..77a8636
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.2f,7c,305.ttf
Binary files differ
diff --git a/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cce064f
--- /dev/null
+++ b/test/subset/data/expected/math/STIXTwoMath-Regular.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.default.58,59.ttf b/test/subset/data/expected/sbix/sbix.default.58,59.ttf
new file mode 100644
index 0000000..e34206f
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.default.58,59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.default.58.ttf b/test/subset/data/expected/sbix/sbix.default.58.ttf
new file mode 100644
index 0000000..1a341f2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.default.58.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.default.59.ttf b/test/subset/data/expected/sbix/sbix.default.59.ttf
new file mode 100644
index 0000000..fa8b291
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.default.59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf
new file mode 100644
index 0000000..b6996f2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf
new file mode 100644
index 0000000..ea593b2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf
new file mode 100644
index 0000000..7ad2194
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf
new file mode 100644
index 0000000..b6996f2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf
new file mode 100644
index 0000000..ea593b2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf
new file mode 100644
index 0000000..6e7b201
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf
new file mode 100644
index 0000000..e34206f
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf
new file mode 100644
index 0000000..1a341f2
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf
Binary files differ
diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf
new file mode 100644
index 0000000..32379ea
--- /dev/null
+++ b/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf
Binary files differ
diff --git a/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf b/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf
new file mode 100644
index 0000000..10e5fe3
--- /dev/null
+++ b/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf
Binary files differ
diff --git a/test/subset/data/expected/variable/Fraunces.default.61.ttf b/test/subset/data/expected/variable/Fraunces.default.61.ttf
new file mode 100644
index 0000000..bc03e40
--- /dev/null
+++ b/test/subset/data/expected/variable/Fraunces.default.61.ttf
Binary files differ
diff --git a/test/subset/data/fonts/AdobeBlank-Regular.ttf b/test/subset/data/fonts/AdobeBlank-Regular.ttf
new file mode 100644
index 0000000..817f51a
--- /dev/null
+++ b/test/subset/data/fonts/AdobeBlank-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/AdobeVFPrototype.otf b/test/subset/data/fonts/AdobeVFPrototype.otf
new file mode 100644
index 0000000..2f1b173
--- /dev/null
+++ b/test/subset/data/fonts/AdobeVFPrototype.otf
Binary files differ
diff --git a/test/subset/data/fonts/AlegreyaSans-BlackItalic.ttf b/test/subset/data/fonts/AlegreyaSans-BlackItalic.ttf
new file mode 100644
index 0000000..76a389d
--- /dev/null
+++ b/test/subset/data/fonts/AlegreyaSans-BlackItalic.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Amiri-Regular.ttf b/test/subset/data/fonts/Amiri-Regular.ttf
new file mode 100644
index 0000000..508a1bf
--- /dev/null
+++ b/test/subset/data/fonts/Amiri-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Fraunces.ttf b/test/subset/data/fonts/Fraunces.ttf
new file mode 100644
index 0000000..8210f94
--- /dev/null
+++ b/test/subset/data/fonts/Fraunces.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Harmattan-Regular.ttf b/test/subset/data/fonts/Harmattan-Regular.ttf
new file mode 100644
index 0000000..0100cf4
--- /dev/null
+++ b/test/subset/data/fonts/Harmattan-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/IndicTestHowrah-Regular.ttf b/test/subset/data/fonts/IndicTestHowrah-Regular.ttf
new file mode 100644
index 0000000..f761b7f
--- /dev/null
+++ b/test/subset/data/fonts/IndicTestHowrah-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf b/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf
new file mode 100644
index 0000000..4d73975
--- /dev/null
+++ b/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Khmer.ttf b/test/subset/data/fonts/Khmer.ttf
new file mode 100644
index 0000000..4c37487
--- /dev/null
+++ b/test/subset/data/fonts/Khmer.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Molengo-Regular.ttf b/test/subset/data/fonts/Molengo-Regular.ttf
new file mode 100644
index 0000000..da82a52
--- /dev/null
+++ b/test/subset/data/fonts/Molengo-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf b/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf
new file mode 100644
index 0000000..73b395e
--- /dev/null
+++ b/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf
new file mode 100644
index 0000000..885059a
--- /dev/null
+++ b/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf
new file mode 100644
index 0000000..df1ff9b
--- /dev/null
+++ b/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
new file mode 100644
index 0000000..cdccded
--- /dev/null
+++ b/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.ttf
new file mode 100644
index 0000000..14a544a
--- /dev/null
+++ b/test/subset/data/fonts/NotoColorEmoji.subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoColrEmojiGlyf-Regular.subset.ttf b/test/subset/data/fonts/NotoColrEmojiGlyf-Regular.subset.ttf
new file mode 100644
index 0000000..76f565b
--- /dev/null
+++ b/test/subset/data/fonts/NotoColrEmojiGlyf-Regular.subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoIKEAHebrewLatin-Regular.ttf b/test/subset/data/fonts/NotoIKEAHebrewLatin-Regular.ttf
new file mode 100644
index 0000000..7566808
--- /dev/null
+++ b/test/subset/data/fonts/NotoIKEAHebrewLatin-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf
new file mode 100644
index 0000000..d05dabe
--- /dev/null
+++ b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf b/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf
new file mode 100644
index 0000000..1437c34
--- /dev/null
+++ b/test/subset/data/fonts/NotoNastaliqUrdu-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/NotoSerifMyanmar-Regular.otf b/test/subset/data/fonts/NotoSerifMyanmar-Regular.otf
new file mode 100644
index 0000000..ec4ed44
--- /dev/null
+++ b/test/subset/data/fonts/NotoSerifMyanmar-Regular.otf
Binary files differ
diff --git a/test/subset/data/fonts/STIXTwoMath-Regular.ttf b/test/subset/data/fonts/STIXTwoMath-Regular.ttf
new file mode 100644
index 0000000..351bfab
--- /dev/null
+++ b/test/subset/data/fonts/STIXTwoMath-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/SourceSerifVariable-Roman.ttf b/test/subset/data/fonts/SourceSerifVariable-Roman.ttf
new file mode 100644
index 0000000..4a73845
--- /dev/null
+++ b/test/subset/data/fonts/SourceSerifVariable-Roman.ttf
Binary files differ
diff --git a/test/subset/data/fonts/TestCOLRv1.ttf b/test/subset/data/fonts/TestCOLRv1.ttf
new file mode 100644
index 0000000..631da66
--- /dev/null
+++ b/test/subset/data/fonts/TestCOLRv1.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Tinos-Italic.ttf b/test/subset/data/fonts/Tinos-Italic.ttf
new file mode 100644
index 0000000..851621e
--- /dev/null
+++ b/test/subset/data/fonts/Tinos-Italic.ttf
Binary files differ
diff --git a/test/subset/data/fonts/TwemojiMozilla.subset.ttf b/test/subset/data/fonts/TwemojiMozilla.subset.ttf
new file mode 100644
index 0000000..357dda3
--- /dev/null
+++ b/test/subset/data/fonts/TwemojiMozilla.subset.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Ubuntu-Regular.ttf b/test/subset/data/fonts/Ubuntu-Regular.ttf
new file mode 100644
index 0000000..2001d6e
--- /dev/null
+++ b/test/subset/data/fonts/Ubuntu-Regular.ttf
Binary files differ
diff --git a/test/subset/data/fonts/cmap14_font2.otf b/test/subset/data/fonts/cmap14_font2.otf
new file mode 100644
index 0000000..4a7da80
--- /dev/null
+++ b/test/subset/data/fonts/cmap14_font2.otf
Binary files differ
diff --git a/test/subset/data/fonts/colr-table.ttf b/test/subset/data/fonts/colr-table.ttf
new file mode 100644
index 0000000..c4b2a55
--- /dev/null
+++ b/test/subset/data/fonts/colr-table.ttf
Binary files differ
diff --git a/test/subset/data/fonts/glyf_bug_3131.ttf b/test/subset/data/fonts/glyf_bug_3131.ttf
new file mode 100644
index 0000000..a251936
--- /dev/null
+++ b/test/subset/data/fonts/glyf_bug_3131.ttf
Binary files differ
diff --git a/test/subset/data/fonts/gpos2_2_font5.otf b/test/subset/data/fonts/gpos2_2_font5.otf
index 63af3bc..19833cf 100644
--- a/test/subset/data/fonts/gpos2_2_font5.otf
+++ b/test/subset/data/fonts/gpos2_2_font5.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos4_multiple_anchors_1.otf b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf
new file mode 100644
index 0000000..e77cbb6
--- /dev/null
+++ b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos5_font1.otf b/test/subset/data/fonts/gpos5_font1.otf
new file mode 100644
index 0000000..c7e2132
--- /dev/null
+++ b/test/subset/data/fonts/gpos5_font1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos6_font1.otf b/test/subset/data/fonts/gpos6_font1.otf
new file mode 100644
index 0000000..fd640ac
--- /dev/null
+++ b/test/subset/data/fonts/gpos6_font1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos9_font2.otf b/test/subset/data/fonts/gpos9_font2.otf
new file mode 100644
index 0000000..1378f81
--- /dev/null
+++ b/test/subset/data/fonts/gpos9_font2.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf
new file mode 100644
index 0000000..721115e
--- /dev/null
+++ b/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf
new file mode 100644
index 0000000..ef7f635
--- /dev/null
+++ b/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_chaining3_simple_f1.otf b/test/subset/data/fonts/gpos_chaining3_simple_f1.otf
new file mode 100644
index 0000000..b6f1863
--- /dev/null
+++ b/test/subset/data/fonts/gpos_chaining3_simple_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf
new file mode 100644
index 0000000..fc84d1f
--- /dev/null
+++ b/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf
new file mode 100644
index 0000000..c5afd3e
--- /dev/null
+++ b/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos_context3_simple_f1.otf b/test/subset/data/fonts/gpos_context3_simple_f1.otf
new file mode 100644
index 0000000..fad7550
--- /dev/null
+++ b/test/subset/data/fonts/gpos_context3_simple_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub8_manually_created.otf b/test/subset/data/fonts/gsub8_manually_created.otf
new file mode 100644
index 0000000..00cbb4b
--- /dev/null
+++ b/test/subset/data/fonts/gsub8_manually_created.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_alternate_substitution.otf b/test/subset/data/fonts/gsub_alternate_substitution.otf
new file mode 100644
index 0000000..188b8e8
--- /dev/null
+++ b/test/subset/data/fonts/gsub_alternate_substitution.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf b/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf
new file mode 100644
index 0000000..cb62adb
--- /dev/null
+++ b/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf b/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf
new file mode 100644
index 0000000..fe5b94b
--- /dev/null
+++ b/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_context3_successive_f1.otf b/test/subset/data/fonts/gsub_context3_successive_f1.otf
new file mode 100644
index 0000000..682520a
--- /dev/null
+++ b/test/subset/data/fonts/gsub_context3_successive_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/sbix.ttf b/test/subset/data/fonts/sbix.ttf
new file mode 100644
index 0000000..575af90
--- /dev/null
+++ b/test/subset/data/fonts/sbix.ttf
Binary files differ
diff --git a/test/subset/data/profiles/gids.txt b/test/subset/data/profiles/gids.txt
new file mode 100644
index 0000000..4fa4f6e
--- /dev/null
+++ b/test/subset/data/profiles/gids.txt
@@ -0,0 +1 @@
+--gids=1,2,3
diff --git a/test/subset/data/profiles/glyph-names.txt b/test/subset/data/profiles/glyph-names.txt
new file mode 100644
index 0000000..57df5af
--- /dev/null
+++ b/test/subset/data/profiles/glyph-names.txt
@@ -0,0 +1 @@
+--glyph-names
diff --git a/test/subset/data/profiles/keep-all-layout-features.txt b/test/subset/data/profiles/keep-all-layout-features.txt
new file mode 100644
index 0000000..97241e0
--- /dev/null
+++ b/test/subset/data/profiles/keep-all-layout-features.txt
@@ -0,0 +1 @@
+--layout-features=*
diff --git a/test/subset/data/profiles/keep-gdef-gpos.txt b/test/subset/data/profiles/keep-gdef-gpos.txt
new file mode 100644
index 0000000..071f341
--- /dev/null
+++ b/test/subset/data/profiles/keep-gdef-gpos.txt
@@ -0,0 +1 @@
+--drop-tables-=GDEF,GPOS
diff --git a/test/subset/data/profiles/keep-gdef.txt b/test/subset/data/profiles/keep-gdef.txt
new file mode 100644
index 0000000..4252d67
--- /dev/null
+++ b/test/subset/data/profiles/keep-gdef.txt
@@ -0,0 +1 @@
+--drop-tables-=GDEF
diff --git a/test/subset/data/profiles/keep-layout-retain-gids.txt b/test/subset/data/profiles/keep-layout-retain-gids.txt
deleted file mode 100644
index f4787ad..0000000
--- a/test/subset/data/profiles/keep-layout-retain-gids.txt
+++ /dev/null
@@ -1,2 +0,0 @@
---drop-tables-=GSUB,GPOS
---retain-gids
diff --git a/test/subset/data/profiles/keep-layout.txt b/test/subset/data/profiles/keep-layout.txt
deleted file mode 100644
index 56da0ff..0000000
--- a/test/subset/data/profiles/keep-layout.txt
+++ /dev/null
@@ -1 +0,0 @@
---drop-tables-=GSUB,GPOS
diff --git a/test/subset/data/profiles/layout-features.txt b/test/subset/data/profiles/layout-features.txt
new file mode 100644
index 0000000..15456e6
--- /dev/null
+++ b/test/subset/data/profiles/layout-features.txt
@@ -0,0 +1 @@
+--layout-features=kern,mark,liga
diff --git a/test/subset/data/profiles/layout-test-retain-gids.txt b/test/subset/data/profiles/layout-test-retain-gids.txt
new file mode 100644
index 0000000..63c67eb
--- /dev/null
+++ b/test/subset/data/profiles/layout-test-retain-gids.txt
@@ -0,0 +1,3 @@
+--layout-features=*
+--notdef-outline
+--retain-gids
diff --git a/test/subset/data/profiles/layout-test.txt b/test/subset/data/profiles/layout-test.txt
new file mode 100644
index 0000000..d98633a
--- /dev/null
+++ b/test/subset/data/profiles/layout-test.txt
@@ -0,0 +1,2 @@
+--layout-features=*
+--notdef-outline
diff --git a/test/subset/data/profiles/name-languages.txt b/test/subset/data/profiles/name-languages.txt
new file mode 100644
index 0000000..1a6f933
--- /dev/null
+++ b/test/subset/data/profiles/name-languages.txt
@@ -0,0 +1 @@
+--name-languages=*
diff --git a/test/subset/data/profiles/name-legacy.txt b/test/subset/data/profiles/name-legacy.txt
new file mode 100644
index 0000000..1867445
--- /dev/null
+++ b/test/subset/data/profiles/name-legacy.txt
@@ -0,0 +1 @@
+--name-legacy
diff --git a/test/subset/data/profiles/no-prune-unicode-ranges.txt b/test/subset/data/profiles/no-prune-unicode-ranges.txt
new file mode 100644
index 0000000..4d6872a
--- /dev/null
+++ b/test/subset/data/profiles/no-prune-unicode-ranges.txt
@@ -0,0 +1 @@
+--no-prune-unicode-ranges
diff --git a/test/subset/data/profiles/notdef-outline-desubroutinize-retain-gids.txt b/test/subset/data/profiles/notdef-outline-desubroutinize-retain-gids.txt
new file mode 100644
index 0000000..8648705
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-desubroutinize-retain-gids.txt
@@ -0,0 +1,3 @@
+--notdef-outline
+--desubroutinize
+--retain-gids
diff --git a/test/subset/data/profiles/notdef-outline-desubroutinize.txt b/test/subset/data/profiles/notdef-outline-desubroutinize.txt
new file mode 100644
index 0000000..c5f0ac5
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-desubroutinize.txt
@@ -0,0 +1,2 @@
+--notdef-outline
+--desubroutinize
diff --git a/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize-retain-gids.txt b/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize-retain-gids.txt
new file mode 100644
index 0000000..22236be
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize-retain-gids.txt
@@ -0,0 +1,4 @@
+--notdef-outline
+--no-hinting
+--desubroutinize
+--retain-gids
diff --git a/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize.txt b/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize.txt
new file mode 100644
index 0000000..a1fd783
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-drop-hints-desubroutinize.txt
@@ -0,0 +1,3 @@
+--notdef-outline
+--no-hinting
+--desubroutinize
diff --git a/test/subset/data/profiles/notdef-outline-drop-hints-retain-gids.txt b/test/subset/data/profiles/notdef-outline-drop-hints-retain-gids.txt
new file mode 100644
index 0000000..1f98591
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-drop-hints-retain-gids.txt
@@ -0,0 +1,3 @@
+--notdef-outline
+--no-hinting
+--retain-gids
diff --git a/test/subset/data/profiles/notdef-outline-drop-hints.txt b/test/subset/data/profiles/notdef-outline-drop-hints.txt
new file mode 100644
index 0000000..10fb10c
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-drop-hints.txt
@@ -0,0 +1,2 @@
+--notdef-outline
+--no-hinting
diff --git a/test/subset/data/profiles/notdef-outline-gids.txt b/test/subset/data/profiles/notdef-outline-gids.txt
new file mode 100644
index 0000000..ab9c86a
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-gids.txt
@@ -0,0 +1,2 @@
+--notdef-outline
+--gids=1,2,3
diff --git a/test/subset/data/profiles/notdef-outline-name-ids.txt b/test/subset/data/profiles/notdef-outline-name-ids.txt
new file mode 100644
index 0000000..8f66494
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-name-ids.txt
@@ -0,0 +1,2 @@
+--notdef-outline
+--name-IDs=0,1,2
diff --git a/test/subset/data/profiles/notdef-outline-retain-gids.txt b/test/subset/data/profiles/notdef-outline-retain-gids.txt
new file mode 100644
index 0000000..277308e
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline-retain-gids.txt
@@ -0,0 +1,2 @@
+--notdef-outline
+--retain-gids
diff --git a/test/subset/data/profiles/notdef-outline.txt b/test/subset/data/profiles/notdef-outline.txt
new file mode 100644
index 0000000..3a5e4f5
--- /dev/null
+++ b/test/subset/data/profiles/notdef-outline.txt
@@ -0,0 +1 @@
+--notdef-outline
diff --git a/test/subset/data/repack_tests/Makefile.am b/test/subset/data/repack_tests/Makefile.am
new file mode 100644
index 0000000..f85af6a
--- /dev/null
+++ b/test/subset/data/repack_tests/Makefile.am
@@ -0,0 +1,21 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+CLEANFILES =
+SUBDIRS =
+
+# Convenience targets:
+lib: libs # Always build subsetter lib in this subdir
+libs:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
+
+TEST_EXTENSIONS = .tests
+TESTS_LOG_COMPILER = $(srcdir)/../../run-repack-tests.py $(top_builddir)/util/hb-subset$(EXEEXT)
+include Makefile.sources
+
+EXTRA_DIST += \
+	$(TESTS) \
+	$(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/test/subset/data/repack_tests/Makefile.sources b/test/subset/data/repack_tests/Makefile.sources
new file mode 100644
index 0000000..9e85174
--- /dev/null
+++ b/test/subset/data/repack_tests/Makefile.sources
@@ -0,0 +1,14 @@
+TESTS = \
+	basic.tests \
+	prioritization.tests \
+	table_duplication.tests \
+        isolation.tests \
+	advanced_prioritization.tests \
+	space_splitting.tests \
+	$(NULL)
+
+XFAIL_TESTS = \
+	$(NULL)
+
+DISABLED_TESTS = \
+	$(NULL)
diff --git a/test/subset/data/repack_tests/advanced_prioritization.tests b/test/subset/data/repack_tests/advanced_prioritization.tests
new file mode 100644
index 0000000..adcbb00
--- /dev/null
+++ b/test/subset/data/repack_tests/advanced_prioritization.tests
@@ -0,0 +1,72 @@
+NotoNastaliqUrdu-Bold.ttf
+0x0020
+0x0028
+0x0029
+0x002C
+0x002D
+0x002E
+0x0030
+0x0031
+0x0032
+0x0033
+0x0034
+0x0035
+0x0036
+0x0037
+0x0038
+0x0039
+0x003A
+0x060C
+0x061F
+0x0621
+0x0622
+0x0623
+0x0624
+0x0625
+0x0626
+0x0627
+0x0628
+0x0629
+0x062A
+0x062B
+0x062C
+0x062D
+0x062E
+0x062F
+0x0630
+0x0631
+0x0632
+0x0633
+0x0634
+0x0635
+0x0636
+0x0637
+0x0638
+0x0639
+0x063A
+0x0640
+0x0641
+0x0642
+0x0643
+0x0644
+0x0645
+0x0646
+0x0647
+0x0648
+0x0649
+0x064A
+0x064B
+0x064C
+0x064F
+0x0651
+0x067E
+0x0686
+0x0698
+0x06A9
+0x06AF
+0x06BE
+0x06CC
+0x200C
+0x200D
+0x200E
+
diff --git a/test/subset/data/repack_tests/basic.tests b/test/subset/data/repack_tests/basic.tests
new file mode 100644
index 0000000..896cc9b
--- /dev/null
+++ b/test/subset/data/repack_tests/basic.tests
@@ -0,0 +1,52 @@
+NotoNastaliqUrdu-Bold.ttf
+0x060C
+0x061F
+0x0621
+0x0622
+0x0623
+0x0624
+0x0625
+0x0626
+0x0627
+0x0628
+0x0629
+0x062A
+0x062B
+0x062C
+0x062D
+0x062E
+0x062F
+0x0630
+0x0631
+0x0632
+0x0633
+0x0634
+0x0635
+0x0636
+0x0637
+0x0638
+0x0639
+0x063A
+0x0640
+0x0641
+0x0642
+0x0643
+0x0644
+0x0645
+0x0646
+0x0647
+0x0648
+0x0649
+0x064A
+0x064B
+0x064F
+0x0651
+0x067E
+0x0686
+0x0698
+0x06A9
+0x06AF
+0x06CC
+0x200C
+0x200D
+0x200E
diff --git a/test/subset/data/repack_tests/isolation.tests b/test/subset/data/repack_tests/isolation.tests
new file mode 100644
index 0000000..46317b5
--- /dev/null
+++ b/test/subset/data/repack_tests/isolation.tests
@@ -0,0 +1,96 @@
+NotoNastaliqUrdu-Regular.ttf
+0x0020
+0x060b
+0x0621
+0x0622
+0x0623
+0x0624
+0x0625
+0x0626
+0x0627
+0x0628
+0x0629
+0x062a
+0x062b
+0x062c
+0x062d
+0x062e
+0x062f
+0x0630
+0x0631
+0x0632
+0x0633
+0x0634
+0x0635
+0x0636
+0x0637
+0x0638
+0x0639
+0x063a
+0x0641
+0x0642
+0x0643
+0x0644
+0x0645
+0x0646
+0x0647
+0x0648
+0x0649
+0x064a
+0x0653
+0x0654
+0x0655
+0x0671
+0x0679
+0x067a
+0x067b
+0x067c
+0x067d
+0x067e
+0x067f
+0x0680
+0x0681
+0x0683
+0x0684
+0x0685
+0x0686
+0x0687
+0x0688
+0x0689
+0x068a
+0x068c
+0x068d
+0x068f
+0x0691
+0x0693
+0x0696
+0x0698
+0x0699
+0x069a
+0x06a4
+0x06a6
+0x06a9
+0x06ab
+0x06af
+0x06b1
+0x06b3
+0x06ba
+0x06bb
+0x06bc
+0x06be
+0x06c0
+0x06c1
+0x06c2
+0x06c3
+0x06cc
+0x06cd
+0x06d0
+0x06d2
+0x06d3
+0x06d5
+0x06de
+0x06e9
+0xfdf2
+0xfdfa
+0xfdfc
+0xfdfd
diff --git a/test/subset/data/repack_tests/prioritization.tests b/test/subset/data/repack_tests/prioritization.tests
new file mode 100644
index 0000000..63b437c
--- /dev/null
+++ b/test/subset/data/repack_tests/prioritization.tests
@@ -0,0 +1,77 @@
+NotoNastaliqUrdu-Bold.ttf
+0x0020
+0x0028
+0x0029
+0x002C
+0x002D
+0x002E
+0x0030
+0x0031
+0x0032
+0x0033
+0x0034
+0x0035
+0x0036
+0x0037
+0x0038
+0x0039
+0x003A
+0x060C
+0x061F
+0x0621
+0x0622
+0x0623
+0x0624
+0x0625
+0x0626
+0x0627
+0x0628
+0x0629
+0x062A
+0x062B
+0x062C
+0x062D
+0x062E
+0x062F
+0x0630
+0x0631
+0x0632
+0x0633
+0x0634
+0x0635
+0x0636
+0x0637
+0x0638
+0x0639
+0x063A
+0x0640
+0x0641
+0x0642
+0x0643
+0x0644
+0x0645
+0x0646
+0x0647
+0x0648
+0x0649
+0x064A
+0x064B
+0x064F
+0x0651
+0x0653
+0x0679
+0x067E
+0x0686
+0x0688
+0x0691
+0x0698
+0x06A9
+0x06AF
+0x06BA
+0x06BE
+0x06C1
+0x06CC
+0x06D2
+0x200C
+0x200D
+0x200E
diff --git a/test/subset/data/repack_tests/space_splitting.tests b/test/subset/data/repack_tests/space_splitting.tests
new file mode 100644
index 0000000..0c1f179
--- /dev/null
+++ b/test/subset/data/repack_tests/space_splitting.tests
@@ -0,0 +1,2 @@
+Harmattan-Regular.ttf
+*
diff --git a/test/subset/data/repack_tests/table_duplication.tests b/test/subset/data/repack_tests/table_duplication.tests
new file mode 100644
index 0000000..3cc90d6
--- /dev/null
+++ b/test/subset/data/repack_tests/table_duplication.tests
@@ -0,0 +1,97 @@
+NotoNastaliqUrdu-Bold.ttf
+0x0028
+0x0029
+0x002C
+0x002D
+0x002E
+0x0030
+0x0031
+0x0032
+0x0033
+0x0034
+0x0035
+0x0036
+0x0037
+0x0038
+0x0039
+0x003A
+0x0041
+0x0042
+0x0043
+0x0044
+0x0045
+0x0046
+0x0047
+0x0048
+0x0049
+0x004C
+0x004D
+0x004E
+0x004F
+0x0050
+0x0052
+0x0053
+0x0054
+0x0055
+0x0056
+0x0057
+0x0061
+0x0062
+0x0063
+0x0064
+0x0065
+0x0066
+0x0067
+0x0068
+0x0069
+0x006B
+0x006C
+0x006D
+0x006E
+0x006F
+0x0070
+0x0072
+0x0073
+0x0074
+0x0075
+0x0076
+0x0077
+0x0078
+0x0079
+0x060C
+0x0626
+0x0627
+0x0628
+0x062A
+0x062C
+0x062D
+0x062E
+0x062F
+0x0631
+0x0632
+0x0633
+0x0634
+0x0635
+0x0636
+0x0637
+0x0638
+0x0639
+0x0641
+0x0642
+0x0644
+0x0645
+0x0646
+0x0648
+0x0653
+0x0679
+0x067E
+0x0686
+0x0688
+0x0691
+0x06A9
+0x06AF
+0x06BA
+0x06BE
+0x06C1
+0x06CC
+0x06D2
diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests
index 772f33c..12ac8b0 100644
--- a/test/subset/data/tests/basics.tests
+++ b/test/subset/data/tests/basics.tests
@@ -1,13 +1,22 @@
 FONTS:
 Roboto-Regular.abc.ttf
 Comfortaa-Regular-new.ttf
+NanumMyeongjo-Regular-subset.ttf
 
 PROFILES:
 default.txt
 drop-hints.txt
 drop-hints-retain-gids.txt
 retain-gids.txt
+notdef-outline.txt
 name-ids.txt
+name-languages.txt
+name-legacy.txt
+gids.txt
+layout-features.txt
+keep-all-layout-features.txt
+no-prune-unicode-ranges.txt
+glyph-names.txt
 
 SUBSETS:
 abc
diff --git a/test/subset/data/tests/cbdt.tests b/test/subset/data/tests/cbdt.tests
new file mode 100644
index 0000000..5e74fef
--- /dev/null
+++ b/test/subset/data/tests/cbdt.tests
@@ -0,0 +1,20 @@
+FONTS:
+NotoColorEmoji.subset.ttf
+NotoColorEmoji.subset.index_format3.ttf
+NotoColorEmoji.subset.multiple_size_tables.ttf
+NotoColorEmoji.subset.gap.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+89®⁉8⃣
+8®⁉
+8⁉

+9
+⁉
+8⃣
diff --git a/test/subset/data/tests/cff-full-font.tests b/test/subset/data/tests/cff-full-font.tests
index e55f21e..babcacd 100644
--- a/test/subset/data/tests/cff-full-font.tests
+++ b/test/subset/data/tests/cff-full-font.tests
@@ -2,17 +2,16 @@
 SourceSansPro-Regular.otf
 
 PROFILES:
-default.txt
-drop-hints.txt
-drop-hints-retain-gids.txt
-retain-gids.txt
-desubroutinize.txt
-desubroutinize-retain-gids.txt
-drop-hints-desubroutinize.txt
-drop-hints-desubroutinize-retain-gids.txt
+notdef-outline.txt
+notdef-outline-drop-hints.txt
+notdef-outline-drop-hints-retain-gids.txt
+notdef-outline-retain-gids.txt
+notdef-outline-desubroutinize.txt
+notdef-outline-desubroutinize-retain-gids.txt
+notdef-outline-drop-hints-desubroutinize.txt
+notdef-outline-drop-hints-desubroutinize-retain-gids.txt
 
 SUBSETS:
 abc
 Ǽ!A bc
 ×ØÙÚÞ
-
diff --git a/test/subset/data/tests/cff-japanese.tests b/test/subset/data/tests/cff-japanese.tests
index d69396f..a0a9c6f 100644
--- a/test/subset/data/tests/cff-japanese.tests
+++ b/test/subset/data/tests/cff-japanese.tests
@@ -17,6 +17,3 @@
 明極珠度輸清
 あいうえおか
 あいう珠度輸
-
-
-
diff --git a/test/subset/data/tests/cff.notoserifmyanmar.tests b/test/subset/data/tests/cff.notoserifmyanmar.tests
new file mode 100644
index 0000000..155d062
--- /dev/null
+++ b/test/subset/data/tests/cff.notoserifmyanmar.tests
@@ -0,0 +1,9 @@
+FONTS:
+NotoSerifMyanmar-Regular.otf
+
+PROFILES:
+notdef-outline.txt
+
+SUBSETS:
+႒
+#စက်ပစ္စည်းတွေ၊
diff --git a/test/subset/data/tests/cmap.tests b/test/subset/data/tests/cmap.tests
new file mode 100644
index 0000000..7d5cba7
--- /dev/null
+++ b/test/subset/data/tests/cmap.tests
@@ -0,0 +1,16 @@
+FONTS:
+AdobeBlank-Regular.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+name-ids.txt
+
+SUBSETS:
+ﻺ
+ﻹﻺ
+ﻦﻏ
+ab
+aﻺ
diff --git a/test/subset/data/tests/cmap14.tests b/test/subset/data/tests/cmap14.tests
index 6575870..abfec32 100644
--- a/test/subset/data/tests/cmap14.tests
+++ b/test/subset/data/tests/cmap14.tests
@@ -1,12 +1,14 @@
 FONTS:
 cmap14_font1.otf
+cmap14_font2.otf
 
 PROFILES:
-default.txt
-drop-hints.txt
-drop-hints-retain-gids.txt
-retain-gids.txt
-name-ids.txt
+notdef-outline.txt
+notdef-outline-drop-hints.txt
+notdef-outline-drop-hints-retain-gids.txt
+notdef-outline-retain-gids.txt
+notdef-outline-name-ids.txt
+notdef-outline-gids.txt
 
 SUBSETS:
 一丂七
diff --git a/test/subset/data/tests/colr.tests b/test/subset/data/tests/colr.tests
new file mode 100644
index 0000000..5da60b6
--- /dev/null
+++ b/test/subset/data/tests/colr.tests
@@ -0,0 +1,17 @@
+FONTS:
+TwemojiMozilla.subset.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+2
+㊗
+㊙
+2㊗
+2㊙
+㊗㊙
+2㊗㊙
diff --git a/test/subset/data/tests/colr_with_components.tests b/test/subset/data/tests/colr_with_components.tests
new file mode 100644
index 0000000..5d7c66e
--- /dev/null
+++ b/test/subset/data/tests/colr_with_components.tests
@@ -0,0 +1,11 @@
+FONTS:
+colr-table.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+k
diff --git a/test/subset/data/tests/colrv1.notoemoji.tests b/test/subset/data/tests/colrv1.notoemoji.tests
new file mode 100644
index 0000000..f5bd276
--- /dev/null
+++ b/test/subset/data/tests/colrv1.notoemoji.tests
@@ -0,0 +1,12 @@
+FONTS:
+NotoColrEmojiGlyf-Regular.subset.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+U+1f696
+U+1f35e
diff --git a/test/subset/data/tests/colrv1.tests b/test/subset/data/tests/colrv1.tests
new file mode 100644
index 0000000..a15ad92
--- /dev/null
+++ b/test/subset/data/tests/colrv1.tests
@@ -0,0 +1,23 @@
+FONTS:
+TestCOLRv1.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+U+E000
+U+E001
+U+E002
+U+E003
+U+E004
+U+E000,U+E001
+U+E002,U+E003
+U+E000,U+E004
+U+E003,U+E004
+U+E000,U+E001,U+E002
+U+E000,U+E001,U+E002,U+E003
+U+E002,U+E003,U+E004
+*
diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests
index 225bb48..d9519b6 100644
--- a/test/subset/data/tests/full-font.tests
+++ b/test/subset/data/tests/full-font.tests
@@ -1,5 +1,6 @@
 FONTS:
 Roboto-Regular.ttf
+SourceSerifVariable-Roman.ttf
 
 PROFILES:
 default.txt
diff --git a/test/subset/data/tests/glyf_bug_3131.tests b/test/subset/data/tests/glyf_bug_3131.tests
new file mode 100644
index 0000000..d0fd5dc
--- /dev/null
+++ b/test/subset/data/tests/glyf_bug_3131.tests
@@ -0,0 +1,11 @@
+# Tests for https://github.com/harfbuzz/harfbuzz/issues/3131
+FONTS:
+glyf_bug_3131.ttf
+
+PROFILES:
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+cdeopqr
+*
diff --git a/test/subset/data/tests/glyph_names.tests b/test/subset/data/tests/glyph_names.tests
new file mode 100644
index 0000000..a710a39
--- /dev/null
+++ b/test/subset/data/tests/glyph_names.tests
@@ -0,0 +1,9 @@
+FONTS:
+Ubuntu-Regular.ttf
+
+PROFILES:
+glyph-names.txt
+
+SUBSETS:
+U+0x0,U+0x8,U+0x9,U+0x1d,U+0x20,U+0xb7
+*
diff --git a/test/subset/data/tests/japanese.tests b/test/subset/data/tests/japanese.tests
index 5a04380..110fe07 100644
--- a/test/subset/data/tests/japanese.tests
+++ b/test/subset/data/tests/japanese.tests
@@ -4,6 +4,7 @@
 PROFILES:
 default.txt
 drop-hints.txt
+keep-gdef.txt
 
 SUBSETS:

@@ -11,6 +12,5 @@
 明極珠度輸清
 あいうえおか
 あいう珠度輸
-
-
-
+𝜕𝟘AB
+𥝱
diff --git a/test/subset/data/tests/layout.context.tests b/test/subset/data/tests/layout.context.tests
new file mode 100644
index 0000000..dacd555
--- /dev/null
+++ b/test/subset/data/tests/layout.context.tests
@@ -0,0 +1,15 @@
+FONTS:
+gpos_context1_multiple_subrules_f1.otf
+gpos_context2_multiple_subrules_f1.otf
+gpos_context3_simple_f1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+AB
+AC
+ABC
+*
diff --git a/test/subset/data/tests/layout.duplicate_features.tests b/test/subset/data/tests/layout.duplicate_features.tests
new file mode 100644
index 0000000..d6bc9a2
--- /dev/null
+++ b/test/subset/data/tests/layout.duplicate_features.tests
@@ -0,0 +1,11 @@
+FONTS:
+AlegreyaSans-BlackItalic.ttf
+
+PROFILES:
+default.txt
+glyph-names.txt
+notdef-outline.txt
+
+SUBSETS:
+U+20,U+2f,U+38,U+49,U+4c,U+51,U+53,U+66,U+67,U+6f,U+b4,U+2044
+*
diff --git a/test/subset/data/tests/layout.gdef-attachlist.tests b/test/subset/data/tests/layout.gdef-attachlist.tests
new file mode 100644
index 0000000..b380ac1
--- /dev/null
+++ b/test/subset/data/tests/layout.gdef-attachlist.tests
@@ -0,0 +1,13 @@
+FONTS:
+IndicTestJalandhar-Regular.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+keep-gdef.txt
+
+SUBSETS:
+ਁ
+ਅਆ
+ਇਛ
+*
diff --git a/test/subset/data/tests/layout.gdef-varstore.tests b/test/subset/data/tests/layout.gdef-varstore.tests
new file mode 100644
index 0000000..45b9065
--- /dev/null
+++ b/test/subset/data/tests/layout.gdef-varstore.tests
@@ -0,0 +1,14 @@
+FONTS:
+AdobeVFPrototype.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+AB
+ABC
+BW
+AVW
+ABCW
diff --git a/test/subset/data/tests/layout.gdef.glyphset.tests b/test/subset/data/tests/layout.gdef.glyphset.tests
new file mode 100644
index 0000000..b5591ef
--- /dev/null
+++ b/test/subset/data/tests/layout.gdef.glyphset.tests
@@ -0,0 +1,11 @@
+FONTS:
+IndicTestHowrah-Regular.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+retain-gids.txt
+
+SUBSETS:
+U+9dd
+*
diff --git a/test/subset/data/tests/layout.gdef.tests b/test/subset/data/tests/layout.gdef.tests
new file mode 100644
index 0000000..def862f
--- /dev/null
+++ b/test/subset/data/tests/layout.gdef.tests
@@ -0,0 +1,14 @@
+FONTS:
+Roboto-Regular.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+keep-gdef-gpos.txt
+
+SUBSETS:
+Ḁ̃


+̉ ̏ 
+ABC
diff --git a/test/subset/data/tests/layout.gpos.tests b/test/subset/data/tests/layout.gpos.tests
index 2d0f936..a6d3b83 100644
--- a/test/subset/data/tests/layout.gpos.tests
+++ b/test/subset/data/tests/layout.gpos.tests
@@ -2,10 +2,13 @@
 gpos1_2_font.otf
 
 PROFILES:
-keep-layout-retain-gids.txt
+layout-test.txt
+layout-test-retain-gids.txt
 
 SUBSETS:
+A
 AC
 CF
 AF
+BD
 *
diff --git a/test/subset/data/tests/layout.gpos2.tests b/test/subset/data/tests/layout.gpos2.tests
index 94fe78a..98c9c92 100644
--- a/test/subset/data/tests/layout.gpos2.tests
+++ b/test/subset/data/tests/layout.gpos2.tests
@@ -3,10 +3,12 @@
 gpos2_2_font5.otf
 
 PROFILES:
-keep-layout.txt
-keep-layout-retain-gids.txt
+layout-test.txt
+layout-test-retain-gids.txt
 
 SUBSETS:
 !#
 !#%
+.#
+ABC
 *
diff --git a/test/subset/data/tests/layout.gpos3.tests b/test/subset/data/tests/layout.gpos3.tests
index 409272f..7a129df 100644
--- a/test/subset/data/tests/layout.gpos3.tests
+++ b/test/subset/data/tests/layout.gpos3.tests
@@ -2,11 +2,12 @@
 gpos3_font3.otf
 
 PROFILES:
-keep-layout.txt
-keep-layout-retain-gids.txt
+layout-test.txt
+layout-test-retain-gids.txt
 
 SUBSETS:
 ()
 (+
 )+
+ABC
 *
diff --git a/test/subset/data/tests/layout.gpos4.tests b/test/subset/data/tests/layout.gpos4.tests
new file mode 100644
index 0000000..307a877
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos4.tests
@@ -0,0 +1,18 @@
+FONTS:
+gpos4_multiple_anchors_1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+AB
+AC
+ABC
+ACE
+ABCE
+ACD
+ACDEF
+ABCD
+*
diff --git a/test/subset/data/tests/layout.gpos5.tests b/test/subset/data/tests/layout.gpos5.tests
new file mode 100644
index 0000000..490e34e
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos5.tests
@@ -0,0 +1,18 @@
+FONTS:
+gpos5_font1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+B
+AB
+AC
+ABC
+ABE
+ABCE
+ABD
+ABCD
+*
diff --git a/test/subset/data/tests/layout.gpos6.tests b/test/subset/data/tests/layout.gpos6.tests
new file mode 100644
index 0000000..27202d2
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos6.tests
@@ -0,0 +1,18 @@
+FONTS:
+gpos6_font1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+AB
+AC
+ABC
+ACE
+ABCE
+ACD
+ACDEF
+ABCD
+*
diff --git a/test/subset/data/tests/layout.gpos8.amiri.tests b/test/subset/data/tests/layout.gpos8.amiri.tests
new file mode 100644
index 0000000..183d8a9
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos8.amiri.tests
@@ -0,0 +1,13 @@
+FONTS:
+Amiri-Regular.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+
+SUBSETS:
+ال
+الأحلام.
+غير
+سماء لا
+الحب
diff --git a/test/subset/data/tests/layout.gpos8.tests b/test/subset/data/tests/layout.gpos8.tests
new file mode 100644
index 0000000..5ba9db0
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos8.tests
@@ -0,0 +1,13 @@
+FONTS:
+gpos_chaining1_multiple_subrules_f1.otf
+gpos_chaining2_multiple_subrules_f1.otf
+gpos_chaining3_simple_f1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+0123
+ABC
+*
diff --git a/test/subset/data/tests/layout.gpos9.tests b/test/subset/data/tests/layout.gpos9.tests
new file mode 100644
index 0000000..e1fd928
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos9.tests
@@ -0,0 +1,11 @@
+FONTS:
+gpos9_font2.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+B
+AB
diff --git a/test/subset/data/tests/layout.gsub3.tests b/test/subset/data/tests/layout.gsub3.tests
new file mode 100644
index 0000000..35d02fb
--- /dev/null
+++ b/test/subset/data/tests/layout.gsub3.tests
@@ -0,0 +1,12 @@
+FONTS:
+gsub_alternate_substitution.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+厩
+叱
+厩叱
+*
diff --git a/test/subset/data/tests/layout.gsub5.tests b/test/subset/data/tests/layout.gsub5.tests
new file mode 100644
index 0000000..152a037
--- /dev/null
+++ b/test/subset/data/tests/layout.gsub5.tests
@@ -0,0 +1,15 @@
+FONTS:
+gsub_context1_multiple_subrules_f2.otf
+gsub_context2_multiple_subrules_f2.otf
+gsub_context3_successive_f1.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+A
+AB
+AC
+ABC
+*
diff --git a/test/subset/data/tests/layout.gsub5_format2.tests b/test/subset/data/tests/layout.gsub5_format2.tests
new file mode 100644
index 0000000..8b3d68e
--- /dev/null
+++ b/test/subset/data/tests/layout.gsub5_format2.tests
@@ -0,0 +1,10 @@
+FONTS:
+Molengo-Regular.ttf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+U+268,U+301,U+302,U+324
+*
diff --git a/test/subset/data/tests/layout.gsub6.tests b/test/subset/data/tests/layout.gsub6.tests
index 47399b8..755f71d 100644
--- a/test/subset/data/tests/layout.gsub6.tests
+++ b/test/subset/data/tests/layout.gsub6.tests
@@ -4,9 +4,10 @@
 gsub_chaining3_simple_f2.otf
 
 PROFILES:
-keep-layout.txt
-keep-layout-retain-gids.txt
+layout-test.txt
+layout-test-retain-gids.txt
 
 SUBSETS:
 0123
+ABC
 *
diff --git a/test/subset/data/tests/layout.gsub8.tests b/test/subset/data/tests/layout.gsub8.tests
new file mode 100644
index 0000000..dc17be4
--- /dev/null
+++ b/test/subset/data/tests/layout.gsub8.tests
@@ -0,0 +1,17 @@
+FONTS:
+gsub8_manually_created.otf
+
+PROFILES:
+layout-test.txt
+layout-test-retain-gids.txt
+
+SUBSETS:
+a
+A
+ABC
+ABCDEF
+ABCDEFG
+ABCDEFGHI
+ABCDEFM
+ABCDEFQ
+*
diff --git a/test/subset/data/tests/layout.khmer.tests b/test/subset/data/tests/layout.khmer.tests
new file mode 100644
index 0000000..8c94482
--- /dev/null
+++ b/test/subset/data/tests/layout.khmer.tests
@@ -0,0 +1,11 @@
+FONTS:
+Khmer.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+
+SUBSETS:
+1
+ក
+ញុំបានមើ
diff --git a/test/subset/data/tests/layout.notonastaliqurdu.tests b/test/subset/data/tests/layout.notonastaliqurdu.tests
new file mode 100644
index 0000000..e305117
--- /dev/null
+++ b/test/subset/data/tests/layout.notonastaliqurdu.tests
@@ -0,0 +1,13 @@
+FONTS:
+NotoNastaliqUrdu-Bold.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+
+SUBSETS:
+ال
+الأحلام.
+غير
+سماء لا
+الحب
diff --git a/test/subset/data/tests/layout.tests b/test/subset/data/tests/layout.tests
index dd1c26e..20e6152 100644
--- a/test/subset/data/tests/layout.tests
+++ b/test/subset/data/tests/layout.tests
@@ -2,8 +2,8 @@
 Roboto-Regular.smallcaps.ttf
 
 PROFILES:
-keep-layout.txt
-keep-layout-retain-gids.txt
+default.txt
+retain-gids.txt
 
 SUBSETS:
 ABC
diff --git a/test/subset/data/tests/layout.tinos.tests b/test/subset/data/tests/layout.tinos.tests
new file mode 100644
index 0000000..64a9dab
--- /dev/null
+++ b/test/subset/data/tests/layout.tinos.tests
@@ -0,0 +1,12 @@
+FONTS:
+Tinos-Italic.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+glyph-names.txt
+notdef-outline.txt
+
+SUBSETS:
+U+5bf,U+5f0,U+5f1,U+5f2,U+fb21,U+fb22,U+fb23,U+fb24,U+fb25,U+fb26,U+fb27,U+fb28
+*
diff --git a/test/subset/data/tests/layout.unsorted_featurelist.tests b/test/subset/data/tests/layout.unsorted_featurelist.tests
new file mode 100644
index 0000000..9c77a7a
--- /dev/null
+++ b/test/subset/data/tests/layout.unsorted_featurelist.tests
@@ -0,0 +1,11 @@
+FONTS:
+NotoIKEAHebrewLatin-Regular.ttf
+
+PROFILES:
+layout-test.txt
+default.txt
+retain-gids.txt
+
+SUBSETS:
+U+392,U+3a7,U+3b2,U+3c7
+*
diff --git a/test/subset/data/tests/math.tests b/test/subset/data/tests/math.tests
new file mode 100644
index 0000000..91a2405
--- /dev/null
+++ b/test/subset/data/tests/math.tests
@@ -0,0 +1,12 @@
+FONTS:
+STIXTwoMath-Regular.ttf
+
+PROFILES:
+default.txt
+retain-gids.txt
+glyph-names.txt
+notdef-outline.txt
+
+SUBSETS:
+U+2f,U+7c,U+305
+*
diff --git a/test/subset/data/tests/sbix.tests b/test/subset/data/tests/sbix.tests
new file mode 100644
index 0000000..2796873
--- /dev/null
+++ b/test/subset/data/tests/sbix.tests
@@ -0,0 +1,13 @@
+FONTS:
+sbix.ttf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+
+SUBSETS:
+X
+Y
+XY
diff --git a/test/subset/data/tests/variable.tests b/test/subset/data/tests/variable.tests
new file mode 100644
index 0000000..bda5875
--- /dev/null
+++ b/test/subset/data/tests/variable.tests
@@ -0,0 +1,9 @@
+FONTS:
+Fraunces.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+a
+&fiĤĥ
diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 6c65627..2182643 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -1,41 +1,80 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Pre-generates the expected output subset files (via fonttools) for
 # specified subset test suite(s).
 
-from __future__ import print_function, division, absolute_import
-
-import io
 import os
 import sys
+import shutil
+import io
+import re
+import tempfile
+
+from difflib import unified_diff
+from fontTools.ttLib import TTFont
 
 from subprocess import check_call
 from subset_test_suite import SubsetTestSuite
 
 
 def usage():
-	print("Usage: generate-expected-outputs.py <test suite file> ...")
+	print("Usage: generate-expected-outputs.py hb-subset <test suite file> ...")
 
 
-def generate_expected_output(input_file, unicodes, profile_flags, output_path):
+def strip_check_sum (ttx_string):
+	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
+		       'checkSumAdjustment value="0x00000000"',
+		       ttx_string, count=1)
+
+
+def generate_expected_output(input_file, unicodes, profile_flags, output_directory, font_name):
+	fonttools_path = os.path.join(tempfile.mkdtemp (), font_name)
 	args = ["fonttools", "subset", input_file]
-	args.extend(["--notdef-outline",
-		     "--name-languages=*",
-		     "--name-legacy",
-                     "--layout-features=*",
-		     "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR",
+	args.extend(["--drop-tables+=DSIG",
+		     "--drop-tables-=sbix",
 		     "--unicodes=%s" % unicodes,
-		     "--output-file=%s" % output_path])
+		     "--output-file=%s" % fonttools_path])
 	args.extend(profile_flags)
 	check_call(args)
+	with io.StringIO () as fp:
+		with TTFont (fonttools_path) as font:
+			font.saveXML (fp)
+		fonttools_ttx = strip_check_sum (fp.getvalue ())
+
+	harfbuzz_path = os.path.join(tempfile.mkdtemp (), font_name)
+	args = [
+		hb_subset,
+		"--font-file=" + input_file,
+		"--output-file=" + harfbuzz_path,
+		"--unicodes=%s" % unicodes,
+		"--drop-tables+=DSIG",
+		"--drop-tables-=sbix"]
+	args.extend(profile_flags)
+	check_call(args)
+	with io.StringIO () as fp:
+		with TTFont (harfbuzz_path) as font:
+			font.saveXML (fp)
+		harfbuzz_ttx = strip_check_sum (fp.getvalue ())
+
+	if harfbuzz_ttx != fonttools_ttx:
+		for line in unified_diff (fonttools_ttx.splitlines (1), harfbuzz_ttx.splitlines (1), fonttools_path, harfbuzz_path):
+			sys.stdout.write (line)
+		sys.stdout.flush ()
+		raise Exception ('ttx for fonttools and harfbuzz does not match.')
+
+	output_path = os.path.join(output_directory, font_name)
+	shutil.copy(harfbuzz_path, output_path)
 
 
 args = sys.argv[1:]
 if not args:
 	usage()
+hb_subset, args = args[0], args[1:]
+if not args:
+	usage()
 
 for path in args:
-	with io.open(path, mode="r", encoding="utf-8") as f:
+	with open(path, mode="r", encoding="utf-8") as f:
 		test_suite = SubsetTestSuite(path, f.read())
 		output_directory = test_suite.get_output_directory()
 
@@ -45,5 +84,4 @@
 			font_name = test.get_font_name()
 			print("Creating subset %s/%s" % (output_directory, font_name))
 			generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
-						 os.path.join(output_directory,
-							      font_name))
+						 output_directory, font_name)
diff --git a/test/subset/meson.build b/test/subset/meson.build
new file mode 100644
index 0000000..729aa3b
--- /dev/null
+++ b/test/subset/meson.build
@@ -0,0 +1,89 @@
+tests = [
+  'basics',
+  'full-font',
+  'cff-full-font',
+  'japanese',
+  'cff-japanese',
+  'cff.notoserifmyanmar',
+  'glyf_bug_3131',
+  'layout',
+  'layout.gpos',
+  'layout.gpos2',
+  'layout.gpos3',
+  'layout.gpos4',
+  'layout.gpos5',
+  'layout.gpos6',
+  'layout.gpos8',
+  'layout.gpos8.amiri',
+  'layout.gpos9',
+  'layout.gsub3',
+  'layout.gsub5',
+  'layout.gsub5_format2',
+  'layout.gsub6',
+  'layout.gsub8',
+  'layout.gdef',
+  'layout.gdef.glyphset',
+  'layout.khmer',
+  'layout.context',
+  'layout.gdef-varstore',
+  'layout.gdef-attachlist',
+  'layout.notonastaliqurdu',
+  'layout.tinos',
+  'layout.duplicate_features',
+  'layout.unsorted_featurelist',
+  'cmap',
+  'cmap14',
+  'sbix',
+  'colr',
+  'math',
+# TODO: re-enable once colrv1 subsetting is stabilized.
+# 'colrv1.notoemoji',
+  'colrv1',
+  'colr_with_components',
+  'cbdt',
+  'variable',
+  'glyph_names',
+]
+
+repack_tests = [
+  'basic',
+  'prioritization',
+  'table_duplication',
+  'isolation',
+  'advanced_prioritization',
+  'space_splitting',
+]
+
+
+run_test = find_program('run-tests.py')
+
+foreach t : tests
+  fname = '@0@.tests'.format(t)
+
+  test(t, run_test,
+    args: [
+      hb_subset,
+      join_paths(meson.current_source_dir(), 'data', 'tests', fname),
+    ],
+    # as the tests are ran concurrently let's raise acceptable time here
+    # ideally better to break and let meson handles them in parallel
+    timeout: 500,
+    workdir: join_paths(meson.current_build_dir(), '..', '..'),
+    suite: 'subset',
+  )
+endforeach
+
+run_repack_test = find_program('run-repack-tests.py')
+
+foreach t : repack_tests
+  fname = '@0@.tests'.format(t)
+
+  test(t, run_repack_test,
+    args: [
+      hb_subset,
+      join_paths(meson.current_source_dir(), 'data', 'repack_tests', fname),
+    ],
+    workdir: join_paths(meson.current_build_dir(), '..', '..'),
+    suite: ['subset', 'repack'],
+  )
+endforeach
diff --git a/test/subset/repack_test.py b/test/subset/repack_test.py
new file mode 100644
index 0000000..2b53dd3
--- /dev/null
+++ b/test/subset/repack_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+import os
+
+# Parses a single repacking test file. The first line of the file is
+# the name of the font to use and the remaining lines define the set of
+# codepoints in the subset.
+class RepackTest:
+
+	def __init__(self, test_path, definition):
+		self.test_path = test_path
+		self.font_name = None
+		self.codepoints = set ()
+		self._parse(definition)
+
+	def font_path(self):
+		return os.path.join (self._base_path (), "fonts", self.font_name)
+
+	def codepoints_string (self):
+		return ",".join (self.codepoints)
+
+	def _base_path(self):
+	        return os.path.join(
+		    os.path.dirname(self.test_path),
+		    "../")
+
+
+	def _parse(self, definition):
+		lines = definition.splitlines ()
+		self.font_name = lines.pop (0)
+		for line in lines:
+			line = line.strip()
+			if not line:
+				continue
+
+			self.codepoints.add (line)
diff --git a/test/subset/run-repack-tests.py b/test/subset/run-repack-tests.py
new file mode 100755
index 0000000..9c25b2b
--- /dev/null
+++ b/test/subset/run-repack-tests.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+
+# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
+# to subsetting via fonttools.
+
+from difflib import unified_diff
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import shutil
+import io
+
+from repack_test import RepackTest
+
+try:
+	from fontTools.ttLib import TTFont
+except ImportError:
+	print ("fonttools is not present, skipping test.")
+	sys.exit (77)
+
+ots_sanitize = shutil.which ("ots-sanitize")
+
+def subset_cmd (command):
+	global hb_subset, process
+	print (hb_subset + ' ' + " ".join(command))
+	process.stdin.write ((';'.join (command) + '\n').encode ("utf-8"))
+	process.stdin.flush ()
+	return process.stdout.readline().decode ("utf-8").strip ()
+
+def cmd (command):
+	p = subprocess.Popen (
+		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+		universal_newlines=True)
+	(stdoutdata, stderrdata) = p.communicate ()
+	print (stderrdata, end="", file=sys.stderr)
+	return stdoutdata, p.returncode
+
+def fail_test (test, cli_args, message):
+	print ('ERROR: %s' % message)
+	print ('Test State:')
+	print ('  test.font_name    %s' % test.font_name)
+	print ('  test.test_path %s' % os.path.abspath (test.test_path))
+	return 1
+
+def run_test (test, should_check_ots):
+	out_file = os.path.join (tempfile.mkdtemp (), test.font_name + '-subset.ttf')
+	cli_args = ["--font-file=" + test.font_path (),
+		    "--output-file=" + out_file,
+		    "--unicodes=%s" % test.codepoints_string (),
+		    "--drop-tables-=GPOS,GSUB,GDEF",]
+	print (' '.join (cli_args))
+	ret = subset_cmd (cli_args)
+
+	if ret != "success":
+		return fail_test (test, cli_args, "%s failed" % ' '.join (cli_args))
+
+	try:
+		with TTFont (out_file) as font:
+			pass
+	except Exception as e:
+		print (e)
+		return fail_test (test, cli_args, "ttx failed to parse the result")
+
+	if should_check_ots:
+		print ("Checking output with ots-sanitize.")
+		if not check_ots (out_file):
+			return fail_test (test, cli_args, 'ots for subsetted file fails.')
+
+	return 0
+
+def has_ots ():
+	if not ots_sanitize:
+		print ("OTS is not present, skipping all ots checks.")
+		return False
+	return True
+
+def check_ots (path):
+	ots_report, returncode = cmd ([ots_sanitize, path])
+	if returncode:
+		print ("OTS Failure: %s" % ots_report)
+		return False
+	return True
+
+args = sys.argv[1:]
+if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
+	sys.exit ("First argument does not seem to point to usable hb-subset.")
+hb_subset, args = args[0], args[1:]
+
+if len (args) != 1:
+	sys.exit ("No tests supplied.")
+
+has_ots = has_ots()
+
+process = subprocess.Popen ([hb_subset, '--batch'],
+                            stdin=subprocess.PIPE,
+                            stdout=subprocess.PIPE,
+                            stderr=sys.stdout)
+
+fails = 0
+
+path = args[0]
+if not path.endswith(".tests"):
+        sys.exit ("Not a valid test case path.")
+
+with open (path, mode="r", encoding="utf-8") as f:
+	# TODO(garretrieger): re-enable OTS checking.
+	fails += run_test (RepackTest (path, f.read ()), False)
+
+
+if fails != 0:
+	sys.exit ("%d test(s) failed." % fails)
+else:
+	print ("All tests passed.")
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index 5d221e6..79830c4 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -1,150 +1,148 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 # Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
 # to subsetting via fonttools.
 
-from __future__ import print_function, division, absolute_import
-
-import io
 from difflib import unified_diff
 import os
 import re
 import subprocess
 import sys
 import tempfile
+import shutil
+import io
+import hashlib
 
 from subset_test_suite import SubsetTestSuite
 
-# https://stackoverflow.com/a/377028
-def which (program):
-	def is_exe (fpath):
-		return os.path.isfile (fpath) and os.access (fpath, os.X_OK)
+try:
+	from fontTools.ttLib import TTFont
+except ImportError:
+    TTFont = None
 
-	fpath, _ = os.path.split (program)
-	if fpath:
-		if is_exe (program):
-			return program
-	else:
-		for path in os.environ["PATH"].split (os.pathsep):
-			exe_file = os.path.join (path, program)
-			if is_exe (exe_file):
-				return exe_file
+ots_sanitize = shutil.which ("ots-sanitize")
 
-	return None
+def subset_cmd (command):
+	global hb_subset, process
+	print (hb_subset + ' ' + " ".join(command))
+	process.stdin.write ((';'.join (command) + '\n').encode ("utf-8"))
+	process.stdin.flush ()
+	return process.stdout.readline().decode ("utf-8").strip ()
 
-fonttools = which ("fonttools")
-ots_sanitize = which ("ots-sanitize")
-
-if not fonttools:
-	print ("fonttools is not present, skipping test.")
-	sys.exit (77)
-
-def cmd(command):
+def cmd (command):
 	p = subprocess.Popen (
-		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+		universal_newlines=True)
 	(stdoutdata, stderrdata) = p.communicate ()
-	print (stderrdata, end="") # file=sys.stderr
+	print (stderrdata, end="", file=sys.stderr)
 	return stdoutdata, p.returncode
 
-def read_binary (file_path):
-	with open (file_path, 'rb') as f:
-		return f.read ()
-
 def fail_test (test, cli_args, message):
 	print ('ERROR: %s' % message)
 	print ('Test State:')
 	print ('  test.font_path    %s' % os.path.abspath (test.font_path))
 	print ('  test.profile_path %s' % os.path.abspath (test.profile_path))
 	print ('  test.unicodes	    %s' % test.unicodes ())
-	expected_file = os.path.join(test_suite.get_output_directory (),
-				     test.get_font_name ())
+	expected_file = os.path.join (test_suite.get_output_directory (),
+				      test.get_font_name ())
 	print ('  expected_file	    %s' % os.path.abspath (expected_file))
 	return 1
 
 def run_test (test, should_check_ots):
 	out_file = os.path.join (tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
-	cli_args = [hb_subset,
-		    "--font-file=" + test.font_path,
+	cli_args = ["--font-file=" + test.font_path,
 		    "--output-file=" + out_file,
 		    "--unicodes=%s" % test.unicodes (),
-		    "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR"]
+		    "--drop-tables+=DSIG",
+		    "--drop-tables-=sbix"]
 	cli_args.extend (test.get_profile_flags ())
-	print (' '.join (cli_args))
-	_, return_code = cmd (cli_args)
+	ret = subset_cmd (cli_args)
 
-	if return_code:
-		return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code))
+	if ret != "success":
+		return fail_test (test, cli_args, "%s failed" % ' '.join (cli_args))
 
-	expected_ttx, return_code = run_ttx (os.path.join (test_suite.get_output_directory (),
-					     test.get_font_name ()))
-	if return_code:
-		return fail_test (test, cli_args, "ttx (expected) returned %d" % (return_code))
+	expected_file = os.path.join (test_suite.get_output_directory (), test.get_font_name ())
+	with open (expected_file, "rb") as fp:
+		expected_hash = hashlib.sha224(fp.read()).hexdigest()
+	with open (out_file, "rb") as fp:
+		actual_hash = hashlib.sha224(fp.read()).hexdigest()
 
-	actual_ttx, return_code = run_ttx (out_file)
-	if return_code:
-		return fail_test (test, cli_args, "ttx (actual) returned %d" % (return_code))
+	if expected_hash == actual_hash:
+		if should_check_ots:
+			print ("Checking output with ots-sanitize.")
+			if not check_ots (out_file):
+				return fail_test (test, cli_args, 'ots for subsetted file fails.')
+		return 0
 
-	print ("stripping checksums.")
-	expected_ttx = strip_check_sum (expected_ttx)
-	actual_ttx = strip_check_sum (actual_ttx)
+	if TTFont is None:
+		print ("fonttools is not present, skipping TTX diff.")
+		return fail_test (test, cli_args, "hash for expected and actual does not match.")
 
-	if not actual_ttx == expected_ttx:
+	with io.StringIO () as fp:
+		try:
+			with TTFont (expected_file) as font:
+				font.saveXML (fp)
+		except Exception as e:
+			print (e)
+			return fail_test (test, cli_args, "ttx failed to parse the expected result")
+		expected_ttx = fp.getvalue ()
+
+	with io.StringIO () as fp:
+		try:
+			with TTFont (out_file) as font:
+				font.saveXML (fp)
+		except Exception as e:
+			print (e)
+			return fail_test (test, cli_args, "ttx failed to parse the actual result")
+		actual_ttx = fp.getvalue ()
+
+	if actual_ttx != expected_ttx:
 		for line in unified_diff (expected_ttx.splitlines (1), actual_ttx.splitlines (1)):
 			sys.stdout.write (line)
 		sys.stdout.flush ()
 		return fail_test (test, cli_args, 'ttx for expected and actual does not match.')
 
-	if should_check_ots:
-		print ("Checking output with ots-sanitize.")
-		if not check_ots (out_file):
-			return fail_test (test, cli_args, 'ots for subsetted file fails.')
+	return fail_test (test, cli_args, 'hash for expected and actual does not match, '
+	                                  'but the ttx matches. Expected file needs to be updated?')
 
-	return 0
-
-def run_ttx (file):
-	print ("fonttools ttx %s" % file)
-	return cmd ([fonttools, "ttx", "-q", "-o-", file])
-
-def strip_check_sum (ttx_string):
-	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
-		       'checkSumAdjustment value="0x00000000"',
-		       ttx_string.decode ("utf-8"), count=1)
 
 def has_ots ():
 	if not ots_sanitize:
-		print("OTS is not present, skipping all ots checks.")
+		print ("OTS is not present, skipping all ots checks.")
 		return False
 	return True
 
 def check_ots (path):
 	ots_report, returncode = cmd ([ots_sanitize, path])
 	if returncode:
-		print("OTS Failure: %s" % ots_report);
+		print ("OTS Failure: %s" % ots_report)
 		return False
 	return True
 
 args = sys.argv[1:]
 if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
-	print ("First argument does not seem to point to usable hb-subset.")
-	sys.exit (1)
+	sys.exit ("First argument does not seem to point to usable hb-subset.")
 hb_subset, args = args[0], args[1:]
 
 if not len (args):
-	print ("No tests supplied.")
-	sys.exit (1)
+	sys.exit ("No tests supplied.")
 
 has_ots = has_ots()
 
+process = subprocess.Popen ([hb_subset, '--batch'],
+                            stdin=subprocess.PIPE,
+                            stdout=subprocess.PIPE,
+                            stderr=sys.stdout)
+
 fails = 0
 for path in args:
-	with io.open (path, mode="r", encoding="utf-8") as f:
+	with open (path, mode="r", encoding="utf-8") as f:
 		print ("Running tests in " + path)
 		test_suite = SubsetTestSuite (path, f.read ())
 		for test in test_suite.tests ():
 			fails += run_test (test, has_ots)
 
 if fails != 0:
-	print (str (fails) + " test(s) failed.")
-	sys.exit(1)
+	sys.exit ("%d test(s) failed." % fails)
 else:
 	print ("All tests passed.")
diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py
index 47664d0..a58d017 100644
--- a/test/subset/subset_test_suite.py
+++ b/test/subset/subset_test_suite.py
@@ -1,6 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-import io
 import os
 
 # A single test in a subset test suite. Identifies a font
@@ -12,14 +11,18 @@
 		self.subset = subset
 
 	def unicodes(self):
+		import re
 		if self.subset == '*':
 			return self.subset[0]
+		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 get_profile_flags(self):
-		with io.open(self.profile_path, mode="r", encoding="utf-8") as f:
-		    return f.read().splitlines();
+		with open (self.profile_path, mode="r", encoding="utf-8") as f:
+		    return f.read().splitlines()
 
 	def get_font_name(self):
 		font_base_name = os.path.basename(self.font_path)
diff --git a/util/Makefile.am b/util/Makefile.am
index 5298e77..cabb9ef 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -6,6 +6,8 @@
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
+EXTRA_DIST += meson.build
+
 include Makefile.sources
 
 # Convenience targets:
@@ -23,6 +25,7 @@
 	$(GLIB_CFLAGS) \
 	$(FREETYPE_CFLAGS) \
 	$(CAIRO_FT_CFLAGS) \
+	$(CHAFA_CFLAGS) \
 	$(NULL)
 LDADD = \
 	$(top_builddir)/src/libharfbuzz.la \
@@ -40,6 +43,7 @@
 	$(LDADD) \
 	$(CAIRO_LIBS) \
 	$(CAIRO_FT_LIBS) \
+	$(CHAFA_LIBS) \
 	$(NULL)
 bin_PROGRAMS += hb-view
 endif # HAVE_CAIRO_FT
diff --git a/util/Makefile.sources b/util/Makefile.sources
index bcf85f5..df3ad4a 100644
--- a/util/Makefile.sources
+++ b/util/Makefile.sources
@@ -1,38 +1,49 @@
 HB_VIEW_sources = \
-	hb-view.cc \
-	options.cc \
-	options.hh \
-	main-font-text.hh \
-	shape-consumer.hh \
-	ansi-print.cc \
 	ansi-print.hh \
-	helper-cairo.cc \
-	helper-cairo.hh \
-	helper-cairo-ansi.cc \
+	face-options.hh \
+	font-options.hh \
+	hb-view.cc \
 	helper-cairo-ansi.hh \
-	view-cairo.cc \
+	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 \
 	$(NULL)
 
 HB_SHAPE_sources = \
+	batch.hh \
+	face-options.hh \
+	font-options.hh \
 	hb-shape.cc \
-	options.cc \
-	options.hh \
 	main-font-text.hh \
+	options.hh \
+	output-options.hh \
 	shape-consumer.hh \
-	$(NULL)
-
-HB_OT_SHAPE_CLOSURE_sources = \
-	hb-ot-shape-closure.cc \
-	options.cc \
-	options.hh \
-	main-font-text.hh \
+	shape-format.hh \
+	shape-options.hh \
+	text-options.hh \
 	$(NULL)
 
 HB_SUBSET_CLI_sources = \
+	batch.hh \
+	face-options.hh \
 	hb-subset.cc \
-	options.cc \
-	options-subset.cc \
-	options.hh \
 	main-font-text.hh \
+	options.hh \
+	output-options.hh \
+	text-options.hh \
+	$(NULL)
+
+HB_OT_SHAPE_CLOSURE_sources = \
+	face-options.hh \
+	font-options.hh \
+	hb-ot-shape-closure.cc \
+	main-font-text.hh \
+	options.hh \
+	text-options.hh \
 	$(NULL)
diff --git a/util/ansi-print.cc b/util/ansi-print.cc
deleted file mode 100644
index 58df0a6..0000000
--- a/util/ansi-print.cc
+++ /dev/null
@@ -1,427 +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
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "ansi-print.hh"
-
-#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
-lround (double x)
-{
-  if (x >= 0)
-    return floor (x + 0.5);
-  else
-    return ceil (x - 0.5);
-}
-#endif
-
-#define ESC_E (char)27
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-#define CELL_W 8
-#define CELL_H (2 * CELL_W)
-
-struct color_diff_t
-{
-  int dot (const color_diff_t &o)
-  { return v[0]*o.v[0] + v[1]*o.v[1] + v[2]*o.v[2] + v[3]*o.v[3]; }
-
-  int v[4];
-};
-
-struct color_t
-{
-  static color_t from_ansi (unsigned int x)
-  {
-    color_t c = {(0xFFu<<24) | ((0xFFu*(x&1))<<16) | ((0xFFu*((x >> 1)&1))<<8) | (0xFFu*((x >> 2)&1))};
-    return c;
-  }
-  unsigned int to_ansi ()
-  {
-    return ((v >> 23) & 1) | ((v >> 14)&2) | ((v >> 5)&4);
-  }
-
-  color_diff_t diff (const color_t &o)
-  {
-    color_diff_t d;
-    for (unsigned int i = 0; i < 4; i++)
-      d.v[i] = (int) ((v >> (i*8))&0xFF) - (int) ((o.v >> (i*8))&0xFF);
-    return d;
-  }
-
-  uint32_t v;
-};
-
-struct image_t
-{
-  public:
-
-  image_t (unsigned int width_,
-	   unsigned int height_,
-	   const uint32_t *data_,
-	   unsigned int stride_) :
-		width (width_),
-		height (height_),
-		own_data (false),
-		data ((color_t *) data_),
-		stride (stride_) {}
-  image_t (unsigned int width_,
-	   unsigned int height_) :
-		width (width_),
-		height (height_),
-		own_data (true),
-		data ((color_t *) malloc (sizeof (data[0]) * width * height)),
-		stride (width) {}
-  ~image_t ()
-  { if (own_data) free (data); }
-
-  color_t &operator () (unsigned int x, unsigned int y)
-  { return data[x + y * stride]; }
-
-  color_t operator () (unsigned int x, unsigned int y) const
-  { return data[x + y * stride]; }
-
-  void
-  copy_sub_image (const image_t &s,
-		  unsigned int x, unsigned int y,
-		  unsigned int w, unsigned int h)
-  {
-    assert (x < width);
-    assert (y < height);
-    for (unsigned int row = 0; row < h; row++) {
-      color_t *p = data + x + MIN (y + row, height - 1) * stride;
-      color_t *q = s.data + row * s.stride;
-      if (x + w <= width)
-	for (unsigned int col = 0; col < w; col++)
-	  *q++ = *p++;
-      else {
-	unsigned int limit = width - x;
-	for (unsigned int col = 0; col < limit; col++)
-	  *q++ = *p++;
-	p--;
-	for (unsigned int col = limit; col < w; col++)
-	  *q++ = *p;
-      }
-    }
-  }
-
-  const unsigned int width;
-  const unsigned int height;
-
-  private:
-  bool own_data;
-  color_t * const data;
-  const unsigned int stride;
-};
-
-struct biimage_t
-{
-  public:
-
-  biimage_t (unsigned int width, unsigned int height) :
-		width (width),
-		height (height),
-		bg (0), fg (0), unicolor (true),
-		data ((uint8_t *) malloc (sizeof (data[0]) * width * height)) {}
-  ~biimage_t ()
-  { free (data); }
-
-  void set (const image_t &image)
-  {
-    assert (image.width == width);
-    assert (image.height == height);
-    int freq[8] = {0};
-    for (unsigned int y = 0; y < height; y++)
-      for (unsigned int x = 0; x < width; x++) {
-	color_t c = image (x, y);
-	freq[c.to_ansi ()]++;
-      }
-    bg = 0;
-    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 = i;
-    if (fg == bg || freq[fg] == 0) {
-      fg = bg;
-      unicolor = true;
-    }
-    else
-      unicolor = false;
-
-    /* Set the data... */
-
-    if (unicolor) {
-      memset (data, 0, sizeof (data[0]) * width * height);
-      return;
-    }
-
-    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);
-    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);
-      }
-  }
-
-  uint8_t &operator () (unsigned int x, unsigned int y)
-  { return data[x + y * width]; }
-
-  uint8_t operator () (unsigned int x, unsigned int y) const
-  { return data[x + y * width]; }
-
-  const unsigned int width;
-  const unsigned int height;
-  unsigned int bg;
-  unsigned int fg;
-  bool unicolor;
-
-  private:
-  uint8_t * const data;
-};
-
-static const char *
-block_best (const biimage_t &bi, bool *inverse)
-{
-  assert (bi.width  <= CELL_W);
-  assert (bi.height <= CELL_H);
-
-  unsigned int score = (unsigned int) -1;
-  unsigned int row_sum[CELL_H] = {0};
-  unsigned int col_sum[CELL_W] = {0};
-  unsigned int row_sum_i[CELL_H] = {0};
-  unsigned int col_sum_i[CELL_W] = {0};
-  unsigned int quad[2][2] = {{0}};
-  unsigned int quad_i[2][2] = {{0}};
-  unsigned int total = 0;
-  unsigned int total_i = 0;
-  for (unsigned int y = 0; y < bi.height; y++)
-    for (unsigned int x = 0; x < bi.width; x++) {
-      unsigned int c = bi (x, y);
-      unsigned int c_i = 255 - c;
-      row_sum[y] += c;
-      row_sum_i[y] += c_i;
-      col_sum[x] += c;
-      col_sum_i[x] += c_i;
-      quad[2 * y / bi.height][2 * x / bi.width] += c;
-      quad_i[2 * y / bi.height][2 * x / bi.width] += c_i;
-      total += c;
-      total_i += c_i;
-    }
-
-  /* Make the sums cummulative */
-  for (unsigned int i = 1; i < bi.height; i++) {
-    row_sum[i] += row_sum[i - 1];
-    row_sum_i[i] += row_sum_i[i - 1];
-  }
-  for (unsigned int i = 1; i < bi.width;  i++) {
-    col_sum[i] += col_sum[i - 1];
-    col_sum_i[i] += col_sum_i[i - 1];
-  }
-
-  const char *best_c = " ";
-
-  /* Maybe empty is better! */
-  if (total < score) {
-    score = total;
-    *inverse = false;
-    best_c = " ";
-  }
-  /* Maybe full is better! */
-  if (total_i < score) {
-    score = total_i;
-    *inverse = true;
-    best_c = " ";
-  }
-
-  /* Find best lower line */
-  if (1) {
-    unsigned int best_s = (unsigned int) -1;
-    bool best_inv = false;
-    int best_i = 0;
-    for (unsigned int i = 0; i < bi.height - 1; i++)
-    {
-      unsigned int s;
-      s = row_sum[i] + total_i - row_sum_i[i];
-      if (s < best_s) {
-	best_s = s;
-	best_i = i;
-	best_inv = false;
-      }
-      s = row_sum_i[i] + total - row_sum[i];
-      if (s < best_s) {
-	best_s = s;
-	best_i = i;
-	best_inv = true;
-      }
-    }
-    if (best_s < score) {
-      static const char *lower[7] = {"▁", "▂", "▃", "▄", "▅", "▆", "▇"};
-      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.height);
-      if (1 <= which && which <= 7) {
-	score = best_s;
-	*inverse = best_inv;
-	best_c = lower[7 - which];
-      }
-    }
-  }
-
-  /* Find best left line */
-  if (1) {
-    unsigned int best_s = (unsigned int) -1;
-    bool best_inv = false;
-    int best_i = 0;
-    for (unsigned int i = 0; i < bi.width - 1; i++)
-    {
-      unsigned int s;
-      s = col_sum[i] + total_i - col_sum_i[i];
-      if (s < best_s) {
-	best_s = s;
-	best_i = i;
-	best_inv = true;
-      }
-      s = col_sum_i[i] + total - col_sum[i];
-      if (s < best_s) {
-	best_s = s;
-	best_i = i;
-	best_inv = false;
-      }
-    }
-    if (best_s < score) {
-      static const char *left [7] = {"▏", "▎", "▍", "▌", "▋", "▊", "▉"};
-      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.width);
-      if (1 <= which && which <= 7) {
-	score = best_s;
-	*inverse = best_inv;
-	best_c = left[which - 1];
-      }
-    }
-  }
-
-  /* Find best quadrant */
-  if (1) {
-    unsigned int q = 0;
-    unsigned int qs = 0;
-    for (unsigned int i = 0; i < 2; i++)
-      for (unsigned int j = 0; j < 2; j++)
-	if (quad[i][j] > quad_i[i][j]) {
-	  q += 1 << (2 * i + j);
-	  qs += quad_i[i][j];
-	} else
-	  qs += quad[i][j];
-    if (qs < score) {
-      const char *c = nullptr;
-      bool inv = false;
-      switch (q) {
-	case 1:  c = "▟"; inv = true;  break;
-	case 2:  c = "▙"; inv = true;  break;
-	case 4:  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;
-      }
-      if (c) {
-	score = qs;
-	*inverse = inv;
-	best_c = c;
-      }
-    }
-  }
-
-  return best_c;
-}
-
-void
-ansi_print_image_rgb24 (const uint32_t *data,
-			unsigned int width,
-			unsigned int height,
-			unsigned int stride)
-{
-  image_t image (width, height, data, stride);
-
-  unsigned int rows = (height + CELL_H - 1) / CELL_H;
-  unsigned int cols = (width +  CELL_W - 1) / CELL_W;
-  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++) {
-      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);
-	  last_bg = bi.bg;
-	}
-	printf (" ");
-      } 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);
-	    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);
-	    last_bg = bi.bg;
-	    last_fg = bi.fg;
-	  }
-	}
-	printf ("%s", c);
-      }
-    }
-    printf ("%c[0m\n", ESC_E); /* Reset */
-    last_bg = last_fg = -1;
-  }
-}
diff --git a/util/ansi-print.hh b/util/ansi-print.hh
index 9640d89..d251e54 100644
--- a/util/ansi-print.hh
+++ b/util/ansi-print.hh
@@ -29,11 +29,398 @@
 
 #include "hb.hh"
 
-void
+#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
+lround (double x)
+{
+  if (x >= 0)
+    return floor (x + 0.5);
+  else
+    return ceil (x - 0.5);
+}
+#endif
+
+#define ESC_E (char)27
+
+#define CELL_W 8
+#define CELL_H (2 * CELL_W)
+
+struct color_diff_t
+{
+  int dot (const color_diff_t &o)
+  { return v[0]*o.v[0] + v[1]*o.v[1] + v[2]*o.v[2] + v[3]*o.v[3]; }
+
+  int v[4];
+};
+
+struct color_t
+{
+  static color_t from_ansi (unsigned int x)
+  {
+    color_t c = {(0xFFu<<24) | ((0xFFu*(x&1))<<16) | ((0xFFu*((x >> 1)&1))<<8) | (0xFFu*((x >> 2)&1))};
+    return c;
+  }
+  unsigned int to_ansi ()
+  {
+    return ((v >> 23) & 1) | ((v >> 14)&2) | ((v >> 5)&4);
+  }
+
+  color_diff_t diff (const color_t &o)
+  {
+    color_diff_t d;
+    for (unsigned int i = 0; i < 4; i++)
+      d.v[i] = (int) ((v >> (i*8))&0xFF) - (int) ((o.v >> (i*8))&0xFF);
+    return d;
+  }
+
+  uint32_t v;
+};
+
+struct image_t
+{
+  public:
+
+  image_t (unsigned int width_,
+	   unsigned int height_,
+	   const uint32_t *data_,
+	   unsigned int stride_) :
+		width (width_),
+		height (height_),
+		own_data (false),
+		data ((color_t *) data_),
+		stride (stride_) {}
+  image_t (unsigned int width_,
+	   unsigned int height_) :
+		width (width_),
+		height (height_),
+		own_data (true),
+		data ((color_t *) malloc (sizeof (data[0]) * width * height)),
+		stride (width) {}
+  ~image_t ()
+  { if (own_data) free (data); }
+
+  color_t &operator () (unsigned int x, unsigned int y)
+  { return data[x + y * stride]; }
+
+  color_t operator () (unsigned int x, unsigned int y) const
+  { return data[x + y * stride]; }
+
+  void
+  copy_sub_image (const image_t &s,
+		  unsigned int x, unsigned int y,
+		  unsigned int w, unsigned int h)
+  {
+    assert (x < width);
+    assert (y < height);
+    for (unsigned int row = 0; row < h; row++) {
+      color_t *p = data + x + hb_min (y + row, height - 1) * stride;
+      color_t *q = s.data + row * s.stride;
+      if (x + w <= width)
+	for (unsigned int col = 0; col < w; col++)
+	  *q++ = *p++;
+      else {
+	unsigned int limit = width - x;
+	for (unsigned int col = 0; col < limit; col++)
+	  *q++ = *p++;
+	p--;
+	for (unsigned int col = limit; col < w; col++)
+	  *q++ = *p;
+      }
+    }
+  }
+
+  const unsigned int width;
+  const unsigned int height;
+
+  private:
+  bool own_data;
+  color_t * const data;
+  const unsigned int stride;
+};
+
+struct biimage_t
+{
+  public:
+
+  biimage_t (unsigned int width, unsigned int height) :
+		width (width),
+		height (height),
+		bg (0), fg (0), unicolor (true),
+		data ((uint8_t *) malloc (sizeof (data[0]) * width * height)) {}
+  ~biimage_t ()
+  { free (data); }
+
+  void set (const image_t &image)
+  {
+    assert (image.width == width);
+    assert (image.height == height);
+    int freq[8] = {0};
+    for (unsigned int y = 0; y < height; y++)
+      for (unsigned int x = 0; x < width; x++) {
+	color_t c = image (x, y);
+	freq[c.to_ansi ()]++;
+      }
+    bg = 0;
+    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 = i;
+    if (fg == bg || freq[fg] == 0) {
+      fg = bg;
+      unicolor = true;
+    }
+    else
+      unicolor = false;
+
+    /* Set the data... */
+
+    if (unicolor) {
+      memset (data, 0, sizeof (data[0]) * width * height);
+      return;
+    }
+
+    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);
+    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);
+      }
+  }
+
+  uint8_t &operator () (unsigned int x, unsigned int y)
+  { return data[x + y * width]; }
+
+  uint8_t operator () (unsigned int x, unsigned int y) const
+  { return data[x + y * width]; }
+
+  const unsigned int width;
+  const unsigned int height;
+  unsigned int bg;
+  unsigned int fg;
+  bool unicolor;
+
+  private:
+  uint8_t * const data;
+};
+
+static const char *
+block_best (const biimage_t &bi, bool *inverse)
+{
+  assert (bi.width  <= CELL_W);
+  assert (bi.height <= CELL_H);
+
+  unsigned int score = UINT_MAX;
+  unsigned int row_sum[CELL_H] = {0};
+  unsigned int col_sum[CELL_W] = {0};
+  unsigned int row_sum_i[CELL_H] = {0};
+  unsigned int col_sum_i[CELL_W] = {0};
+  unsigned int quad[2][2] = {{0}};
+  unsigned int quad_i[2][2] = {{0}};
+  unsigned int total = 0;
+  unsigned int total_i = 0;
+  for (unsigned int y = 0; y < bi.height; y++)
+    for (unsigned int x = 0; x < bi.width; x++) {
+      unsigned int c = bi (x, y);
+      unsigned int c_i = 255 - c;
+      row_sum[y] += c;
+      row_sum_i[y] += c_i;
+      col_sum[x] += c;
+      col_sum_i[x] += c_i;
+      quad[2 * y / bi.height][2 * x / bi.width] += c;
+      quad_i[2 * y / bi.height][2 * x / bi.width] += c_i;
+      total += c;
+      total_i += c_i;
+    }
+
+  /* Make the sums cummulative */
+  for (unsigned int i = 1; i < bi.height; i++) {
+    row_sum[i] += row_sum[i - 1];
+    row_sum_i[i] += row_sum_i[i - 1];
+  }
+  for (unsigned int i = 1; i < bi.width;  i++) {
+    col_sum[i] += col_sum[i - 1];
+    col_sum_i[i] += col_sum_i[i - 1];
+  }
+
+  const char *best_c = " ";
+
+  /* Maybe empty is better! */
+  if (total < score) {
+    score = total;
+    *inverse = false;
+    best_c = " ";
+  }
+  /* Maybe full is better! */
+  if (total_i < score) {
+    score = total_i;
+    *inverse = true;
+    best_c = " ";
+  }
+
+  /* Find best lower line */
+  if (1) {
+    unsigned int best_s = UINT_MAX;
+    bool best_inv = false;
+    int best_i = 0;
+    for (unsigned int i = 0; i < bi.height - 1; i++)
+    {
+      unsigned int s;
+      s = row_sum[i] + total_i - row_sum_i[i];
+      if (s < best_s) {
+	best_s = s;
+	best_i = i;
+	best_inv = false;
+      }
+      s = row_sum_i[i] + total - row_sum[i];
+      if (s < best_s) {
+	best_s = s;
+	best_i = i;
+	best_inv = true;
+      }
+    }
+    if (best_s < score) {
+      static const char *lower[7] = {"▁", "▂", "▃", "▄", "▅", "▆", "▇"};
+      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.height);
+      if (1 <= which && which <= 7) {
+	score = best_s;
+	*inverse = best_inv;
+	best_c = lower[7 - which];
+      }
+    }
+  }
+
+  /* Find best left line */
+  if (1) {
+    unsigned int best_s = UINT_MAX;
+    bool best_inv = false;
+    int best_i = 0;
+    for (unsigned int i = 0; i < bi.width - 1; i++)
+    {
+      unsigned int s;
+      s = col_sum[i] + total_i - col_sum_i[i];
+      if (s < best_s) {
+	best_s = s;
+	best_i = i;
+	best_inv = true;
+      }
+      s = col_sum_i[i] + total - col_sum[i];
+      if (s < best_s) {
+	best_s = s;
+	best_i = i;
+	best_inv = false;
+      }
+    }
+    if (best_s < score) {
+      static const char *left [7] = {"▏", "▎", "▍", "▌", "▋", "▊", "▉"};
+      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.width);
+      if (1 <= which && which <= 7) {
+	score = best_s;
+	*inverse = best_inv;
+	best_c = left[which - 1];
+      }
+    }
+  }
+
+  /* Find best quadrant */
+  if (1) {
+    unsigned int q = 0;
+    unsigned int qs = 0;
+    for (unsigned int i = 0; i < 2; i++)
+      for (unsigned int j = 0; j < 2; j++)
+	if (quad[i][j] > quad_i[i][j]) {
+	  q += 1 << (2 * i + j);
+	  qs += quad_i[i][j];
+	} else
+	  qs += quad[i][j];
+    if (qs < score) {
+      const char *c = nullptr;
+      bool inv = false;
+      switch (q) {
+	case 1:  c = "▟"; inv = true;  break;
+	case 2:  c = "▙"; inv = true;  break;
+	case 4:  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;
+      }
+      if (c) {
+	score = qs;
+	*inverse = inv;
+	best_c = c;
+      }
+    }
+  }
+
+  return best_c;
+}
+
+static inline void
 ansi_print_image_rgb24 (const uint32_t *data,
 			unsigned int width,
 			unsigned int height,
-			unsigned int stride);
+			unsigned int stride)
+{
+  image_t image (width, height, data, stride);
 
+  unsigned int rows = (height + CELL_H - 1) / CELL_H;
+  unsigned int cols = (width +  CELL_W - 1) / CELL_W;
+  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++) {
+      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);
+	  last_bg = bi.bg;
+	}
+	printf (" ");
+      } 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);
+	    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);
+	    last_bg = bi.bg;
+	    last_fg = bi.fg;
+	  }
+	}
+	printf ("%s", c);
+      }
+    }
+    printf ("%c[0m\n", ESC_E); /* Reset */
+    last_bg = last_fg = -1;
+  }
+}
 
 #endif
diff --git a/util/batch.hh b/util/batch.hh
new file mode 100644
index 0000000..8c0217d
--- /dev/null
+++ b/util/batch.hh
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2021  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 BATCH_HH
+#define BATCH_HH
+
+#include "options.hh"
+
+typedef int (*main_func_t) (int argc, char **argv);
+
+template <typename main_t, bool report_status=false>
+int
+batch_main (int argc, char **argv)
+{
+  if (argc == 2 && !strcmp (argv[1], "--batch"))
+  {
+    int ret = 0;
+    char buf[4092];
+    while (fgets (buf, sizeof (buf), stdin))
+    {
+      size_t l = strlen (buf);
+      if (l && buf[l - 1] == '\n') buf[l - 1] = '\0';
+
+      char *args[64];
+      argc = 0;
+      args[argc++] = argv[0];
+      char *p = buf, *e;
+      args[argc++] = p;
+      while ((e = strchr (p, ';')) && argc < (int) ARRAY_LENGTH (args))
+      {
+	*e++ = '\0';
+	while (*e == ';')
+	  e++;
+	args[argc++] = p = e;
+      }
+
+      int result = main_t () (argc, args);
+
+      if (report_status)
+	fprintf (stdout, result == 0 ? "success\n" : "failure\n");
+      fflush (stdout);
+
+      ret = MAX (ret, result);
+    }
+    return ret;
+  }
+
+  int ret = main_t () (argc, argv);
+  if (report_status && ret != 0)
+    fprintf (stdout, "error: Operation failed. Probably a bug. File github issue.\n");
+  return ret;
+}
+
+#endif
diff --git a/util/face-options.hh b/util/face-options.hh
new file mode 100644
index 0000000..f680e05
--- /dev/null
+++ b/util/face-options.hh
@@ -0,0 +1,142 @@
+/*
+ * 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
+ */
+
+#ifndef FACE_OPTIONS_HH
+#define FACE_OPTIONS_HH
+
+#include "options.hh"
+
+struct face_options_t
+{
+  ~face_options_t ()
+  {
+    g_free (font_file);
+  }
+
+  void set_face (hb_face_t *face_)
+  { face = face_; }
+
+  void add_options (option_parser_t *parser);
+
+  void post_parse (GError **error);
+
+  static struct cache_t
+  {
+    ~cache_t ()
+    {
+      g_free (font_path);
+      hb_blob_destroy (blob);
+      hb_face_destroy (face);
+    }
+
+    char *font_path = nullptr;
+    hb_blob_t *blob = nullptr;
+    unsigned face_index = (unsigned) -1;
+    hb_face_t *face = nullptr;
+  } cache;
+
+  char *font_file = nullptr;
+  unsigned face_index = 0;
+
+  hb_blob_t *blob = nullptr;
+  hb_face_t *face = nullptr;
+};
+
+
+face_options_t::cache_t face_options_t::cache {};
+
+void
+face_options_t::post_parse (GError **error)
+{
+  if (!font_file)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		 "No font file set");
+    return;
+  }
+
+  assert (font_file);
+
+  const char *font_path = font_file;
+
+  if (0 == strcmp (font_path, "-"))
+  {
+#if defined(_WIN32) || defined(__CYGWIN__)
+    setmode (fileno (stdin), O_BINARY);
+    font_path = "STDIN";
+#else
+    font_path = "/dev/stdin";
+#endif
+  }
+
+  if (!cache.font_path || 0 != strcmp (cache.font_path, font_path))
+  {
+    hb_blob_destroy (cache.blob);
+    cache.blob = hb_blob_create_from_file_or_fail (font_path);
+
+    free ((char *) cache.font_path);
+    cache.font_path = g_strdup (font_path);
+
+    if (!cache.blob)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		   "%s: Failed reading file", font_path);
+      return;
+    }
+
+    hb_face_destroy (cache.face);
+    cache.face = nullptr;
+    cache.face_index = (unsigned) -1;
+  }
+
+  if (cache.face_index != face_index)
+  {
+    hb_face_destroy (cache.face);
+    cache.face = hb_face_create (cache.blob, face_index);
+    cache.face_index = face_index;
+  }
+
+  blob = cache.blob;
+  face = cache.face;
+}
+
+void
+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"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "face",
+		     "Font-face options:",
+		     "Options for the font face",
+		     this);
+}
+
+#endif
diff --git a/util/font-options.hh b/util/font-options.hh
new file mode 100644
index 0000000..fa1cffa
--- /dev/null
+++ b/util/font-options.hh
@@ -0,0 +1,303 @@
+/*
+ * 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
+ */
+
+#ifndef FONT_OPTIONS_HH
+#define FONT_OPTIONS_HH
+
+#include "face-options.hh"
+
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
+#include <hb-ot.h>
+
+#define FONT_SIZE_UPEM 0x7FFFFFFF
+#define FONT_SIZE_NONE 0
+
+extern const unsigned DEFAULT_FONT_SIZE;
+extern const unsigned SUBPIXEL_BITS;
+
+struct font_options_t : face_options_t
+{
+  ~font_options_t ()
+  {
+    free (variations);
+    g_free (font_funcs);
+    hb_font_destroy (font);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  void post_parse (GError **error);
+
+  hb_variation_t *variations = nullptr;
+  unsigned int num_variations = 0;
+  int x_ppem = 0;
+  int y_ppem = 0;
+  double ptem = 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;
+
+  hb_font_t *font = nullptr;
+};
+
+
+static struct supported_font_funcs_t {
+	char name[4];
+	void (*func) (hb_font_t *);
+} supported_font_funcs[] =
+{
+#ifdef HAVE_FREETYPE
+  {"ft",	hb_ft_font_set_funcs},
+#endif
+  {"ot",	hb_ot_font_set_funcs},
+};
+
+
+void
+font_options_t::post_parse (GError **error)
+{
+  assert (!font);
+  font = hb_font_create (face);
+
+  if (font_size_x == FONT_SIZE_UPEM)
+    font_size_x = hb_face_get_upem (face);
+  if (font_size_y == FONT_SIZE_UPEM)
+    font_size_y = hb_face_get_upem (face);
+
+  hb_font_set_ppem (font, x_ppem, y_ppem);
+  hb_font_set_ptem (font, ptem);
+
+  int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
+  int scale_y = (int) scalbnf (font_size_y, subpixel_bits);
+  hb_font_set_scale (font, scale_x, scale_y);
+
+  hb_font_set_variations (font, variations, num_variations);
+
+  void (*set_font_funcs) (hb_font_t *) = nullptr;
+  if (!font_funcs)
+  {
+    set_font_funcs = supported_font_funcs[0].func;
+  }
+  else
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name))
+      {
+	set_font_funcs = supported_font_funcs[i].func;
+	break;
+      }
+    if (!set_font_funcs)
+    {
+      GString *s = g_string_new (nullptr);
+      for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      {
+	if (i)
+	  g_string_append_c (s, '/');
+	g_string_append (s, supported_font_funcs[i].name);
+      }
+      g_string_append_c (s, '\n');
+      char *p = g_string_free (s, FALSE);
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Unknown font function implementation `%s'; supported values are: %s; default is %s",
+		   font_funcs,
+		   p,
+		   supported_font_funcs[0].name);
+      free (p);
+      return;
+    }
+  }
+  set_font_funcs (font);
+#ifdef HAVE_FREETYPE
+  hb_ft_font_set_load_flags (font, ft_load_flags);
+#endif
+}
+
+
+static gboolean
+parse_variations (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;
+  char *s = (char *) arg;
+  char *p;
+
+  font_opts->num_variations = 0;
+  g_free (font_opts->variations);
+  font_opts->variations = nullptr;
+
+  if (!*s)
+    return true;
+
+  /* count the variations first, so we can allocate memory */
+  p = s;
+  do {
+    font_opts->num_variations++;
+    p = strchr (p, ',');
+    if (p)
+      p++;
+  } while (p);
+
+  font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations));
+  if (!font_opts->variations)
+    return false;
+
+  /* now do the actual parsing */
+  p = s;
+  font_opts->num_variations = 0;
+  while (p && *p) {
+    char *end = strchr (p, ',');
+    if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
+      font_opts->num_variations++;
+    p = end ? end + 1 : nullptr;
+  }
+
+  return true;
+}
+
+static gboolean
+parse_font_size (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;
+  if (0 == strcmp (arg, "upem"))
+  {
+    font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM;
+    return true;
+  }
+  switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
+    case 1: font_opts->font_size_y = font_opts->font_size_x; 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_ppem (const char *name G_GNUC_UNUSED,
+		 const char *arg,
+		 gpointer    data,
+		 GError    **error G_GNUC_UNUSED)
+{
+  font_options_t *font_opts = (font_options_t *) data;
+  switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) {
+    case 1: font_opts->y_ppem = font_opts->x_ppem; 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;
+  }
+}
+
+void
+font_options_t::add_options (option_parser_t *parser)
+{
+  face_options_t::add_options (parser);
+
+  char *text = nullptr;
+
+  {
+    static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
+		   "No supported font-funcs found.");
+    GString *s = g_string_new (nullptr);
+    g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n    Supported font function implementations are: %s",
+		     supported_font_funcs[0].name,
+		     supported_font_funcs[0].name);
+    for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++)
+    {
+      g_string_append_c (s, '/');
+      g_string_append (s, supported_font_funcs[i].name);
+    }
+    text = g_string_free (s, FALSE);
+    parser->free_later (text);
+  }
+
+  char *font_size_text;
+  if (DEFAULT_FONT_SIZE == FONT_SIZE_UPEM)
+    font_size_text = (char *) "Font size (default: upem)";
+  else
+  {
+    font_size_text = g_strdup_printf ("Font size (default: %d)", DEFAULT_FONT_SIZE);
+    parser->free_later (font_size_text);
+  }
+
+  int font_size_flags = DEFAULT_FONT_SIZE == FONT_SIZE_NONE ? G_OPTION_FLAG_HIDDEN : 0;
+  GOptionEntry entries[] =
+  {
+    {"font-size",	0, font_size_flags,
+			      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,
+			      G_OPTION_ARG_DOUBLE,	&this->ptem,			"Set font point-size (default: 0; disabled)",	"point-size"},
+    {"font-funcs",	0, 0, G_OPTION_ARG_STRING,	&this->font_funcs,		text,						"impl"},
+    {"ft-load-flags",	0, 0, G_OPTION_ARG_INT,		&this->ft_load_flags,		"Set FreeType load-flags (default: 2)",		"integer"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "font",
+		     "Font-instance options:",
+		     "Options for the font instance",
+		     this,
+		     false /* We add below. */);
+
+  const gchar *variations_help = "Comma-separated list of font variations\n"
+    "\n"
+    "    Variations are set globally. The format for specifying variation settings\n"
+    "    follows.  All valid CSS font-variation-settings values other than 'normal'\n"
+    "    and 'inherited' are also accepted, though, not documented below.\n"
+    "\n"
+    "    The format is a tag, optionally followed by an equals sign, followed by a\n"
+    "    number. For example:\n"
+    "\n"
+    "      \"wght=500\"\n"
+    "      \"slnt=-7.5\"";
+
+  GOptionEntry entries2[] =
+  {
+    {"variations",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_variations,	variations_help,	"list"},
+    {nullptr}
+  };
+  parser->add_group (entries2,
+		     "variations",
+		     "Variations options:",
+		     "Options for font variations used",
+		     this);
+}
+
+#endif
diff --git a/util/hb-fc-list.c b/util/hb-fc-list.c
index 39cbb4b..40c6b32 100644
--- a/util/hb-fc-list.c
+++ b/util/hb-fc-list.c
@@ -199,7 +199,7 @@
 	    }
 	    else
 	    {
-	        FcChar8 *s;
+		FcChar8 *s;
 
 		s = FcPatternFormat (fs->fonts[j], format);
 		if (s)
diff --git a/util/hb-ot-shape-closure.cc b/util/hb-ot-shape-closure.cc
index 33f531b..7321f93 100644
--- a/util/hb-ot-shape-closure.cc
+++ b/util/hb-ot-shape-closure.cc
@@ -24,23 +24,22 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "batch.hh"
+#include "font-options.hh"
 #include "main-font-text.hh"
+#include "shape-options.hh"
+#include "text-options.hh"
 
-#ifdef HAVE_FREETYPE
-#include <hb-ft.h>
-#endif
+const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_NONE;
+const unsigned SUBPIXEL_BITS = 0;
 
-struct shape_closure_consumer_t : option_group_t
+struct shape_closure_consumer_t
 {
-  shape_closure_consumer_t (option_parser_t *parser) :
-			    shaper (parser),
-			    show_glyph_names (true)
+  void add_options (struct option_parser_t *parser)
   {
-    add_options (parser);
-  }
+    parser->set_summary ("Find glyph set from input text under shaping closure.");
+    shaper.add_options (parser);
 
-  void add_options (struct option_parser_t *parser) override
-  {
     GOptionEntry entries[] =
     {
       {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Use glyph indices instead of names",	nullptr},
@@ -53,24 +52,26 @@
 		       this);
   }
 
-  void init (hb_buffer_t  *buffer_,
-	     const font_options_t *font_opts)
+  void init (const font_options_t *font_opts)
   {
     glyphs = hb_set_create ();
-    font = hb_font_reference (font_opts->get_font ());
+    font = hb_font_reference (font_opts->font);
     failed = false;
-    buffer = hb_buffer_reference (buffer_);
+    buffer = hb_buffer_create ();
   }
-  void consume_line (const char   *text,
-		     unsigned int  text_len,
-		     const char   *text_before,
-		     const char   *text_after)
+  template <typename text_options_t>
+  bool consume_line (text_options_t &text_opts)
   {
+    unsigned int text_len;
+    const char *text;
+    if (!(text = text_opts.get_line (&text_len)))
+      return false;
+
     hb_set_clear (glyphs);
     shaper.shape_closure (text, text_len, font, buffer, glyphs);
 
     if (hb_set_is_empty (glyphs))
-      return;
+      return true;
 
     /* Print it out! */
     bool first = true;
@@ -88,6 +89,8 @@
       } else
 	printf ("%u", i);
     }
+
+    return true;
   }
   void finish (const font_options_t *font_opts)
   {
@@ -104,16 +107,16 @@
 
   protected:
   shape_options_t shaper;
-  hb_bool_t show_glyph_names;
+  hb_bool_t show_glyph_names = false;
 
-  hb_set_t *glyphs;
-  hb_font_t *font;
-  hb_buffer_t *buffer;
+  hb_set_t *glyphs = nullptr;
+  hb_font_t *font = nullptr;
+  hb_buffer_t *buffer = nullptr;
 };
 
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<shape_closure_consumer_t, FONT_SIZE_NONE, 0> driver;
-  return driver.main (argc, argv);
+  using main_t = main_font_text_t<shape_closure_consumer_t, font_options_t, text_options_t>;
+  return batch_main<main_t> (argc, argv);
 }
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index bab5cba..13c277a 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -25,44 +25,49 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#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 "text-options.hh"
 
-struct output_buffer_t
+const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
+const unsigned SUBPIXEL_BITS = 0;
+
+struct output_buffer_t : output_options_t<>
 {
-  output_buffer_t (option_parser_t *parser)
-		  : options (parser, hb_buffer_serialize_list_formats ()),
-		    format (parser),
-		    gs (nullptr),
-		    line_no (0),
-		    font (nullptr),
-		    output_format (HB_BUFFER_SERIALIZE_FORMAT_INVALID),
-		    format_flags (HB_BUFFER_SERIALIZE_FLAG_DEFAULT) {}
+  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)
   {
-    options.get_file_handle ();
     gs = g_string_new (nullptr);
     line_no = 0;
-    font = hb_font_reference (font_opts->get_font ());
+    font = hb_font_reference (font_opts->font);
 
-    if (!options.output_format)
-      output_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+    if (!output_format)
+      serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
     else
-      output_format = hb_buffer_serialize_format_from_string (options.output_format, -1);
+      serialize_format = hb_buffer_serialize_format_from_string (output_format, -1);
     /* An empty "output_format" parameter basically skips output generating.
      * Useful for benchmarking. */
-    if ((!options.output_format || *options.output_format) &&
-	!hb_buffer_serialize_format_to_string (output_format))
+    if ((!output_format || *output_format) &&
+	!hb_buffer_serialize_format_to_string (serialize_format))
     {
-      if (options.explicit_output_format)
+      if (explicit_output_format)
 	fail (false, "Unknown output format `%s'; supported formats are: %s",
-	      options.output_format,
-	      g_strjoinv ("/", const_cast<char**> (options.supported_formats)));
+	      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. */
-	output_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+	serialize_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
     }
 
     unsigned int flags = HB_BUFFER_SERIALIZE_FLAG_DEFAULT;
@@ -78,7 +83,7 @@
       flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
     if (format.show_flags)
       flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
-    format_flags = (hb_buffer_serialize_flags_t) flags;
+    serialize_flags = (hb_buffer_serialize_flags_t) flags;
 
     if (format.trace)
       hb_buffer_set_message_func (buffer, message_func, this, nullptr);
@@ -91,13 +96,13 @@
   {
     g_string_set_size (gs, 0);
     format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
-    fprintf (options.fp, "%s", gs->str);
+    fprintf (out_fp, "%s", gs->str);
   }
   void error (const char *message)
   {
     g_string_set_size (gs, 0);
     format.serialize_message (line_no, "error", message, gs);
-    fprintf (options.fp, "%s", gs->str);
+    fprintf (out_fp, "%s", gs->str);
   }
   void consume_glyphs (hb_buffer_t  *buffer,
 		       const char   *text,
@@ -106,8 +111,8 @@
   {
     g_string_set_size (gs, 0);
     format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
-				       output_format, format_flags, gs);
-    fprintf (options.fp, "%s", gs->str);
+				       serialize_format, serialize_flags, gs);
+    fprintf (out_fp, "%s", gs->str);
   }
   void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
@@ -137,54 +142,26 @@
     g_string_set_size (gs, 0);
     format.serialize_line_no (line_no, gs);
     g_string_append_printf (gs, "trace: %s	buffer: ", message);
-    format.serialize_glyphs (buffer, font, output_format, format_flags, gs);
+    format.serialize (buffer, font, serialize_format, serialize_flags, gs);
     g_string_append_c (gs, '\n');
-    fprintf (options.fp, "%s", gs->str);
+    fprintf (out_fp, "%s", gs->str);
   }
 
 
   protected:
-  output_options_t options;
-  format_options_t format;
 
-  GString *gs;
-  unsigned int line_no;
-  hb_font_t *font;
-  hb_buffer_serialize_format_t output_format;
-  hb_buffer_serialize_flags_t format_flags;
+  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)
 {
-  if (argc == 2 && !strcmp (argv[1], "--batch"))
-  {
-    unsigned int ret = 0;
-    char buf[4092];
-    while (fgets (buf, sizeof (buf), stdin))
-    {
-      size_t l = strlen (buf);
-      if (l && buf[l - 1] == '\n') buf[l - 1] = '\0';
-      main_font_text_t<shape_consumer_t<output_buffer_t>, FONT_SIZE_UPEM, 0> driver;
-      char *args[32];
-      argc = 0;
-      char *p = buf, *e;
-      args[argc++] = p;
-      while ((e = strchr (p, ' ')) && argc < (int) (int) ARRAY_LENGTH (args))
-      {
-	*e++ = '\0';
-	while (*e == ' ')
-	  e++;
-	args[argc++] = p = e;
-      }
-      ret |= driver.main (argc, args);
-      fflush (stdout);
-
-      if (ret)
-	break;
-    }
-    return ret;
-  }
-  main_font_text_t<shape_consumer_t<output_buffer_t>, FONT_SIZE_UPEM, 0> driver;
-  return driver.main (argc, argv);
+  using main_t = main_font_text_t<shape_consumer_t<output_buffer_t>, font_options_t, shape_text_options_t>;
+  return batch_main<main_t> (argc, argv);
 }
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index 008e4e6..ec76330 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -25,105 +25,817 @@
  * Google Author(s): Garret Rieger, Rod Sheeter
  */
 
-#include <stdio.h>
-
+#include "batch.hh"
+#include "face-options.hh"
 #include "main-font-text.hh"
-#include "hb-subset.h"
+#include "output-options.hh"
+
+#include <hb-subset.h>
 
 /*
  * Command line interface to the harfbuzz font subsetter.
  */
 
-struct subset_consumer_t
+struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
 {
-  subset_consumer_t (option_parser_t *parser)
-      : failed (false), options (parser), subset_options (parser), font (nullptr), input (nullptr) {}
-
-  void init (hb_buffer_t  *buffer_,
-	     const font_options_t *font_opts)
+  subset_main_t ()
+  : input (hb_subset_input_create_or_fail ())
+  {}
+  ~subset_main_t ()
   {
-    font = hb_font_reference (font_opts->get_font ());
-    input = hb_subset_input_reference (subset_options.input);
+    hb_subset_input_destroy (input);
   }
 
-  void consume_line (const char   *text,
-		     unsigned int  text_len,
-		     const char   *text_before,
-		     const char   *text_after)
+  void parse_face (int argc, const char * const *argv)
   {
-    // TODO(Q1) does this only get called with at least 1 codepoint?
-    hb_set_t *codepoints = hb_subset_input_unicode_set (input);
-    if (0 == strcmp (text, "*"))
+    option_parser_t parser;
+    face_options_t face_opts;
+
+    face_opts.add_options (&parser);
+
+    GOptionEntry entries[] =
     {
-      hb_face_t *face = hb_font_get_face (font);
-      hb_face_collect_unicodes (face, codepoints);
-      return;
-    }
+      {G_OPTION_REMAINING,	0, G_OPTION_FLAG_IN_MAIN,
+				G_OPTION_ARG_CALLBACK,	(gpointer) &collect_face,	nullptr,	"[FONT-FILE] [TEXT]"},
+      {nullptr}
+    };
+    parser.add_main_group (entries, &face_opts);
+    parser.add_options ();
 
-    gchar *c = (gchar *)text;
-    do {
-      gunichar cp = g_utf8_get_char(c);
-      hb_codepoint_t hb_cp = cp;
-      hb_set_add (codepoints, hb_cp);
-    } while ((c = g_utf8_find_next_char(c, text + text_len)) != nullptr);
+    g_option_context_set_ignore_unknown_options (parser.context, true);
+    g_option_context_set_help_enabled (parser.context, false);
+
+    char **args = (char **)
+#if GLIB_CHECK_VERSION (2, 68, 0)
+      g_memdup2
+#else
+      g_memdup
+#endif
+      (argv, argc * sizeof (*argv));
+    parser.parse (&argc, &args);
+    g_free (args);
+
+    set_face (face_opts.face);
   }
 
-  hb_bool_t
-  write_file (const char *output_file, hb_blob_t *blob) {
-    unsigned int data_length;
-    const char* data = hb_blob_get_data (blob, &data_length);
+  void parse (int argc, char **argv)
+  {
+    bool help = false;
+    for (auto i = 1; i < argc; i++)
+      if (!strncmp ("--help", argv[i], 6))
+      {
+	help = true;
+	break;
+      }
 
-    FILE *fp_out = fopen(output_file, "wb");
-    if (fp_out == nullptr) {
-      fprintf(stderr, "Unable to open output file\n");
-      return false;
+    if (likely (!help))
+    {
+      /* Do a preliminary parse to load font-face, such that we can use it
+       * during main option parsing. */
+      parse_face (argc, argv);
     }
-    int bytes_written = fwrite(data, 1, data_length, fp_out);
 
-    fclose (fp_out);
+    add_options ();
+    option_parser_t::parse (&argc, &argv);
+  }
 
-    if (bytes_written == -1) {
-      fprintf(stderr, "Unable to write output file\n");
-      return false;
+  int operator () (int argc, char **argv)
+  {
+    parse (argc, argv);
+
+    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);
     }
-    if ((unsigned int) bytes_written != data_length) {
-      fprintf(stderr, "Expected %u bytes written, got %d\n", data_length,
-	      bytes_written);
-      return false;
+
+    bool success = new_face;
+    if (success)
+    {
+      hb_blob_t *result = hb_face_reference_blob (new_face);
+      write_file (output_file, result);
+      hb_blob_destroy (result);
     }
+
+    hb_face_destroy (new_face);
+
+    return success ? 0 : 1;
+  }
+
+  bool
+  write_file (const char *output_file, hb_blob_t *blob)
+  {
+    assert (out_fp);
+
+    unsigned int size;
+    const char* data = hb_blob_get_data (blob, &size);
+
+    while (size)
+    {
+      size_t ret = fwrite (data, 1, size, out_fp);
+      size -= ret;
+      data += ret;
+      if (size && ferror (out_fp))
+        fail (false, "Failed to write output: %s", strerror (errno));
+    }
+
     return true;
   }
 
-  void finish (const font_options_t *font_opts)
-  {
-    hb_face_t *face = hb_font_get_face (font);
+  void add_options ();
 
-    hb_face_t *new_face = hb_subset (face, input);
-    hb_blob_t *result = hb_face_reference_blob (new_face);
-
-    failed = !hb_blob_get_length (result);
-    if (!failed)
-      write_file (options.output_file, result);
-
-    hb_subset_input_destroy (input);
-    hb_blob_destroy (result);
-    hb_face_destroy (new_face);
-    hb_font_destroy (font);
-  }
+  protected:
+  static gboolean
+  collect_face (const char *name,
+		const char *arg,
+		gpointer    data,
+		GError    **error);
+  static gboolean
+  collect_rest (const char *name,
+		const char *arg,
+		gpointer    data,
+		GError    **error);
 
   public:
-  bool failed;
 
-  private:
-  output_options_t options;
-  subset_options_t subset_options;
-  hb_font_t *font;
-  hb_subset_input_t *input;
+  unsigned num_iterations = 1;
+  hb_subset_input_t *input = nullptr;
 };
 
+static gboolean
+parse_gids (const char *name G_GNUC_UNUSED,
+	    const char *arg,
+	    gpointer    data,
+	    GError    **error)
+{
+  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 *gids = hb_subset_input_glyph_set (subset_main->input);
+
+  if (!is_remove && !is_add) hb_set_clear (gids);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (gids);
+    if (!is_remove)
+      hb_set_invert (gids);
+    return true;
+  }
+
+  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-index at: '%s'", s);
+      return false;
+    }
+
+    if (p && p[0] == '-') // ranges
+    {
+      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-index at: '%s'", s);
+	return false;
+      }
+
+      if (end_code < start_code)
+      {
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		     "Invalid glyph-index range %u-%u", start_code, end_code);
+	return false;
+      }
+      if (!is_remove)
+        hb_set_add_range (gids, start_code, end_code);
+      else
+        hb_set_del_range (gids, start_code, end_code);
+    }
+    else
+    {
+      if (!is_remove)
+        hb_set_add (gids, start_code);
+      else
+        hb_set_del (gids, start_code);
+    }
+
+    s = p;
+  }
+
+  return true;
+}
+
+static gboolean
+parse_glyphs (const char *name G_GNUC_UNUSED,
+	      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 *gids = hb_subset_input_glyph_set (subset_main->input);
+
+  if (!is_remove && !is_add) hb_set_clear (gids);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (gids);
+    if (!is_remove)
+      hb_set_invert (gids);
+    return true;
+  }
+
+  const char *p = arg;
+  const char *p_end = arg + strlen (arg);
+
+  hb_font_t *font = hb_font_create (subset_main->face);
+  while (p < p_end)
+  {
+    while (p < p_end && (*p == ' ' || *p == ','))
+      p++;
+
+    const char *end = p;
+    while (end < p_end && *end != ' ' && *end != ',')
+      end++;
+
+    if (p < end)
+    {
+      hb_codepoint_t gid;
+      if (!hb_font_get_glyph_from_name (font, p, end - p, &gid))
+      {
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		     "Failed parsing glyph name: '%s'", p);
+	return false;
+      }
+
+      if (!is_remove)
+        hb_set_add (gids, gid);
+      else
+        hb_set_del (gids, gid);
+    }
+
+    p = end + 1;
+  }
+  hb_font_destroy (font);
+
+  return true;
+}
+
+static gboolean
+parse_text (const char *name G_GNUC_UNUSED,
+	    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 *unicodes = hb_subset_input_unicode_set (subset_main->input);
+
+  if (!is_remove && !is_add) hb_set_clear (unicodes);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (unicodes);
+    if (!is_remove)
+      hb_set_invert (unicodes);
+    return true;
+  }
+
+  for (gchar *c = (gchar *) arg;
+       *c;
+       c = g_utf8_find_next_char(c, nullptr))
+  {
+    gunichar cp = g_utf8_get_char(c);
+    if (!is_remove)
+      hb_set_add (unicodes, cp);
+    else
+      hb_set_del (unicodes, cp);
+  }
+  return true;
+}
+
+static gboolean
+parse_unicodes (const char *name G_GNUC_UNUSED,
+		const char *arg,
+		gpointer    data,
+		GError    **error)
+{
+  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 *unicodes = hb_subset_input_unicode_set (subset_main->input);
+
+  if (!is_remove && !is_add) hb_set_clear (unicodes);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (unicodes);
+    if (!is_remove)
+      hb_set_invert (unicodes);
+    return true;
+  }
+
+  // XXX TODO Ranges
+#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r "
+
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (DELIMITERS, *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t start_code = strtoul (s, &p, 16);
+    if (errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing Unicode at: '%s'", s);
+      return false;
+    }
+
+    if (p && p[0] == '-') // ranges
+    {
+      s = ++p;
+      hb_codepoint_t end_code = strtoul (s, &p, 16);
+      if (s[0] == '-' || errno || s == p)
+      {
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		     "Failed parsing Unicode at: '%s'", s);
+	return false;
+      }
+
+      if (end_code < start_code)
+      {
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		     "Invalid Unicode range %u-%u", start_code, end_code);
+	return false;
+      }
+      if (!is_remove)
+        hb_set_add_range (unicodes, start_code, end_code);
+      else
+        hb_set_del_range (unicodes, start_code, end_code);
+    }
+    else
+    {
+      if (!is_remove)
+        hb_set_add (unicodes, start_code);
+      else
+        hb_set_del (unicodes, start_code);
+    }
+
+    s = p;
+  }
+
+  return true;
+}
+
+static gboolean
+parse_nameids (const char *name,
+	       const char *arg,
+	       gpointer    data,
+	       GError    **error)
+{
+  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 *name_ids = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_NAME_ID);
+
+
+  if (!is_remove && !is_add) hb_set_clear (name_ids);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (name_ids);
+    if (!is_remove)
+      hb_set_invert (name_ids);
+    return true;
+  }
+
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (", ", *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 10);
+    if (errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing nameID at: '%s'", s);
+      return false;
+    }
+
+    if (!is_remove)
+    {
+      hb_set_add (name_ids, u);
+    } else {
+      hb_set_del (name_ids, u);
+    }
+
+    s = p;
+  }
+
+  return true;
+}
+
+static gboolean
+parse_name_languages (const char *name,
+		      const char *arg,
+		      gpointer    data,
+		      GError    **error)
+{
+  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 *name_languages = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_NAME_LANG_ID);
+
+  if (!is_remove && !is_add) hb_set_clear (name_languages);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (name_languages);
+    if (!is_remove)
+      hb_set_invert (name_languages);
+    return true;
+  }
+
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (", ", *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 10);
+    if (errno || s == p)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing name-language code at: '%s'", s);
+      return false;
+    }
+
+    if (!is_remove)
+    {
+      hb_set_add (name_languages, u);
+    } else {
+      hb_set_del (name_languages, u);
+    }
+
+    s = p;
+  }
+
+  return true;
+}
+
+template <hb_subset_flags_t flag>
+static gboolean
+set_flag (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_set_flags (subset_main->input,
+			     hb_subset_input_get_flags (subset_main->input) | flag);
+
+  return true;
+}
+
+static gboolean
+parse_layout_features (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);
+
+  if (!is_remove && !is_add) hb_set_clear (layout_features);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (layout_features);
+    if (!is_remove)
+      hb_set_invert (layout_features);
+    return true;
+  }
+
+  char *s = strtok((char *) arg, ", ");
+  while (s)
+  {
+    if (strlen (s) > 4) // table 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);
+      return false;
+    }
+
+    hb_tag_t tag = hb_tag_from_string (s, strlen (s));
+
+    if (!is_remove)
+      hb_set_add (layout_features, tag);
+    else
+      hb_set_del (layout_features, tag);
+
+    s = strtok(nullptr, ", ");
+  }
+
+  return true;
+}
+
+static gboolean
+parse_drop_tables (const char *name,
+		   const char *arg,
+		   gpointer    data,
+		   GError    **error)
+{
+  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 *drop_tables = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_DROP_TABLE_TAG);
+
+  if (!is_remove && !is_add) hb_set_clear (drop_tables);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    hb_set_clear (drop_tables);
+    if (!is_remove)
+      hb_set_invert (drop_tables);
+    return true;
+  }
+
+  char *s = strtok((char *) arg, ", ");
+  while (s)
+  {
+    if (strlen (s) > 4) // Table 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);
+      return false;
+    }
+
+    hb_tag_t tag = hb_tag_from_string (s, strlen (s));
+
+    if (!is_remove)
+      hb_set_add (drop_tables, tag);
+    else
+      hb_set_del (drop_tables, tag);
+
+    s = strtok(nullptr, ", ");
+  }
+
+  return true;
+}
+
+template <GOptionArgFunc line_parser, bool allow_comments=true>
+static gboolean
+parse_file_for (const char *name,
+		const char *arg,
+		gpointer    data,
+		GError    **error)
+{
+  FILE *fp = nullptr;
+  if (0 != strcmp (arg, "-"))
+    fp = fopen (arg, "r");
+  else
+    fp = stdin;
+
+  if (!fp)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		 "Failed opening file `%s': %s",
+		 arg, strerror (errno));
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  do
+  {
+    g_string_set_size (gs, 0);
+    char buf[BUFSIZ];
+    while (fgets (buf, sizeof (buf), fp))
+    {
+      unsigned bytes = strlen (buf);
+      if (bytes && buf[bytes - 1] == '\n')
+      {
+	bytes--;
+	g_string_append_len (gs, buf, bytes);
+	break;
+      }
+      g_string_append_len (gs, buf, bytes);
+    }
+    if (ferror (fp))
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		   "Failed reading file `%s': %s",
+		   arg, strerror (errno));
+      return false;
+    }
+    g_string_append_c (gs, '\0');
+
+    if (allow_comments)
+    {
+      char *comment = strchr (gs->str, '#');
+      if (comment)
+        *comment = '\0';
+    }
+
+    line_parser ("+", gs->str, data, error);
+
+    if (*error)
+      break;
+  }
+  while (!feof (fp));
+
+  g_string_free (gs, false);
+
+  return true;
+}
+
+gboolean
+subset_main_t::collect_face (const char *name,
+			     const char *arg,
+			     gpointer    data,
+			     GError    **error)
+{
+  face_options_t *thiz = (face_options_t *) data;
+
+  if (!thiz->font_file)
+  {
+    thiz->font_file = g_strdup (arg);
+    return true;
+  }
+
+  return true;
+}
+
+gboolean
+subset_main_t::collect_rest (const char *name,
+			     const char *arg,
+			     gpointer    data,
+			     GError    **error)
+{
+  subset_main_t *thiz = (subset_main_t *) data;
+
+  if (!thiz->font_file)
+  {
+    thiz->font_file = g_strdup (arg);
+    return true;
+  }
+
+  parse_text (name, arg, data, error);
+  return true;
+}
+
+void
+subset_main_t::add_options ()
+{
+  set_summary ("Subset fonts to specification.");
+
+  face_options_t::add_options (this);
+
+  GOptionEntry glyphset_entries[] =
+  {
+    {"gids",		0, 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 *"},
+    {"gids-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_gids>,	"Specify file to read glyph IDs or ranges from", "filename"},
+    {"glyphs",		0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to include in the subset. Use --glyphs-=... to subtract glyphs from the current set.", "list of glyph names or *"},
+    {"glyphs+",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to include in the subset", "list of glyph names"},
+    {"glyphs-",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to remove from the subset", "list of glyph names"},
+
+
+    {"glyphs-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>,	"Specify file to read glyph names fromt", "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-",		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,
+     "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 *"},
+    {"unicodes+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Specify Unicode codepoints or ranges to include in the subset", "list of hex numbers/ranges or *"},
+
+    {"unicodes-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_unicodes>,"Specify file to read Unicode codepoints or ranges from", "filename"},
+    {nullptr}
+  };
+  add_group (glyphset_entries,
+	     "subset-glyphset",
+	     "Subset glyph-set option:",
+	     "Subsetting glyph-set options",
+	     this);
+
+  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 *"},
+    {"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, 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 *"},
+    {"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 *"},
+    {nullptr}
+  };
+  add_group (other_entries,
+	     "subset-other",
+	     "Subset other option:",
+	     "Subsetting other options",
+	     this);
+
+  GOptionEntry flag_entries[] =
+  {
+    {"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},
+    {"name-legacy",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NAME_LEGACY>,		"Keep legacy (non-Unicode) 'name' table entries", nullptr},
+    {"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},
+    {"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},
+    {nullptr}
+  };
+  add_group (flag_entries,
+	     "subset-flags",
+	     "Subset boolean option:",
+	     "Subsetting boolean options",
+	     this);
+
+  GOptionEntry app_entries[] =
+  {
+    {"num-iterations",	'n', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT,
+     &this->num_iterations,
+     "Run subsetter N times (default: 1)", "N"},
+    {nullptr}
+  };
+  add_group (app_entries,
+	     "subset-app",
+	     "Subset app option:",
+	     "Subsetting application options",
+	     this);
+
+  output_options_t::add_options (this);
+
+  GOptionEntry entries[] =
+  {
+    {G_OPTION_REMAINING,	0, G_OPTION_FLAG_IN_MAIN,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &collect_rest,	nullptr,	"[FONT-FILE] [TEXT]"},
+    {nullptr}
+  };
+  add_main_group (entries, this);
+  option_parser_t::add_options ();
+}
+
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<subset_consumer_t, 10, 0> driver;
-  return driver.main (argc, argv);
+  return batch_main<subset_main_t, true> (argc, argv);
 }
diff --git a/util/hb-view.cc b/util/hb-view.cc
index 69a4c95..82761fb 100644
--- a/util/hb-view.cc
+++ b/util/hb-view.cc
@@ -25,16 +25,19 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "batch.hh"
+#include "font-options.hh"
 #include "main-font-text.hh"
 #include "shape-consumer.hh"
+#include "text-options.hh"
 #include "view-cairo.hh"
 
-#define DEFAULT_FONT_SIZE 256
-#define SUBPIXEL_BITS 6
+const unsigned DEFAULT_FONT_SIZE = 256;
+const unsigned SUBPIXEL_BITS = 6;
 
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<shape_consumer_t<view_cairo_t>, DEFAULT_FONT_SIZE, SUBPIXEL_BITS> driver;
-  return driver.main (argc, argv);
+  using main_t = main_font_text_t<shape_consumer_t<view_cairo_t>, font_options_t, shape_text_options_t>;
+  return batch_main<main_t> (argc, argv);
 }
diff --git a/util/helper-cairo-ansi.cc b/util/helper-cairo-ansi.cc
deleted file mode 100644
index cbda493..0000000
--- a/util/helper-cairo-ansi.cc
+++ /dev/null
@@ -1,102 +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
- */
-
-#include "helper-cairo-ansi.hh"
-#include "options.hh"
-
-#include "ansi-print.hh"
-
-
-cairo_status_t
-helper_cairo_surface_write_to_ansi_stream (cairo_surface_t	*surface,
-					   cairo_write_func_t	write_func,
-					   void			*closure)
-{
-  unsigned int width = cairo_image_surface_get_width (surface);
-  unsigned int height = cairo_image_surface_get_height (surface);
-  if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) {
-    cairo_surface_t *new_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
-    cairo_t *cr = cairo_create (new_surface);
-    if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_A8) {
-      cairo_set_source_rgb (cr, 0., 0., 0.);
-      cairo_paint (cr);
-      cairo_set_source_rgb (cr, 1., 1., 1.);
-      cairo_mask_surface (cr, surface, 0, 0);
-    } else {
-      cairo_set_source_rgb (cr, 1., 1., 1.);
-      cairo_paint (cr);
-      cairo_set_source_surface (cr, surface, 0, 0);
-      cairo_paint (cr);
-    }
-    cairo_destroy (cr);
-    surface = new_surface;
-  } else
-    cairo_surface_reference (surface);
-
-  unsigned int stride = cairo_image_surface_get_stride (surface);
-  const uint32_t *data = (uint32_t *) (void *) cairo_image_surface_get_data (surface);
-
-  /* We don't have rows to spare on the terminal window...
-   * Find the tight image top/bottom and only print in between. */
-
-  /* Use corner color as background color. */
-  uint32_t bg_color = data ? * (uint32_t *) data : 0;
-
-  /* Drop first row while empty */
-  while (height)
-  {
-    unsigned int i;
-    for (i = 0; i < width; i++)
-      if (data[i] != bg_color)
-	break;
-    if (i < width)
-      break;
-    data += stride / 4;
-    height--;
-  }
-
-  /* Drop last row while empty */
-  unsigned int orig_height = height;
-  while (height)
-  {
-    const uint32_t *row = data + (height - 1) * stride / 4;
-    unsigned int i;
-    for (i = 0; i < width; i++)
-      if (row[i] != bg_color)
-	break;
-    if (i < width)
-      break;
-    height--;
-  }
-  if (height < orig_height)
-    height++; /* Add one last blank row for padding. */
-
-  if (width && height)
-    ansi_print_image_rgb24 (data, width, height, stride / 4);
-
-  cairo_surface_destroy (surface);
-  return CAIRO_STATUS_SUCCESS;
-}
diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh
index bc23132..8c8a1ee 100644
--- a/util/helper-cairo-ansi.hh
+++ b/util/helper-cairo-ansi.hh
@@ -31,10 +31,180 @@
 
 #include <cairo.h>
 
-cairo_status_t
+#include "ansi-print.hh"
+
+#ifdef HAVE_CHAFA
+# include <chafa.h>
+
+/* Similar to ansi-print.cc */
+# define CELL_W 8
+# define CELL_H (2 * CELL_W)
+
+static void
+chafa_print_image_rgb24 (const void *data, int width, int height, int stride)
+{
+  ChafaTermInfo *term_info;
+  ChafaSymbolMap *symbol_map;
+  ChafaCanvasConfig *config;
+  ChafaCanvas *canvas;
+  GString *gs;
+  unsigned int cols = (width +  CELL_W - 1) / CELL_W;
+  unsigned int rows = (height + CELL_H - 1) / CELL_H;
+  gchar **environ;
+  ChafaCanvasMode mode;
+  ChafaPixelMode pixel_mode;
+
+  /* Adapt to terminal; use sixels if available, and fall back to symbols
+   * with as many colors as are supported */
+
+  environ = g_get_environ ();
+  term_info = chafa_term_db_detect (chafa_term_db_get_default (),
+                                    environ);
+
+  pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS;
+
+  if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_BEGIN_SIXELS))
+  {
+    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_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;
+
+  /* Create the configuration */
+
+  symbol_map = chafa_symbol_map_new ();
+  chafa_symbol_map_add_by_tags (symbol_map,
+                                (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK
+                                                   | CHAFA_SYMBOL_TAG_SPACE));
+
+  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_geometry (config, cols, rows);
+  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);
+
+  /* Create canvas, draw to it and render output string */
+
+  canvas = chafa_canvas_new (config);
+  chafa_canvas_draw_all_pixels (canvas,
+                                /* Cairo byte order is host native */
+                                G_BYTE_ORDER == G_LITTLE_ENDIAN
+                                  ? CHAFA_PIXEL_BGRA8_PREMULTIPLIED
+                                  : CHAFA_PIXEL_ARGB8_PREMULTIPLIED,
+                                (const guint8 *) data,
+                                width,
+                                height,
+                                stride);
+  gs = chafa_canvas_print (canvas, term_info);
+
+  /* Print the string */
+
+  fwrite (gs->str, sizeof (char), gs->len, stdout);
+
+  if (pixel_mode != CHAFA_PIXEL_MODE_SIXELS)
+    fputc ('\n', stdout);
+
+  /* Free resources */
+
+  g_string_free (gs, TRUE);
+  chafa_canvas_unref (canvas);
+  chafa_canvas_config_unref (config);
+  chafa_symbol_map_unref (symbol_map);
+  chafa_term_info_unref (term_info);
+  g_strfreev (environ);
+}
+
+#endif /* HAVE_CHAFA */
+
+static inline cairo_status_t
 helper_cairo_surface_write_to_ansi_stream (cairo_surface_t	*surface,
 					   cairo_write_func_t	write_func,
-					   void			*closure);
+					   void			*closure)
+{
+  unsigned int width = cairo_image_surface_get_width (surface);
+  unsigned int height = cairo_image_surface_get_height (surface);
+  if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) {
+    cairo_surface_t *new_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+    cairo_t *cr = cairo_create (new_surface);
+    if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_A8) {
+      cairo_set_source_rgb (cr, 0., 0., 0.);
+      cairo_paint (cr);
+      cairo_set_source_rgb (cr, 1., 1., 1.);
+      cairo_mask_surface (cr, surface, 0, 0);
+    } else {
+      cairo_set_source_rgb (cr, 1., 1., 1.);
+      cairo_paint (cr);
+      cairo_set_source_surface (cr, surface, 0, 0);
+      cairo_paint (cr);
+    }
+    cairo_destroy (cr);
+    surface = new_surface;
+  } else
+    cairo_surface_reference (surface);
+
+  unsigned int stride = cairo_image_surface_get_stride (surface);
+  const uint32_t *data = (uint32_t *) (void *) cairo_image_surface_get_data (surface);
+
+  /* We don't have rows to spare on the terminal window...
+   * Find the tight image top/bottom and only print in between. */
+
+  /* Use corner color as background color. */
+  uint32_t bg_color = data ? * (uint32_t *) data : 0;
+
+  /* Drop first row while empty */
+  while (height)
+  {
+    unsigned int i;
+    for (i = 0; i < width; i++)
+      if (data[i] != bg_color)
+	break;
+    if (i < width)
+      break;
+    data += stride / 4;
+    height--;
+  }
+
+  /* Drop last row while empty */
+  unsigned int orig_height = height;
+  while (height)
+  {
+    const uint32_t *row = data + (height - 1) * stride / 4;
+    unsigned int i;
+    for (i = 0; i < width; i++)
+      if (row[i] != bg_color)
+	break;
+    if (i < width)
+      break;
+    height--;
+  }
+  if (height < orig_height)
+    height++; /* Add one last blank row for padding. */
+
+  if (width && height)
+  {
+#ifdef HAVE_CHAFA
+    if (true)
+      chafa_print_image_rgb24 (data, width, height, stride);
+    else
+#endif
+      ansi_print_image_rgb24 (data, width, height, stride / 4);
+  }
+
+  cairo_surface_destroy (surface);
+  return CAIRO_STATUS_SUCCESS;
+}
 
 
 #endif
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
deleted file mode 100644
index 42cce71..0000000
--- a/util/helper-cairo.cc
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * 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
- */
-
-#include "helper-cairo.hh"
-
-#include <cairo-ft.h>
-#include <hb-ft.h>
-#include FT_MULTIPLE_MASTERS_H
-
-#include "helper-cairo-ansi.hh"
-#ifdef CAIRO_HAS_SVG_SURFACE
-#  include <cairo-svg.h>
-#endif
-#ifdef CAIRO_HAS_PDF_SURFACE
-#  include <cairo-pdf.h>
-#endif
-#ifdef CAIRO_HAS_PS_SURFACE
-#  include <cairo-ps.h>
-#  if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0)
-#    define HAS_EPS 1
-
-static cairo_surface_t *
-_cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
-				      void               *closure,
-				      double              width,
-				      double              height)
-{
-  cairo_surface_t *surface;
-
-  surface = cairo_ps_surface_create_for_stream (write_func, closure, width, height);
-  cairo_ps_surface_set_eps (surface, true);
-
-  return surface;
-}
-
-#  else
-#    undef HAS_EPS
-#  endif
-#endif
-
-
-static FT_Library ft_library;
-
-#ifdef HAVE_ATEXIT
-static inline
-void free_ft_library ()
-{
-  FT_Done_FreeType (ft_library);
-}
-#endif
-
-cairo_scaled_font_t *
-helper_cairo_create_scaled_font (const font_options_t *font_opts)
-{
-  hb_font_t *font = hb_font_reference (font_opts->get_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);
-#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
-  {
-#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);
-      }
-    }
-#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;
-
-  cairo_matrix_init_identity (&ctm);
-  cairo_matrix_init_scale (&font_matrix,
-			   font_opts->font_size_x,
-			   font_opts->font_size_y);
-  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);
-
-  cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
-							       &font_matrix,
-							       &ctm,
-							       font_options);
-
-  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;
-}
-
-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);
-  }
-#endif
-  return ret;
-}
-
-
-struct finalize_closure_t {
-  void (*callback)(finalize_closure_t *);
-  cairo_surface_t *surface;
-  cairo_write_func_t write_func;
-  void *closure;
-};
-static cairo_user_data_key_t finalize_closure_key;
-
-
-static void
-finalize_ansi (finalize_closure_t *closure)
-{
-  cairo_status_t status;
-  status = helper_cairo_surface_write_to_ansi_stream (closure->surface,
-						      closure->write_func,
-						      closure->closure);
-  if (status != CAIRO_STATUS_SUCCESS)
-    fail (false, "Failed to write output: %s",
-	  cairo_status_to_string (status));
-}
-
-static cairo_surface_t *
-_cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func,
-				       void *closure,
-				       double width,
-				       double height,
-				       cairo_content_t content)
-{
-  cairo_surface_t *surface;
-  int w = ceil (width);
-  int h = ceil (height);
-
-  switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
-      break;
-    default:
-    case CAIRO_CONTENT_COLOR:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
-      break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
-      break;
-  }
-  cairo_status_t status = cairo_surface_status (surface);
-  if (status != CAIRO_STATUS_SUCCESS)
-    fail (false, "Failed to create cairo surface: %s",
-	  cairo_status_to_string (status));
-
-  finalize_closure_t *ansi_closure = g_new0 (finalize_closure_t, 1);
-  ansi_closure->callback = finalize_ansi;
-  ansi_closure->surface = surface;
-  ansi_closure->write_func = write_func;
-  ansi_closure->closure = closure;
-
-  if (cairo_surface_set_user_data (surface,
-				   &finalize_closure_key,
-				   (void *) ansi_closure,
-				   (cairo_destroy_func_t) g_free))
-    g_free ((void *) closure);
-
-  return surface;
-}
-
-
-#ifdef CAIRO_HAS_PNG_FUNCTIONS
-
-static void
-finalize_png (finalize_closure_t *closure)
-{
-  cairo_status_t status;
-  status = cairo_surface_write_to_png_stream (closure->surface,
-					      closure->write_func,
-					      closure->closure);
-  if (status != CAIRO_STATUS_SUCCESS)
-    fail (false, "Failed to write output: %s",
-	  cairo_status_to_string (status));
-}
-
-static cairo_surface_t *
-_cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
-				      void *closure,
-				      double width,
-				      double height,
-				      cairo_content_t content)
-{
-  cairo_surface_t *surface;
-  int w = ceil (width);
-  int h = ceil (height);
-
-  switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
-      break;
-    default:
-    case CAIRO_CONTENT_COLOR:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
-      break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
-      break;
-  }
-  cairo_status_t status = cairo_surface_status (surface);
-  if (status != CAIRO_STATUS_SUCCESS)
-    fail (false, "Failed to create cairo surface: %s",
-	  cairo_status_to_string (status));
-
-  finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
-  png_closure->callback = finalize_png;
-  png_closure->surface = surface;
-  png_closure->write_func = write_func;
-  png_closure->closure = closure;
-
-  if (cairo_surface_set_user_data (surface,
-				   &finalize_closure_key,
-				   (void *) png_closure,
-				   (cairo_destroy_func_t) g_free))
-    g_free ((void *) closure);
-
-  return surface;
-}
-
-#endif
-
-static cairo_status_t
-stdio_write_func (void                *closure,
-		  const unsigned char *data,
-		  unsigned int         size)
-{
-  FILE *fp = (FILE *) closure;
-
-  while (size) {
-    size_t ret = fwrite (data, 1, size, fp);
-    size -= ret;
-    data += ret;
-    if (size && ferror (fp))
-      fail (false, "Failed to write output: %s", strerror (errno));
-  }
-
-  return CAIRO_STATUS_SUCCESS;
-}
-
-const char *helper_cairo_supported_formats[] =
-{
-  "ansi",
-  #ifdef CAIRO_HAS_PNG_FUNCTIONS
-  "png",
-  #endif
-  #ifdef CAIRO_HAS_SVG_SURFACE
-  "svg",
-  #endif
-  #ifdef CAIRO_HAS_PDF_SURFACE
-  "pdf",
-  #endif
-  #ifdef CAIRO_HAS_PS_SURFACE
-  "ps",
-   #ifdef HAS_EPS
-    "eps",
-   #endif
-  #endif
-  nullptr
-};
-
-cairo_t *
-helper_cairo_create_context (double w, double h,
-			     view_options_t *view_opts,
-			     output_options_t *out_opts,
-			     cairo_content_t content)
-{
-  cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
-				   void *closure,
-				   double width,
-				   double height) = nullptr;
-  cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
-				    void *closure,
-				    double width,
-				    double height,
-				    cairo_content_t content) = nullptr;
-
-  const char *extension = out_opts->output_format;
-  if (!extension) {
-#if HAVE_ISATTY
-    if (isatty (fileno (out_opts->get_file_handle ())))
-      extension = "ansi";
-    else
-#endif
-    {
-#ifdef CAIRO_HAS_PNG_FUNCTIONS
-      extension = "png";
-#else
-      extension = "ansi";
-#endif
-    }
-  }
-  if (0)
-    ;
-    else if (0 == g_ascii_strcasecmp (extension, "ansi"))
-      constructor2 = _cairo_ansi_surface_create_for_stream;
-  #ifdef CAIRO_HAS_PNG_FUNCTIONS
-    else if (0 == g_ascii_strcasecmp (extension, "png"))
-      constructor2 = _cairo_png_surface_create_for_stream;
-  #endif
-  #ifdef CAIRO_HAS_SVG_SURFACE
-    else if (0 == g_ascii_strcasecmp (extension, "svg"))
-      constructor = cairo_svg_surface_create_for_stream;
-  #endif
-  #ifdef CAIRO_HAS_PDF_SURFACE
-    else if (0 == g_ascii_strcasecmp (extension, "pdf"))
-      constructor = cairo_pdf_surface_create_for_stream;
-  #endif
-  #ifdef CAIRO_HAS_PS_SURFACE
-    else if (0 == g_ascii_strcasecmp (extension, "ps"))
-      constructor = cairo_ps_surface_create_for_stream;
-   #ifdef HAS_EPS
-    else if (0 == g_ascii_strcasecmp (extension, "eps"))
-      constructor = _cairo_eps_surface_create_for_stream;
-   #endif
-  #endif
-
-
-  unsigned int fr, fg, fb, fa, br, bg, bb, ba;
-  const char *color;
-  br = bg = bb = 0; ba = 255;
-  color = view_opts->back ? view_opts->back : DEFAULT_BACK;
-  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &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);
-
-  if (content == CAIRO_CONTENT_ALPHA)
-  {
-    if (view_opts->annotate ||
-	br != bg || bg != bb ||
-	fr != fg || fg != fb)
-      content = CAIRO_CONTENT_COLOR;
-  }
-  if (ba != 255)
-    content = CAIRO_CONTENT_COLOR_ALPHA;
-
-  cairo_surface_t *surface;
-  FILE *f = out_opts->get_file_handle ();
-  if (constructor)
-    surface = constructor (stdio_write_func, f, w, h);
-  else if (constructor2)
-    surface = constructor2 (stdio_write_func, f, w, h, content);
-  else
-    fail (false, "Unknown output format `%s'; supported formats are: %s%s",
-	  extension,
-	  g_strjoinv ("/", const_cast<char**> (helper_cairo_supported_formats)),
-	  out_opts->explicit_output_format ? "" :
-	  "\nTry setting format using --output-format");
-
-  cairo_t *cr = cairo_create (surface);
-  content = cairo_surface_get_content (surface);
-
-  switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-      cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
-      cairo_paint (cr);
-      cairo_set_source_rgba (cr, 1., 1., 1.,
-			     (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
-      break;
-    default:
-    case CAIRO_CONTENT_COLOR:
-    case CAIRO_CONTENT_COLOR_ALPHA:
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-      cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
-      cairo_paint (cr);
-      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-      cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
-      break;
-  }
-
-  cairo_surface_destroy (surface);
-  return cr;
-}
-
-void
-helper_cairo_destroy_context (cairo_t *cr)
-{
-  finalize_closure_t *closure = (finalize_closure_t *)
-				cairo_surface_get_user_data (cairo_get_target (cr),
-							     &finalize_closure_key);
-  if (closure)
-    closure->callback (closure);
-
-  cairo_status_t status = cairo_status (cr);
-  if (status != CAIRO_STATUS_SUCCESS)
-    fail (false, "Failed: %s",
-	  cairo_status_to_string (status));
-  cairo_destroy (cr);
-}
-
-
-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;
-    }
-  }
-}
diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh
index 5bfbf7b..b8d4612 100644
--- a/util/helper-cairo.hh
+++ b/util/helper-cairo.hh
@@ -27,28 +27,560 @@
 #ifndef HELPER_CAIRO_HH
 #define HELPER_CAIRO_HH
 
-#include "hb.hh"
-#include "options.hh"
+#include "view-options.hh"
+#include "output-options.hh"
 
-#include <cairo.h>
+#include <cairo-ft.h>
+#include <hb-ft.h>
+#include FT_MULTIPLE_MASTERS_H
+
+#include "helper-cairo-ansi.hh"
+#ifdef CAIRO_HAS_SVG_SURFACE
+#  include <cairo-svg.h>
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+#  include <cairo-pdf.h>
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+#  include <cairo-ps.h>
+#  if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0)
+#    define HAS_EPS 1
+
+static cairo_surface_t *
+_cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
+				      void               *closure,
+				      double              width,
+				      double              height)
+{
+  cairo_surface_t *surface;
+
+  surface = cairo_ps_surface_create_for_stream (write_func, closure, width, height);
+  cairo_ps_surface_set_eps (surface, true);
+
+  return surface;
+}
+
+#  else
+#    undef HAS_EPS
+#  endif
+#endif
 
 
-cairo_scaled_font_t *
-helper_cairo_create_scaled_font (const font_options_t *font_opts);
+static FT_Library ft_library;
 
-bool
-helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font);
+#ifdef HAVE_ATEXIT
+static inline
+void free_ft_library ()
+{
+  FT_Done_FreeType (ft_library);
+}
+#endif
 
-extern const char *helper_cairo_supported_formats[];
+static inline cairo_scaled_font_t *
+helper_cairo_create_scaled_font (const font_options_t *font_opts)
+{
+  hb_font_t *font = hb_font_reference (font_opts->font);
 
-cairo_t *
+  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
+  {
+#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);
+      }
+    }
+#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;
+
+  cairo_matrix_init_identity (&ctm);
+  cairo_matrix_init_scale (&font_matrix,
+			   font_opts->font_size_x,
+			   font_opts->font_size_y);
+  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);
+
+  cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
+							       &font_matrix,
+							       &ctm,
+							       font_options);
+
+  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);
+  }
+#endif
+  return ret;
+}
+
+
+enum class image_protocol_t {
+  NONE = 0,
+  ITERM2,
+  KITTY,
+};
+
+struct finalize_closure_t {
+  void (*callback)(finalize_closure_t *);
+  cairo_surface_t *surface;
+  cairo_write_func_t write_func;
+  void *closure;
+  image_protocol_t protocol;
+};
+static cairo_user_data_key_t finalize_closure_key;
+
+
+static void
+finalize_ansi (finalize_closure_t *closure)
+{
+  cairo_status_t status;
+  status = helper_cairo_surface_write_to_ansi_stream (closure->surface,
+						      closure->write_func,
+						      closure->closure);
+  if (status != CAIRO_STATUS_SUCCESS)
+    fail (false, "Failed to write output: %s",
+	  cairo_status_to_string (status));
+}
+
+static cairo_surface_t *
+_cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func,
+				       void *closure,
+				       double width,
+				       double height,
+				       cairo_content_t content,
+				       image_protocol_t protocol HB_UNUSED)
+{
+  cairo_surface_t *surface;
+  int w = ceil (width);
+  int h = ceil (height);
+
+  switch (content) {
+    case CAIRO_CONTENT_ALPHA:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
+      break;
+    default:
+    case CAIRO_CONTENT_COLOR:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
+      break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+      break;
+  }
+  cairo_status_t status = cairo_surface_status (surface);
+  if (status != CAIRO_STATUS_SUCCESS)
+    fail (false, "Failed to create cairo surface: %s",
+	  cairo_status_to_string (status));
+
+  finalize_closure_t *ansi_closure = g_new0 (finalize_closure_t, 1);
+  ansi_closure->callback = finalize_ansi;
+  ansi_closure->surface = surface;
+  ansi_closure->write_func = write_func;
+  ansi_closure->closure = closure;
+
+  if (cairo_surface_set_user_data (surface,
+				   &finalize_closure_key,
+				   (void *) ansi_closure,
+				   (cairo_destroy_func_t) g_free))
+    g_free ((void *) closure);
+
+  return surface;
+}
+
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+
+static cairo_status_t
+byte_array_write_func (void                *closure,
+		       const unsigned char *data,
+		       unsigned int         size)
+{
+  g_byte_array_append ((GByteArray *) closure, data, size);
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+finalize_png (finalize_closure_t *closure)
+{
+  cairo_status_t status;
+  GByteArray *bytes = nullptr;
+  GString *string;
+  gchar *base64;
+  size_t base64_len;
+
+  if (closure->protocol == image_protocol_t::NONE)
+  {
+    status = cairo_surface_write_to_png_stream (closure->surface,
+						closure->write_func,
+						closure->closure);
+  }
+  else
+  {
+    bytes = g_byte_array_new ();
+    status = cairo_surface_write_to_png_stream (closure->surface,
+						byte_array_write_func,
+						bytes);
+  }
+
+  if (status != CAIRO_STATUS_SUCCESS)
+    fail (false, "Failed to write output: %s",
+	  cairo_status_to_string (status));
+
+  if (closure->protocol == image_protocol_t::NONE)
+    return;
+
+  base64 = g_base64_encode (bytes->data, bytes->len);
+  base64_len = strlen (base64);
+
+  string = g_string_new (NULL);
+  if (closure->protocol == image_protocol_t::ITERM2)
+  {
+    /* https://iterm2.com/documentation-images.html */
+    g_string_printf (string, "\033]1337;File=inline=1;size=%zu:%s\a\n",
+		     base64_len, base64);
+  }
+  else if (closure->protocol == image_protocol_t::KITTY)
+  {
+#define CHUNK_SIZE 4096
+    /* https://sw.kovidgoyal.net/kitty/graphics-protocol.html */
+    for (size_t pos = 0; pos < base64_len; pos += CHUNK_SIZE)
+    {
+      size_t len = base64_len - pos;
+
+      if (pos == 0)
+	g_string_append (string, "\033_Ga=T,f=100,m=");
+      else
+	g_string_append (string, "\033_Gm=");
+
+      if (len > CHUNK_SIZE)
+      {
+	g_string_append (string, "1;");
+	g_string_append_len (string, base64 + pos, CHUNK_SIZE);
+      }
+      else
+      {
+	g_string_append (string, "0;");
+	g_string_append_len (string, base64 + pos, len);
+      }
+
+      g_string_append (string, "\033\\");
+    }
+    g_string_append (string, "\n");
+#undef CHUNK_SIZE
+  }
+
+  closure->write_func (closure->closure, (unsigned char *) string->str, string->len);
+
+  g_byte_array_unref (bytes);
+  g_free (base64);
+  g_string_free (string, TRUE);
+}
+
+static cairo_surface_t *
+_cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
+				      void *closure,
+				      double width,
+				      double height,
+				      cairo_content_t content,
+				      image_protocol_t protocol)
+{
+  cairo_surface_t *surface;
+  int w = ceil (width);
+  int h = ceil (height);
+
+  switch (content) {
+    case CAIRO_CONTENT_ALPHA:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
+      break;
+    default:
+    case CAIRO_CONTENT_COLOR:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
+      break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+      break;
+  }
+  cairo_status_t status = cairo_surface_status (surface);
+  if (status != CAIRO_STATUS_SUCCESS)
+    fail (false, "Failed to create cairo surface: %s",
+	  cairo_status_to_string (status));
+
+  finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
+  png_closure->callback = finalize_png;
+  png_closure->surface = surface;
+  png_closure->write_func = write_func;
+  png_closure->closure = closure;
+  png_closure->protocol = protocol;
+
+  if (cairo_surface_set_user_data (surface,
+				   &finalize_closure_key,
+				   (void *) png_closure,
+				   (cairo_destroy_func_t) g_free))
+    g_free ((void *) closure);
+
+  return surface;
+}
+
+#endif
+
+static cairo_status_t
+stdio_write_func (void                *closure,
+		  const unsigned char *data,
+		  unsigned int         size)
+{
+  FILE *fp = (FILE *) closure;
+
+  while (size) {
+    size_t ret = fwrite (data, 1, size, fp);
+    size -= ret;
+    data += ret;
+    if (size && ferror (fp))
+      fail (false, "Failed to write output: %s", strerror (errno));
+  }
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static const char *helper_cairo_supported_formats[] =
+{
+  "ansi",
+  #ifdef CAIRO_HAS_PNG_FUNCTIONS
+  "png",
+  #endif
+  #ifdef CAIRO_HAS_SVG_SURFACE
+  "svg",
+  #endif
+  #ifdef CAIRO_HAS_PDF_SURFACE
+  "pdf",
+  #endif
+  #ifdef CAIRO_HAS_PS_SURFACE
+  "ps",
+   #ifdef HAS_EPS
+    "eps",
+   #endif
+  #endif
+  nullptr
+};
+
+template <typename view_options_t,
+	 typename output_options_t>
+static inline cairo_t *
 helper_cairo_create_context (double w, double h,
 			     view_options_t *view_opts,
 			     output_options_t *out_opts,
-			     cairo_content_t content);
+			     cairo_content_t content)
+{
+  cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
+				   void *closure,
+				   double width,
+				   double height) = nullptr;
+  cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
+				    void *closure,
+				    double width,
+				    double height,
+				    cairo_content_t content,
+				    image_protocol_t protocol) = nullptr;
 
-void
-helper_cairo_destroy_context (cairo_t *cr);
+  image_protocol_t protocol = image_protocol_t::NONE;
+  const char *extension = out_opts->output_format;
+  if (!extension) {
+#if HAVE_ISATTY
+    if (isatty (fileno (out_opts->out_fp)))
+    {
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+      const char *name;
+      /* https://gitlab.com/gnachman/iterm2/-/issues/7154 */
+      if ((name = getenv ("LC_TERMINAL")) != nullptr &&
+	  0 == g_ascii_strcasecmp (name, "iTerm2"))
+      {
+	extension = "png";
+	protocol = image_protocol_t::ITERM2;
+      }
+      else if ((name = getenv ("TERM")) != nullptr &&
+	       0 == g_ascii_strcasecmp (name, "xterm-kitty"))
+      {
+	extension = "png";
+	protocol = image_protocol_t::KITTY;
+      }
+      else
+	extension = "ansi";
+#else
+      extension = "ansi";
+#endif
+    }
+    else
+#endif
+    {
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+      extension = "png";
+#else
+      extension = "ansi";
+#endif
+    }
+  }
+  if (0)
+    ;
+    else if (0 == g_ascii_strcasecmp (extension, "ansi"))
+      constructor2 = _cairo_ansi_surface_create_for_stream;
+  #ifdef CAIRO_HAS_PNG_FUNCTIONS
+    else if (0 == g_ascii_strcasecmp (extension, "png"))
+      constructor2 = _cairo_png_surface_create_for_stream;
+  #endif
+  #ifdef CAIRO_HAS_SVG_SURFACE
+    else if (0 == g_ascii_strcasecmp (extension, "svg"))
+      constructor = cairo_svg_surface_create_for_stream;
+  #endif
+  #ifdef CAIRO_HAS_PDF_SURFACE
+    else if (0 == g_ascii_strcasecmp (extension, "pdf"))
+      constructor = cairo_pdf_surface_create_for_stream;
+  #endif
+  #ifdef CAIRO_HAS_PS_SURFACE
+    else if (0 == g_ascii_strcasecmp (extension, "ps"))
+      constructor = cairo_ps_surface_create_for_stream;
+   #ifdef HAS_EPS
+    else if (0 == g_ascii_strcasecmp (extension, "eps"))
+      constructor = _cairo_eps_surface_create_for_stream;
+   #endif
+  #endif
+
+
+  unsigned int fr, fg, fb, fa, br, bg, bb, ba;
+  const char *color;
+  br = bg = bb = 0; ba = 255;
+  color = view_opts->back ? view_opts->back : DEFAULT_BACK;
+  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &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);
+
+  if (content == CAIRO_CONTENT_ALPHA)
+  {
+    if (view_opts->annotate ||
+	br != bg || bg != bb ||
+	fr != fg || fg != fb)
+      content = CAIRO_CONTENT_COLOR;
+  }
+  if (ba != 255)
+    content = CAIRO_CONTENT_COLOR_ALPHA;
+
+  cairo_surface_t *surface;
+  FILE *f = out_opts->out_fp;
+  if (constructor)
+    surface = constructor (stdio_write_func, f, w, h);
+  else if (constructor2)
+    surface = constructor2 (stdio_write_func, f, w, h, content, protocol);
+  else
+    fail (false, "Unknown output format `%s'; supported formats are: %s%s",
+	  extension,
+	  g_strjoinv ("/", const_cast<char**> (helper_cairo_supported_formats)),
+	  out_opts->explicit_output_format ? "" :
+	  "\nTry setting format using --output-format");
+
+  cairo_t *cr = cairo_create (surface);
+  content = cairo_surface_get_content (surface);
+
+  switch (content) {
+    case CAIRO_CONTENT_ALPHA:
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
+      cairo_paint (cr);
+      cairo_set_source_rgba (cr, 1., 1., 1.,
+			     (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
+      break;
+    default:
+    case CAIRO_CONTENT_COLOR:
+    case CAIRO_CONTENT_COLOR_ALPHA:
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
+      cairo_paint (cr);
+      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+      cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
+      break;
+  }
+
+  cairo_surface_destroy (surface);
+  return cr;
+}
+
+static inline void
+helper_cairo_destroy_context (cairo_t *cr)
+{
+  finalize_closure_t *closure = (finalize_closure_t *)
+				cairo_surface_get_user_data (cairo_get_target (cr),
+							     &finalize_closure_key);
+  if (closure)
+    closure->callback (closure);
+
+  cairo_status_t status = cairo_status (cr);
+  if (status != CAIRO_STATUS_SUCCESS)
+    fail (false, "Failed: %s",
+	  cairo_status_to_string (status));
+  cairo_destroy (cr);
+}
 
 
 struct helper_cairo_line_t {
@@ -75,12 +607,94 @@
   }
 };
 
-void
+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);
+			       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
diff --git a/util/main-font-text.hh b/util/main-font-text.hh
index 36b654b..dabbd32 100644
--- a/util/main-font-text.hh
+++ b/util/main-font-text.hh
@@ -27,70 +27,72 @@
 #ifndef HB_MAIN_FONT_TEXT_HH
 #define HB_MAIN_FONT_TEXT_HH
 
-#include "hb.hh"
 #include "options.hh"
 
 /* main() body for utilities taking font and processing text.*/
 
-static char *
-locale_to_utf8 (char *s)
+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
 {
-  char *t;
-  GError *error = nullptr;
-
-  t = g_locale_to_utf8 (s, -1, nullptr, nullptr, &error);
-  if (!t)
+  int operator () (int argc, char **argv)
   {
-     fail (true, "Failed converting text to UTF-8");
-  }
+    add_options ();
+    parse (&argc, &argv);
 
-  return t;
-}
+    this->init (this);
 
-template <typename consumer_t, int default_font_size, int subpixel_bits>
-struct main_font_text_t
-{
-  main_font_text_t ()
-		  : options ("[FONT-FILE] [TEXT]"),
-		    font_opts (&options, default_font_size, subpixel_bits),
-		    input (&options),
-		    consumer (&options) {}
+    while (this->consume_line (*this))
+      ;
 
-  int
-  main (int argc, char **argv)
-  {
-    options.parse (&argc, &argv);
+    this->finish (this);
 
-    argc--, argv++;
-    if (argc && !font_opts.font_file) font_opts.font_file = locale_to_utf8 (argv[0]), argc--, argv++;
-    if (argc && !input.text && !input.text_file) input.text = locale_to_utf8 (argv[0]), argc--, argv++;
-    if (argc)
-      fail (true, "Too many arguments on the command line");
-    if (!font_opts.font_file)
-      options.usage ();
-    if (!input.text && !input.text_file)
-      input.text_file = g_strdup ("-");
-
-    hb_buffer_t *buffer = hb_buffer_create ();
-    consumer.init (buffer, &font_opts);
-    hb_buffer_destroy (buffer);
-
-    unsigned int text_len;
-    const char *text;
-    while ((text = input.get_line (&text_len)))
-      consumer.consume_line (text, text_len, input.text_before, input.text_after);
-
-    consumer.finish (&font_opts);
-
-    return consumer.failed ? 1 : 0;
+    return this->failed ? 1 : 0;
   }
 
   protected:
-  option_parser_t options;
-  font_options_t font_opts;
-  text_options_t input;
-  consumer_t consumer;
+
+  void add_options ()
+  {
+    font_options_t::add_options (this);
+    text_options_t::add_options (this);
+    consumer_t::add_options (this);
+
+    GOptionEntry entries[] =
+    {
+      {G_OPTION_REMAINING,	0, G_OPTION_FLAG_IN_MAIN,
+				G_OPTION_ARG_CALLBACK,	(gpointer) &collect_rest,	nullptr,	"[FONT-FILE] [TEXT]"},
+      {nullptr}
+    };
+    add_main_group (entries, this);
+    option_parser_t::add_options ();
+  }
+
+  private:
+
+  static gboolean
+  collect_rest (const char *name G_GNUC_UNUSED,
+		const char *arg,
+		gpointer    data,
+		GError    **error)
+  {
+    main_font_text_t *thiz = (main_font_text_t *) data;
+
+    if (!thiz->font_file)
+    {
+      thiz->font_file = g_strdup (arg);
+      return true;
+    }
+
+    if (!thiz->text && !thiz->text_file)
+    {
+      thiz->text = g_strdup (arg);
+      return true;
+    }
+
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		 "Too many arguments on the command line");
+    return false;
+  }
 };
 
 #endif
-
diff --git a/util/meson.build b/util/meson.build
new file mode 100644
index 0000000..fdab620
--- /dev/null
+++ b/util/meson.build
@@ -0,0 +1,58 @@
+hb_view_sources = [
+  'hb-view.cc',
+]
+
+hb_shape_sources = [
+  'hb-shape.cc',
+]
+
+hb_ot_shape_closure_sources = [
+  'hb-ot-shape-closure.cc',
+]
+
+hb_subset_cli_sources = [
+  'hb-subset.cc',
+]
+
+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
+
+    hb_view = executable('hb-view', hb_view_sources,
+      cpp_args: cpp_args,
+      include_directories: [incconfig, incsrc],
+      dependencies: [util_deps, chafa_dep],
+      link_with: [libharfbuzz],
+      install: true,
+    )
+  endif
+
+  hb_shape = executable('hb-shape', hb_shape_sources,
+    cpp_args: cpp_args,
+    include_directories: [incconfig, incsrc],
+    dependencies: util_deps,
+    link_with: [libharfbuzz],
+    install: true,
+  )
+
+  hb_subset = executable('hb-subset', hb_subset_cli_sources,
+    cpp_args: cpp_args,
+    include_directories: [incconfig, incsrc],
+    dependencies: util_deps,
+    link_with: [libharfbuzz, libharfbuzz_subset],
+    install: true,
+  )
+
+  hb_ot_shape_closure = executable('hb-ot-shape-closure', hb_ot_shape_closure_sources,
+    cpp_args: cpp_args,
+    include_directories: [incconfig, incsrc],
+    dependencies: util_deps,
+    link_with: [libharfbuzz],
+    install: true,
+  )
+else
+  # Disable tests that use this
+  hb_shape = disabler()
+  hb_subset = disabler()
+endif
diff --git a/util/options-subset.cc b/util/options-subset.cc
deleted file mode 100644
index 35fa05e..0000000
--- a/util/options-subset.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright © 2019  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 "options.hh"
-
-#include "hb-subset-input.hh"
-
-static gboolean
-parse_nameids (const char *name,
-	       const char *arg,
-	       gpointer    data,
-	       GError    **error G_GNUC_UNUSED)
-{
-  subset_options_t *subset_opts = (subset_options_t *) data;
-  hb_set_t *name_ids = subset_opts->input->name_ids;
-
-  char last_name_char = name[strlen (name) - 1];
-
-  if (last_name_char != '+' && last_name_char != '-')
-    hb_set_clear (name_ids);
-
-  if (0 == strcmp (arg, "*"))
-  {
-    if (last_name_char == '-')
-      hb_set_del_range (name_ids, 0, 0x7FFF);
-    else
-      hb_set_add_range (name_ids, 0, 0x7FFF);
-    return true;
-  }
-
-  char *s = (char *) arg;
-  char *p;
-
-  while (s && *s)
-  {
-    while (*s && strchr (", ", *s))
-      s++;
-    if (!*s)
-      break;
-
-    errno = 0;
-    hb_codepoint_t u = strtoul (s, &p, 10);
-    if (errno || s == p)
-    {
-      hb_set_destroy (name_ids);
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Failed parsing nameID values at: '%s'", s);
-      return false;
-    }
-
-    if (last_name_char != '-')
-    {
-      hb_set_add (name_ids, u);
-    } else {
-      hb_set_del (name_ids, u);
-    }
-
-    s = p;
-  }
-
-  return true;
-}
-
-static gboolean
-parse_drop_tables (const char *name,
-		   const char *arg,
-		   gpointer    data,
-		   GError    **error G_GNUC_UNUSED)
-{
-  subset_options_t *subset_opts = (subset_options_t *) data;
-  hb_set_t *drop_tables = subset_opts->input->drop_tables;
-
-  char last_name_char = name[strlen (name) - 1];
-
-  if (last_name_char != '+' && last_name_char != '-')
-    hb_set_clear (drop_tables);
-
-  char *s = strtok((char *) arg, ", ");
-  while (s)
-  {
-    if (strlen (s) > 4) // Table tags are at most 4 bytes.
-    {
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Failed parsing table tag values at: '%s'", s);
-      return false;
-    }
-
-    hb_tag_t tag = hb_tag_from_string (s, strlen (s));
-
-    if (last_name_char != '-')
-      hb_set_add (drop_tables, tag);
-    else
-      hb_set_del (drop_tables, tag);
-
-    s = strtok(nullptr, ", ");
-  }
-
-  return true;
-}
-
-void
-subset_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"no-hinting", 0, 0, G_OPTION_ARG_NONE,  &this->input->drop_hints,   "Whether to drop hints",   nullptr},
-    {"retain-gids", 0, 0, G_OPTION_ARG_NONE,  &this->input->retain_gids,   "If set don't renumber glyph ids in the subset.",   nullptr},
-    {"desubroutinize", 0, 0, G_OPTION_ARG_NONE,  &this->input->desubroutinize,   "Remove CFF/CFF2 use of subroutines",   nullptr},
-    {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_nameids,  "Subset specified nameids", "list of int numbers"},
-    {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
-    {"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
-    {"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
-
-    {nullptr}
-  };
-  parser->add_group (entries,
-	 "subset",
-	 "Subset options:",
-	 "Options subsetting",
-	 this);
-}
diff --git a/util/options.cc b/util/options.cc
deleted file mode 100644
index 43ff90a..0000000
--- a/util/options.cc
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * 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
- */
-
-#include "options.hh"
-
-#ifdef HAVE_FREETYPE
-#include <hb-ft.h>
-#endif
-#include <hb-ot.h>
-
-#define DELIMITERS "<+>{},;&#\\xXuUnNiI\n\t\v\f\r "
-
-static struct supported_font_funcs_t {
-	char name[4];
-	void (*func) (hb_font_t *);
-} supported_font_funcs[] =
-{
-#ifdef HAVE_FREETYPE
-  {"ft",	hb_ft_font_set_funcs},
-#endif
-  {"ot",	hb_ot_font_set_funcs},
-};
-
-
-void
-fail (hb_bool_t suggest_help, const char *format, ...)
-{
-  const char *msg;
-
-  va_list vap;
-  va_start (vap, format);
-  msg = g_strdup_vprintf (format, vap);
-  va_end (vap);
-  const char *prgname = g_get_prgname ();
-  g_printerr ("%s: %s\n", prgname, msg);
-  if (suggest_help)
-    g_printerr ("Try `%s --help' for more information.\n", prgname);
-
-  exit (1);
-}
-
-
-static gchar *
-shapers_to_string ()
-{
-  GString *shapers = g_string_new (nullptr);
-  const char **shaper_list = hb_shape_list_shapers ();
-
-  for (; *shaper_list; shaper_list++) {
-    g_string_append (shapers, *shaper_list);
-    g_string_append_c (shapers, ',');
-  }
-  g_string_truncate (shapers, MAX (0, (gint)shapers->len - 1));
-
-  return g_string_free (shapers, false);
-}
-
-static G_GNUC_NORETURN gboolean
-show_version (const char *name G_GNUC_UNUSED,
-	      const char *arg G_GNUC_UNUSED,
-	      gpointer    data G_GNUC_UNUSED,
-	      GError    **error G_GNUC_UNUSED)
-{
-  g_printf ("%s (%s) %s\n", g_get_prgname (), PACKAGE_NAME, PACKAGE_VERSION);
-
-  char *shapers = shapers_to_string ();
-  g_printf ("Available shapers: %s\n", shapers);
-  g_free (shapers);
-  if (strcmp (HB_VERSION_STRING, hb_version_string ()))
-    g_printf ("Linked HarfBuzz library has a different version: %s\n", hb_version_string ());
-
-  exit(0);
-}
-
-
-void
-option_parser_t::add_main_options ()
-{
-  GOptionEntry entries[] =
-  {
-    {"version",		0, G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &show_version,	"Show version numbers",			nullptr},
-    {nullptr}
-  };
-  g_option_context_add_main_entries (context, entries, nullptr);
-}
-
-static gboolean
-pre_parse (GOptionContext *context G_GNUC_UNUSED,
-	   GOptionGroup *group G_GNUC_UNUSED,
-	   gpointer data,
-	   GError **error)
-{
-  option_group_t *option_group = (option_group_t *) data;
-  option_group->pre_parse (error);
-  return *error == nullptr;
-}
-
-static gboolean
-post_parse (GOptionContext *context G_GNUC_UNUSED,
-	    GOptionGroup *group G_GNUC_UNUSED,
-	    gpointer data,
-	    GError **error)
-{
-  option_group_t *option_group = static_cast<option_group_t *>(data);
-  option_group->post_parse (error);
-  return *error == nullptr;
-}
-
-void
-option_parser_t::add_group (GOptionEntry   *entries,
-			    const gchar    *name,
-			    const gchar    *description,
-			    const gchar    *help_description,
-			    option_group_t *option_group)
-{
-  GOptionGroup *group = g_option_group_new (name, description, help_description,
-					    static_cast<gpointer>(option_group), nullptr);
-  g_option_group_add_entries (group, entries);
-  g_option_group_set_parse_hooks (group, pre_parse, post_parse);
-  g_option_context_add_group (context, group);
-}
-
-void
-option_parser_t::parse (int *argc, char ***argv)
-{
-  setlocale (LC_ALL, "");
-
-  GError *parse_error = nullptr;
-  if (!g_option_context_parse (context, argc, argv, &parse_error))
-  {
-    if (parse_error != nullptr) {
-      fail (true, "%s", parse_error->message);
-      //g_error_free (parse_error);
-    } else
-      fail (true, "Option parse error");
-  }
-}
-
-
-static gboolean
-parse_margin (const char *name G_GNUC_UNUSED,
-	      const char *arg,
-	      gpointer    data,
-	      GError    **error G_GNUC_UNUSED)
-{
-  view_options_t *view_opts = (view_options_t *) data;
-  view_options_t::margin_t &m = view_opts->margin;
-  switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf", &m.t, &m.r, &m.b, &m.l)) {
-    case 1: m.r = m.t; HB_FALLTHROUGH;
-    case 2: m.b = m.t; HB_FALLTHROUGH;
-    case 3: m.l = m.r; HB_FALLTHROUGH;
-    case 4: return true;
-    default:
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "%s argument should be one to four space-separated numbers",
-		   name);
-      return false;
-  }
-}
-
-
-static gboolean
-parse_shapers (const char *name G_GNUC_UNUSED,
-	       const char *arg,
-	       gpointer    data,
-	       GError    **error)
-{
-  shape_options_t *shape_opts = (shape_options_t *) data;
-  char **shapers = g_strsplit (arg, ",", 0);
-
-  for (char **shaper = shapers; *shaper; shaper++) {
-    bool found = false;
-    for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) {
-      if (strcmp (*shaper, *hb_shaper) == 0) {
-	found = true;
-	break;
-      }
-    }
-    if (!found) {
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Unknown or unsupported shaper: %s", *shaper);
-      g_strfreev (shapers);
-      return false;
-    }
-  }
-
-  g_strfreev (shape_opts->shapers);
-  shape_opts->shapers = shapers;
-  return true;
-}
-
-static G_GNUC_NORETURN gboolean
-list_shapers (const char *name G_GNUC_UNUSED,
-	      const char *arg G_GNUC_UNUSED,
-	      gpointer    data G_GNUC_UNUSED,
-	      GError    **error G_GNUC_UNUSED)
-{
-  for (const char **shaper = hb_shape_list_shapers (); *shaper; shaper++)
-    g_printf ("%s\n", *shaper);
-
-  exit(0);
-}
-
-
-static gboolean
-parse_features (const char *name G_GNUC_UNUSED,
-		const char *arg,
-		gpointer    data,
-		GError    **error G_GNUC_UNUSED)
-{
-  shape_options_t *shape_opts = (shape_options_t *) data;
-  char *s = (char *) arg;
-  char *p;
-
-  shape_opts->num_features = 0;
-  g_free (shape_opts->features);
-  shape_opts->features = nullptr;
-
-  if (!*s)
-    return true;
-
-  /* count the features first, so we can allocate memory */
-  p = s;
-  do {
-    shape_opts->num_features++;
-    p = strchr (p, ',');
-    if (p)
-      p++;
-  } while (p);
-
-  shape_opts->features = (hb_feature_t *) calloc (shape_opts->num_features, sizeof (*shape_opts->features));
-  if (!shape_opts->features)
-    return false;
-
-  /* now do the actual parsing */
-  p = s;
-  shape_opts->num_features = 0;
-  while (p && *p) {
-    char *end = strchr (p, ',');
-    if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
-      shape_opts->num_features++;
-    p = end ? end + 1 : nullptr;
-  }
-
-  return true;
-}
-
-static gboolean
-parse_variations (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;
-  char *s = (char *) arg;
-  char *p;
-
-  font_opts->num_variations = 0;
-  g_free (font_opts->variations);
-  font_opts->variations = nullptr;
-
-  if (!*s)
-    return true;
-
-  /* count the variations first, so we can allocate memory */
-  p = s;
-  do {
-    font_opts->num_variations++;
-    p = strchr (p, ',');
-    if (p)
-      p++;
-  } while (p);
-
-  font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations));
-  if (!font_opts->variations)
-    return false;
-
-  /* now do the actual parsing */
-  p = s;
-  font_opts->num_variations = 0;
-  while (p && *p) {
-    char *end = strchr (p, ',');
-    if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
-      font_opts->num_variations++;
-    p = end ? end + 1 : nullptr;
-  }
-
-  return true;
-}
-
-static gboolean
-parse_text (const char *name G_GNUC_UNUSED,
-	    const char *arg,
-	    gpointer    data,
-	    GError    **error G_GNUC_UNUSED)
-{
-  text_options_t *text_opts = (text_options_t *) data;
-
-  if (text_opts->text)
-  {
-    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		 "Either --text or --unicodes can be provided but not both");
-    return false;
-  }
-
-  text_opts->text_len = -1;
-  text_opts->text = g_strdup (arg);
-  return true;
-}
-
-
-static gboolean
-parse_unicodes (const char *name G_GNUC_UNUSED,
-		const char *arg,
-		gpointer    data,
-		GError    **error G_GNUC_UNUSED)
-{
-  text_options_t *text_opts = (text_options_t *) data;
-
-  if (text_opts->text)
-  {
-    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		 "Either --text or --unicodes can be provided but not both");
-    return false;
-  }
-
-  GString *gs = g_string_new (nullptr);
-  if (0 == strcmp (arg, "*"))
-  {
-    g_string_append_c (gs, '*');
-  }
-  else
-  {
-
-    char *s = (char *) arg;
-    char *p;
-
-    while (s && *s)
-    {
-      while (*s && strchr (DELIMITERS, *s))
-	s++;
-      if (!*s)
-	break;
-
-      errno = 0;
-      hb_codepoint_t u = strtoul (s, &p, 16);
-      if (errno || s == p)
-      {
-	g_string_free (gs, TRUE);
-	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-  		   "Failed parsing Unicode values at: '%s'", s);
-	return false;
-      }
-
-      g_string_append_unichar (gs, u);
-
-      s = p;
-    }
-  }
-
-  text_opts->text_len = gs->len;
-  text_opts->text = g_string_free (gs, FALSE);
-  return true;
-}
-
-
-void
-view_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"annotate",	0, 0, G_OPTION_ARG_NONE,	&this->annotate,		"Annotate output rendering",				nullptr},
-    {"background",	0, 0, G_OPTION_ARG_STRING,	&this->back,			"Set background color (default: " DEFAULT_BACK ")",	"rrggbb/rrggbbaa"},
-    {"foreground",	0, 0, G_OPTION_ARG_STRING,	&this->fore,			"Set foreground color (default: " DEFAULT_FORE ")",	"rrggbb/rrggbbaa"},
-    {"line-space",	0, 0, G_OPTION_ARG_DOUBLE,	&this->line_space,		"Set space between lines (default: 0)",			"units"},
-    {"margin",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_margin,	"Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "view",
-		     "View options:",
-		     "Options for output rendering",
-		     this);
-}
-
-void
-shape_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"list-shapers",	0, G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &list_shapers,	"List available shapers and quit",	nullptr},
-    {"shaper",		0, G_OPTION_FLAG_HIDDEN,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Hidden duplicate of --shapers",	nullptr},
-    {"shapers",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Set comma-separated list of shapers to try","list"},
-    {"direction",	0, 0, G_OPTION_ARG_STRING,	&this->direction,		"Set text direction (default: auto)",	"ltr/rtl/ttb/btt"},
-    {"language",	0, 0, G_OPTION_ARG_STRING,	&this->language,		"Set text language (default: $LANG)",	"langstr"},
-    {"script",		0, 0, G_OPTION_ARG_STRING,	&this->script,			"Set text script (default: auto)",	"ISO-15924 tag"},
-    {"bot",		0, 0, G_OPTION_ARG_NONE,	&this->bot,			"Treat text as beginning-of-paragraph",	nullptr},
-    {"eot",		0, 0, G_OPTION_ARG_NONE,	&this->eot,			"Treat text as end-of-paragraph",	nullptr},
-    {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->preserve_default_ignorables,	"Preserve Default-Ignorable characters",	nullptr},
-    {"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->remove_default_ignorables,	"Remove Default-Ignorable characters",	nullptr},
-    {"invisible-glyph",	0, 0, G_OPTION_ARG_INT,		&this->invisible_glyph,		"Glyph value to replace Default-Ignorables with",	nullptr},
-    {"utf8-clusters",	0, 0, G_OPTION_ARG_NONE,	&this->utf8_clusters,		"Use UTF8 byte indices, not char indices",	nullptr},
-    {"cluster-level",	0, 0, G_OPTION_ARG_INT,		&this->cluster_level,		"Cluster merging level (default: 0)",	"0/1/2"},
-    {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,	&this->normalize_glyphs,	"Rearrange glyph clusters in nominal order",	nullptr},
-    {"verify",		0, 0, G_OPTION_ARG_NONE,	&this->verify,			"Perform sanity checks on shaping results",	nullptr},
-    {"num-iterations", 'n', 0, G_OPTION_ARG_INT,		&this->num_iterations,		"Run shaper N times (default: 1)",	"N"},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "shape",
-		     "Shape options:",
-		     "Options for the shaping process",
-		     this);
-
-  const gchar *features_help = "Comma-separated list of font features\n"
-    "\n"
-    "    Features can be enabled or disabled, either globally or limited to\n"
-    "    specific character ranges.  The format for specifying feature settings\n"
-    "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
-    "    and the global values are also accepted, though not documented below.\n"
-    "    CSS string escapes are not supported."
-    "\n"
-    "    The range indices refer to the positions between Unicode characters,\n"
-    "    unless the --utf8-clusters is provided, in which case range indices\n"
-    "    refer to UTF-8 byte indices. The position before the first character\n"
-    "    is always 0.\n"
-    "\n"
-    "    The format is Python-esque.  Here is how it all works:\n"
-    "\n"
-    "      Syntax:       Value:    Start:    End:\n"
-    "\n"
-    "    Setting value:\n"
-    "      \"kern\"        1         0         ∞         # Turn feature on\n"
-    "      \"+kern\"       1         0         ∞         # Turn feature on\n"
-    "      \"-kern\"       0         0         ∞         # Turn feature off\n"
-    "      \"kern=0\"      0         0         ∞         # Turn feature off\n"
-    "      \"kern=1\"      1         0         ∞         # Turn feature on\n"
-    "      \"aalt=2\"      2         0         ∞         # Choose 2nd alternate\n"
-    "\n"
-    "    Setting index:\n"
-    "      \"kern[]\"      1         0         ∞         # Turn feature on\n"
-    "      \"kern[:]\"     1         0         ∞         # Turn feature on\n"
-    "      \"kern[5:]\"    1         5         ∞         # Turn feature on, partial\n"
-    "      \"kern[:5]\"    1         0         5         # Turn feature on, partial\n"
-    "      \"kern[3:5]\"   1         3         5         # Turn feature on, range\n"
-    "      \"kern[3]\"     1         3         3+1       # Turn feature on, single char\n"
-    "\n"
-    "    Mixing it all:\n"
-    "\n"
-    "      \"aalt[3:5]=2\" 2         3         5         # Turn 2nd alternate on for range";
-
-  GOptionEntry entries2[] =
-  {
-    {"features",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_features,	features_help,	"list"},
-    {nullptr}
-  };
-  parser->add_group (entries2,
-		     "features",
-		     "Features options:",
-		     "Options for font features used",
-		     this);
-}
-
-static gboolean
-parse_font_size (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;
-  if (0 == strcmp (arg, "upem"))
-  {
-    font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM;
-    return true;
-  }
-  switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
-    case 1: font_opts->font_size_y = font_opts->font_size_x; 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_ppem (const char *name G_GNUC_UNUSED,
-		 const char *arg,
-		 gpointer    data,
-		 GError    **error G_GNUC_UNUSED)
-{
-  font_options_t *font_opts = (font_options_t *) data;
-  switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) {
-    case 1: font_opts->y_ppem = font_opts->x_ppem; 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;
-  }
-}
-
-void
-font_options_t::add_options (option_parser_t *parser)
-{
-  char *text = nullptr;
-
-  {
-    static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
-		   "No supported font-funcs found.");
-    GString *s = g_string_new (nullptr);
-    g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n    Supported font function implementations are: %s",
-		     supported_font_funcs[0].name,
-		     supported_font_funcs[0].name);
-    for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++)
-    {
-      g_string_append_c (s, '/');
-      g_string_append (s, supported_font_funcs[i].name);
-    }
-    text = g_string_free (s, FALSE);
-    parser->free_later (text);
-  }
-
-  char *font_size_text;
-  if (default_font_size == FONT_SIZE_UPEM)
-    font_size_text = (char *) "Font size (default: upem)";
-  else
-  {
-    font_size_text = g_strdup_printf ("Font size (default: %d)", default_font_size);
-    parser->free_later (font_size_text);
-  }
-
-  GOptionEntry entries[] =
-  {
-    {"font-file",	0, 0, G_OPTION_ARG_STRING,	&this->font_file,		"Set font file-name",				"filename"},
-    {"face-index",	0, 0, G_OPTION_ARG_INT,		&this->face_index,		"Set face index (default: 0)",			"index"},
-    {"font-size",	0, default_font_size ? 0 : G_OPTION_FLAG_HIDDEN,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_font_size,	font_size_text,					"1/2 integers or 'upem'"},
-    {"font-ppem",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_font_ppem,	"Set x,y pixels per EM (default: 0; disabled)",	"1/2 integers"},
-    {"font-ptem",	0, 0, G_OPTION_ARG_DOUBLE,	&this->ptem,			"Set font point-size (default: 0; disabled)",	"point-size"},
-    {"font-funcs",	0, 0, G_OPTION_ARG_STRING,	&this->font_funcs,		text,						"impl"},
-    {"ft-load-flags",	0, 0, G_OPTION_ARG_INT,		&this->ft_load_flags,		"Set FreeType load-flags (default: 2)",		"integer"},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "font",
-		     "Font options:",
-		     "Options for the font",
-		     this);
-
-  const gchar *variations_help = "Comma-separated list of font variations\n"
-    "\n"
-    "    Variations are set globally. The format for specifying variation settings\n"
-    "    follows.  All valid CSS font-variation-settings values other than 'normal'\n"
-    "    and 'inherited' are also accepted, though, not documented below.\n"
-    "\n"
-    "    The format is a tag, optionally followed by an equals sign, followed by a\n"
-    "    number. For example:\n"
-    "\n"
-    "      \"wght=500\"\n"
-    "      \"slnt=-7.5\"\n";
-
-  GOptionEntry entries2[] =
-  {
-    {"variations",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_variations,	variations_help,	"list"},
-    {nullptr}
-  };
-  parser->add_group (entries2,
-		     "variations",
-		     "Variations options:",
-		     "Options for font variations used",
-		     this);
-}
-
-void
-text_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"text",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text,		"Set input text",			"string"},
-    {"text-file",	0, 0, G_OPTION_ARG_STRING,	&this->text_file,		"Set input text file-name\n\n    If no text is provided, standard input is used for input.\n",		"filename"},
-    {"unicodes",      'u', 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes,		"Set input Unicode codepoints",		"list of hex numbers"},
-    {"text-before",	0, 0, G_OPTION_ARG_STRING,	&this->text_before,		"Set text context before each line",	"string"},
-    {"text-after",	0, 0, G_OPTION_ARG_STRING,	&this->text_after,		"Set text context after each line",	"string"},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "text",
-		     "Text options:",
-		     "Options for the input text",
-		     this);
-}
-
-void
-output_options_t::add_options (option_parser_t *parser)
-{
-  const char *text;
-
-  if (nullptr == supported_formats)
-    text = "Set output serialization format";
-  else
-  {
-    char *items = g_strjoinv ("/", const_cast<char **> (supported_formats));
-    text = g_strdup_printf ("Set output format\n\n    Supported output formats are: %s", items);
-    g_free (items);
-    parser->free_later ((char *) text);
-  }
-
-  GOptionEntry entries[] =
-  {
-    {"output-file",   'o', 0, G_OPTION_ARG_STRING,	&this->output_file,		"Set output file-name (default: stdout)","filename"},
-    {"output-format", 'O', 0, G_OPTION_ARG_STRING,	&this->output_format,		text,					"format"},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "output",
-		     "Output destination & format options:",
-		     "Options for the destination & form of the output",
-		     this);
-}
-
-
-
-hb_font_t *
-font_options_t::get_font () const
-{
-  if (font)
-    return font;
-
-  /* Create the blob */
-  if (!font_file)
-    fail (true, "No font file set");
-
-  const char *font_path = font_file;
-
-  if (0 == strcmp (font_path, "-"))
-  {
-#if defined(_WIN32) || defined(__CYGWIN__)
-    setmode (fileno (stdin), O_BINARY);
-    font_path = "STDIN";
-#else
-    font_path = "/dev/stdin";
-#endif
-  }
-
-  blob = hb_blob_create_from_file (font_path);
-
-  if (blob == hb_blob_get_empty ())
-    fail (false, "Couldn't read or find %s, or it was empty.", font_path);
-
-  /* Create the face */
-  hb_face_t *face = hb_face_create (blob, face_index);
-  hb_blob_destroy (blob);
-
-
-  font = hb_font_create (face);
-
-  if (font_size_x == FONT_SIZE_UPEM)
-    font_size_x = hb_face_get_upem (face);
-  if (font_size_y == FONT_SIZE_UPEM)
-    font_size_y = hb_face_get_upem (face);
-
-  hb_font_set_ppem (font, x_ppem, y_ppem);
-  hb_font_set_ptem (font, ptem);
-
-  int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
-  int scale_y = (int) scalbnf (font_size_y, subpixel_bits);
-  hb_font_set_scale (font, scale_x, scale_y);
-  hb_face_destroy (face);
-
-  hb_font_set_variations (font, variations, num_variations);
-
-  void (*set_font_funcs) (hb_font_t *) = nullptr;
-  if (!font_funcs)
-  {
-    set_font_funcs = supported_font_funcs[0].func;
-  }
-  else
-  {
-    for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
-      if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name))
-      {
-	set_font_funcs = supported_font_funcs[i].func;
-	break;
-      }
-    if (!set_font_funcs)
-    {
-      GString *s = g_string_new (nullptr);
-      for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
-      {
-	if (i)
-	  g_string_append_c (s, '/');
-	g_string_append (s, supported_font_funcs[i].name);
-      }
-      char *p = g_string_free (s, FALSE);
-      fail (false, "Unknown font function implementation `%s'; supported values are: %s; default is %s",
-	    font_funcs,
-	    p,
-	    supported_font_funcs[0].name);
-      //free (p);
-    }
-  }
-  set_font_funcs (font);
-#ifdef HAVE_FREETYPE
-  hb_ft_font_set_load_flags (font, ft_load_flags);
-#endif
-
-  return font;
-}
-
-
-const char *
-text_options_t::get_line (unsigned int *len)
-{
-  if (text) {
-    if (!line)
-    {
-      line = text;
-      line_len = text_len;
-    }
-    if (line_len == (unsigned int) -1)
-      line_len = strlen (line);
-
-    if (!line_len) {
-      *len = 0;
-      return nullptr;
-    }
-
-    const char *ret = line;
-    const char *p = (const char *) memchr (line, '\n', line_len);
-    unsigned int ret_len;
-    if (!p) {
-      ret_len = line_len;
-      line += ret_len;
-      line_len = 0;
-    } else {
-      ret_len = p - ret;
-      line += ret_len + 1;
-      line_len -= ret_len + 1;
-    }
-
-    *len = ret_len;
-    return ret;
-  }
-
-  if (!fp) {
-    if (!text_file)
-      fail (true, "At least one of text or text-file must be set");
-
-    if (0 != strcmp (text_file, "-"))
-      fp = fopen (text_file, "r");
-    else
-      fp = stdin;
-
-    if (!fp)
-      fail (false, "Failed opening text file `%s': %s",
-	    text_file, strerror (errno));
-
-    gs = g_string_new (nullptr);
-  }
-
-  g_string_set_size (gs, 0);
-  char buf[BUFSIZ];
-  while (fgets (buf, sizeof (buf), fp)) {
-    unsigned int bytes = strlen (buf);
-    if (bytes && buf[bytes - 1] == '\n') {
-      bytes--;
-      g_string_append_len (gs, buf, bytes);
-      break;
-    }
-      g_string_append_len (gs, buf, bytes);
-  }
-  if (ferror (fp))
-    fail (false, "Failed reading text: %s",
-	  strerror (errno));
-  *len = gs->len;
-  return !*len && feof (fp) ? nullptr : gs->str;
-}
-
-
-FILE *
-output_options_t::get_file_handle ()
-{
-  if (fp)
-    return fp;
-
-  if (output_file)
-    fp = fopen (output_file, "wb");
-  else {
-#if defined(_WIN32) || defined(__CYGWIN__)
-    setmode (fileno (stdout), O_BINARY);
-#endif
-    fp = stdout;
-  }
-  if (!fp)
-    fail (false, "Cannot open output file `%s': %s",
-	  g_filename_display_name (output_file), strerror (errno));
-
-  return fp;
-}
-
-static gboolean
-parse_verbose (const char *name G_GNUC_UNUSED,
-	       const char *arg G_GNUC_UNUSED,
-	       gpointer    data G_GNUC_UNUSED,
-	       GError    **error G_GNUC_UNUSED)
-{
-  format_options_t *format_opts = (format_options_t *) data;
-  format_opts->show_text = format_opts->show_unicode = format_opts->show_line_num = true;
-  return true;
-}
-
-static gboolean
-parse_ned (const char *name G_GNUC_UNUSED,
-	   const char *arg G_GNUC_UNUSED,
-	   gpointer    data G_GNUC_UNUSED,
-	   GError    **error G_GNUC_UNUSED)
-{
-  format_options_t *format_opts = (format_options_t *) data;
-  format_opts->show_clusters = format_opts->show_advances = false;
-  return true;
-}
-
-void
-format_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"show-text",	0, 0, G_OPTION_ARG_NONE,	&this->show_text,		"Prefix each line of output with its corresponding input text",		nullptr},
-    {"show-unicode",	0, 0, G_OPTION_ARG_NONE,	&this->show_unicode,		"Prefix each line of output with its corresponding input codepoint(s)",	nullptr},
-    {"show-line-num",	0, 0, G_OPTION_ARG_NONE,	&this->show_line_num,		"Prefix each line of output with its corresponding input line number",	nullptr},
-    {"verbose",	      'v', G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_verbose,	"Prefix each line of output with all of the above",			nullptr},
-    {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Output glyph indices instead of names",				nullptr},
-    {"no-positions",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_positions,		"Do not output glyph positions",					nullptr},
-    {"no-advances",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_advances,		"Do not output glyph advances",						nullptr},
-    {"no-clusters",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_clusters,		"Do not output cluster indices",					nullptr},
-    {"show-extents",	0, 0, G_OPTION_ARG_NONE,	&this->show_extents,		"Output glyph extents",							nullptr},
-    {"show-flags",	0, 0, G_OPTION_ARG_NONE,	&this->show_flags,		"Output glyph flags",							nullptr},
-    {"ned",	      'v', G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_ned,		"No Extra Data; Do not output clusters or advances",			nullptr},
-    {"trace",	      'V', 0, G_OPTION_ARG_NONE,	&this->trace,			"Output interim shaping results",					nullptr},
-    {nullptr}
-  };
-  parser->add_group (entries,
-		     "output-syntax",
-		     "Output syntax:\n"
-	 "    text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
-	 "    json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
-	 "\nOutput syntax options:",
-		     "Options for the syntax of the output",
-		     this);
-}
-
-void
-format_options_t::serialize_unicode (hb_buffer_t *buffer,
-				     GString     *gs)
-{
-  unsigned int num_glyphs = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
-
-  g_string_append_c (gs, '<');
-  for (unsigned int i = 0; i < num_glyphs; i++)
-  {
-    if (i)
-      g_string_append_c (gs, ',');
-    g_string_append_printf (gs, "U+%04X", info->codepoint);
-    info++;
-  }
-  g_string_append_c (gs, '>');
-}
-
-void
-format_options_t::serialize_glyphs (hb_buffer_t *buffer,
-				    hb_font_t   *font,
-				    hb_buffer_serialize_format_t output_format,
-				    hb_buffer_serialize_flags_t flags,
-				    GString     *gs)
-{
-  g_string_append_c (gs, '[');
-  unsigned int num_glyphs = hb_buffer_get_length (buffer);
-  unsigned int start = 0;
-
-  while (start < num_glyphs)
-  {
-    char buf[1024];
-    unsigned int consumed;
-    start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs,
-					 buf, sizeof (buf), &consumed,
-					 font, output_format, flags);
-    if (!consumed)
-      break;
-    g_string_append (gs, buf);
-  }
-  g_string_append_c (gs, ']');
-}
-void
-format_options_t::serialize_line_no (unsigned int  line_no,
-				     GString      *gs)
-{
-  if (show_line_num)
-    g_string_append_printf (gs, "%d: ", line_no);
-}
-void
-format_options_t::serialize_buffer_of_text (hb_buffer_t  *buffer,
-					    unsigned int  line_no,
-					    const char   *text,
-					    unsigned int  text_len,
-					    hb_font_t    *font,
-					    GString      *gs)
-{
-  if (show_text)
-  {
-    serialize_line_no (line_no, gs);
-    g_string_append_c (gs, '(');
-    g_string_append_len (gs, text, text_len);
-    g_string_append_c (gs, ')');
-    g_string_append_c (gs, '\n');
-  }
-
-  if (show_unicode)
-  {
-    serialize_line_no (line_no, gs);
-    serialize_unicode (buffer, gs);
-    g_string_append_c (gs, '\n');
-  }
-}
-void
-format_options_t::serialize_message (unsigned int  line_no,
-				     const char   *type,
-				     const char   *msg,
-				     GString      *gs)
-{
-  serialize_line_no (line_no, gs);
-  g_string_append_printf (gs, "%s: %s", type, msg);
-  g_string_append_c (gs, '\n');
-}
-void
-format_options_t::serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
-					      unsigned int  line_no,
-					      const char   *text,
-					      unsigned int  text_len,
-					      hb_font_t    *font,
-					      hb_buffer_serialize_format_t output_format,
-					      hb_buffer_serialize_flags_t format_flags,
-					      GString      *gs)
-{
-  serialize_line_no (line_no, gs);
-  serialize_glyphs (buffer, font, output_format, format_flags, gs);
-  g_string_append_c (gs, '\n');
-}
diff --git a/util/options.hh b/util/options.hh
index 9e22b40..790650b 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -28,7 +28,6 @@
 #define OPTIONS_HH
 
 #include "hb.hh"
-#include "hb-subset.h"
 
 #include <stdlib.h>
 #include <stddef.h>
@@ -51,30 +50,32 @@
 #include <glib.h>
 #include <glib/gprintf.h>
 
-void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
 
-struct option_group_t
+static inline void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
+
+static inline void
+fail (hb_bool_t suggest_help, const char *format, ...)
 {
-  virtual ~option_group_t () {}
+  const char *msg;
 
-  virtual void add_options (struct option_parser_t *parser) = 0;
+  va_list vap;
+  va_start (vap, format);
+  msg = g_strdup_vprintf (format, vap);
+  va_end (vap);
+  const char *prgname = g_get_prgname ();
+  g_printerr ("%s: %s\n", prgname, msg);
+  if (suggest_help)
+    g_printerr ("Try `%s --help' for more information.\n", prgname);
 
-  virtual void pre_parse (GError **error G_GNUC_UNUSED) {}
-  virtual void post_parse (GError **error G_GNUC_UNUSED) {}
-};
-
+  exit (1);
+}
 
 struct option_parser_t
 {
-  option_parser_t (const char *usage)
-  {
-    memset (this, 0, sizeof (*this));
-    usage_str = usage;
-    context = g_option_context_new (usage);
-    to_free = g_ptr_array_new ();
-
-    add_main_options ();
-  }
+  option_parser_t (const char *parameter_string = nullptr)
+  : context (g_option_context_new (parameter_string)),
+    to_free (g_ptr_array_new ())
+  {}
 
   static void _g_free_g_func (void *p, void * G_GNUC_UNUSED) { g_free (p); }
 
@@ -85,608 +86,142 @@
     g_ptr_array_free (to_free, TRUE);
   }
 
-  void add_main_options ();
+  void add_options ();
 
+  static void
+  post_parse_ (void *thiz, GError **error) {}
+  template <typename Type>
+  static auto
+  post_parse_ (Type *thiz, GError **error) -> decltype (thiz->post_parse (error))
+  { thiz->post_parse (error); }
+  template <typename Type>
+  static gboolean
+  post_parse (GOptionContext *context G_GNUC_UNUSED,
+	      GOptionGroup *group G_GNUC_UNUSED,
+	      gpointer data,
+	      GError **error)
+  {
+    option_parser_t::post_parse_ (static_cast<Type *> (data), error);
+    return !*error;
+  }
+
+  template <typename Type>
   void add_group (GOptionEntry   *entries,
 		  const gchar    *name,
 		  const gchar    *description,
 		  const gchar    *help_description,
-		  option_group_t *option_group);
+		  Type           *closure,
+		  bool		  add_parse_hooks = true)
+  {
+    GOptionGroup *group = g_option_group_new (name, description, help_description,
+					      static_cast<gpointer>(closure), nullptr);
+    g_option_group_add_entries (group, entries);
+    if (add_parse_hooks)
+      g_option_group_set_parse_hooks (group, nullptr, post_parse<Type>);
+    g_option_context_add_group (context, group);
+  }
+
+  template <typename Type>
+  void add_main_group (GOptionEntry   *entries,
+		       Type           *closure)
+  {
+    GOptionGroup *group = g_option_group_new (nullptr, nullptr, nullptr,
+					      static_cast<gpointer>(closure), nullptr);
+    g_option_group_add_entries (group, entries);
+    /* https://gitlab.gnome.org/GNOME/glib/-/issues/2460 */
+    //g_option_group_set_parse_hooks (group, nullptr, post_parse<Type>);
+    g_option_context_set_main_group (context, group);
+  }
+
+  void set_summary (const char *summary)
+  {
+    g_option_context_set_summary (context, summary);
+  }
+  void set_description (const char *description)
+  {
+    g_option_context_set_description (context, description);
+  }
 
   void free_later (char *p) {
     g_ptr_array_add (to_free, p);
   }
 
-  void parse (int *argc, char ***argv);
+  bool parse (int *argc, char ***argv, bool ignore_error = false);
 
-  G_GNUC_NORETURN void usage () {
-    g_printerr ("Usage: %s [OPTION...] %s\n", g_get_prgname (), usage_str);
-    exit (1);
-  }
-
-  private:
-  const char *usage_str;
   GOptionContext *context;
+  protected:
   GPtrArray *to_free;
 };
 
 
-#define DEFAULT_MARGIN 16
-#define DEFAULT_FORE "#000000"
-#define DEFAULT_BACK "#FFFFFF"
-#define FONT_SIZE_UPEM 0x7FFFFFFF
-#define FONT_SIZE_NONE 0
-
-struct view_options_t : option_group_t
+static inline gchar *
+shapers_to_string ()
 {
-  view_options_t (option_parser_t *parser)
-  {
-    annotate = false;
-    fore = nullptr;
-    back = nullptr;
-    line_space = 0;
-    margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
+  GString *shapers = g_string_new (nullptr);
+  const char **shaper_list = hb_shape_list_shapers ();
 
-    add_options (parser);
+  for (; *shaper_list; shaper_list++) {
+    g_string_append (shapers, *shaper_list);
+    g_string_append_c (shapers, ',');
   }
-  ~view_options_t () override
-  {
-    g_free (fore);
-    g_free (back);
-  }
+  g_string_truncate (shapers, MAX (0, (gint)shapers->len - 1));
 
-  void add_options (option_parser_t *parser) override;
+  return g_string_free (shapers, false);
+}
 
-  hb_bool_t annotate;
-  char *fore;
-  char *back;
-  double line_space;
-  struct margin_t {
-    double t, r, b, l;
-  } margin;
-};
-
-
-struct shape_options_t : option_group_t
+static G_GNUC_NORETURN gboolean
+show_version (const char *name G_GNUC_UNUSED,
+	      const char *arg G_GNUC_UNUSED,
+	      gpointer    data G_GNUC_UNUSED,
+	      GError    **error G_GNUC_UNUSED)
 {
-  shape_options_t (option_parser_t *parser)
+  g_printf ("%s (%s) %s\n", g_get_prgname (), PACKAGE_NAME, PACKAGE_VERSION);
+
+  char *shapers = shapers_to_string ();
+  g_printf ("Available shapers: %s\n", shapers);
+  g_free (shapers);
+  if (strcmp (HB_VERSION_STRING, hb_version_string ()))
+    g_printf ("Linked HarfBuzz library has a different version: %s\n", hb_version_string ());
+
+  exit(0);
+}
+
+inline void
+option_parser_t::add_options ()
+{
+  GOptionEntry entries[] =
   {
-    direction = language = script = nullptr;
-    bot = eot = preserve_default_ignorables = remove_default_ignorables = false;
-    features = nullptr;
-    num_features = 0;
-    shapers = nullptr;
-    utf8_clusters = false;
-    invisible_glyph = 0;
-    cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
-    normalize_glyphs = false;
-    verify = false;
-    num_iterations = 1;
+    {"version",		0, G_OPTION_FLAG_NO_ARG,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &show_version,	"Show version numbers",			nullptr},
+    {nullptr}
+  };
+  g_option_context_add_main_entries (context, entries, nullptr);
+}
 
-    add_options (parser);
-  }
-  ~shape_options_t () override
+inline bool
+option_parser_t::parse (int *argc, char ***argv, bool ignore_error)
+{
+  setlocale (LC_ALL, "");
+
+  GError *parse_error = nullptr;
+  if (!g_option_context_parse (context, argc, argv, &parse_error))
   {
-    g_free (direction);
-    g_free (language);
-    g_free (script);
-    free (features);
-    g_strfreev (shapers);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  void setup_buffer (hb_buffer_t *buffer)
-  {
-    hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
-    hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
-    hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
-    hb_buffer_set_flags (buffer, (hb_buffer_flags_t)
-				 (HB_BUFFER_FLAG_DEFAULT |
-				  (bot ? HB_BUFFER_FLAG_BOT : 0) |
-				  (eot ? HB_BUFFER_FLAG_EOT : 0) |
-				  (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
-				  (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
-				  0));
-    hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
-    hb_buffer_set_cluster_level (buffer, cluster_level);
-    hb_buffer_guess_segment_properties (buffer);
-  }
-
-  static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src)
-  {
-    hb_segment_properties_t props;
-    hb_buffer_get_segment_properties (src, &props);
-    hb_buffer_set_segment_properties (dst, &props);
-    hb_buffer_set_flags (dst, hb_buffer_get_flags (src));
-    hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src));
-  }
-
-  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
-			const char *text_before, const char *text_after)
-  {
-    hb_buffer_clear_contents (buffer);
-    if (text_before) {
-      unsigned int len = strlen (text_before);
-      hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
-    }
-    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
-    if (text_after) {
-      hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
-    }
-
-    if (!utf8_clusters) {
-      /* Reset cluster values to refer to Unicode character index
-       * instead of UTF-8 index. */
-      unsigned int num_glyphs = hb_buffer_get_length (buffer);
-      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
-      for (unsigned int i = 0; i < num_glyphs; i++)
-      {
-	info->cluster = i;
-	info++;
-      }
-    }
-
-    setup_buffer (buffer);
-  }
-
-  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
-  {
-    hb_buffer_t *text_buffer = nullptr;
-    if (verify)
+    if (parse_error)
     {
-      text_buffer = hb_buffer_create ();
-      hb_buffer_append (text_buffer, buffer, 0, -1);
+      if (!ignore_error)
+	fail (true, "%s", parse_error->message);
+      g_error_free (parse_error);
     }
-
-    if (!hb_shape_full (font, buffer, features, num_features, shapers))
+    else
     {
-      if (error)
-	*error = "all shapers failed.";
-      goto fail;
+      if (!ignore_error)
+	fail (true, "Option parse error");
     }
-
-    if (normalize_glyphs)
-      hb_buffer_normalize_glyphs (buffer);
-
-    if (verify && !verify_buffer (buffer, text_buffer, font, error))
-      goto fail;
-
-    if (text_buffer)
-      hb_buffer_destroy (text_buffer);
-
-    return true;
-
-  fail:
-    if (text_buffer)
-      hb_buffer_destroy (text_buffer);
-
     return false;
   }
+  return true;
+}
 
-  bool verify_buffer (hb_buffer_t  *buffer,
-		      hb_buffer_t  *text_buffer,
-		      hb_font_t    *font,
-		      const char  **error=nullptr)
-  {
-    if (!verify_buffer_monotone (buffer, error))
-      return false;
-    if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error))
-      return false;
-    return true;
-  }
-
-  bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr)
-  {
-    /* Check that clusters are monotone. */
-    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
-	cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
-    {
-      bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
-
-      unsigned int num_glyphs;
-      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
-
-      for (unsigned int i = 1; i < num_glyphs; i++)
-	if (info[i-1].cluster != info[i].cluster &&
-	    (info[i-1].cluster < info[i].cluster) != is_forward)
-	{
-	  if (error)
-	    *error = "clusters are not monotone.";
-	  return false;
-	}
-    }
-
-    return true;
-  }
-
-  bool verify_buffer_safe_to_break (hb_buffer_t  *buffer,
-				    hb_buffer_t  *text_buffer,
-				    hb_font_t    *font,
-				    const char  **error=nullptr)
-  {
-    if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
-	cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
-    {
-      /* Cannot perform this check without monotone clusters.
-       * Then again, unsafe-to-break flag is much harder to use without
-       * monotone clusters. */
-      return true;
-    }
-
-    /* Check that breaking up shaping at safe-to-break is indeed safe. */
-
-    hb_buffer_t *fragment = hb_buffer_create ();
-    hb_buffer_t *reconstruction = hb_buffer_create ();
-    copy_buffer_properties (reconstruction, buffer);
-
-    unsigned int num_glyphs;
-    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
-
-    unsigned int num_chars;
-    hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
-
-    /* Chop text and shape fragments. */
-    bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
-    unsigned int start = 0;
-    unsigned int text_start = forward ? 0 : num_chars;
-    unsigned int text_end = text_start;
-    for (unsigned int end = 1; end < num_glyphs + 1; end++)
-    {
-      if (end < num_glyphs &&
-	  (info[end].cluster == info[end-1].cluster ||
-	   info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
-	  continue;
-
-      /* Shape segment corresponding to glyphs start..end. */
-      if (end == num_glyphs)
-      {
-	if (forward)
-	  text_end = num_chars;
-	else
-	  text_start = 0;
-      }
-      else
-      {
-	if (forward)
-	{
-	  unsigned int cluster = info[end].cluster;
-	  while (text_end < num_chars && text[text_end].cluster < cluster)
-	    text_end++;
-	}
-	else
-	{
-	  unsigned int cluster = info[end - 1].cluster;
-	  while (text_start && text[text_start - 1].cluster >= cluster)
-	    text_start--;
-	}
-      }
-      assert (text_start < text_end);
-
-      if (0)
-	printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
-
-      hb_buffer_clear_contents (fragment);
-      copy_buffer_properties (fragment, buffer);
-
-      /* TODO: Add pre/post context text. */
-      hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
-      if (0 < text_start)
-	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
-      if (text_end < num_chars)
-	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
-      hb_buffer_set_flags (fragment, flags);
-
-      hb_buffer_append (fragment, text_buffer, text_start, text_end);
-      if (!hb_shape_full (font, fragment, features, num_features, shapers))
-      {
-	if (error)
-	  *error = "all shapers failed while shaping fragment.";
-	hb_buffer_destroy (reconstruction);
-	hb_buffer_destroy (fragment);
-	return false;
-      }
-      hb_buffer_append (reconstruction, fragment, 0, -1);
-
-      start = end;
-      if (forward)
-	text_start = text_end;
-      else
-	text_end = text_start;
-    }
-
-    bool ret = true;
-    hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
-    if (diff)
-    {
-      if (error)
-	*error = "Safe-to-break test failed.";
-      ret = false;
-
-      /* Return the reconstructed result instead so it can be inspected. */
-      hb_buffer_set_length (buffer, 0);
-      hb_buffer_append (buffer, reconstruction, 0, -1);
-    }
-
-    hb_buffer_destroy (reconstruction);
-    hb_buffer_destroy (fragment);
-
-    return ret;
-  }
-
-  void shape_closure (const char *text, int text_len,
-		      hb_font_t *font, hb_buffer_t *buffer,
-		      hb_set_t *glyphs)
-  {
-    hb_buffer_reset (buffer);
-    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
-    setup_buffer (buffer);
-    hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
-  }
-
-  /* Buffer properties */
-  char *direction;
-  char *language;
-  char *script;
-
-  /* Buffer flags */
-  hb_bool_t bot;
-  hb_bool_t eot;
-  hb_bool_t preserve_default_ignorables;
-  hb_bool_t remove_default_ignorables;
-
-  hb_feature_t *features;
-  unsigned int num_features;
-  char **shapers;
-  hb_bool_t utf8_clusters;
-  hb_codepoint_t invisible_glyph;
-  hb_buffer_cluster_level_t cluster_level;
-  hb_bool_t normalize_glyphs;
-  hb_bool_t verify;
-  unsigned int num_iterations;
-};
-
-
-struct font_options_t : option_group_t
-{
-  font_options_t (option_parser_t *parser,
-		  int default_font_size_,
-		  unsigned int subpixel_bits_)
-  {
-    variations = nullptr;
-    num_variations = 0;
-    default_font_size = default_font_size_;
-    x_ppem = 0;
-    y_ppem = 0;
-    ptem = 0.;
-    subpixel_bits = subpixel_bits_;
-    font_file = nullptr;
-    face_index = 0;
-    font_size_x = font_size_y = default_font_size;
-    font_funcs = nullptr;
-    ft_load_flags = 2;
-
-    blob = nullptr;
-    font = nullptr;
-
-    add_options (parser);
-  }
-  ~font_options_t () override
-  {
-    g_free (font_file);
-    free (variations);
-    g_free (font_funcs);
-    hb_font_destroy (font);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  hb_font_t *get_font () const;
-
-  char *font_file;
-  mutable hb_blob_t *blob;
-  int face_index;
-  hb_variation_t *variations;
-  unsigned int num_variations;
-  int default_font_size;
-  int x_ppem;
-  int y_ppem;
-  double ptem;
-  unsigned int subpixel_bits;
-  mutable double font_size_x;
-  mutable double font_size_y;
-  char *font_funcs;
-  int ft_load_flags;
-
-  private:
-  mutable hb_font_t *font;
-};
-
-
-struct text_options_t : option_group_t
-{
-  text_options_t (option_parser_t *parser)
-  {
-    text_before = nullptr;
-    text_after = nullptr;
-
-    text_len = -1;
-    text = nullptr;
-    text_file = nullptr;
-
-    fp = nullptr;
-    gs = nullptr;
-    line = nullptr;
-    line_len = (unsigned int) -1;
-
-    add_options (parser);
-  }
-  ~text_options_t () override
-  {
-    g_free (text_before);
-    g_free (text_after);
-    g_free (text);
-    g_free (text_file);
-    if (gs)
-      g_string_free (gs, true);
-    if (fp && fp != stdin)
-      fclose (fp);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  void post_parse (GError **error G_GNUC_UNUSED) override {
-    if (text && text_file)
-      g_set_error (error,
-		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Only one of text and text-file can be set");
-  }
-
-  const char *get_line (unsigned int *len);
-
-  char *text_before;
-  char *text_after;
-
-  int text_len;
-  char *text;
-  char *text_file;
-
-  private:
-  FILE *fp;
-  GString *gs;
-  char *line;
-  unsigned int line_len;
-};
-
-struct output_options_t : option_group_t
-{
-  output_options_t (option_parser_t *parser,
-		    const char **supported_formats_ = nullptr)
-  {
-    output_file = nullptr;
-    output_format = nullptr;
-    supported_formats = supported_formats_;
-    explicit_output_format = false;
-
-    fp = nullptr;
-
-    add_options (parser);
-  }
-  ~output_options_t () override
-  {
-    g_free (output_file);
-    g_free (output_format);
-    if (fp && fp != stdout)
-      fclose (fp);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  void post_parse (GError **error G_GNUC_UNUSED) override
-  {
-    if (output_format)
-      explicit_output_format = true;
-
-    if (output_file && !output_format) {
-      output_format = strrchr (output_file, '.');
-      if (output_format)
-      {
-	  output_format++; /* skip the dot */
-	  output_format = g_strdup (output_format);
-      }
-    }
-
-    if (output_file && 0 == strcmp (output_file, "-"))
-      output_file = nullptr; /* STDOUT */
-  }
-
-  FILE *get_file_handle ();
-
-  char *output_file;
-  char *output_format;
-  const char **supported_formats;
-  bool explicit_output_format;
-
-  mutable FILE *fp;
-};
-
-struct format_options_t : option_group_t
-{
-  format_options_t (option_parser_t *parser) {
-    show_glyph_names = true;
-    show_positions = true;
-    show_advances = true;
-    show_clusters = true;
-    show_text = false;
-    show_unicode = false;
-    show_line_num = false;
-    show_extents = false;
-    show_flags = false;
-    trace = false;
-
-    add_options (parser);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  void serialize_unicode (hb_buffer_t  *buffer,
-			  GString      *gs);
-  void serialize_glyphs (hb_buffer_t  *buffer,
-			 hb_font_t    *font,
-			 hb_buffer_serialize_format_t format,
-			 hb_buffer_serialize_flags_t flags,
-			 GString      *gs);
-  void serialize_line_no (unsigned int  line_no,
-			  GString      *gs);
-  void serialize_buffer_of_text (hb_buffer_t  *buffer,
-				 unsigned int  line_no,
-				 const char   *text,
-				 unsigned int  text_len,
-				 hb_font_t    *font,
-				 GString      *gs);
-  void serialize_message (unsigned int  line_no,
-			  const char   *type,
-			  const char   *msg,
-			  GString      *gs);
-  void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
-				   unsigned int  line_no,
-				   const char   *text,
-				   unsigned int  text_len,
-				   hb_font_t    *font,
-				   hb_buffer_serialize_format_t output_format,
-				   hb_buffer_serialize_flags_t format_flags,
-				   GString      *gs);
-
-
-  hb_bool_t show_glyph_names;
-  hb_bool_t show_positions;
-  hb_bool_t show_advances;
-  hb_bool_t show_clusters;
-  hb_bool_t show_text;
-  hb_bool_t show_unicode;
-  hb_bool_t show_line_num;
-  hb_bool_t show_extents;
-  hb_bool_t show_flags;
-  hb_bool_t trace;
-};
-
-struct subset_options_t : option_group_t
-{
-  subset_options_t (option_parser_t *parser)
-  {
-    input = hb_subset_input_create_or_fail ();
-    add_options (parser);
-  }
-
-  ~subset_options_t () override
-  {
-    hb_subset_input_destroy (input);
-  }
-
-  void add_options (option_parser_t *parser) override;
-
-  hb_subset_input_t *input;
-};
 
 /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
 #if defined (_MSC_VER) && (_MSC_VER < 1800)
diff --git a/util/output-options.hh b/util/output-options.hh
new file mode 100644
index 0000000..270e9f1
--- /dev/null
+++ b/util/output-options.hh
@@ -0,0 +1,117 @@
+/*
+ * 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
+ */
+
+#ifndef OUTPUT_OPTIONS_HH
+#define OUTPUT_OPTIONS_HH
+
+#include "options.hh"
+
+template <bool default_stdout = true>
+struct output_options_t
+{
+  ~output_options_t ()
+  {
+    g_free (output_file);
+    g_free (output_format);
+    if (out_fp && out_fp != stdout)
+      fclose (out_fp);
+  }
+
+  void add_options (option_parser_t *parser,
+		    const char **supported_formats = nullptr)
+  {
+    const char *text = nullptr;
+
+    if (supported_formats)
+    {
+      char *items = g_strjoinv ("/", const_cast<char **> (supported_formats));
+      text = g_strdup_printf ("Set output format\n\n    Supported output formats are: %s", items);
+      g_free (items);
+      parser->free_later ((char *) text);
+    }
+
+    GOptionEntry entries[] =
+    {
+      {"output-file",   'o', 0, G_OPTION_ARG_STRING,	&this->output_file,		"Set output file-name (default: stdout)","filename"},
+      {"output-format", 'O', supported_formats ? 0 : G_OPTION_FLAG_HIDDEN,
+				G_OPTION_ARG_STRING,	&this->output_format,		text,					"format"},
+      {nullptr}
+    };
+    parser->add_group (entries,
+		       "output",
+		       "Output destination & format options:",
+		       "Options for the destination & form of the output",
+		       this);
+  }
+
+  void post_parse (GError **error)
+  {
+    if (output_format)
+      explicit_output_format = true;
+
+    if (output_file && !output_format)
+    {
+      output_format = strrchr (output_file, '.');
+      if (output_format)
+      {
+	  output_format++; /* skip the dot */
+	  output_format = g_strdup (output_format);
+      }
+    }
+
+    if (output_file && 0 != strcmp (output_file, "-"))
+      out_fp = fopen (output_file, "wb");
+    else
+    {
+      if (!default_stdout && !output_file)
+      {
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		     "No output file was specified");
+        return;
+      }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+      setmode (fileno (stdout), O_BINARY);
+#endif
+      out_fp = stdout;
+    }
+    if (!out_fp)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		   "Cannot open output file `%s': %s",
+		   g_filename_display_name (output_file), strerror (errno));
+      return;
+    }
+  }
+
+  char *output_file = nullptr;
+  char *output_format = nullptr;
+
+  bool explicit_output_format = false;
+  FILE *out_fp = nullptr;
+};
+
+#endif
diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh
index da0d880..2115189 100644
--- a/util/shape-consumer.hh
+++ b/util/shape-consumer.hh
@@ -27,74 +27,74 @@
 #ifndef HB_SHAPE_CONSUMER_HH
 #define HB_SHAPE_CONSUMER_HH
 
-#include "hb.hh"
-#include "options.hh"
+#include "font-options.hh"
+#include "shape-options.hh"
+#include "text-options.hh"
 
 
 template <typename output_t>
-struct shape_consumer_t
+struct shape_consumer_t : shape_options_t
 {
-  shape_consumer_t (option_parser_t *parser)
-		  : failed (false),
-		    shaper (parser),
-		    output (parser),
-		    font (nullptr),
-		    buffer (nullptr) {}
-
-  void init (hb_buffer_t  *buffer_,
-	     const font_options_t *font_opts)
+  void add_options (option_parser_t *parser)
   {
-    font = hb_font_reference (font_opts->get_font ());
-    failed = false;
-    buffer = hb_buffer_reference (buffer_);
-
-    output.init (buffer, font_opts);
+    shape_options_t::add_options (parser);
+    output.add_options (parser);
   }
-  void consume_line (const char   *text,
-		     unsigned int  text_len,
-		     const char   *text_before,
-		     const char   *text_after)
+
+  template <typename app_t>
+  void init (const app_t *app)
   {
+    failed = false;
+    buffer = hb_buffer_create ();
+
+    output.init (buffer, app);
+  }
+  template <typename app_t>
+  bool consume_line (app_t &app)
+  {
+    unsigned int text_len;
+    const char *text;
+    if (!(text = app.get_line (&text_len)))
+      return false;
+
     output.new_line ();
 
-    for (unsigned int n = shaper.num_iterations; n; n--)
+    for (unsigned int n = num_iterations; n; n--)
     {
       const char *error = nullptr;
 
-      shaper.populate_buffer (buffer, text, text_len, text_before, text_after);
+      populate_buffer (buffer, text, text_len, app.text_before, app.text_after);
       if (n == 1)
-	output.consume_text (buffer, text, text_len, shaper.utf8_clusters);
-      if (!shaper.shape (font, buffer, &error))
+	output.consume_text (buffer, text, text_len, utf8_clusters);
+      if (!shape (app.font, buffer, &error))
       {
 	failed = true;
 	output.error (error);
 	if (hb_buffer_get_content_type (buffer) == HB_BUFFER_CONTENT_TYPE_GLYPHS)
 	  break;
 	else
-	  return;
+	  return true;
       }
     }
 
-    output.consume_glyphs (buffer, text, text_len, shaper.utf8_clusters);
+    output.consume_glyphs (buffer, text, text_len, utf8_clusters);
+    return true;
   }
-  void finish (const font_options_t *font_opts)
+  template <typename app_t>
+  void finish (const app_t *app)
   {
-    output.finish (buffer, font_opts);
-    hb_font_destroy (font);
-    font = nullptr;
+    output.finish (buffer, app);
     hb_buffer_destroy (buffer);
     buffer = nullptr;
   }
 
   public:
-  bool failed;
+  bool failed = false;
 
   protected:
-  shape_options_t shaper;
   output_t output;
 
-  hb_font_t *font;
-  hb_buffer_t *buffer;
+  hb_buffer_t *buffer = nullptr;
 };
 
 
diff --git a/util/shape-format.hh b/util/shape-format.hh
new file mode 100644
index 0000000..18b0b96
--- /dev/null
+++ b/util/shape-format.hh
@@ -0,0 +1,214 @@
+/*
+ * 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
+ */
+
+#ifndef SHAPE_FORMAT_OPTIONS_HH
+#define SHAPE_FORMAT_OPTIONS_HH
+
+#include "options.hh"
+
+
+struct shape_format_options_t
+{
+  void add_options (option_parser_t *parser);
+
+  void serialize (hb_buffer_t  *buffer,
+			 hb_font_t    *font,
+			 hb_buffer_serialize_format_t format,
+			 hb_buffer_serialize_flags_t flags,
+			 GString      *gs);
+  void serialize_line_no (unsigned int  line_no,
+			  GString      *gs);
+  void serialize_buffer_of_text (hb_buffer_t  *buffer,
+				 unsigned int  line_no,
+				 const char   *text,
+				 unsigned int  text_len,
+				 hb_font_t    *font,
+				 GString      *gs);
+  void serialize_message (unsigned int  line_no,
+			  const char   *type,
+			  const char   *msg,
+			  GString      *gs);
+  void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
+				   unsigned int  line_no,
+				   const char   *text,
+				   unsigned int  text_len,
+				   hb_font_t    *font,
+				   hb_buffer_serialize_format_t output_format,
+				   hb_buffer_serialize_flags_t format_flags,
+				   GString      *gs);
+
+
+  hb_bool_t show_glyph_names = true;
+  hb_bool_t show_positions = true;
+  hb_bool_t show_advances = true;
+  hb_bool_t show_clusters = true;
+  hb_bool_t show_text = false;
+  hb_bool_t show_unicode = false;
+  hb_bool_t show_line_num = false;
+  hb_bool_t show_extents = false;
+  hb_bool_t show_flags = false;
+  hb_bool_t trace = false;
+};
+
+
+static gboolean
+parse_verbose (const char *name G_GNUC_UNUSED,
+	       const char *arg G_GNUC_UNUSED,
+	       gpointer    data G_GNUC_UNUSED,
+	       GError    **error G_GNUC_UNUSED)
+{
+  shape_format_options_t *format_opts = (shape_format_options_t *) data;
+  format_opts->show_text = format_opts->show_unicode = format_opts->show_line_num = true;
+  return true;
+}
+
+static gboolean
+parse_ned (const char *name G_GNUC_UNUSED,
+	   const char *arg G_GNUC_UNUSED,
+	   gpointer    data G_GNUC_UNUSED,
+	   GError    **error G_GNUC_UNUSED)
+{
+  shape_format_options_t *format_opts = (shape_format_options_t *) data;
+  format_opts->show_clusters = format_opts->show_advances = false;
+  return true;
+}
+
+inline void
+shape_format_options_t::serialize (hb_buffer_t *buffer,
+				   hb_font_t   *font,
+				   hb_buffer_serialize_format_t output_format,
+				   hb_buffer_serialize_flags_t flags,
+				   GString     *gs)
+{
+  unsigned int num_glyphs = hb_buffer_get_length (buffer);
+  unsigned int start = 0;
+
+  while (start < num_glyphs)
+  {
+    char buf[32768];
+    unsigned int consumed;
+    start += hb_buffer_serialize (buffer, start, num_glyphs,
+				  buf, sizeof (buf), &consumed,
+				  font, output_format, flags);
+    if (!consumed)
+      break;
+    g_string_append (gs, buf);
+  }
+}
+
+inline void
+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);
+}
+inline void
+shape_format_options_t::serialize_buffer_of_text (hb_buffer_t  *buffer,
+						  unsigned int  line_no,
+						  const char   *text,
+						  unsigned int  text_len,
+						  hb_font_t    *font,
+						  GString      *gs)
+{
+  if (show_text)
+  {
+    serialize_line_no (line_no, gs);
+    g_string_append_c (gs, '(');
+    g_string_append_len (gs, text, text_len);
+    g_string_append_c (gs, ')');
+    g_string_append_c (gs, '\n');
+  }
+
+  if (show_unicode)
+  {
+    serialize_line_no (line_no, gs);
+    serialize (buffer, font, HB_BUFFER_SERIALIZE_FORMAT_TEXT, HB_BUFFER_SERIALIZE_FLAG_DEFAULT, gs);
+    g_string_append_c (gs, '\n');
+  }
+}
+inline void
+shape_format_options_t::serialize_message (unsigned int  line_no,
+					   const char   *type,
+					   const char   *msg,
+					   GString      *gs)
+{
+  serialize_line_no (line_no, gs);
+  g_string_append_printf (gs, "%s: %s", type, msg);
+  g_string_append_c (gs, '\n');
+}
+inline void
+shape_format_options_t::serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
+						    unsigned int  line_no,
+						    const char   *text,
+						    unsigned int  text_len,
+						    hb_font_t    *font,
+						    hb_buffer_serialize_format_t output_format,
+						    hb_buffer_serialize_flags_t format_flags,
+						    GString      *gs)
+{
+  serialize_line_no (line_no, gs);
+  serialize (buffer, font, output_format, format_flags, gs);
+  g_string_append_c (gs, '\n');
+}
+
+
+void
+shape_format_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"show-text",	0, 0, G_OPTION_ARG_NONE,	&this->show_text,		"Prefix each line of output with its corresponding input text",		nullptr},
+    {"show-unicode",	0, 0, G_OPTION_ARG_NONE,	&this->show_unicode,		"Prefix each line of output with its corresponding input codepoint(s)",	nullptr},
+    {"show-line-num",	0, 0, G_OPTION_ARG_NONE,	&this->show_line_num,		"Prefix each line of output with its corresponding input line number",	nullptr},
+    {"verbose",	      'v', G_OPTION_FLAG_NO_ARG,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_verbose,	"Prefix each line of output with all of the above",			nullptr},
+    {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Output glyph indices instead of names",				nullptr},
+    {"no-positions",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_positions,		"Do not output glyph positions",					nullptr},
+    {"no-advances",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_advances,		"Do not output glyph advances",						nullptr},
+    {"no-clusters",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_clusters,		"Do not output cluster indices",					nullptr},
+    {"show-extents",	0, 0, G_OPTION_ARG_NONE,	&this->show_extents,		"Output glyph extents",							nullptr},
+    {"show-flags",	0, 0, G_OPTION_ARG_NONE,	&this->show_flags,		"Output glyph flags",							nullptr},
+    {"ned",	      'v', G_OPTION_FLAG_NO_ARG,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_ned,		"No Extra Data; Do not output clusters or advances",			nullptr},
+    {"trace",	      'V', 0, G_OPTION_ARG_NONE,	&this->trace,			"Output interim shaping results",					nullptr},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "output-syntax",
+		     "Output syntax:\n"
+	 "    text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
+	 "    json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
+	 "\nOutput syntax options:",
+		     "Options for the syntax of the output",
+		     this);
+}
+
+#endif
diff --git a/util/shape-options.hh b/util/shape-options.hh
new file mode 100644
index 0000000..8d33184
--- /dev/null
+++ b/util/shape-options.hh
@@ -0,0 +1,496 @@
+/*
+ * 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
+ */
+
+#ifndef SHAPE_OPTIONS_HH
+#define SHAPE_OPTIONS_HH
+
+#include "options.hh"
+
+struct shape_options_t
+{
+  ~shape_options_t ()
+  {
+    g_free (direction);
+    g_free (language);
+    g_free (script);
+    free (features);
+    g_strfreev (shapers);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  void setup_buffer (hb_buffer_t *buffer)
+  {
+    hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
+    hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
+    hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
+    hb_buffer_set_flags (buffer, (hb_buffer_flags_t)
+				 (HB_BUFFER_FLAG_DEFAULT |
+				  (bot ? HB_BUFFER_FLAG_BOT : 0) |
+				  (eot ? HB_BUFFER_FLAG_EOT : 0) |
+				  (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
+				  (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
+				  0));
+    hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
+    hb_buffer_set_not_found_glyph (buffer, not_found_glyph);
+    hb_buffer_set_cluster_level (buffer, cluster_level);
+    hb_buffer_guess_segment_properties (buffer);
+  }
+
+  static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src)
+  {
+    hb_segment_properties_t props;
+    hb_buffer_get_segment_properties (src, &props);
+    hb_buffer_set_segment_properties (dst, &props);
+    hb_buffer_set_flags (dst, hb_buffer_get_flags (src));
+    hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src));
+  }
+
+  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
+			const char *text_before, const char *text_after)
+  {
+    hb_buffer_clear_contents (buffer);
+    if (text_before) {
+      unsigned int len = strlen (text_before);
+      hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
+    }
+    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
+    if (text_after) {
+      hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
+    }
+
+    if (!utf8_clusters) {
+      /* Reset cluster values to refer to Unicode character index
+       * instead of UTF-8 index. */
+      unsigned int num_glyphs = hb_buffer_get_length (buffer);
+      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
+      for (unsigned int i = 0; i < num_glyphs; i++)
+      {
+	info->cluster = i;
+	info++;
+      }
+    }
+
+    setup_buffer (buffer);
+  }
+
+  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
+  {
+    hb_buffer_t *text_buffer = nullptr;
+    if (verify)
+    {
+      text_buffer = hb_buffer_create ();
+      hb_buffer_append (text_buffer, buffer, 0, -1);
+    }
+
+    if (!hb_shape_full (font, buffer, features, num_features, shapers))
+    {
+      if (error)
+	*error = "All shapers failed.";
+      goto fail;
+    }
+
+    if (normalize_glyphs)
+      hb_buffer_normalize_glyphs (buffer);
+
+    if (verify && !verify_buffer (buffer, text_buffer, font, error))
+      goto fail;
+
+    if (text_buffer)
+      hb_buffer_destroy (text_buffer);
+
+    return true;
+
+  fail:
+    if (text_buffer)
+      hb_buffer_destroy (text_buffer);
+
+    return false;
+  }
+
+  bool verify_buffer (hb_buffer_t  *buffer,
+		      hb_buffer_t  *text_buffer,
+		      hb_font_t    *font,
+		      const char  **error=nullptr)
+  {
+    if (!verify_buffer_monotone (buffer, error))
+      return false;
+    if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error))
+      return false;
+    return true;
+  }
+
+  bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr)
+  {
+    /* Check that clusters are monotone. */
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
+	cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+    {
+      bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+      unsigned int num_glyphs;
+      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+      for (unsigned int i = 1; i < num_glyphs; i++)
+	if (info[i-1].cluster != info[i].cluster &&
+	    (info[i-1].cluster < info[i].cluster) != is_forward)
+	{
+	  if (error)
+	    *error = "clusters are not monotone.";
+	  return false;
+	}
+    }
+
+    return true;
+  }
+
+  bool verify_buffer_safe_to_break (hb_buffer_t  *buffer,
+				    hb_buffer_t  *text_buffer,
+				    hb_font_t    *font,
+				    const char  **error=nullptr)
+  {
+    if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+	cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+    {
+      /* Cannot perform this check without monotone clusters.
+       * Then again, unsafe-to-break flag is much harder to use without
+       * monotone clusters. */
+      return true;
+    }
+
+    /* Check that breaking up shaping at safe-to-break is indeed safe. */
+
+    hb_buffer_t *fragment = hb_buffer_create ();
+    hb_buffer_t *reconstruction = hb_buffer_create ();
+    copy_buffer_properties (reconstruction, buffer);
+
+    unsigned int num_glyphs;
+    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+    unsigned int num_chars;
+    hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+    /* Chop text and shape fragments. */
+    bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+    unsigned int start = 0;
+    unsigned int text_start = forward ? 0 : num_chars;
+    unsigned int text_end = text_start;
+    for (unsigned int end = 1; end < num_glyphs + 1; end++)
+    {
+      if (end < num_glyphs &&
+	  (info[end].cluster == info[end-1].cluster ||
+	   info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
+	  continue;
+
+      /* Shape segment corresponding to glyphs start..end. */
+      if (end == num_glyphs)
+      {
+	if (forward)
+	  text_end = num_chars;
+	else
+	  text_start = 0;
+      }
+      else
+      {
+	if (forward)
+	{
+	  unsigned int cluster = info[end].cluster;
+	  while (text_end < num_chars && text[text_end].cluster < cluster)
+	    text_end++;
+	}
+	else
+	{
+	  unsigned int cluster = info[end - 1].cluster;
+	  while (text_start && text[text_start - 1].cluster >= cluster)
+	    text_start--;
+	}
+      }
+      assert (text_start < text_end);
+
+      if (0)
+	printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+      hb_buffer_clear_contents (fragment);
+      copy_buffer_properties (fragment, buffer);
+
+      hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
+      if (0 < text_start)
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+      if (text_end < num_chars)
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+      hb_buffer_set_flags (fragment, flags);
+
+      hb_buffer_append (fragment, text_buffer, text_start, text_end);
+      if (!hb_shape_full (font, fragment, features, num_features, shapers))
+      {
+	if (error)
+	  *error = "All shapers failed while shaping fragment.";
+	hb_buffer_destroy (reconstruction);
+	hb_buffer_destroy (fragment);
+	return false;
+      }
+      hb_buffer_append (reconstruction, fragment, 0, -1);
+
+      start = end;
+      if (forward)
+	text_start = text_end;
+      else
+	text_end = text_start;
+    }
+
+    bool ret = true;
+    hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff)
+    {
+      if (error)
+	*error = "Safe-to-break test failed.";
+      ret = false;
+
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
+
+    hb_buffer_destroy (reconstruction);
+    hb_buffer_destroy (fragment);
+
+    return ret;
+  }
+
+  void shape_closure (const char *text, int text_len,
+		      hb_font_t *font, hb_buffer_t *buffer,
+		      hb_set_t *glyphs)
+  {
+    hb_buffer_reset (buffer);
+    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
+    setup_buffer (buffer);
+    hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
+  }
+
+  /* Buffer properties */
+  char *direction = nullptr;
+  char *language = nullptr;
+  char *script = nullptr;
+
+  /* Buffer flags */
+  hb_bool_t bot = false;
+  hb_bool_t eot = false;
+  hb_bool_t preserve_default_ignorables = false;
+  hb_bool_t remove_default_ignorables = false;
+
+  hb_feature_t *features = nullptr;
+  unsigned int num_features = 0;
+  char **shapers = nullptr;
+  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 verify = false;
+  unsigned int num_iterations = 1;
+};
+
+
+static gboolean
+parse_shapers (const char *name G_GNUC_UNUSED,
+	       const char *arg,
+	       gpointer    data,
+	       GError    **error)
+{
+  shape_options_t *shape_opts = (shape_options_t *) data;
+  char **shapers = g_strsplit (arg, ",", 0);
+
+  for (char **shaper = shapers; *shaper; shaper++)
+  {
+    bool found = false;
+    for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) {
+      if (strcmp (*shaper, *hb_shaper) == 0)
+      {
+	found = true;
+	break;
+      }
+    }
+    if (!found)
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Unknown or unsupported shaper: %s", *shaper);
+      g_strfreev (shapers);
+      return false;
+    }
+  }
+
+  g_strfreev (shape_opts->shapers);
+  shape_opts->shapers = shapers;
+  return true;
+}
+
+static G_GNUC_NORETURN gboolean
+list_shapers (const char *name G_GNUC_UNUSED,
+	      const char *arg G_GNUC_UNUSED,
+	      gpointer    data G_GNUC_UNUSED,
+	      GError    **error G_GNUC_UNUSED)
+{
+  for (const char **shaper = hb_shape_list_shapers (); *shaper; shaper++)
+    g_printf ("%s\n", *shaper);
+
+  exit(0);
+}
+
+
+static gboolean
+parse_features (const char *name G_GNUC_UNUSED,
+		const char *arg,
+		gpointer    data,
+		GError    **error G_GNUC_UNUSED)
+{
+  shape_options_t *shape_opts = (shape_options_t *) data;
+  char *s = (char *) arg;
+  size_t l = strlen (s);
+  char *p;
+
+  shape_opts->num_features = 0;
+  g_free (shape_opts->features);
+  shape_opts->features = nullptr;
+
+  /* if the string is quoted, strip the quotes */
+  if (s[0] == s[l - 1] && (s[0] == '\"' || s[0] == '\''))
+  {
+    s[l - 1] = '\0';
+    s++;
+  }
+
+  if (!*s)
+    return true;
+
+  /* count the features first, so we can allocate memory */
+  p = s;
+  do {
+    shape_opts->num_features++;
+    p = strchr (p, ',');
+    if (p)
+      p++;
+  } while (p);
+
+  shape_opts->features = (hb_feature_t *) calloc (shape_opts->num_features, sizeof (*shape_opts->features));
+  if (!shape_opts->features)
+    return false;
+
+  /* now do the actual parsing */
+  p = s;
+  shape_opts->num_features = 0;
+  while (p && *p) {
+    char *end = strchr (p, ',');
+    if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
+      shape_opts->num_features++;
+    p = end ? end + 1 : nullptr;
+  }
+
+  return true;
+}
+
+void
+shape_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"list-shapers",	0, G_OPTION_FLAG_NO_ARG,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &list_shapers,	"List available shapers and quit",	nullptr},
+    {"shaper",		0, G_OPTION_FLAG_HIDDEN,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Hidden duplicate of --shapers",	nullptr},
+    {"shapers",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Set comma-separated list of shapers to try","list"},
+    {"direction",	0, 0, G_OPTION_ARG_STRING,	&this->direction,		"Set text direction (default: auto)",	"ltr/rtl/ttb/btt"},
+    {"language",	0, 0, G_OPTION_ARG_STRING,	&this->language,		"Set text language (default: $LANG)",	"BCP 47 tag"},
+    {"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},
+    {"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},
+    {"not-found-glyph",	0, 0, G_OPTION_ARG_INT,		&this->not_found_glyph,		"Glyph value to replace not-found characters with",	nullptr},
+    {"utf8-clusters",	0, 0, G_OPTION_ARG_NONE,	&this->utf8_clusters,		"Use UTF8 byte indices, not char indices",	nullptr},
+    {"cluster-level",	0, 0, G_OPTION_ARG_INT,		&this->cluster_level,		"Cluster merging level (default: 0)",	"0/1/2"},
+    {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,	&this->normalize_glyphs,	"Rearrange glyph clusters in nominal order",	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,
+			      G_OPTION_ARG_INT,		&this->num_iterations,		"Run shaper N times (default: 1)",	"N"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "shape",
+		     "Shape options:",
+		     "Options for the shaping process",
+		     this);
+
+  const gchar *features_help = "Comma-separated list of font features\n"
+    "\n"
+    "    Features can be enabled or disabled, either globally or limited to\n"
+    "    specific character ranges.  The format for specifying feature settings\n"
+    "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
+    "    and the global values are also accepted, though not documented below.\n"
+    "    CSS string escapes are not supported."
+    "\n"
+    "    The range indices refer to the positions between Unicode characters,\n"
+    "    unless the --utf8-clusters is provided, in which case range indices\n"
+    "    refer to UTF-8 byte indices. The position before the first character\n"
+    "    is always 0.\n"
+    "\n"
+    "    The format is Python-esque.  Here is how it all works:\n"
+    "\n"
+    "      Syntax:       Value:    Start:    End:\n"
+    "\n"
+    "    Setting value:\n"
+    "      \"kern\"        1         0         ∞         # Turn feature on\n"
+    "      \"+kern\"       1         0         ∞         # Turn feature on\n"
+    "      \"-kern\"       0         0         ∞         # Turn feature off\n"
+    "      \"kern=0\"      0         0         ∞         # Turn feature off\n"
+    "      \"kern=1\"      1         0         ∞         # Turn feature on\n"
+    "      \"aalt=2\"      2         0         ∞         # Choose 2nd alternate\n"
+    "\n"
+    "    Setting index:\n"
+    "      \"kern[]\"      1         0         ∞         # Turn feature on\n"
+    "      \"kern[:]\"     1         0         ∞         # Turn feature on\n"
+    "      \"kern[5:]\"    1         5         ∞         # Turn feature on, partial\n"
+    "      \"kern[:5]\"    1         0         5         # Turn feature on, partial\n"
+    "      \"kern[3:5]\"   1         3         5         # Turn feature on, range\n"
+    "      \"kern[3]\"     1         3         3+1       # Turn feature on, single char\n"
+    "\n"
+    "    Mixing it all:\n"
+    "\n"
+    "      \"aalt[3:5]=2\" 2         3         5         # Turn 2nd alternate on for range";
+
+  GOptionEntry entries2[] =
+  {
+    {"features",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_features,	features_help,	"list"},
+    {nullptr}
+  };
+  parser->add_group (entries2,
+		     "features",
+		     "Features options:",
+		     "Options for font features used",
+		     this);
+}
+
+#endif
diff --git a/util/text-options.hh b/util/text-options.hh
new file mode 100644
index 0000000..82ca6c0
--- /dev/null
+++ b/util/text-options.hh
@@ -0,0 +1,346 @@
+/*
+ * 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
+ */
+
+#ifndef TEXT_OPTIONS_HH
+#define TEXT_OPTIONS_HH
+
+#include "options.hh"
+
+struct text_options_t
+{
+  text_options_t ()
+  : gs (g_string_new (nullptr))
+  {}
+  ~text_options_t ()
+  {
+    g_free (text);
+    g_free (text_file);
+    if (gs)
+      g_string_free (gs, true);
+    if (in_fp && in_fp != stdin)
+      fclose (in_fp);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  void post_parse (GError **error G_GNUC_UNUSED)
+  {
+    if (!text && !text_file)
+      text_file = g_strdup ("-");
+
+    if (text && text_file)
+    {
+      g_set_error (error,
+		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Only one of text and text-file can be set");
+      return;
+    }
+
+    if (text_file)
+    {
+      if (0 != strcmp (text_file, "-"))
+	in_fp = fopen (text_file, "r");
+      else
+	in_fp = stdin;
+
+      if (!in_fp)
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
+		     "Failed opening text file `%s': %s",
+		     text_file, strerror (errno));
+    }
+  }
+
+  const char *get_line (unsigned int *len);
+
+  int text_len = -1;
+  char *text = nullptr;
+  char *text_file = nullptr;
+
+  private:
+  FILE *in_fp = nullptr;
+  GString *gs = nullptr;
+};
+
+struct shape_text_options_t : text_options_t
+{
+  ~shape_text_options_t ()
+  {
+    g_free (text_before);
+    g_free (text_after);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  char *text_before = nullptr;
+  char *text_after = nullptr;
+};
+
+
+static gboolean
+parse_text (const char *name G_GNUC_UNUSED,
+	    const char *arg,
+	    gpointer    data,
+	    GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  text_opts->text_len = -1;
+  text_opts->text = g_strdup (arg);
+  return true;
+}
+
+static bool
+encode_unicodes (const char *unicodes,
+		 GString    *gs,
+		 GError    **error)
+{
+#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r "
+
+  char *s = (char *) unicodes;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (DELIMITERS, *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 16);
+    if (errno || s == p)
+    {
+      g_string_free (gs, TRUE);
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing Unicode value at: '%s'", s);
+      return false;
+    }
+
+    g_string_append_unichar (gs, u);
+
+    s = p;
+  }
+
+#undef DELIMITERS
+
+  return true;
+}
+
+static gboolean
+parse_unicodes (const char *name G_GNUC_UNUSED,
+		const char *arg,
+		gpointer    data,
+		GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (0 == strcmp (arg, "*"))
+    g_string_append_c (gs, '*');
+  else
+    if (!encode_unicodes (arg, gs, error))
+      return false;
+
+  text_opts->text_len = gs->len;
+  text_opts->text = g_string_free (gs, FALSE);
+  return true;
+}
+
+static gboolean
+parse_text_before (const char *name G_GNUC_UNUSED,
+		   const char *arg,
+		   gpointer    data,
+		   GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_before)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-before or --unicodes-before can be provided but not both");
+    return false;
+  }
+
+  opts->text_before = g_strdup (arg);
+  fprintf(stderr, "%s\n", opts->text_before);
+  return true;
+}
+
+static gboolean
+parse_unicodes_before (const char *name G_GNUC_UNUSED,
+		       const char *arg,
+		       gpointer    data,
+		       GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_before)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-before or --unicodes-before can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (!encode_unicodes (arg, gs, error))
+    return false;
+
+  opts->text_before = g_string_free (gs, FALSE);
+  return true;
+}
+
+static gboolean
+parse_text_after (const char *name G_GNUC_UNUSED,
+		  const char *arg,
+		  gpointer    data,
+		  GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_after)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-after or --unicodes-after can be provided but not both");
+    return false;
+  }
+
+  opts->text_after = g_strdup (arg);
+  return true;
+}
+
+static gboolean
+parse_unicodes_after (const char *name G_GNUC_UNUSED,
+		      const char *arg,
+		      gpointer    data,
+		      GError    **error)
+{
+  auto *opts = (shape_text_options_t *) data;
+
+  if (opts->text_after)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text-after or --unicodes-after can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  if (!encode_unicodes (arg, gs, error))
+    return false;
+
+  opts->text_after = g_string_free (gs, FALSE);
+  return true;
+}
+
+const char *
+text_options_t::get_line (unsigned int *len)
+{
+  if (text)
+  {
+    if (text_len == -2)
+    {
+      *len = 0;
+      return nullptr;
+    }
+
+    if (text_len == -1)
+      text_len = strlen (text);
+
+    *len = text_len;
+    text_len = -2;
+    return text;
+  }
+
+  g_string_set_size (gs, 0);
+  char buf[BUFSIZ];
+  while (fgets (buf, sizeof (buf), in_fp))
+  {
+    unsigned bytes = strlen (buf);
+    if (bytes && buf[bytes - 1] == '\n')
+    {
+      bytes--;
+      g_string_append_len (gs, buf, bytes);
+      break;
+    }
+    g_string_append_len (gs, buf, bytes);
+  }
+  if (ferror (in_fp))
+    fail (false, "Failed reading text: %s", strerror (errno));
+  *len = gs->len;
+  return !*len && feof (in_fp) ? nullptr : gs->str;
+}
+
+void
+text_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"text",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text,		"Set input text",			"string"},
+    {"text-file",	0, 0, G_OPTION_ARG_STRING,	&this->text_file,		"Set input text file-name",		"filename"},
+    {"unicodes",      'u', 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes,	"Set input Unicode codepoints\n\n    If no text is provided, standard input is used for input.",		"list of hex numbers"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "text",
+		     "Text options:",
+		     "Options for the input text",
+		     this);
+}
+
+void
+shape_text_options_t::add_options (option_parser_t *parser)
+{
+  text_options_t::add_options (parser);
+
+  GOptionEntry entries[] =
+  {
+    {"text-before",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text_before,		"Set text context before each line",	"string"},
+    {"text-after",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text_after,		"Set text context after each line",	"string"},
+    {"unicodes-before",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes_before,	"Set Unicode codepoints context before each line",	"list of hex numbers"},
+    {"unicodes-after",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes_after,	"Set Unicode codepoints context after each line",	"list of hex numbers"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "text-context",
+		     "Textual context options:",
+		     "Options for the input context text",
+		     this);
+}
+
+#endif
diff --git a/util/view-cairo.cc b/util/view-cairo.cc
deleted file mode 100644
index e8e334b..0000000
--- a/util/view-cairo.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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
- */
-
-#include "view-cairo.hh"
-
-#include <assert.h>
-
-
-void
-view_cairo_t::render (const font_options_t *font_opts)
-{
-  bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
-  int vert  = vertical ? 1 : 0;
-  int horiz = vertical ? 0 : 1;
-
-  int x_sign = font_opts->font_size_x < 0 ? -1 : +1;
-  int y_sign = font_opts->font_size_y < 0 ? -1 : +1;
-
-  hb_font_t *font = font_opts->get_font();
-  hb_font_extents_t extents;
-  hb_font_get_extents_for_direction (font, direction, &extents);
-
-  double ascent = y_sign * scalbn ((double) extents.ascender, scale_bits);
-  double descent = y_sign * -scalbn ((double) extents.descender, scale_bits);
-  double font_height = y_sign * scalbn ((double) extents.ascender - extents.descender + extents.line_gap, scale_bits);
-  double leading = font_height + view_options.line_space;
-
-  /* Calculate surface size. */
-  double w = 0, h = 0;
-  (vertical ? w : h) = (int) lines->len * leading - view_options.line_space;
-  (vertical ? h : w) = 0;
-  for (unsigned int i = 0; i < lines->len; i++) {
-    helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
-    double x_advance, y_advance;
-    line.get_advance (&x_advance, &y_advance);
-    if (vertical)
-      h =  MAX (h, y_sign * y_advance);
-    else
-      w =  MAX (w, x_sign * x_advance);
-  }
-
-  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
-
-  /* See if font needs color. */
-  cairo_content_t content = CAIRO_CONTENT_ALPHA;
-  if (helper_cairo_scaled_font_has_color (scaled_font))
-    content = CAIRO_CONTENT_COLOR;
-
-  /* Create surface. */
-  cairo_t *cr = helper_cairo_create_context (w + view_options.margin.l + view_options.margin.r,
-					     h + view_options.margin.t + view_options.margin.b,
-					     &view_options, &output_options, content);
-  cairo_set_scaled_font (cr, scaled_font);
-
-  /* Setup coordinate system. */
-  cairo_translate (cr, view_options.margin.l, view_options.margin.t);
-  if (vertical)
-    cairo_translate (cr,
-		     w /* We stack lines right to left */
-		     -font_height * .5 /* "ascent" for vertical */,
-		     y_sign < 0 ? h : 0);
-  else
-   {
-    cairo_translate (cr,
-		     x_sign < 0 ? w : 0,
-		     y_sign < 0 ? descent : ascent);
-   }
-
-  /* Draw. */
-  cairo_translate (cr, +vert * leading, -horiz * leading);
-  for (unsigned int i = 0; i < lines->len; i++)
-  {
-    helper_cairo_line_t &l = g_array_index (lines, helper_cairo_line_t, i);
-
-    cairo_translate (cr, -vert * leading, +horiz * leading);
-
-    if (view_options.annotate) {
-      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_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);
-	cairo_rel_line_to (cr, 0, 0);
-      }
-      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)
-      cairo_show_text_glyphs (cr,
-			      l.utf8, l.utf8_len,
-			      l.glyphs, l.num_glyphs,
-			      l.clusters, l.num_clusters,
-			      l.cluster_flags);
-    else
-      cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
-  }
-
-  /* Clean up. */
-  helper_cairo_destroy_context (cr);
-  cairo_scaled_font_destroy (scaled_font);
-}
diff --git a/util/view-cairo.hh b/util/view-cairo.hh
index 1f51f0e..1578f13 100644
--- a/util/view-cairo.hh
+++ b/util/view-cairo.hh
@@ -27,22 +27,24 @@
 #ifndef VIEW_CAIRO_HH
 #define VIEW_CAIRO_HH
 
-#include "hb.hh"
-#include "options.hh"
+#include "view-options.hh"
+#include "output-options.hh"
 #include "helper-cairo.hh"
 
-
-struct view_cairo_t
+struct view_cairo_t : view_options_t, output_options_t<>
 {
-  view_cairo_t (option_parser_t *parser)
-	       : output_options (parser, helper_cairo_supported_formats),
-		 view_options (parser),
-		 direction (HB_DIRECTION_INVALID),
-		 lines (0), scale_bits (0) {}
-  ~view_cairo_t () {
+  ~view_cairo_t ()
+  {
     cairo_debug_reset_static_data ();
   }
 
+  void add_options (option_parser_t *parser)
+  {
+    parser->set_summary ("View text with given font.");
+    view_options_t::add_options (parser);
+    output_options_t::add_options (parser, helper_cairo_supported_formats);
+  }
+
   void init (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
@@ -82,14 +84,123 @@
 
   protected:
 
-  output_options_t output_options;
-  view_options_t view_options;
-
   void render (const font_options_t *font_opts);
 
-  hb_direction_t direction; // Remove this, make segment_properties accessible
-  GArray *lines;
-  int scale_bits;
+  hb_direction_t direction = HB_DIRECTION_INVALID; // Remove this, make segment_properties accessible
+  GArray *lines = nullptr;
+  int scale_bits = 0;
 };
 
+inline void
+view_cairo_t::render (const font_options_t *font_opts)
+{
+  bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
+  int vert  = vertical ? 1 : 0;
+  int horiz = vertical ? 0 : 1;
+
+  int x_sign = font_opts->font_size_x < 0 ? -1 : +1;
+  int y_sign = font_opts->font_size_y < 0 ? -1 : +1;
+
+  hb_font_t *font = font_opts->font;
+
+  if (!have_font_extents)
+  {
+    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);
+    have_font_extents = true;
+  }
+
+  double ascent = y_sign * font_extents.ascent;
+  double descent = y_sign * font_extents.descent;
+  double line_gap = y_sign * font_extents.line_gap + line_space;
+  double leading = ascent + descent + line_gap;
+
+  /* Calculate surface size. */
+  double w = 0, h = 0;
+  (vertical ? w : h) = (int) lines->len * leading - (font_extents.line_gap + line_space);
+  (vertical ? h : w) = 0;
+  for (unsigned int i = 0; i < lines->len; i++) {
+    helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
+    double x_advance, y_advance;
+    line.get_advance (&x_advance, &y_advance);
+    if (vertical)
+      h =  MAX (h, y_sign * y_advance);
+    else
+      w =  MAX (w, x_sign * x_advance);
+  }
+
+  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
+
+  /* See if font needs color. */
+  cairo_content_t content = CAIRO_CONTENT_ALPHA;
+  if (helper_cairo_scaled_font_has_color (scaled_font))
+    content = CAIRO_CONTENT_COLOR;
+
+  /* Create surface. */
+  cairo_t *cr = helper_cairo_create_context (w + margin.l + margin.r,
+					     h + margin.t + margin.b,
+					     this,
+					     this,
+					     content);
+  cairo_set_scaled_font (cr, scaled_font);
+
+  /* Setup coordinate system. */
+  cairo_translate (cr, margin.l, margin.t);
+  if (vertical)
+    cairo_translate (cr,
+		     w - ascent, /* We currently always stack lines right to left */
+		     y_sign < 0 ? h : 0);
+  else
+   {
+    cairo_translate (cr,
+		     x_sign < 0 ? w : 0,
+		     y_sign < 0 ? descent : ascent);
+   }
+
+  /* Draw. */
+  cairo_translate (cr, +vert * leading, -horiz * leading);
+  for (unsigned int i = 0; i < lines->len; i++)
+  {
+    helper_cairo_line_t &l = g_array_index (lines, helper_cairo_line_t, i);
+
+    cairo_translate (cr, -vert * leading, +horiz * leading);
+
+    if (annotate) {
+      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_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);
+	cairo_rel_line_to (cr, 0, 0);
+      }
+      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)
+      cairo_show_text_glyphs (cr,
+			      l.utf8, l.utf8_len,
+			      l.glyphs, l.num_glyphs,
+			      l.clusters, l.num_clusters,
+			      l.cluster_flags);
+    else
+      cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
+  }
+
+  /* Clean up. */
+  helper_cairo_destroy_context (cr);
+  cairo_scaled_font_destroy (scaled_font);
+}
+
 #endif
diff --git a/util/view-options.hh b/util/view-options.hh
new file mode 100644
index 0000000..322009a
--- /dev/null
+++ b/util/view-options.hh
@@ -0,0 +1,123 @@
+/*
+ * 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
+ */
+
+#ifndef VIEW_OPTIONS_HH
+#define VIEW_OPTIONS_HH
+
+#include "options.hh"
+
+#define DEFAULT_MARGIN 16
+#define DEFAULT_FORE "#000000"
+#define DEFAULT_BACK "#FFFFFF"
+
+struct view_options_t
+{
+  ~view_options_t ()
+  {
+    g_free (fore);
+    g_free (back);
+  }
+
+  void add_options (option_parser_t *parser);
+
+  hb_bool_t annotate = false;
+  char *fore = nullptr;
+  char *back = nullptr;
+  double line_space = 0;
+  bool have_font_extents = false;
+  struct font_extents_t {
+    double ascent, descent, line_gap;
+  } font_extents = {0., 0., 0.};
+  struct margin_t {
+    double t, r, b, l;
+  } margin = {DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN};
+};
+
+
+static gboolean
+parse_font_extents (const char *name G_GNUC_UNUSED,
+		    const char *arg,
+		    gpointer    data,
+		    GError    **error G_GNUC_UNUSED)
+{
+  view_options_t *view_opts = (view_options_t *) data;
+  view_options_t::font_extents_t &e = view_opts->font_extents;
+  switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf", &e.ascent, &e.descent, &e.line_gap)) {
+    case 1: HB_FALLTHROUGH;
+    case 2: HB_FALLTHROUGH;
+    case 3:
+      view_opts->have_font_extents = true;
+      return true;
+    default:
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "%s argument should be one to three space-separated numbers",
+		   name);
+      return false;
+  }
+}
+
+static gboolean
+parse_margin (const char *name G_GNUC_UNUSED,
+	      const char *arg,
+	      gpointer    data,
+	      GError    **error G_GNUC_UNUSED)
+{
+  view_options_t *view_opts = (view_options_t *) data;
+  view_options_t::margin_t &m = view_opts->margin;
+  switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf", &m.t, &m.r, &m.b, &m.l)) {
+    case 1: m.r = m.t; HB_FALLTHROUGH;
+    case 2: m.b = m.t; HB_FALLTHROUGH;
+    case 3: m.l = m.r; HB_FALLTHROUGH;
+    case 4: return true;
+    default:
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "%s argument should be one to four space-separated numbers",
+		   name);
+      return false;
+  }
+}
+
+void
+view_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"annotate",	0, 0, G_OPTION_ARG_NONE,	&this->annotate,		"Annotate output rendering",				nullptr},
+    {"background",	0, 0, G_OPTION_ARG_STRING,	&this->back,			"Set background color (default: " DEFAULT_BACK ")",	"rrggbb/rrggbbaa"},
+    {"foreground",	0, 0, G_OPTION_ARG_STRING,	&this->fore,			"Set foreground color (default: " DEFAULT_FORE ")",	"rrggbb/rrggbbaa"},
+    {"line-space",	0, 0, G_OPTION_ARG_DOUBLE,	&this->line_space,		"Set space between lines (default: 0)",			"units"},
+    {"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"},
+    {nullptr}
+  };
+  parser->add_group (entries,
+		     "view",
+		     "View options:",
+		     "Options for output rendering",
+		     this);
+}
+
+#endif