diff --git a/source/build-aux/compile b/source/build-aux/compile
index 2078fc8332c32ddad9428d55c7943d8171ccf00c..dfc9465939ffe7a7eff66d341975d3c8579cbc67 100644
--- a/source/build-aux/compile
+++ b/source/build-aux/compile
@@ -256,6 +256,7 @@ EOF
     exit $?
     ;;
   cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+  clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \
   icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
     func_cl_wrapper "$@"      # Doesn't return...
     ;;
diff --git a/source/libs/README b/source/libs/README
index f680af8c5973f70f1b56c17f152ecee57bd9d193..554845a097b48621ea17955c0b75c6e58dd973cc 100644
--- a/source/libs/README
+++ b/source/libs/README
@@ -1,4 +1,4 @@
-$Id: README 63761 2022-06-29 20:49:55Z kakuto $
+$Id: README 63966 2022-07-23 21:54:27Z kakuto $
 Public domain.  Originally created by Karl Berry, 2005.
 
 Libraries we compile for TeX Live.
@@ -25,8 +25,8 @@ graphite2 1.3.14 - checked 10apr20
   http://sourceforge.net/projects/silgraphite/files/graphite2/
   (requires C++11)
 
-harfbuzz 4.4.1 - checked 30jun22
-  https://github.com/harfbuzz/harfbuzz/releases/download/4.4.1/
+harfbuzz 5.0.1 - checked 24jul22
+  https://github.com/harfbuzz/harfbuzz/releases/download/5.0.1/
 
 icu 70.1 - checked 16jan22
   https://github.com/unicode-org/icu/releases/
diff --git a/source/libs/harfbuzz/ChangeLog b/source/libs/harfbuzz/ChangeLog
index 6e5f3ce6239759eebf99258fcbd7ff93976559b8..a312e752ab12b9dcdd27fc6a2158a35b0655a57d 100644
--- a/source/libs/harfbuzz/ChangeLog
+++ b/source/libs/harfbuzz/ChangeLog
@@ -1,6 +1,11 @@
+2022-07-24  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
+
+	Import harfbuzz-5.0.1.
+	* version.ac, Makefile.am: Adjusted.
+
 2022-07/18  Andreas Scherer  <andreas_github@freenet.de>
 
-	Add a patch 0001-Fix-harfbuzz-4.4.1-for-older-g for older gcc.
+	Add a patch 0001-Fix-harfbuzz-4.4.1-for-older-g.patch for older gcc.
 
 2022-06-30  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
 
diff --git a/source/libs/harfbuzz/Makefile.am b/source/libs/harfbuzz/Makefile.am
index 8f2f1a0b87d1b31d241234ff562ba671c06a4597..03dce470bc23783dd1e1c2b7ffcbff1692ffebe8 100644
--- a/source/libs/harfbuzz/Makefile.am
+++ b/source/libs/harfbuzz/Makefile.am
@@ -1,4 +1,4 @@
-## $Id: Makefile.am 63761 2022-06-29 20:49:55Z kakuto $
+## $Id: Makefile.am 63966 2022-07-23 21:54:27Z kakuto $
 ## Proxy Makefile.am to build harfbuzz for TeX Live.
 ##
 ##   Copyright 2016-2017 Karl Berry <tex-live@tug.org>
@@ -239,6 +239,10 @@ libharfbuzz_a_SOURCES += \
 	@HARFBUZZ_TREE@/src/OT/glyf/SimpleGlyph.hh \
 	@HARFBUZZ_TREE@/src/OT/glyf/CompositeGlyph.hh \
 	@HARFBUZZ_TREE@/src/OT/glyf/SubsetGlyph.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/Coverage.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/CoverageFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/CoverageFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/RangeRecord.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/Common.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/Sequence.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SingleSubstFormat1.hh \
@@ -261,35 +265,39 @@ libharfbuzz_a_SOURCES += \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SubstLookupSubTable.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SubstLookup.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/GSUB.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Anchor.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ExtensionPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat3.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Anchor.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorMatrix.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ChainContextPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Common.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ValueFormat.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorMatrix.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ContextPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ExtensionPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/GPOS.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/LigatureArray.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkArray.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkBasePosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat3.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookup.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat2.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkBasePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkArray.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookupSubTable.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkRecord.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat2.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ContextPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairSet.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairValueRecord.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookup.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookupSubTable.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ValueFormat.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/types.hh \
 	@HARFBUZZ_TREE@/src/graph/graph.hh \
 	@HARFBUZZ_TREE@/src/graph/serialize.hh
 
diff --git a/source/libs/harfbuzz/Makefile.in b/source/libs/harfbuzz/Makefile.in
index b65437a5d0cf10865d4ed4ba4d6aef5cab98fb1e..35a9836881eb713952a2daf25d26e944934131ca 100644
--- a/source/libs/harfbuzz/Makefile.in
+++ b/source/libs/harfbuzz/Makefile.in
@@ -908,6 +908,10 @@ libharfbuzz_a_SOURCES = @HARFBUZZ_TREE@/src/hb-algs.hh \
 	@HARFBUZZ_TREE@/src/OT/glyf/SimpleGlyph.hh \
 	@HARFBUZZ_TREE@/src/OT/glyf/CompositeGlyph.hh \
 	@HARFBUZZ_TREE@/src/OT/glyf/SubsetGlyph.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/Coverage.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/CoverageFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/CoverageFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/Common/RangeRecord.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/Common.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/Sequence.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SingleSubstFormat1.hh \
@@ -930,35 +934,39 @@ libharfbuzz_a_SOURCES = @HARFBUZZ_TREE@/src/hb-algs.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SubstLookupSubTable.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/SubstLookup.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GSUB/GSUB.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Anchor.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ExtensionPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat3.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Anchor.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorMatrix.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ChainContextPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/Common.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ValueFormat.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorMatrix.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ContextPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ExtensionPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/GPOS.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/LigatureArray.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkArray.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkBasePosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat3.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookup.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat2.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkBasePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkLigPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkArray.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/CursivePos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookupSubTable.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkMarkPos.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/MarkRecord.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/AnchorFormat2.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ContextPos.hh \
-	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairPos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairSet.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PairValueRecord.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookup.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/PosLookupSubTable.hh \
 	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat1.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePosFormat2.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/SinglePos.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/GPOS/ValueFormat.hh \
+	@HARFBUZZ_TREE@/src/OT/Layout/types.hh \
 	@HARFBUZZ_TREE@/src/graph/graph.hh \
 	@HARFBUZZ_TREE@/src/graph/serialize.hh \
 	@HARFBUZZ_TREE@/src/hb-graphite2.cc
diff --git a/source/libs/harfbuzz/TLpatches/ChangeLog b/source/libs/harfbuzz/TLpatches/ChangeLog
index 0f4a2c04e81f35ca4068d97beb90022cf6eeded1..8f3cb648bd1ca542b5976eb6ec5fadbcd1848cd3 100644
--- a/source/libs/harfbuzz/TLpatches/ChangeLog
+++ b/source/libs/harfbuzz/TLpatches/ChangeLog
@@ -1,3 +1,10 @@
+2022-07-24  Akira Kakuto  <kakuto@jcom.zaq.ne.jp>
+
+	Imported harfbuzz-5.0.1 source tree from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/5.0.1/
+	* 0001-Fix-harfbuzz-4.4.1-for-older-g.patch: Remove.
+	* 0002-Fix-dispatch_recurse_func-for-older-g.patch: Remove.
+
 2022-07-18  Andreas Scherer  <andreas_github@freenet.de>
 
 	* 0001-Fix-harfbuzz-4.4.1-for-older-g.patch,
diff --git a/source/libs/harfbuzz/TLpatches/TL-Changes b/source/libs/harfbuzz/TLpatches/TL-Changes
index 2d284498e9c4b89ba94cc0313c6b92799971a2ca..c3fbe22f14919a308bc29cd7d0bf07b6f349afad 100644
--- a/source/libs/harfbuzz/TLpatches/TL-Changes
+++ b/source/libs/harfbuzz/TLpatches/TL-Changes
@@ -1,5 +1,5 @@
-Changes applied to the harfbuzz-4.4.1/ tree as obtained from:
-	https://github.com/harfbuzz/harfbuzz/releases/download/4.4.1/
+Changes applied to the harfbuzz-5.0.1/ tree as obtained from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/5.0.1/
 
 Removed:
 	COPYING
diff --git a/source/libs/harfbuzz/configure b/source/libs/harfbuzz/configure
index a5b48895c605ef7b01a19d1f576e007d2675da4e..ad5f1932ea724635183484278c51faccd0dd3b69 100755
--- a/source/libs/harfbuzz/configure
+++ b/source/libs/harfbuzz/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for harfbuzz (TeX Live) 4.4.1.
+# Generated by GNU Autoconf 2.71 for harfbuzz (TeX Live) 5.0.1.
 #
 # Report bugs to <tex-k@tug.org>.
 #
@@ -611,8 +611,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='harfbuzz (TeX Live)'
 PACKAGE_TARNAME='harfbuzz--tex-live-'
-PACKAGE_VERSION='4.4.1'
-PACKAGE_STRING='harfbuzz (TeX Live) 4.4.1'
+PACKAGE_VERSION='5.0.1'
+PACKAGE_STRING='harfbuzz (TeX Live) 5.0.1'
 PACKAGE_BUGREPORT='tex-k@tug.org'
 PACKAGE_URL=''
 
@@ -1346,7 +1346,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures harfbuzz (TeX Live) 4.4.1 to adapt to many kinds of systems.
+\`configure' configures harfbuzz (TeX Live) 5.0.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1418,7 +1418,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 4.4.1:";;
+     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 5.0.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1523,7 +1523,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-harfbuzz (TeX Live) configure 4.4.1
+harfbuzz (TeX Live) configure 5.0.1
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2064,7 +2064,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by harfbuzz (TeX Live) $as_me 4.4.1, which was
+It was created by harfbuzz (TeX Live) $as_me 5.0.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4823,7 +4823,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='harfbuzz--tex-live-'
- VERSION='4.4.1'
+ VERSION='5.0.1'
 
 
 # Some tools Automake needs.
@@ -5033,10 +5033,10 @@ WARNING_CFLAGS=$kpse_cv_warning_cflags
 
 
 
-HB_VERSION_MAJOR=4
-HB_VERSION_MINOR=4
+HB_VERSION_MAJOR=5
+HB_VERSION_MINOR=0
 HB_VERSION_MICRO=1
-HB_VERSION=4.4.1
+HB_VERSION=5.0.1
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -8817,7 +8817,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by harfbuzz (TeX Live) $as_me 4.4.1, which was
+This file was extended by harfbuzz (TeX Live) $as_me 5.0.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8885,7 +8885,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-harfbuzz (TeX Live) config.status 4.4.1
+harfbuzz (TeX Live) config.status 5.0.1
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt b/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
index 9a1d9032fcde002c27ab5b06c9665c1ca843d13a..d4759ce131d8000d6e024cd529753a1c831b9737 100644
--- a/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
+++ b/source/libs/harfbuzz/harfbuzz-src/CMakeLists.txt
@@ -80,6 +80,7 @@ include (FindPythonInterp)
 ## Functions and headers
 include (CheckFunctionExists)
 include (CheckIncludeFile)
+include (CheckIncludeFiles)
 macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
   foreach (func_name ${ARGN})
     string(TOUPPER ${func_name} definition_to_add)
@@ -308,9 +309,16 @@ if (WIN32 AND HB_HAVE_UNISCRIBE)
 endif ()
 
 if (WIN32 AND HB_HAVE_DIRECTWRITE)
+  if (CMAKE_VERSION VERSION_GREATER 3.12)
+    check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H LANGUAGE CXX)
+  else ()
+    check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H)
+  endif ()
+  if (NOT HAVE_DWRITE_1_H)
+    message(FATAL_ERROR "DirectWrite was enabled explicitly, but required header is missing")
+  endif ()
   add_definitions(-DHAVE_DIRECTWRITE)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
-  list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
 endif ()
 
 if (HB_HAVE_GOBJECT)
@@ -426,7 +434,7 @@ target_include_directories(harfbuzz PUBLIC
                            "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
                            "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
 if (HB_HAVE_FREETYPE AND TARGET freetype)
-  target_link_libraries(harfbuzz PUBLIC freetype)
+  target_link_libraries(harfbuzz freetype)
 endif ()
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/ChangeLog b/source/libs/harfbuzz/harfbuzz-src/ChangeLog
index 59b5b780d27a69f75bb9babaefcb8506b4ba3943..c4d54f469dc5214db6edabdea1ca47a787548231 100644
--- a/source/libs/harfbuzz/harfbuzz-src/ChangeLog
+++ b/source/libs/harfbuzz/harfbuzz-src/ChangeLog
@@ -1,3 +1,3068 @@
+commit cbccadba8d1e51d6cc03a891b7c3a17f598e774c
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 22:09:06 2022 +0200
+
+    5.0.1
+
+ NEWS             | 6 ++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 10 insertions(+), 4 deletions(-)
+
+commit 61d0c547010096e37ced5b8629a0638cceaefddb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 13:25:54 2022 -0600
+
+    [ft] Pass design, not normalized, coords to freetype
+    
+    Needed for avar2 to work.
+
+ src/hb-ft.cc            | 6 +++---
+ util/helper-cairo-ft.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 473a5e5651f36cfade809f78e5322860fe4fc194
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 13:25:40 2022 -0600
+
+    [font] Fix design-coords
+    
+    Ouch!
+
+ src/hb-font.cc              | 4 ++++
+ src/hb-ot-var-fvar-table.hh | 6 +++++-
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+commit efab763885d73376018dab07a7c4006ecdf4a6ac
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 20:26:56 2022 +0200
+
+    [ci] Fix docs deployment
+    
+    Trigger build on tag pushes, and simplify the condition for calling
+    .ci/deploy-docs.sh.
+
+ .ci/deploy-docs.sh             | 5 -----
+ .github/workflows/linux-ci.yml | 3 ++-
+ 2 files changed, 2 insertions(+), 6 deletions(-)
+
+commit 40b21edf48932cde4df94f081959aa61386da3d5
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Sat Jul 23 16:45:32 2022 +0200
+
+    5.0.0
+
+ NEWS                   | 41 +++++++++++++++++++++++++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-common.cc       |  2 +-
+ src/hb-subset.h        |  2 +-
+ src/hb-version.h       |  8 ++++----
+ 7 files changed, 50 insertions(+), 8 deletions(-)
+
+commit 4cb83967aacf0aaf2622fc55539f04eb9ce2b7a0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:59:42 2022 -0600
+
+    [subset/ClassDefFormat2] Fix timeout
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5417800474165248
+
+ src/hb-ot-layout-common.hh                               |   3 ++-
+ ...-testcase-minimized-hb-subset-fuzzer-5417800474165248 | Bin 0 -> 3161 bytes
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+commit 32c85b8c8c1994e318dce49b928a7298a0b23560
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:50:26 2022 -0600
+
+    [avar2] Fix mapping when coords length don't match
+    
+    Ouch.
+    
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49407
+
+ src/hb-ot-var-avar-table.hh                               |   3 +++
+ ...zz-testcase-minimized-hb-shape-fuzzer-4523349576908800 | Bin 0 -> 140 bytes
+ 2 files changed, 3 insertions(+)
+
+commit 06c3ec0a19e6f552275773fdd667229ccd9b1977
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:36:39 2022 -0600
+
+    [avar2] Minor sanitize rewrite
+
+ src/hb-ot-var-avar-table.hh | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+commit f94a3ba1db674591952fcae00864f97bd67713fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 23 10:36:08 2022 -0600
+
+    [varStore] Better protect against HB_NO_VAR builds
+
+ src/hb-ot-layout-common.hh | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+commit 17863bd16bc82c54fb68627cbf1e65702693dd09
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 22:38:08 2022 -0600
+
+    [config/avar2] add HB_NO_VARIATIONS2
+
+ src/hb-config.hh            |  1 +
+ src/hb-ot-var-avar-table.hh | 14 +++++++++++---
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+commit 5a9c7930efc8ec055f60cae5ec2567ff8de0e972
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 21:33:15 2022 -0600
+
+    Add HB_NO_BEYOND_64K
+
+ src/hb-config.hh               |  4 ++++
+ src/hb-ot-hmtx-table.hh        |  2 +-
+ src/hb-ot-layout-common.hh     | 26 +++++++++++++-------------
+ src/hb-ot-layout-gdef-table.hh | 32 ++++++++++++++++----------------
+ src/hb-ot-layout-gsubgpos.hh   | 40 ++++++++++++++++++++--------------------
+ src/hb-ot-var-avar-table.hh    |  2 +-
+ src/hb-static.cc               |  4 ++--
+ 7 files changed, 57 insertions(+), 53 deletions(-)
+
+commit c76fd3c5f9fca4fc095031ce41d35b6d04d8ebfa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:29:38 2022 -0600
+
+    [avar2] Add link to "Spec".
+
+ src/hb-ot-var-avar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit edca52c3b644f6ebc90eeeb307ed3e87a7245348
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:17:32 2022 -0600
+
+    [avar2] Use a varStore cache
+
+ src/hb-ot-var-avar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 59f8afa73e3e0e1a7e3db5ffab06014dad5fd151
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 15:12:21 2022 -0600
+
+    [avar2] Remove XXX item
+
+ src/hb-ot-var-avar-table.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit d6c4f757a4bfeabfea35804103cfce10650a101e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 29 11:09:54 2022 -0600
+
+    [avar2] Clamp out values
+
+ src/hb-ot-var-avar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d0e2ad9297053635b65d0ad4c97c49f14f0cccee
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 21:19:15 2022 -0600
+
+    [avar] Pre-alloc vector
+
+ src/hb-ot-var-avar-table.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 2a877b554a4377f1c973ed007ae17ff5448483d1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 17:10:10 2022 -0600
+
+    [avar2] First stab at mapping v2 values
+
+ src/hb-ot-var-avar-table.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit c3eb6713e90340109e1084924945d570e52bbe28
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jun 28 16:42:28 2022 -0600
+
+    [avar2] Add v2 structure and sanitize
+
+ src/hb-ot-var-avar-table.hh | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+commit c9e843942e39fb053cc5c05df85603720cbcbc2e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 09:01:07 2022 -0600
+
+    [min/max] Don't forward argument
+
+ src/hb-algs.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 7a219ca9f0f8140906cb7fd3b879b5bf5259badc
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jul 22 14:18:59 2022 +0200
+
+    [ci] Install glib-utils on macOS
+    
+    The glib utils have been split into a separate homebrew package.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3747
+
+ .github/workflows/macos-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cb5ca6be29ef61d13b2d0dae7cf3fbf740ae20ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 05:48:27 2022 -0600
+
+    [ft] Actually call check_changed() from _changed()
+    
+    Ouch!
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3746
+
+ src/hb-ft.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit fd535a240bf56afcb4787c2038b0e33b4a6ddba3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 22 05:48:12 2022 -0600
+
+    [ft] Remove check_changed from get_glyph_shape()
+    
+    Leftover.
+
+ src/hb-ft.cc | 2 --
+ 1 file changed, 2 deletions(-)
+
+commit 7cdde6a24174ea2f29da141bcb265feb9b15eb2b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 17:17:59 2022 -0600
+
+    [ClassDef] Write a loop as range for
+
+ src/hb-ot-layout-common.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 0cc2f3c218ec60377ef284ab0cded150fc57650a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 16:46:45 2022 -0600
+
+    [algs] Remove hb_pair_t()
+
+ src/hb-algs.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 9eab3ac72dc9cbd404da3dc4ef82b798d5e42c0e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:35:19 2022 -0600
+
+    [CoverageFormat2] Remove hand-written loop
+    
+    While on a fuzzer-found test case (added) that loop was faster,
+    on real fonts, including NotoNastaliq in our benchmark, it was
+    actually slower, which intuitively I would have expected.
+    
+    Still no idea why on that fuzzer case it's faster though. :(
+
+ src/OT/Layout/Common/CoverageFormat2.hh            |  35 +++------------------
+ ...ase-minimized-hb-subset-fuzzer-4549523149553664 | Bin 0 -> 66032 bytes
+ 2 files changed, 5 insertions(+), 30 deletions(-)
+
+commit bbb4db90dd2f24b237c3bbcf6ab24389f970d1b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:34:46 2022 -0600
+
+    [Coverage/SingleSubst] Move hand-written loop to Coverage
+
+ src/OT/Layout/Common/CoverageFormat2.hh  | 35 ++++++++++++++++++++++++-----
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 38 ++++++--------------------------
+ 2 files changed, 37 insertions(+), 36 deletions(-)
+
+commit 7b95783efb36e35cc6acf579e4bb88bcefd50ae9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:18:51 2022 -0600
+
+    [Coverage] Internal rename
+
+ src/OT/Layout/Common/Coverage.hh        | 6 +++---
+ src/OT/Layout/Common/CoverageFormat1.hh | 6 +++---
+ src/OT/Layout/Common/CoverageFormat2.hh | 6 +++---
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+commit afa65f2903b2a1d32bbb70d445666b9343c86837
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:17:08 2022 -0600
+
+    [Coverage] Minor type change
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b38587aa0ba3521c2b6aa22594e46e026035f70b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:14:06 2022 -0600
+
+    [Coverage] Internal renames
+
+ src/OT/Layout/Common/Coverage.hh        | 16 ++++++++--------
+ src/OT/Layout/Common/CoverageFormat1.hh |  5 ++---
+ src/OT/Layout/Common/CoverageFormat2.hh |  7 +++----
+ 3 files changed, 13 insertions(+), 15 deletions(-)
+
+commit 84d38df828e69e6ac1a796fc0460ba33e3bd3f29
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:12:04 2022 -0600
+
+    [Coverage] Minor use range-based loop
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+commit b017b73ffe0e24bf7c621592ee3c31cc209a2155
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:06:55 2022 -0600
+
+    [Coverage] Minor remove a couple unnecessary as_array()'s
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9e650b4e0cd0571caf9e67f0186ea3690e615710
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 12:01:52 2022 -0600
+
+    [Coverage] Speedup intersect_set
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit efa388074d76339c2dc80fec675c6dbbb6511c91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:52:36 2022 -0600
+
+    [subset/SingleSubsetFormat1] Use Coverage.intersect_set
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+commit 00dfbbce1c65c2e709b3ffaac45d234bdd02528d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:39:32 2022 -0600
+
+    [Coverage] Rename and templatize intersected_coverage_glyphs
+
+ src/OT/Layout/Common/Coverage.hh         | 12 ++++++-----
+ src/OT/Layout/Common/CoverageFormat1.hh  |  8 +++++---
+ src/OT/Layout/Common/CoverageFormat2.hh  | 12 ++++++-----
+ src/OT/Layout/Common/RangeRecord.hh      |  4 ++--
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh |  2 +-
+ src/hb-ot-layout-common.hh               |  6 +++---
+ src/hb-ot-layout-gsubgpos.hh             | 35 ++++++++++++++++----------------
+ 8 files changed, 43 insertions(+), 38 deletions(-)
+
+commit d0eb273791814b36d3a9298caf99f60bef857dc3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:24:56 2022 -0600
+
+    [subset/GSUB/GPOS] Use more intersected_coverage_glyphs()
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  6 ++++--
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 34 ++------------------------------
+ 2 files changed, 6 insertions(+), 34 deletions(-)
+
+commit 450d834679738820e1d9afa579de125bb8087dbf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 11:05:35 2022 -0600
+
+    [subset/PairPosFormat1] Speed up significantly
+
+ src/OT/Layout/GPOS/SinglePosFormat1.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 5d7556e1841bafc851d043bb9d0195651edb0ce3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:42:29 2022 -0600
+
+    Revert "[subst/SingleSubstFormat1] Rewrite nicer"
+    
+    This reverts commit bababe10724c27b2cbb09bf25e7dcf4aeea07588.
+    
+    The hand-written code is still much faster :(.
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 64 +++++++++++++++++++++++++-------
+ 1 file changed, 50 insertions(+), 14 deletions(-)
+
+commit 71ce931e6ddbb7ba31b9ec3243d3c09eda251ff1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:41:29 2022 -0600
+
+    [PairPos] Don't compute newFormat
+    
+    It was wrong, because it would be writing wrong values.
+    
+    Test suite doesn't seem to catch any.
+
+ src/OT/Layout/GPOS/SinglePos.hh             | 3 ---
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 1 -
+ 2 files changed, 4 deletions(-)
+
+commit 02ca02544348edc9d89f436ed2000f4ba4f50231
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:30:23 2022 -0600
+
+    [layout] Add large_int to Types
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 6 +++---
+ src/OT/Layout/types.hh                  | 2 ++
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit bababe10724c27b2cbb09bf25e7dcf4aeea07588
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:25:27 2022 -0600
+
+    [subst/SingleSubstFormat1] Rewrite nicer
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 64 +++++++-------------------------
+ 1 file changed, 14 insertions(+), 50 deletions(-)
+
+commit cf123e6a0dae59131b028676ed919c5a09dae919
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 10:21:57 2022 -0600
+
+    [Coverage] Add get_population ()
+
+ src/OT/Layout/Common/Coverage.hh        | 13 +++++++++++++
+ src/OT/Layout/Common/CoverageFormat1.hh |  5 +++++
+ src/OT/Layout/Common/CoverageFormat2.hh |  8 ++++++++
+ src/OT/Layout/Common/RangeRecord.hh     |  6 ++++++
+ 4 files changed, 32 insertions(+)
+
+commit 2ad3c0c7709fe07122934e4842225f55267ce84c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 21 09:46:25 2022 -0600
+
+    Fix uninitialized variable
+
+ src/hb-ot-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fa471043fccb94444510e3300ac2573297c82137
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:42:18 2022 -0600
+
+    [subset] Fix previous commit
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c4d2ef90047e8b6747adcf99a42984730979fbc3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:36:35 2022 -0600
+
+    [subset] Speed up subsetting of SingleSubstFormat1_3
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 36 ++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+commit d01e6babe6660ca5ac3b941b1e977af9dcda954f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 22:17:33 2022 -0600
+
+    [subset] Speed up SingleSubstFormat1_3 closure
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 38 +++++++++++++++++++++++++++-----
+ 1 file changed, 33 insertions(+), 5 deletions(-)
+
+commit 0f800769379d05a3086cd3fc56f0c4c1a19076f8
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Wed Jul 20 14:59:02 2022 -0700
+
+    [subset] Do not repeat COLR table closure
+
+ src/hb-subset-plan.cc | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+commit 9fc31db6faa29eeac734bbb3196dbce2eabaa4c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 16:03:02 2022 -0600
+
+    [blob] Initialize members if ever on the stack
+
+ src/hb-blob.hh | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 60a9175f2c711e5b1b76b25c8121440177848513
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:59:46 2022 -0600
+
+    [blob] Remove fini_shallow()
+
+ src/hb-blob.cc | 2 --
+ src/hb-blob.hh | 2 +-
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit bcd59b5142d6c8bee71c252c8f44240542ab9dab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:57:09 2022 -0600
+
+    [set/map] Remove init_shallow/fini_shallow()
+
+ src/hb-map.hh | 18 ++++++------------
+ src/hb-set.hh |  6 ++----
+ 2 files changed, 8 insertions(+), 16 deletions(-)
+
+commit 79b23cc25d1e029ce87676a13a41f2ff8c6b980c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:38:34 2022 -0600
+
+    Fix another leak
+
+ src/hb-shape-plan.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3fad942ee21f7e5bbb29b2c5af6b1c3b77f484dd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:26:32 2022 -0600
+
+    Try fix leak
+
+ src/hb-ot-shape.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit e1b5f2f806f4aafec5eaa26cb528622e7e0b1606
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 15:03:20 2022 -0600
+
+    [object] Call destructor in hb_object_destroy()
+
+ src/hb-map.cc         | 2 --
+ src/hb-map.hh         | 2 +-
+ src/hb-object.hh      | 5 ++++-
+ src/hb-set.cc         | 2 --
+ src/hb-shape-plan.cc  | 4 ----
+ src/hb-subset-plan.cc | 2 --
+ 6 files changed, 5 insertions(+), 12 deletions(-)
+
+commit 9ea4ab60514d5f22d360a0a199cf8a126adf5e18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:57:32 2022 -0600
+
+    [object] Call constructor
+
+ src/hb-font.cc   | 1 +
+ src/hb-map.cc    | 2 --
+ src/hb-map.hh    | 2 --
+ src/hb-object.hh | 3 +++
+ src/hb-set.cc    | 2 --
+ 5 files changed, 4 insertions(+), 6 deletions(-)
+
+commit 61c04384256390d3ef5d0fd576bd2bc2fb34624e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:43:58 2022 -0600
+
+    [map] Allow geting non-const value pointer out with has()
+
+ src/hb-map.hh   | 3 ++-
+ src/test-map.cc | 4 ++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+commit 00cfc5c17d3b792a579356ca998e361bcb414260
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:38:28 2022 -0600
+
+    [map] Don't set out value in has() if not found
+
+ src/hb-map.hh | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit 485f043211ad21d6b0d926505f41c772330890a1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 14:34:55 2022 -0600
+
+    [map] Enable using hashmap with unique_ptr
+
+ src/hb-map.hh   | 11 +++++++++++
+ src/test-map.cc |  6 ++++++
+ 2 files changed, 17 insertions(+)
+
+commit 53fd4c92368abe260673649330e5eb19e9df7a60
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:33:49 2022 -0600
+
+    [set] A variable rename
+
+ src/hb-bit-page.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6826b2c3fdd881a98bd0eb3be5c114bda0282bbe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:25:34 2022 -0600
+
+    [gsubgpos/closure] Minor condition use bool operator
+
+ src/hb-ot-layout-gsubgpos.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 55a1e0bb1195332414acc2f832600269894e2f7b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:10:28 2022 -0600
+
+    [ot-map] Use hb_array for a return value
+
+ src/hb-ot-map.hh          | 14 +++++---------
+ src/hb-ot-shaper-indic.cc | 12 +++++-------
+ 2 files changed, 10 insertions(+), 16 deletions(-)
+
+commit a92d988d3d793f1f5660b443de301eedd715fd7d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 13:01:29 2022 -0600
+
+    Revert "[ci] Upgrade codecov-action to v3.1"
+    
+    This reverts commit 5b8bff8dca3a81de02878c596f3721d268d29bb4.
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 5b8bff8dca3a81de02878c596f3721d268d29bb4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:59:36 2022 -0600
+
+    [ci] Upgrade codecov-action to v3.1
+
+ .github/workflows/linux-ci.yml | 2 +-
+ .github/workflows/macos-ci.yml | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 8d923363dbc7738d0c53a1f78e9407c24010ac53
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:08:18 2022 -0600
+
+    [layout] Reduce number of closure rounds
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 2eb561ebead8276c6c905e33585d4aa216a25b41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 12:02:38 2022 -0600
+
+    [ci] Upgrade macos runner from 10.15 to latest (11)
+
+ .github/workflows/macos-ci.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit aae8c74e0551fd889f041a0c0cce708f8fab0c5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:51:09 2022 -0600
+
+    [>64k:layout:SingleSubstFormat3] Fix masking
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/31
+
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 30 +++++++++++++++++++-----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+commit 3c137ef041850150d54e4817388cdcdc3a3ff0bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:29:30 2022 -0600
+
+    [GPOS/CursivePos] Fix unsafe-to-break marking
+    
+    Fixes test.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7050021fedf549e11056f37cec7234238e7cd7e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:27:12 2022 -0600
+
+    [cursive-positioning.tests] Fix test specification
+    
+    Still failing. Figuring out.
+
+ test/shape/data/in-house/tests/cursive-positioning.tests | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+commit 5998cd00c83864d76788f1a7ee47f4b429ecc866
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:16:32 2022 -0600
+
+    [hebrew] Break out of reordering loop when pattern found
+
+ src/hb-ot-shaper-hebrew.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 42f1d7794b9b4e46cf45de6d6e8139667f1c18bd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 11:13:16 2022 -0600
+
+    Add tests for multiple cursive positioning
+    
+    From https://github.com/harfbuzz/harfbuzz/issues/2469
+
+ .../fonts/be10ea33f28a139f3305db2302af6220f2f9a583.ttf   | Bin 0 -> 1076 bytes
+ test/shape/data/in-house/tests/cursive-positioning.tests |  11 +++++++++++
+ 2 files changed, 11 insertions(+)
+
+commit d861303797e09f202acfe19740ceafdc7726b1b7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 10:57:12 2022 -0600
+
+    [hebrew] Comment
+
+ src/hb-ot-shaper-hebrew.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c60d810d509e16bf29fa7399d35c173b17c924c3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 20 10:24:54 2022 -0600
+
+    [hebrew] Implement Jerusalem mark reordering
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2947
+
+ src/hb-ot-shaper-hebrew.cc | 27 ++++++++++++++++++++++++++-
+ 1 file changed, 26 insertions(+), 1 deletion(-)
+
+commit 605bb1ee3dd1d6ef19676be0194d001c21533d60
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jul 19 21:15:21 2022 +0200
+
+    [subset] Add amalgam harfbuzz-subset.cc
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3733
+
+ .circleci/config.yml   |  2 +-
+ src/Makefile.am        | 14 ++++++++++++-
+ src/gen-harfbuzzcc.py  |  4 +++-
+ src/harfbuzz-subset.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/harfbuzz.cc        | 18 ++++++++--------
+ src/meson.build        |  8 ++++++++
+ 6 files changed, 90 insertions(+), 12 deletions(-)
+
+commit a66ba594b4a31a85de8960b2ddf294aaea2348e8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 16:32:32 2022 -0600
+
+    [util] Fix stack-underflow
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3737
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c6ef11daf51bba4e06c4eabbc387b1058e8ce8ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 15:19:52 2022 -0600
+
+    [util] Fix build with HB_NO_VAR
+
+ util/font-options.hh    | 10 ++++++++++
+ util/helper-cairo-ft.hh |  2 +-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+commit 712bfa8872532b19e6c5be9bf16c9bee36b50922
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jul 19 13:57:14 2022 -0700
+
+    build fix for HB_NO_VAR
+
+ src/hb-subset-plan.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 798a0c8a58852d1eb177db9054ead9e897672175
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:40:47 2022 -0600
+
+    Fix build
+
+ src/hb-ot-layout-gdef-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 8737dea4d9012ea4636db12274532c5f3c6abb40
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:39:47 2022 -0600
+
+    [>64k:layout:GDEF] Implement version 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/36
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gdef-table.hh | 48 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+commit 8080e01afc86fe4921c8fa87c85134f076f40675
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 14:35:58 2022 -0600
+
+    [>64k:layout] Templatize GDEFVersion1
+
+ src/hb-ot-layout-gdef-table.hh | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+commit 1665cf6bc4ac1c57d2e43070cd0aeab7c562e2bc
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 13:56:23 2022 -0600
+
+    [>64k:layout] Split GDEFVersion1
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/36
+
+ src/hb-ot-layout-gdef-table.hh | 315 ++++++++++++++++++++++++++++-------------
+ src/hb-ot-layout-gsubgpos.hh   |   1 -
+ 2 files changed, 213 insertions(+), 103 deletions(-)
+
+commit 1de5591cf743a789b240b1c1f8536d909f63a857
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 19 13:37:30 2022 -0600
+
+    [>64k:layout] Prepare GDEF for templatizing
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/36
+
+ src/hb-ot-layout-gdef-table.hh | 41 +++++++++++++++++++++++------------------
+ src/main.cc                    |  8 ++++----
+ 2 files changed, 27 insertions(+), 22 deletions(-)
+
+commit c0d60bd4964701402aacf98390e0936c9dcba953
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Tue Jul 19 18:21:09 2022 +0200
+
+    [meta] Fix warning with emscripten
+    
+    For whatever reason, em++ takes the first branch and spouts a gazillion
+    warnings like:
+    
+    ./harfbuzz/src/hb-vector.hh:229:20: warning: builtin __has_trivial_assign is deprecated; use __is_trivially_assignable instead [-Wdeprecated-builtins]
+                hb_enable_if (hb_is_trivially_copy_assignable(T))>
+                              ^
+    ./harfbuzz/src/hb-meta.hh:193:44: note: expanded from macro 'hb_is_trivially_copy_assignable'
+
+ src/hb-meta.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 91c60802e646ee10daa8eda0ab2d2ea06206cc41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 22:24:28 2022 -0600
+
+    [open-type] Fix overflow check
+    
+    Without the cast, the compiler is within its rights to reason that
+    overflow didn't happen and optimize away the check, as clang was.
+
+ src/hb-open-type.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 4279304a627d467866aac751548e728eaa841b73
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 22:20:06 2022 -0600
+
+    [stat] Fix double-promotion warnings
+
+ src/hb-ot-stat-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 54e9ab4a91a762dc8a730e22a5b103b206b05db7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 18:57:14 2022 -0600
+
+    [GPOS/Cursive] Fix breaking of parent-child attachment
+    
+    Mostly fixes https://github.com/harfbuzz/harfbuzz/issues/2469
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit c2baf2796cd1c2de60788897502bd42905c78cb0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 15:41:20 2022 -0600
+
+    [arabic] Make more features F_MANUAL_ZWJ
+    
+    The change to `ccmp` fixes shaping of certain sequences with
+    Calibri on Windows 11.  Addition of `liga` and `clig` is
+    speculative.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3530
+
+ src/hb-ot-shaper-arabic.cc | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit ddeef8c87548a57356ec72c3ed6d277c916330c7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 15:13:47 2022 -0600
+
+    [test-ot-glyphname] Fix return value
+
+ src/test-ot-glyphname.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f1a69ff1b94a4fd4de69fddcbc80fba6f819e16b
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 16:22:15 2022 -0700
+
+    [instance] update scripts for testing instancing
+
+ ...lt.retain-all-codepoint.wght=400,wdth=100.0.ttf | Bin 0 -> 6584 bytes
+ ...ult.retain-all-codepoint.wght=drop,wdth=100.ttf | Bin 0 -> 6584 bytes
+ test/subset/data/fonts/Roboto-Variable.ABC.ttf     | Bin 0 -> 13480 bytes
+ test/subset/data/tests/pin_all_at_default.tests    |  12 ++++++++
+ test/subset/generate-expected-outputs.py           |  25 ++++++++++++++--
+ test/subset/run-tests.py                           |   3 ++
+ test/subset/subset_test_suite.py                   |  32 +++++++++++++++++----
+ 7 files changed, 65 insertions(+), 7 deletions(-)
+
+commit be8e8e8c80cc69d9d3a02f357a3ef252738d96e6
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 14:24:36 2022 -0700
+
+    [instance] prune name tables after axes pinned at fixed locations
+    
+    Restricting axes to ranges is not supported yet.
+
+ src/hb-ot-stat-table.hh     | 19 +++++++++++++++-
+ src/hb-ot-var-fvar-table.hh | 53 +++++++++++++++++++++++++++++++++------------
+ src/hb-subset-plan.cc       | 11 ++++++----
+ 3 files changed, 64 insertions(+), 19 deletions(-)
+
+commit df55f840cb4cf2d5cfe9e93e289aa59e7d592f7f
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Thu Jun 30 09:36:19 2022 -0700
+
+    [instance] instantiate STAT table when axes are pinned at fixed locations
+    
+    restricting ranges is not supported yet.
+
+ src/hb-ot-stat-table.hh | 235 ++++++++++++++++++++++++++++++++++++++++++++----
+ src/hb-subset-input.cc  |  11 +--
+ src/hb-subset-plan.cc   |  10 +++
+ src/hb-subset-plan.hh   |   2 +
+ src/hb-subset.cc        |   6 ++
+ 5 files changed, 236 insertions(+), 28 deletions(-)
+
+commit 2a4773e43d528343a1b4a305905d275ba5eda829
+Author: Qunxin Liu <qxliu@google.com>
+Date:   Tue Jun 21 19:29:52 2022 -0700
+
+    add option "--instance", store axes_location in subset_plan and drop all
+    variation tables when all axes are pinned at default
+
+ src/gen-def.py              |  4 ++-
+ src/hb-map.hh               | 24 +++++++++++++
+ src/hb-ot-var-avar-table.hh |  8 +++++
+ src/hb-ot-var-fvar-table.hh |  2 ++
+ src/hb-subset-input.cc      | 65 ++++++++++++++++++++++++++++++++++-
+ src/hb-subset-input.hh      |  4 ++-
+ src/hb-subset-plan.cc       | 84 ++++++++++++++++++++++++++++++---------------
+ src/hb-subset-plan.hh       |  3 ++
+ src/hb-subset.cc            | 10 ++++++
+ src/hb-subset.h             | 15 ++++++++
+ util/hb-subset.cc           | 78 +++++++++++++++++++++++++++++++++++++++++
+ 11 files changed, 267 insertions(+), 30 deletions(-)
+
+commit 5744e951fc5e647c42a8e75652d2a32c7479fc1f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:54:44 2022 -0600
+
+    [gir] Skip graphite API
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2557
+
+ src/hb-graphite2.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 1eb8e820864771509b7aed4ce76a83e8cd2272b0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:47:49 2022 -0600
+
+    [util] Accept space as delimiter for --features/--variations
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3715
+
+ util/font-options.hh  | 4 ++--
+ util/shape-options.hh | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+commit 378663409ac9d2a54d8a738c88a76a5b9873181f
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Mon Jul 18 21:02:41 2022 +0200
+
+    [ci] Deploy docs only on tagged builds
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/2786
+
+ .ci/deploy-docs.sh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 3723b8544b63d4eb95ff1448e4ebfc6a25127360
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 14:00:14 2022 -0600
+
+    [cff] Better max op counting
+
+ src/hb-cff-interp-cs-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3c84aa8416cac7aba1430cc18ec76a393c47f3cd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 13:57:59 2022 -0600
+
+    [cff] Add a max work counter
+    
+    Set to 10,000 per interpretation right now.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3700
+    Fixes https://oss-fuzz.com/testcase-detail/5667125715927040
+
+ src/hb-cff-interp-cs-common.hh                            |   7 +++++++
+ ...uzz-testcase-minimized-hb-draw-fuzzer-5667125715927040 | Bin 0 -> 472 bytes
+ test/fuzzing/hb-draw-fuzzer.cc                            |   1 +
+ 3 files changed, 8 insertions(+)
+
+commit 89de8c700f16bd50617c20a81b77c6555f3a8988
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 13:07:29 2022 -0600
+
+    [CoverageFormat2] Another fix for broken tables
+    
+    Fixes https://oss-fuzz.com/testcase-detail/6005342714068992
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit faac252f9f6876d971c7d487f064261eb6070952
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:23:57 2022 -0600
+
+    [util/hb-ot-shape-closure] Fix showing glyph names
+
+ util/hb-ot-shape-closure.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 38f2ec1703655d1527170c6e48f2647047716d46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:17:08 2022 -0600
+
+    [hb-shape] Move shape_output_t into separate file
+
+ util/Makefile.sources |   1 +
+ util/hb-shape.cc      | 126 +--------------------------------------
+ util/shape-output.hh  | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 161 insertions(+), 125 deletions(-)
+
+commit 94be45980883bea99bb1028445c6ab7100c11409
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 12:13:48 2022 -0600
+
+    [hb-shape] Internal rename
+
+ util/hb-shape.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 4f22397f05f8b0b65897e58a0176c8fa9b85f2a4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 11:03:54 2022 -0600
+
+    [ft] A couple of introspection fixes
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit faa8cdc89877888fbcc182b368490f64a721b067
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 10:22:19 2022 -0600
+
+    [util] Allow HB_CHAFA=2/3 to enable wedges/all symbols in Chafa
+
+ util/helper-cairo-ansi.hh | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+commit b4e95965c8b9b508aca2afdc7483b89d4a56eb99
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 18 10:14:14 2022 -0600
+
+    [util] Revert Chafa to use simple blocks only
+    
+    The wedges are nice but not available on Mac.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3729
+
+ util/helper-cairo-ansi.hh | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+commit f7f6d278bb166942c9a87fd7cefbd7fa294a0ba2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 22:15:42 2022 -0600
+
+    Add hb_language_matches()
+    
+    New API:
+    + hb_language_matches()
+
+ docs/harfbuzz-sections.txt      |  1 +
+ src/hb-aat-layout-morx-table.hh |  2 +-
+ src/hb-common.cc                | 32 ++++++++++++++++++++++++++++++++
+ src/hb-common.h                 |  3 +++
+ src/hb-ot-name-table.hh         | 14 +++++---------
+ src/hb-ot-tag.cc                |  2 ++
+ 6 files changed, 44 insertions(+), 10 deletions(-)
+
+commit d57ce30054ec7bf03fe27fa9bbb3c2e6963e05d6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:56:56 2022 -0600
+
+    [ot-shape] Pass reference to props instead of pointer
+    
+    Since cannot be nullptr.
+
+ src/hb-aat-map.hh  |  4 ++--
+ src/hb-ot-map.cc   |  4 ++--
+ src/hb-ot-map.hh   |  2 +-
+ src/hb-ot-shape.cc | 10 +++++-----
+ src/hb-ot-shape.hh |  2 +-
+ 5 files changed, 11 insertions(+), 11 deletions(-)
+
+commit a972d05d7eea86516d98d494f99b1b0ce719e260
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:42:04 2022 -0600
+
+    [aat] Fix build
+
+ src/hb-aat-layout-morx-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a5dad50072e1881a5fc7595cfbe4942534d2ea5a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:39:24 2022 -0600
+
+    [aat/morx] Add test for previous commit
+    
+    https://github.com/harfbuzz/harfbuzz/issues/1373
+
+ test/shape/data/in-house/tests/macos.tests | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 2124ad8906bb77eee099071dccc49d3c60fe331f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 21:32:27 2022 -0600
+
+    [aat/morx] Implement language-specific forms
+    
+    Test on Mac with, eg.
+    
+    $ hb-view /Library/Fonts/BigCaslon.ttf -u 107
+    vs
+    $ hb-view /Library/Fonts/BigCaslon.ttf -u 107 --language pl
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1373
+
+ src/hb-aat-layout-morx-table.hh | 7 +++++++
+ src/hb-aat-map.hh               | 6 ++++--
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+commit d8574b44ccde97fc7111b4d983f5303e200f0ae8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 18:44:27 2022 -0600
+
+    [CoverageFormat2] Fix iterator to avoid infinite loop
+    
+    on invalid data.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5304497047470080
+
+ src/OT/Layout/Common/CoverageFormat2.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit b475a2ab29eec981ac92c5ebc555b2c30288fe57
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 18:44:11 2022 -0600
+
+    [array] Adjust operator !=
+
+ src/hb-array.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 9518d602f33d157343b273fe1846b8b5c60fe56e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 17:03:40 2022 -0600
+
+    [atomic] Disable compiler memory barrier on MSVC
+    
+    It keeps giving me internal compiler error.
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3728
+
+ src/hb-atomic.hh | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit f0707e2348c455113e5ef9efc86b85920bb107b1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 16:47:16 2022 -0600
+
+    [atomic] Add compiler memory_r_barrier
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3728
+
+ src/hb-atomic.hh    |  7 +++++++
+ src/hb-open-type.hh | 28 ++++++++++++++--------------
+ 2 files changed, 21 insertions(+), 14 deletions(-)
+
+commit f3151b6582a38fb1a377eb6070b8cecedb2ea711
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 16:19:28 2022 -0600
+
+    [ArrayOf family] Use memory barrier before accessing array
+    
+    Without it, the compiler was reordering and batching the read
+    of array length and array[0] if the 0'th member was accessed
+    constantly and function was inlined.  This felt safe to the
+    compiler because HB_VAR_ARRAY is 1, but could be unsafe actually.
+    The memory barrier disallows that.
+    
+    This was found by afl/honggfuzz address sanitizers.
+    Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=49187
+
+ src/hb-open-type.hh        | 14 ++++++++++++++
+ src/hb-ot-layout-common.hh |  2 +-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 90e40f24fed3e0a8ccb16e56fbe926fd5953b970
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 15:01:04 2022 -0600
+
+    [algs] Tweak attribute(packed) usage
+    
+    Allow disabling it. Also don't cast this pointer.
+
+ src/hb-algs.hh | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit af84680f23d1a3078f2a3eb8651e174b40f99bf8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 17 12:00:04 2022 -0600
+
+    [GSUB] Remove a reinterpret_cast
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9843f07658ae6b9b7b586f9c69cdb2c99b24ad18
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:55 2022 -0600
+
+    [OffsetTo] Try catching nullable offsets to unbounded types
+    
+    Doesn't catch all cases; if type is not fully defined at
+    OffsetTo time, we can't know.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1300
+    to the best we can do.
+
+ src/hb-open-type.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 1327d8e3dfcaadba6c5029f830ffaa0903a8647b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:38 2022 -0600
+
+    [layout-common] Reshuffle code so Feature is defined before it's used
+
+ src/hb-ot-layout-common.hh | 865 ++++++++++++++++++++++-----------------------
+ 1 file changed, 432 insertions(+), 433 deletions(-)
+
+commit f7147835eb3e3397ec5ad37bd6b9e1a4dfbd4f9d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:03:25 2022 -0600
+
+    [colr] Add MIN_SIZE to Paint
+
+ src/hb-ot-color-colr-table.hh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit e1d2facd5363951adec78b080cf616e4bc3ff9d3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 16:02:58 2022 -0600
+
+    [null] Add hb_has_null_size() and hb_has_min_size()
+
+ src/hb-null.hh | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+commit c8908f92d77e88d69d6f365290f82c4d3c3d629b
+Merge: 3ac110560 6ed57de15
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 15:32:58 2022 -0600
+
+    Merge pull request #3726 from harfbuzz/ft-bitmap
+    
+    Ft bitmap
+
+commit 6ed57de15c92f5bf04d9872d989d6eb129f4bec0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 15:09:28 2022 -0600
+
+    [ft] Fix negative font sizes for bitmaps
+
+ src/hb-ft.cc | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 307ee9baff687912e4f451a0cc463ff84314554f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 14:48:29 2022 -0600
+
+    [ft] Fix bitmap-only vertical metrics
+
+ src/hb-ft.cc | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+commit 87d338eb61e35d6d8270b083c8225e004f73c03f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 14:19:17 2022 -0600
+
+    [ft] Fix test
+
+ src/hb-ft.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit e294200dac3d7cd41a02e0753f63acfbb5e24820
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Fri Jul 15 21:36:50 2022 +0200
+
+    [ft] Check for FT_Get_Transform at build time
+
+ configure.ac |  2 +-
+ meson.build  |  1 +
+ src/hb-ft.cc | 22 ++++++++++++++++++++++
+ 3 files changed, 24 insertions(+), 1 deletion(-)
+
+commit 901236f721e59e9955637cd44121b28f89c5bebe
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 12:55:31 2022 -0600
+
+    [ft] Implement loading (color) bitmap fonts
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/489
+    
+    Something about the vertical metrics is still off, not matching
+    hb-ot.  I cannot figure out what.
+
+ src/hb-ft.cc | 92 ++++++++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 56 insertions(+), 36 deletions(-)
+
+commit 3ac110560dc3f103d4b95e543afc6e4b6c302728
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 15 12:48:11 2022 -0600
+
+    [ft] Fix scale when font-sizes are negative
+
+ src/hb-ft.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d68507d06212904661d51907e81012f3ce21821c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 11:20:00 2022 -0600
+
+    [arabic] Pause after calt only if no rclt
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1573
+
+ src/hb-ot-map.cc           | 15 +++++++++++++++
+ src/hb-ot-map.hh           |  2 ++
+ src/hb-ot-shaper-arabic.cc | 14 +++++++-------
+ 3 files changed, 24 insertions(+), 7 deletions(-)
+
+commit 8b379ddc765dc1912f768dbc903b94ef106e6a32
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 16:20:04 2022 -0600
+
+    [test-iter] Add back test of OT namespace iteration
+
+ src/test-iter.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit ab21c4c283f2ab37ba4c9ba759d9b92a7eb52b94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 16:02:10 2022 -0600
+
+    [hb-view] Add one to row of padding
+
+ util/helper-cairo-ansi.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 2da36cf99a737d8cf4a145f1f5d540cbb4eb1b95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 15:57:43 2022 -0600
+
+    [hb-view] Use envvar HB_CHAFA=0 to disable Chafa output
+
+ util/helper-cairo-ansi.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit 76e6feb77f373a47fa035620e518daee199e66c9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 13:45:39 2022 -0600
+
+    [util/ansi] Enable all symbols in Chafa
+    
+    Gives vastly smoother output. The previous setting was
+    equivalent to our in-house renderer.
+
+ util/helper-cairo-ansi.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 679c87ca369b4bac851cd7c70b09b6187cacf03a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 13:39:14 2022 -0600
+
+    [util/ansi] Fix chafa cell width/height
+    
+    No idea why it was set to 10/20 instead of 8/16.
+
+ util/helper-cairo-ansi.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b706be540c4db61e228ac0433ee9b88e5286d50b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 14 11:03:04 2022 -0600
+
+    [mingw32] Update instructions
+
+ README.mingw.md | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 5363e40de13425938bc833ae2b6c1d9d565bcf65
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 23:03:54 2022 +0000
+
+    [reorg] update build files.
+
+ src/Makefile.sources | 5 +++++
+ src/meson.build      | 5 +++++
+ 2 files changed, 10 insertions(+)
+
+commit d82ace5c6feba702eea0d869273f5c3090139d0a
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 23:00:01 2022 +0000
+
+    [reorg] add TODO to RangeRecord.
+
+ src/OT/Layout/Common/RangeRecord.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit c1e280ea7824a06c8f3bc14714a255c8e2b35aa3
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 22:43:38 2022 +0000
+
+    [reorg] Move Coverage, RangeRecord into new namespace layout.
+
+ src/OT/Layout/Common/Coverage.hh        | 323 +++++++++++++++++
+ src/OT/Layout/Common/CoverageFormat1.hh | 120 +++++++
+ src/OT/Layout/Common/CoverageFormat2.hh | 224 ++++++++++++
+ src/OT/Layout/Common/RangeRecord.hh     |  75 ++++
+ src/OT/Layout/types.hh                  |  64 ++++
+ src/hb-ot-layout-common.hh              | 601 +-------------------------------
+ src/test-iter.cc                        |   2 -
+ src/test-serialize.cc                   |   3 +-
+ 8 files changed, 816 insertions(+), 596 deletions(-)
+
+commit 9c2518988dcdafb8388f8f1f5e76db6e08ef6a0e
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 22:55:58 2022 +0000
+
+    [repack] Don't count space isolation against round limit.
+    
+    Restore max rounds to 20 but don't count space isolation against the limit. The number of iterations space isolation can make changes for is already bounded to a reasonable max (the number of lookups in the font) so no need to cap the number of iterations.
+
+ src/hb-repacker.hh | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+commit a2f0723148e8bdca7a024929cb8dba6961f26485
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 16:02:39 2022 -0600
+
+    [GPOS] Adjust mark attachment on multiple substitution some more
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1545
+
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh                 |   1 +
+ .../fonts/7c24183f26d60df414578a0a9f5e79ab9d32a22b.ttf   | Bin 0 -> 2544 bytes
+ test/shape/data/in-house/tests/use.tests                 |   1 +
+ 3 files changed, 2 insertions(+)
+
+commit ac216972abd3803947d4f2208380648965d26e94
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 15:32:19 2022 -0600
+
+    [subset] Add table size blowup bound
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3091
+
+ src/hb-subset.cc | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit 4b3afafb000f7aa0fbad3695a5faf7ef68c77897
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 15:13:07 2022 -0600
+
+    [array] Use hb_swap() in reverse()
+
+ src/hb-array.hh | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+commit 87167acfe3aee9e23b2a256f6e3785ee4de5122e
+Merge: a369ab133 7549d447b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 14:58:09 2022 -0600
+
+    Merge pull request #3704 from harfbuzz/64k
+    
+    Towards breaking the 64k in GSUB/GPOS
+
+commit a369ab133b77d17fe58abdac613d8e33215c0820
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 13 19:00:08 2022 +0000
+
+    [repacker] Increase max_rounds when called via public api.
+
+ src/hb-repacker.hh        | 2 +-
+ src/hb-subset-repacker.cc | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 4ee471922d6d99a81bbd6582134ac1a4e07bdcb8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 10:36:53 2022 -0600
+
+    More -Wcomma fixes
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3716
+
+ src/hb-algs.hh       |  2 +-
+ src/hb-ot-metrics.cc | 12 ++++++------
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit c2712ff4f5451145e28c760841646313bc0b8873
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 13:34:11 2022 -0600
+
+    Reorder hb_ot_shaper_t members to save 8 bytes of data per shaper
+
+ src/hb-ot-shaper-arabic.cc  |  4 ++--
+ src/hb-ot-shaper-default.cc |  8 ++++----
+ src/hb-ot-shaper-hangul.cc  |  4 ++--
+ src/hb-ot-shaper-hebrew.cc  |  4 ++--
+ src/hb-ot-shaper-indic.cc   |  4 ++--
+ src/hb-ot-shaper-khmer.cc   |  4 ++--
+ src/hb-ot-shaper-myanmar.cc |  8 ++++----
+ src/hb-ot-shaper-thai.cc    |  4 ++--
+ src/hb-ot-shaper-use.cc     |  4 ++--
+ src/hb-ot-shaper.hh         | 16 ++++++++--------
+ 10 files changed, 30 insertions(+), 30 deletions(-)
+
+commit e5f0bc8f0a903db5f7080bf9116fd258cbb036c0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 13:22:34 2022 -0600
+
+    [set] Save a few kilobytes via type erasure of process()
+
+ src/hb-bit-set.hh | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+commit 42da7da5efe76057b177ed9589947d7b1982435e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:46:36 2022 -0600
+
+    Fix HB_NO_SHAPER HB_NO_OT_SHAPE build
+
+ src/hb-shape-plan.cc | 2 +-
+ src/hb-shaper.cc     | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 015aecfcdd82382e19e85dd4c396ce45667f2548
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:15:01 2022 -0600
+
+    [use-table] Port to using packtab
+    
+    Saves around 9kb.
+
+ src/gen-use-table.py          |   69 +-
+ src/hb-ot-shaper-use-table.hh | 1690 +++++++----------------------------------
+ src/hb-ot-shaper-use.cc       |    2 +-
+ 3 files changed, 266 insertions(+), 1495 deletions(-)
+
+commit 0fcd1decb7ab9bf0b298b302bdd51976620119ab
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 13 12:17:35 2022 -0600
+
+    Fix file permissions
+
+ src/fix_get_types.py  | 0
+ src/gen-arabic-pua.py | 0
+ 2 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 7549d447ba4bb1ef031dedbde764690ff082b22a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 21:52:25 2022 -0600
+
+    [>64k:glyf] Implement composites for >64k
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/42
+
+ src/OT/glyf/CompositeGlyph.hh | 36 ++++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+commit 09de94788b3c588542e6f3f50b6d73577dca8456
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 15:08:22 2022 -0600
+
+    [>64k:glyf] Hid composite glyphIndex
+
+ src/OT/glyf/CompositeGlyph.hh | 4 ++++
+ src/OT/glyf/Glyph.hh          | 2 +-
+ src/OT/glyf/SubsetGlyph.hh    | 4 ++--
+ src/hb-subset-plan.cc         | 2 +-
+ 4 files changed, 8 insertions(+), 4 deletions(-)
+
+commit df7eebf40a080655bd56795b5d3c57f4cce03f08
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 14:14:55 2022 -0600
+
+    [>64k:layout] Fix layout of RangeRecord
+    
+    https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 99f017f41dfcb2add11d3f9e748882d7fe061132
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:13:19 2022 -0600
+
+    [>64k:layout:GSUBGPOS] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/58
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+commit 9ef9fc01148ace504d38ecf304f0e49827e4d27b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:29:23 2022 -0600
+
+    [>64k:layout] Templatize GSUBGPOSFormat1
+
+ src/hb-open-type.hh          |  2 +-
+ src/hb-ot-layout-common.hh   |  4 ++--
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++------
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+commit 5fd0a3f0b9235a50a72e3a89fb8ae41a28fc049e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:10:04 2022 -0600
+
+    [>64k:layout] Templatize GSUBGPOSFormat1
+
+ src/hb-ot-layout-common.hh   |  3 ++-
+ src/hb-ot-layout-gsubgpos.hh | 15 ++++++++-------
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+commit f6c2aaeea46bc10833d225d1514a96254a3e6434
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:06:48 2022 -0600
+
+    [>64k:layout] Add List16OfOffsetTo
+
+ src/hb-open-type.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 6d0e3e677be11f330c44f5e1037f61d268f6a621
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 12:28:53 2022 -0600
+
+    [>64k:layout] Split GSUBGPOSVersion1 into own struct
+
+ src/hb-ot-layout-gsubgpos.hh | 280 +++++++++++++++++++++++++++----------------
+ 1 file changed, 175 insertions(+), 105 deletions(-)
+
+commit 04c5cd4085837cf627aaab328b142a73de6a9c93
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 11:39:41 2022 -0600
+
+    [subset/layout] Move find_duplicate_features to subset from layout
+
+ src/hb-ot-layout-gsubgpos.hh | 62 ----------------------------------------
+ src/hb-subset-plan.cc        | 67 +++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 66 insertions(+), 63 deletions(-)
+
+commit 1bf8fa2f1f67a4f72d14c53bc4242e38e46ab475
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:22:21 2022 -0600
+
+    [>64k:layout:(Chain)Context] Implement format 4
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/34
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 0f13eb1f5ceee50be88a9c5864b0d80a3266b7a5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:43:33 2022 -0600
+
+    [>64k:layout] Templatize (Chain)ContextFormat1
+
+ src/hb-ot-layout-gsubgpos.hh | 64 ++++++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 20 deletions(-)
+
+commit d1f58e5979bb8227e1136fbf72facce7c2e9bb7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:25:07 2022 -0600
+
+    [>64k:layout:(Chain)Context] Implement format 5
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/34
+    
+    Subset does NOT lower format.
+
+ src/hb-ot-layout-gsubgpos.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit a90c5af9d2a9b3fdbf083359d2d6ab7ba73d35e6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 13:11:47 2022 -0600
+
+    [>64k:layout] Templatize (Chain)ContextFormat2
+
+ src/hb-ot-layout-gsubgpos.hh | 48 +++++++++++++++++++++++---------------------
+ 1 file changed, 25 insertions(+), 23 deletions(-)
+
+commit cc83b0b8fde5a6ac5e1800663238c4c9354da1ec
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 12:25:15 2022 -0600
+
+    [>64k:layout:MarkBasePos/MarkMarkPos/MarkLigPos] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/40
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/MarkBasePos.hh | 6 ++++++
+ src/OT/Layout/GPOS/MarkLigPos.hh  | 6 ++++++
+ src/OT/Layout/GPOS/MarkMarkPos.hh | 6 ++++++
+ 3 files changed, 18 insertions(+)
+
+commit 4b43070e2f67b2ea42673056f3f38b87ee9e5a06
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 12:22:16 2022 -0600
+
+    [>64k:layout] Templatize MarkBasePos/MarkMarkPos/MarkLigPos
+
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  4 ++--
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 13 +++++++------
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  4 ++--
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 13 +++++++------
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  4 ++--
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 13 +++++++------
+ 6 files changed, 27 insertions(+), 24 deletions(-)
+
+commit f0d6dda5a61649226ddf82b41a611c147d19729f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:28:24 2022 -0600
+
+    [>64k:layout:PairPos] Implement format 3
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/38
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/PairPos.hh        |  4 +++-
+ src/OT/Layout/GPOS/PairPosFormat1.hh | 12 ++++++------
+ 2 files changed, 9 insertions(+), 7 deletions(-)
+
+commit 298ee47c55640c1ea68409451cf4bad979cafebd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:27:49 2022 -0600
+
+    [>64k:layout] Templatize PairPosFormat1
+
+ src/OT/Layout/GPOS/PairPos.hh         | 2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh  | 8 ++++++--
+ src/OT/Layout/GPOS/PairSet.hh         | 8 ++++++--
+ src/OT/Layout/GPOS/PairValueRecord.hh | 7 +++++--
+ 4 files changed, 18 insertions(+), 7 deletions(-)
+
+commit e9f8010fd0ca12ff008e72e669e4ce5c0f1fa836
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 13:55:26 2022 -0600
+
+    [>64k:layout:PairPos] Templatize & implement format 4
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/38
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GPOS/PairPos.hh        | 12 +++++++++---
+ src/OT/Layout/GPOS/PairPosFormat2.hh | 11 ++++++-----
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+commit ecd8bc5a9cc9ec1616a4f20cc98319fa839c2067
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:49:56 2022 -0600
+
+    [>64k:layout:LigatureSubst] Implement format 2
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/33
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GSUB/LigatureSubst.hh | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 9d0e9faa4358b9800989918fa4710694aa3cb732
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:49:07 2022 -0600
+
+    [>64k:layout] Templatable bunch of GSUBGPOS internal functions
+
+ src/hb-ot-layout-gsubgpos.hh | 66 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 41 insertions(+), 25 deletions(-)
+
+commit 429b387a6f620dc590a3d22e4274519b4f220321
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:37:11 2022 -0600
+
+    [>64k:layout] Support HBUINT24 in skippy_iter
+
+ src/hb-ot-layout-gsubgpos.hh | 61 ++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 53 insertions(+), 8 deletions(-)
+
+commit 1ef67a6d6663b8cc50bdea1a67775e9fc95f9dc8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:28:02 2022 -0600
+
+    [gsubgpos] Remove HBUINT16 from matcher
+
+ src/hb-ot-layout-gsubgpos.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 704e696ad08db74b45baff78acac8ebe53589edb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:19:20 2022 -0600
+
+    [>64k:layout] Templatize LigatureSubst
+
+ src/OT/Layout/GSUB/Ligature.hh             | 10 ++++++----
+ src/OT/Layout/GSUB/LigatureSet.hh          | 13 +++++++------
+ src/OT/Layout/GSUB/LigatureSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh | 21 +++++++++++----------
+ 4 files changed, 26 insertions(+), 22 deletions(-)
+
+commit 27d24212db0c61cf2802409e55a55dff39590dd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:05:21 2022 -0600
+
+    [>64k:layout:AlternateSubst] Implement format 2
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/32
+    
+    Subset does NOT lower format.
+
+ src/OT/Layout/GSUB/AlternateSubst.hh | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit c53d3ad51eddc9a6945aa07e64c85bdb20f3cdcd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 14:03:45 2022 -0600
+
+    [>64k:layout] Templatize AlternateSet
+
+ src/OT/Layout/GSUB/AlternateSet.hh          |  3 ++-
+ src/OT/Layout/GSUB/AlternateSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 13 +++++++------
+ 3 files changed, 11 insertions(+), 9 deletions(-)
+
+commit a58a48622adc2d24daefbc62b1e71e5d850a0f58
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:58:35 2022 -0600
+
+    [>64k:layout:MultipleSubst] Implement format 2
+    
+    Implements part of https://github.com/be-fonts/boring-expansion-spec/issues/32
+    
+    Subset is NOT updated to lower format.
+
+ src/OT/Layout/GSUB/MultipleSubst.hh | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit 684c8fcea7a1ac91dcef256d6242a68445664dd4
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:37:52 2022 -0600
+
+    [>64k:layout] Templatize MultipleSubst
+
+ src/OT/Layout/GSUB/MultipleSubst.hh        |  4 ++--
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 13 +++++++------
+ src/OT/Layout/GSUB/Sequence.hh             |  3 ++-
+ 3 files changed, 11 insertions(+), 9 deletions(-)
+
+commit 8775e9b4a4f985ec29bba609b7fc53424f24834c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:28:17 2022 -0600
+
+    [>64k:layout:SingleSubst] Implement format 3/4
+    
+    Implements https://github.com/be-fonts/boring-expansion-spec/issues/31
+
+ src/OT/Layout/GSUB/SingleSubst.hh        | 32 ++++++++++++++++++++++++++++++--
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh |  2 +-
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+commit e3caf8d50a2c033039c2609b7bf6ebae302741a7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:11:53 2022 -0600
+
+    [>64k:layout] Templatize SingleSubst
+
+ src/OT/Layout/GSUB/SingleSubst.hh        |  6 +++---
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh | 10 ++++++----
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh |  9 +++++----
+ 3 files changed, 14 insertions(+), 11 deletions(-)
+
+commit ca5c8a64191e7bb7ccd79687d1c2c4e7231cbdd7
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:02:49 2022 -0600
+
+    [>64k:layout:Coverage] Implement format 3/4
+    
+    Implements rest of https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 65 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 65 insertions(+)
+
+commit 25de6fb4e7153fee6ce1792aa2c24c556726a116
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:52:03 2022 -0600
+
+    [>64k:layout:ClassDef] Implement format 3/4
+    
+    This implements part of https://github.com/be-fonts/boring-expansion-spec/issues/30
+
+ src/hb-ot-layout-common.hh | 59 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 2 deletions(-)
+
+commit 9286526f3746b7fec0624141632e7859775717cf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:26:58 2022 -0600
+
+    [>64k:layout] Templatize Coverage & ClassDef
+    
+    Have not added new formats yet.
+
+ src/hb-ot-layout-common.hh | 76 +++++++++++++++++++++++++---------------------
+ 1 file changed, 41 insertions(+), 35 deletions(-)
+
+commit e8cce9d1b3211550b584728c2c5b9a4a6d9efb09
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 14:05:43 2022 -0600
+
+    [>64k:layout] Add SmallTypes & MediumTypes
+
+ src/hb-ot-layout-common.hh | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+commit d8f9d517801c5c361f329764329731bc0bde950f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 13:19:31 2022 -0600
+
+    [hashmap] Add keys_ref() and values_ref()
+
+ src/hb-map.hh   | 12 ++++++++++++
+ src/test-map.cc |  7 +++++++
+ 2 files changed, 19 insertions(+)
+
+commit cddcb31065939928050f2804b7a1fc0b69e10c76
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 13:15:38 2022 -0600
+
+    [vector] Remove residual nullptr_t from when hashmap needed it
+
+ src/hb-vector.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 46a36771f4369994df67535e15ac7af71fad345a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 12:03:00 2022 -0600
+
+    [draw] Fix leak from e0a5231657a6f09ca4afc93e1b2224eba7a0b544
+
+ src/hb-draw.cc | 3 +++
+ 1 file changed, 3 insertions(+)
+
+commit f8544cbfc09cbd52cdb7f9241df2eeb2262a9f68
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 12 11:52:33 2022 -0600
+
+    [draw] Fix regression from e0a5231657a6f09ca4afc93e1b2224eba7a0b544
+
+ src/hb-draw.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d15041be7dbbfbd17f1ec21f3acf4a6c6e91ba9f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 13:39:21 2022 -0600
+
+    [GSUB/GPOS] Trace toplevel sanitize
+
+ src/OT/Layout/GPOS/GPOS.hh | 5 ++++-
+ src/OT/Layout/GSUB/GSUB.hh | 5 ++++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+commit 7c4e9080c0f135c1f82e71b946e7883b91a81d0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Mon Jul 11 14:01:52 2022 -0600
+
+    [sanitize] Minor trace format fixup
+    
+    This likely() is unlikely to make a difference, and obscures
+    the return_trace() message by writing out "something" instead
+    of the true/false value.
+
+ src/hb-aat-layout-bsln-table.hh |  4 ++--
+ src/hb-aat-layout-feat-table.hh |  2 +-
+ src/hb-aat-layout-just-table.hh | 12 ++++++------
+ src/hb-aat-layout-kerx-table.hh |  2 +-
+ src/hb-aat-layout-opbd-table.hh |  2 +-
+ src/hb-open-type.hh             |  4 ++--
+ src/hb-ot-color-colr-table.hh   |  2 +-
+ src/hb-ot-layout-base-table.hh  |  2 +-
+ src/hb-ot-post-table.hh         |  8 ++++----
+ src/hb-ot-stat-table.hh         | 12 ++++++------
+ 10 files changed, 25 insertions(+), 25 deletions(-)
+
+commit d826a5920cc6dec5d942768f1c44e1a155de87c2
+Author: Matthias Clasen <mclasen@redhat.com>
+Date:   Sat Jul 9 21:57:25 2022 -0400
+
+    docs: Clarify 0xFFFF as palette index
+    
+    Mention that a palette index of 0xFFFF
+    means to use the foreground color.
+
+ src/hb-ot-color.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 0cd404d0b815898afc695de6e68f0177c43056e4
+Author: jfkthame <jfkthame@gmail.com>
+Date:   Sat Jul 9 20:23:22 2022 +0100
+
+    Typo fix in hb-subset
+    
+    s/substract/subtract/
+
+ util/hb-subset.cc | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+commit 6d051f4018e21ce1ec93fe4876c4a15819d0940a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:08:51 2022 -0600
+
+    [layout] Simplify StructAfter<> usage
+
+ src/hb-ot-layout-gsubgpos.hh | 107 ++++++++++++++++++++++---------------------
+ 1 file changed, 54 insertions(+), 53 deletions(-)
+
+commit 5192294f83a0f6be13bbf7a7c38b9cf4a38d33b2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 14:00:24 2022 -0600
+
+    .
+
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh  |  22 ++--
+ src/hb-ot-layout-gsubgpos.hh                       | 124 ++++++++++-----------
+ 2 files changed, 73 insertions(+), 73 deletions(-)
+
+commit 29f149c16cdee85a1cd2d953e307e27262deee1a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jul 7 20:16:16 2022 +0000
+
+    [subset] cache sanitized tables in subset plan to avoid sanitizing tables multiple times.
+
+ src/hb-subset-plan.cc | 39 +++++++++++++++++++++++++--------------
+ src/hb-subset-plan.hh | 21 +++++++++++++++++++++
+ src/hb-subset.cc      | 16 ++++++++--------
+ 3 files changed, 54 insertions(+), 22 deletions(-)
+
+commit 8b349e1139dfdc8e29d1d19734bff8941024bf2a
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:22:34 2022 -0600
+
+    [gsubgpos] Remove HBUINT16 from match functions signatures
+
+ src/hb-ot-layout-gsubgpos.hh | 37 ++++++++++++++++++++-----------------
+ 1 file changed, 20 insertions(+), 17 deletions(-)
+
+commit f114b18c5871f891c4e59a9d698f7be9eb8df557
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 17:31:46 2022 -0600
+
+    [gsubgpos] Break skippy_iter set_match_func into two
+
+ src/hb-ot-layout-gsubgpos.hh | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+commit 8a107125a5637583ec80256f59dbb348e774863e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 13:46:30 2022 -0600
+
+    [layout] Make SubstLookup:serialize_single take iterators
+
+ src/OT/Layout/GSUB/SubstLookup.hh | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit 8a971d01e98c98dc8848ca1e89894f6dddb73f91
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:37:43 2022 -0600
+
+    [layout] Use is_source_of instead of is_iterator
+
+ src/hb-ot-layout-common.hh | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 0dc0da054d03584a1526ce852d0d3c7839e1d630
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:33:37 2022 -0600
+
+    [iter] Add hb_is_sorted_iterator(_of)
+
+ src/hb-iter.hh             | 2 ++
+ src/hb-ot-layout-common.hh | 6 +++---
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 2c67261723a9a3081ee89549b89a3409ac8306fb
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:26:16 2022 -0600
+
+    [open-type] Add HBGlyph24
+
+ src/hb-open-type.hh | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7cfe7fe651fbf479db75e4f96869b9248227f728
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 12:25:54 2022 -0600
+
+    [null] Change null bytes for RangeRecord
+    
+    Should be harmless.
+
+ src/hb-static.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 486555c6916750a97f1e35f506447594bf03639f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 17:12:59 2022 -0600
+
+    [open-type] Add Array24Of<> and SortedArray24Of<>
+
+ src/hb-open-type.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 1e503f587b3ce368b6b759c1927aa9708096c8f3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 15:44:58 2022 -0600
+
+    [null] Add DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1
+
+ src/hb-aat-layout-common.hh | 13 +------------
+ src/hb-null.hh              | 13 ++++++++++++-
+ src/hb-static.cc            |  3 +--
+ 3 files changed, 14 insertions(+), 15 deletions(-)
+
+commit ea11029a6e72be7b5f0f3b815dd7b78a105195fa
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 8 11:58:43 2022 -0600
+
+    [GPOS] Split LigatureArray.hh
+
+ src/Makefile.sources                    |  1 +
+ src/OT/Layout/GPOS/LigatureArray.hh     | 56 +++++++++++++++++++++++++++++++++
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh | 43 ++-----------------------
+ src/meson.build                         |  1 +
+ 4 files changed, 60 insertions(+), 41 deletions(-)
+
+commit 68b2742fe4eebddf0a8388ca8c57be41e45cee41
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 16:11:15 2022 -0600
+
+    [GPOS] Move code around
+
+ src/OT/Layout/GPOS/PairPosFormat1.hh  |  1 -
+ src/OT/Layout/GPOS/PairSet.hh         | 60 +++++++++++++++++------------------
+ src/OT/Layout/GPOS/PairValueRecord.hh | 18 +++++------
+ 3 files changed, 39 insertions(+), 40 deletions(-)
+
+commit 6a3043a0c146d01f878c4d3b446cb8ff8c52ae7c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:51:37 2022 -0600
+
+    Fix tests
+
+ src/OT/Layout/GPOS/PairSet.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit aa68657434f186f6792d2facda085859b15bbae5
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:07:45 2022 -0600
+
+    [Makefile.sources/meson.build] Sort file names
+
+ src/Makefile.sources | 90 ++++++++++++++++++++++++++--------------------------
+ src/meson.build      | 90 ++++++++++++++++++++++++++--------------------------
+ 2 files changed, 90 insertions(+), 90 deletions(-)
+
+commit 0b0e3b30ce44b3f305d85827780d374bd94ff077
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 14:06:44 2022 -0600
+
+    [GPOS] Break down PairPosFormat1 into new layout
+
+ src/Makefile.sources                  |   2 +
+ src/OT/Layout/GPOS/PairPosFormat1.hh  | 234 +---------------------------------
+ src/OT/Layout/GPOS/PairSet.hh         | 169 ++++++++++++++++++++++++
+ src/OT/Layout/GPOS/PairValueRecord.hh |  94 ++++++++++++++
+ src/meson.build                       |   2 +
+ 5 files changed, 269 insertions(+), 232 deletions(-)
+
+commit aec34e17eb69b67cb0beb5d2f50f544b6f95d22c
+Author: Not-a-Bug Won't Fix <notabugwontfix@proton.me>
+Date:   Thu Jul 7 15:42:51 2022 +0300
+
+    Fix target_link_libraries signatures mixing
+
+ CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a64fc71033a4cff9bb5911ee28ac45ba93f4867a
+Merge: 3a722c535 6fad6b411
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jul 7 13:35:38 2022 -0600
+
+    Merge pull request #3710 from googlefonts/24bit_repacking
+    
+    [subset] Prepare the repacker for handling 24bit offsets in GSUB/GPOS.
+
+commit 6fad6b4113750d3aabea633685bc272f98a2ef83
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 19:18:27 2022 +0000
+
+    [repacker] add tests for special casing of 24bit offsets.
+
+ src/test-repacker.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 84 insertions(+)
+
+commit b4f561dbbf61c7df9b284d1f2d4989b4517fb908
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 18:49:23 2022 +0000
+
+    [subset] Add some comments to find_space_roots/find_32_bit_roots methods.
+
+ src/graph/graph.hh | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+commit 401066bf3d20bf8913d340811fd1c61ed65bb5f1
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jul 6 18:44:40 2022 +0000
+
+    [subset] Prepare the repacker for handling 24bit offsets in GSUB/GPOS.
+    
+    The boring expansion (https://github.com/be-fonts/boring-expansion-spec) plans to introduce 24bit offsets into GSUB/GPOS. This changes the repacker to treat 24 bit offsets similar to 32 bit offsets and assign the top level 24 bit offsets into spaces to improve packing.
+
+ src/graph/graph.hh | 73 +++++++++++++++++++++++++++++++++++++++++++-----------
+ src/hb-repacker.hh |  2 +-
+ 2 files changed, 59 insertions(+), 16 deletions(-)
+
+commit 3a722c53545a5e8fb504a81acaa38f230433fadf
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 19:22:38 2022 +0200
+
+    Fixes for DWrite header checks
+
+ CMakeLists.txt | 11 ++++++++---
+ configure.ac   |  2 +-
+ 2 files changed, 9 insertions(+), 4 deletions(-)
+
+commit c091d029c2038de28f77d104f472b2d3bd417f0c
+Merge: 2587dced4 1abc14b46
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 10:51:04 2022 -0600
+
+    Merge pull request #3706 from lb90/dwrite-dll
+    
+    Load DirectWrite dynamically
+
+commit 1abc14b4635970b6f6358e0f15505f19d34e3612
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 17:52:29 2022 +0200
+
+    Do not link with the DWrite lib
+    
+    It's loaded dynamically now
+
+ CMakeLists.txt  | 5 ++++-
+ configure.ac    | 4 ----
+ meson.build     | 7 +------
+ src/meson.build | 1 -
+ 4 files changed, 5 insertions(+), 12 deletions(-)
+
+commit c22acfa8bd4529583079338150fea4c05abcad41
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Wed Jul 6 13:50:47 2022 +0200
+
+    Fix function pointer typedef
+
+ src/hb-directwrite.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2587dced4ceac75950272949610f6b2780522605
+Merge: 386e1bbad 79eb0f748
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jul 6 09:38:18 2022 -0600
+
+    Merge pull request #3707 from kleisauke/workaround-gcc-bug
+    
+    Fix build on GCC < 7
+
+commit 79eb0f74860fb6309e3162b4f17f98481c05a318
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 13:29:55 2022 +0200
+
+    [GSUB] Fix build on GCC < 7
+
+ src/OT/Layout/GSUB/GSUB.hh     | 5 +++--
+ src/hb-ot-layout-gsub-table.hh | 8 ++++----
+ 2 files changed, 7 insertions(+), 6 deletions(-)
+
+commit 3238cb744bb570a75326ab4438968c59069e9af2
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 13:18:14 2022 +0200
+
+    [GPOS] Fix build on GCC < 7
+
+ src/OT/Layout/GPOS/GPOS.hh     | 17 ++++++++++-------
+ src/hb-ot-layout-gpos-table.hh |  6 ++++--
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+commit 3e881efbe4e8ad0a6c67112b150205297561c38e
+Author: Luca Bacci <luca.bacci982@gmail.com>
+Date:   Mon Jun 27 14:34:18 2022 +0200
+
+    Revert "Revert "Revert "[hb-directwrite] Don't load dwrit.dll dynamically"""
+    
+    This reverts commit 361a438658dcddea29d7c8b9c68bf2bc88109bde.
+
+ src/hb-directwrite.cc | 36 ++++++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+commit 7b51bc95d9cf0d9a2e91a37319fa34e4e5f26927
+Author: Kleis Auke Wolthuizen <github@kleisauke.nl>
+Date:   Wed Jul 6 12:58:15 2022 +0200
+
+    [cplusplus] Fix build on GCC < 7
+
+ src/hb-cplusplus.hh | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit 386e1bbad81e720ac58a1a18c3028d47b27c6de9
+Merge: d9ab805e6 30309ec8d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 12:46:05 2022 -0600
+
+    Merge pull request #3699 from googlefonts/filter_scripts
+    
+    [subset] Add support for --layout-scripts
+
+commit 30309ec8d3eb39f6f5c05ff0e7464095c5d7bfbf
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 5 18:33:19 2022 +0000
+
+    [subset] add null element in _filter_tag_list.
+
+ src/hb-subset-plan.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 216cf5946bdea85b954c73669c085437f9e99a72
+Author: Garret Rieger <grieger@google.com>
+Date:   Tue Jul 5 17:49:12 2022 +0000
+
+    [subset] Allocate space for null entry in script/feature list.
+
+ src/hb-subset-plan.cc | 8 +++-----
+ src/hb-subset.h       | 2 +-
+ 2 files changed, 4 insertions(+), 6 deletions(-)
+
+commit d9ab805e61e0d0aca6623203b4d7b68c84b026b8
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Tue Jul 5 11:45:10 2022 -0600
+
+    Fix LookupFlag negation
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3703
+
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b0cb9a1a635e65889e8bb9888b3c48f556d69db9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 15:32:32 2022 -0600
+
+    Make get_leading_bearing return bool
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3496
+    
+    Part of supporting >64k glyphs correctly.
+
+ src/OT/glyf/Glyph.hh       |  8 +++++---
+ src/OT/glyf/GlyphHeader.hh |  4 +++-
+ src/OT/glyf/glyf.hh        | 13 +++++--------
+ src/hb-ot-font.cc          | 13 +++++++------
+ src/hb-ot-hmtx-table.hh    | 45 ++++++++++++++++++++++++++++-----------------
+ 5 files changed, 48 insertions(+), 35 deletions(-)
+
+commit 115e1a03e7612a888ed248505ef5bd25a55eedb1
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 14:45:12 2022 -0600
+
+    [glyf] Relax condition for matching number of coords
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 800760c5bd894687e5ae1ff9b08cc27e5abdfcf6
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:21:06 2022 -0600
+
+    [glyf] Rename get_extents functions for clarity
+
+ src/OT/glyf/Glyph.hh       | 6 +++---
+ src/OT/glyf/GlyphHeader.hh | 4 ++--
+ src/OT/glyf/glyf.hh        | 2 +-
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+commit ab327f93b79863c598a3497bef82ed9aa43db69e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:17:03 2022 -0600
+
+    [glyf] Fix another bug with scaling
+    
+    Of advances this time.
+    
+    That codepath is never exercised though, if font has HVAR table.
+
+ src/OT/glyf/glyf.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f46ddeba48bee8c8f7a8a4ceadc0e02b7d197632
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:12:49 2022 -0600
+
+    [hmtx/glyf] Rename side-bearing functions for clarity
+
+ src/OT/glyf/Glyph.hh       |  4 ++--
+ src/OT/glyf/GlyphHeader.hh |  2 +-
+ src/OT/glyf/glyf.hh        |  6 +++---
+ src/hb-ot-font.cc          |  6 +++---
+ src/hb-ot-hmtx-table.hh    | 12 ++++++------
+ 5 files changed, 15 insertions(+), 15 deletions(-)
+
+commit 23435d52855b477408548100bb5e5ff3a956b27b
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:04:27 2022 -0600
+
+    [hvar] Rename advance function for clarity
+
+ src/hb-ot-hmtx-table.hh     | 6 +++---
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit 9f974cae4a0f94f069f710ad04541f791d2aef16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:03:12 2022 -0600
+
+    [hvar] Rename lsb function for clarity
+
+ src/hb-ot-hmtx-table.hh     | 4 ++--
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit ab5ce6431387be417bd312c9579208d902c9e222
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 13:00:22 2022 -0600
+
+    [VVAR] Rename vorg function for clarity
+
+ src/hb-ot-font.cc           | 6 +++---
+ src/hb-ot-var-hvar-table.hh | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+commit b2d60cbd6ebbcaa51291144701312578efd90ebd
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:56:48 2022 -0600
+
+    [glyf] Rename advance functions for clarity
+
+ src/OT/glyf/glyf.hh     | 2 +-
+ src/hb-ot-font.cc       | 4 ++--
+ src/hb-ot-hmtx-table.hh | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 35c00c1216f85ca543057bb7faff7247c4e8a491
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:54:17 2022 -0600
+
+    [hmtx] Rename advance functions for clarity
+
+ src/OT/glyf/Glyph.hh    |  4 ++--
+ src/OT/glyf/glyf.hh     |  4 ++--
+ src/hb-ot-font.cc       |  6 +++---
+ src/hb-ot-hmtx-table.hh | 18 +++++++++---------
+ 4 files changed, 16 insertions(+), 16 deletions(-)
+
+commit 6b82d4faa15e6ac00303f086160a61bc8d2027e3
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:45:27 2022 -0600
+
+    [glyf] Make an optional argument non-optional
+
+ src/OT/glyf/glyf.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 3ef590808fb57cc3879c86ed5bf4c7301a2237da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sun Jul 3 12:44:24 2022 -0600
+
+    [glyf] Internal flip a variable
+
+ src/OT/glyf/glyf.hh | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+commit b07fa2bb1a07712bf5350955573512e60cecd53f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 13:43:23 2022 -0600
+
+    [ot-font] Respect VORG even if it has no variations
+
+ src/hb-ot-font.cc | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+commit 71d52e10aa353ab5e6161c66aeb00fcc68d510da
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 11:21:36 2022 -0600
+
+    [var] Fix getting side-bearing variations
+    
+    In HVAR/VVAR, if the side-bearing mappings are null, it means the
+    table does not have them and they should be loaded from glyf table.
+    Previous logic was returning zer0.
+    
+    Part of fixing https://github.com/harfbuzz/harfbuzz/issues/1694
+
+ src/hb-ot-hmtx-table.hh     |  5 +++--
+ src/hb-ot-var-hvar-table.hh | 12 ++++++------
+ 2 files changed, 9 insertions(+), 8 deletions(-)
+
+commit 78b4f3982193fdd0714853dd39fa60e5eafeb379
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 16:37:26 2022 -0600
+
+    [glyf] Fix confusion between scaled vs unscaled lsb
+    
+    Was always broken.
+
+ src/OT/glyf/glyf.hh | 28 ++++++++++++++++++++--------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+commit 6665881c7da58c32e243121809e154eeca33968c
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Sat Jul 2 11:21:12 2022 -0600
+
+    [glyf] Change side-bearing rounding
+
+ src/OT/glyf/glyf.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 0a295fcde6a07271de27bbbd9ca1b47612427cdf
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 17:16:24 2022 -0600
+
+    [var] Fix DeltaSetIndexMapFormat1
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3692
+
+ src/hb-ot-var-common.hh | 63 ++++++++++---------------------------------------
+ 1 file changed, 12 insertions(+), 51 deletions(-)
+
+commit 351cccdb75c434a46dc6193b71ba71d3d12c1857
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:52:49 2022 -0600
+
+    [buffer-deserialize] Deserialize glyph flags
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1482
+
+ src/hb-buffer-deserialize-json.hh   | 425 +++++++++++++++------------
+ src/hb-buffer-deserialize-json.rl   |  31 +-
+ src/hb-buffer-deserialize-text.hh   | 570 ++++++++++++++++++++++++------------
+ src/hb-buffer-deserialize-text.rl   |  13 +-
+ src/hb-number-parser.hh             |   8 +-
+ src/hb-ot-shaper-indic-machine.hh   |  14 +-
+ src/hb-ot-shaper-khmer-machine.hh   |  14 +-
+ src/hb-ot-shaper-myanmar-machine.hh |  14 +-
+ src/hb-ot-shaper-use-machine.hh     |  14 +-
+ src/test-buffer-serialize.cc        |   6 +-
+ 10 files changed, 694 insertions(+), 415 deletions(-)
+
+commit 5134041f216bbe0941ea5d068e008fc534d0732e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:48:47 2022 -0600
+
+    [deserialize-json] Make it actually work!
+    
+    Was not correctly deserializing glyph names as it was not dropping
+    double-quotes from glyph name before parsing.
+
+ src/hb-buffer-deserialize-json.hh | 12 ++++++------
+ src/hb-buffer-deserialize-json.rl |  2 +-
+ src/hb-buffer-deserialize-text.hh | 10 +++++-----
+ 3 files changed, 12 insertions(+), 12 deletions(-)
+
+commit 534b0911f7e6f95e77edf853be2d90d059012b16
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 16:20:31 2022 -0600
+
+    [aat-layout] Add an unlikely()
+
+ src/hb-aat-layout-common.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b8c7c0a0e6ceb133f8c2e8f4ab15ca1633123fd2
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Jul 1 12:11:15 2022 -0600
+
+    [fuzzer] In 50% of runs don't fail the allocator
+
+ test/fuzzing/hb-draw-fuzzer.cc   |  2 +-
+ test/fuzzing/hb-fuzzer.hh        | 16 ++++++++++++++++
+ test/fuzzing/hb-set-fuzzer.cc    |  2 +-
+ test/fuzzing/hb-shape-fuzzer.cc  |  2 +-
+ test/fuzzing/hb-subset-fuzzer.cc |  2 +-
+ 5 files changed, 20 insertions(+), 4 deletions(-)
+
+commit 14b018124c52da6c7bc8ab93a2c571ca2e8c2f80
+Author: Stephan Bergmann <sbergman@redhat.com>
+Date:   Mon Aug 9 17:17:48 2021 +0200
+
+    hb_graphite2_cluster_t::advance can apparently be negative
+    
+    ...as seen with HarfBuzz used by LibreOffice, with `instdir/program/soffice
+    --headless --convert-to pdf` of doc/abi6073-2.doc from the LibreOffice crash-
+    testing corpus when run under UBSan,
+    
+    > hb-graphite2.cc:361:15: runtime error: -1024 is outside the range of representable values of type 'unsigned int'
+    >  #0 in _hb_graphite2_shape at workdir/UnpackedTarball/harfbuzz/src/hb-graphite2.cc:361:15
+    >  #1 in _hb_shape_plan_execute_internal(hb_shape_plan_t*, hb_font_t*, hb_buffer_t*, hb_feature_t const*, unsigned int) at workdir/UnpackedTarball/harfbuzz/src/./hb-shaper-list.hh:38:1
+    >  #2 in hb_shape_plan_execute at workdir/UnpackedTarball/harfbuzz/src/hb-shape-plan.cc:453:14
+    >  #3 in hb_shape_full at workdir/UnpackedTarball/harfbuzz/src/hb-shape.cc:139:19
+    >  #4 in GenericSalLayout::LayoutText(ImplLayoutArgs&, SalLayoutGlyphsImpl const*) at vcl/source/gdi/CommonSalLayout.cxx:495:23
+    >  #5 in OutputDevice::getFallbackLayout(LogicalFontInstance*, int, ImplLayoutArgs&, SalLayoutGlyphs const*) const at vcl/source/outdev/font.cxx:1232:21
+    >  #6 in OutputDevice::ImplGlyphFallbackLayout(std::unique_ptr<SalLayout, std::default_delete<SalLayout> >, ImplLayoutArgs&, SalLayoutGlyphs const*) const at vcl/source/outdev/font.cxx:1300:48
+    >  #7 in OutputDevice::ImplLayout(rtl::OUString const&, int, int, Point const&, long, long const*, SalLayoutFlags, vcl::TextLayoutCache const*, SalLayoutGlyphs const*) const at vcl/source/outdev/text.cxx:1332:22
+    >  #8 in lcl_CreateLayout(SwTextGlyphsKey const&, __gnu_debug::_Safe_iterator<std::_Rb_tree_iterator<std::pair<SwTextGlyphsKey const, SwTextGlyphsData> >, std::__debug::map<SwTextGlyphsKey, SwTextGlyphsData, std::less<SwTextGlyphsKey>, std::allocator<std::pair<SwTextGlyphsKey const, SwTextGlyphsData> > >, std::bidirectional_iterator_tag>) at sw/source/core/txtnode/fntcache.cxx:233:33
+    >  #9 in SwFntObj::GetCachedSalLayoutGlyphs(SwTextGlyphsKey const&) at sw/source/core/txtnode/fntcache.cxx:257:12
+    >  #10 in SwFont::GetTextBreak(SwDrawTextInfo const&, long) at sw/source/core/txtnode/fntcache.cxx:2551:58
+    >  #11 in SwTextSizeInfo::GetTextBreak(long, o3tl::strong_int<int, Tag_TextFrameIndex>, unsigned short, vcl::TextLayoutCache const*) const at sw/source/core/text/inftxt.cxx:450:20
+    >  #12 in SwTextGuess::Guess(SwTextPortion const&, SwTextFormatInfo&, unsigned short) at sw/source/core/text/guess.cxx:205:26
+    >  #13 in SwTextPortion::Format_(SwTextFormatInfo&) at sw/source/core/text/portxt.cxx:305:32
+    >  #14 in SwTextPortion::Format(SwTextFormatInfo&) at sw/source/core/text/portxt.cxx:456:12
+    >  #15 in SwLineLayout::Format(SwTextFormatInfo&) at sw/source/core/text/porlay.cxx:260:31
+    
+    (where in frame #4 GenericSalLayout::LayoutText, pHbBuffer->props.direction is
+    HB_DIRECTION_RTL, in case that is relevant).
+    
+    It is unclear to me whether it is sufficient to only change
+    hb_graphite2_cluster_t::advance from signed to unsigned int, as there are other
+    unsigned int variables (like curradv in _hb_graphite2_shape) whose value depend
+    on hb_graphite2_cluster_t::advance, and which thus might also become negative.
+    But unlike the float -> unsigned int conversion that UBSan warned about here
+    (where gr_slot_origin_X() and xscale are float), those are signed int ->
+    unsigned int conversions that do not cause undefined behavior.  At least, with
+    this change, the above --convert-to pdf and a full `make check screenshot`
+    succeeded for me under without further UBSan warnings.
+    
+    (For the version of HarfBuzz optionally built as part of the LibreOffice build,
+    this has been addressed with
+    <https://git.libreoffice.org/core/+/6e53e03f752c2f85283c4d47efaaf0683299783c%5E!/>
+    "external/harfbuzz: hb_graphite2_cluster_t::advance can apparently be
+    negative.")
+
+ src/hb-graphite2.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit dbfd2bf3275466ea507a8a41614e4785873213f4
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 23:04:35 2022 +0000
+
+    minor.
+
+ src/hb-subset-plan.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d6f579e96affe78919936f24cb54cb18cffe2ea5
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 22:22:03 2022 +0000
+
+    [subset] add tests that exercise script filtering.
+
+ ...egular.filter-scripts-features.1FC,21,41,20,62,63.ttf | Bin 0 -> 2856 bytes
+ ...ular.filter-scripts-features.2.1FC,21,41,20,62,63.ttf | Bin 0 -> 2856 bytes
+ ...ripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 4560 bytes
+ ...Roboto-Regular.filter-scripts-features.2.61,62,63.ttf | Bin 0 -> 2484 bytes
+ ...-Regular.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf | Bin 0 -> 2828 bytes
+ ...scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 3932 bytes
+ .../Roboto-Regular.filter-scripts-features.61,62,63.ttf  | Bin 0 -> 2484 bytes
+ ...to-Regular.filter-scripts-features.D7,D8,D9,DA,DE.ttf | Bin 0 -> 2828 bytes
+ .../Roboto-Regular.filter-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 2972 bytes
+ ...r.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 4140 bytes
+ .../full-font/Roboto-Regular.filter-scripts.61,62,63.ttf | Bin 0 -> 2600 bytes
+ .../Roboto-Regular.filter-scripts.D7,D8,D9,DA,DE.ttf     | Bin 0 -> 2928 bytes
+ .../Roboto-Regular.no-scripts.1FC,21,41,20,62,63.ttf     | Bin 0 -> 2836 bytes
+ ...gular.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 3912 bytes
+ .../full-font/Roboto-Regular.no-scripts.61,62,63.ttf     | Bin 0 -> 2464 bytes
+ .../Roboto-Regular.no-scripts.D7,D8,D9,DA,DE.ttf         | Bin 0 -> 2808 bytes
+ ...-Roman.filter-scripts-features.1FC,21,41,20,62,63.ttf | Bin 0 -> 3476 bytes
+ ...oman.filter-scripts-features.2.1FC,21,41,20,62,63.ttf | Bin 0 -> 3476 bytes
+ ...ripts-features.2.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 8700 bytes
+ ...Variable-Roman.filter-scripts-features.2.61,62,63.ttf | Bin 0 -> 3476 bytes
+ ...le-Roman.filter-scripts-features.2.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3948 bytes
+ ...scripts-features.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 6584 bytes
+ ...ifVariable-Roman.filter-scripts-features.61,62,63.ttf | Bin 0 -> 3476 bytes
+ ...able-Roman.filter-scripts-features.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3948 bytes
+ ...fVariable-Roman.filter-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 3856 bytes
+ ...n.filter-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 9548 bytes
+ ...SourceSerifVariable-Roman.filter-scripts.61,62,63.ttf | Bin 0 -> 3752 bytes
+ ...SerifVariable-Roman.filter-scripts.D7,D8,D9,DA,DE.ttf | Bin 0 -> 4292 bytes
+ ...SerifVariable-Roman.no-scripts.1FC,21,41,20,62,63.ttf | Bin 0 -> 3456 bytes
+ ...Roman.no-scripts.61,62,63,64,65,66,67,68,69,6A,6B.ttf | Bin 0 -> 6564 bytes
+ .../SourceSerifVariable-Roman.no-scripts.61,62,63.ttf    | Bin 0 -> 3456 bytes
+ ...urceSerifVariable-Roman.no-scripts.D7,D8,D9,DA,DE.ttf | Bin 0 -> 3928 bytes
+ test/subset/data/profiles/filter-scripts-features.2.txt  |   2 ++
+ test/subset/data/profiles/filter-scripts-features.txt    |   2 ++
+ test/subset/data/profiles/filter-scripts.txt             |   1 +
+ test/subset/data/profiles/no-scripts.txt                 |   1 +
+ test/subset/data/tests/full-font.tests                   |   4 ++++
+ 37 files changed, 10 insertions(+)
+
+commit 79bdcbef0d63607ac8f652168848e19651c5819f
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 22:20:32 2022 +0000
+
+    [subset] Fix GDEF version downgrade logic.
+
+ src/hb-ot-layout-gdef-table.hh | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+commit 587969af42dad7342871de693bd37683822eb6cf
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:37:42 2022 +0000
+
+    [subset] Drop scripts that are not in the layout_scripts list.
+
+ src/hb-ot-layout-common.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 900476c635b3baaff4b1316d1220d5a073b9b51a
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 19:21:23 2022 +0000
+
+    Move GSUB.hh GPOS.hh back into the GPOS/GSUB sub directories.
+
+ src/Makefile.sources             |  4 ++--
+ src/OT/Layout/{ => GPOS}/GPOS.hh | 14 +++++++-------
+ src/OT/Layout/{ => GSUB}/GSUB.hh | 12 ++++++------
+ src/hb-ot-layout-gpos-table.hh   |  2 +-
+ src/hb-ot-layout-gsub-table.hh   |  2 +-
+ src/meson.build                  |  4 ++--
+ 6 files changed, 19 insertions(+), 19 deletions(-)
+
+commit 5fdae68481a4d53eb5a23285c62986340d7e5715
+Author: Garret Rieger <grieger@google.com>
+Date:   Wed Jun 29 23:52:08 2022 +0000
+
+    [reorg] Move GSUB.hh up one level and change GSUB namespace to GSUB_impl.
+
+ src/Makefile.sources                                |  2 +-
+ src/OT/Layout/{GSUB => }/GSUB.hh                    | 21 +++++++++------------
+ src/OT/Layout/GSUB/AlternateSet.hh                  |  2 +-
+ src/OT/Layout/GSUB/AlternateSubst.hh                |  2 +-
+ src/OT/Layout/GSUB/AlternateSubstFormat1.hh         |  2 +-
+ src/OT/Layout/GSUB/ChainContextSubst.hh             |  2 +-
+ src/OT/Layout/GSUB/Common.hh                        |  2 +-
+ src/OT/Layout/GSUB/ContextSubst.hh                  |  2 +-
+ src/OT/Layout/GSUB/ExtensionSubst.hh                |  2 +-
+ src/OT/Layout/GSUB/Ligature.hh                      |  2 +-
+ src/OT/Layout/GSUB/LigatureSet.hh                   |  2 +-
+ src/OT/Layout/GSUB/LigatureSubst.hh                 |  2 +-
+ src/OT/Layout/GSUB/LigatureSubstFormat1.hh          |  2 +-
+ src/OT/Layout/GSUB/MultipleSubst.hh                 |  2 +-
+ src/OT/Layout/GSUB/MultipleSubstFormat1.hh          |  2 +-
+ src/OT/Layout/GSUB/ReverseChainSingleSubst.hh       |  2 +-
+ .../Layout/GSUB/ReverseChainSingleSubstFormat1.hh   |  2 +-
+ src/OT/Layout/GSUB/Sequence.hh                      |  2 +-
+ src/OT/Layout/GSUB/SingleSubst.hh                   |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat1.hh            |  2 +-
+ src/OT/Layout/GSUB/SingleSubstFormat2.hh            |  2 +-
+ src/OT/Layout/GSUB/SubstLookup.hh                   |  2 +-
+ src/OT/Layout/GSUB/SubstLookupSubTable.hh           |  2 +-
+ src/hb-ot-layout-gsub-table.hh                      |  6 +++---
+ src/hb-ot-layout.cc                                 |  2 +-
+ src/hb-ot-layout.hh                                 |  4 ++--
+ src/hb-subset-plan.cc                               |  2 +-
+ src/hb-subset.cc                                    |  2 +-
+ src/meson.build                                     |  2 +-
+ 29 files changed, 40 insertions(+), 43 deletions(-)
+
+commit 38e81f2be9711f5dcde3b9cae40fdddb9104c493
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:09:11 2022 +0000
+
+    [subset] Add --layout-scripts command line flag.
+
+ util/hb-subset.cc | 61 +++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 48 insertions(+), 13 deletions(-)
+
+commit 70e32a662f53409a849ad175d460dd524da14489
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 21:00:48 2022 +0000
+
+    [subset] Add layout_scripts to subset input.
+
+ src/hb-subset-input.cc | 2 ++
+ src/hb-subset-input.hh | 1 +
+ src/hb-subset-plan.cc  | 3 +--
+ src/hb-subset.h        | 3 +++
+ 4 files changed, 7 insertions(+), 2 deletions(-)
+
+commit 13c499cb26e11494f53709efabcff79a962b3d95
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:25:09 2022 -0600
+
+    [hvar] Minor internal rewiring
+    
+    Not passing font to functions makes it more clear that they don't
+    scale values.
+
+ src/hb-ot-hmtx-table.hh     | 10 ++++++----
+ src/hb-ot-var-hvar-table.hh |  5 ++---
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 41d2c335bcf7f4f57b91ec8469dbfaa4d7b47e84
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:24:42 2022 +0000
+
+    [subset] Apply script list filter when doing layout collection.
+
+ src/hb-subset-plan.cc | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+commit e5c8a2f4e11fa2b5b1b64ecf1d210fc3dc862381
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:14:29 2022 +0000
+
+    [subset] Pass plan through to collect methods.
+    
+    Allows to more easily access the filtering sets as they are added and enables propagating errors to the plan.
+
+ src/hb-subset-plan.cc | 40 ++++++++++++++++------------------------
+ 1 file changed, 16 insertions(+), 24 deletions(-)
+
+commit aba4a4957ad48fd34917d44d7005ffe73b3065e9
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:13:44 2022 -0600
+
+    [ot-font] Disable VORG variation code in HB_NO_VAR
+
+ src/hb-ot-font.cc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit d5921b379b91bdb4a3d5b2b62036d6f8d8613b0f
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:08:29 2022 -0600
+
+    [tt-font] Apply VVAR.vOrg variation to VORG origin
+    
+    Mostly fixes https://github.com/harfbuzz/harfbuzz/issues/1694
+
+ src/hb-ot-font.cc           | 13 ++++++++++++-
+ src/hb-ot-var-hvar-table.hh | 10 ++++++++++
+ 2 files changed, 22 insertions(+), 1 deletion(-)
+
+commit eee29f7327de51d735c56b26798f2d296d1cb485
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 14:03:07 2022 -0600
+
+    [hmtx] Specialize var_table
+
+ src/hb-ot-font.cc       |  4 ++--
+ src/hb-ot-hmtx-table.hh | 10 +++++-----
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+commit 031fd20a5a9e86f96f7fea1598a18f76875d828d
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Thu Jun 30 13:50:18 2022 -0600
+
+    [perf] Update README
+
+ perf/README.md | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+commit 1bf051ef3bafe2d6c24983863dc3bf2f04505b3c
+Author: Garret Rieger <grieger@google.com>
+Date:   Thu Jun 30 20:03:33 2022 +0000
+
+    [subset] refactor feature tag filtering so it can be used for scripts as well.
+
+ src/hb-subset-plan.cc | 68 +++++++++++++++++++++++++++++++++------------------
+ src/hb-subset-plan.hh |  3 +++
+ 2 files changed, 47 insertions(+), 24 deletions(-)
+
+commit f6f93c30f3dd966dd0a041f3a5876a892ebcacfa
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:50:59 2022 +0200
+
+    [docs] Fix warning
+    
+    These comment blocks don’t use gtk-doc syntax.
+
+ src/hb-subset-repacker.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit d9c5292b277116af5317afc46c745f0058e6c042
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:47:49 2022 +0200
+
+    [docs] Remove duplicate or non existing symbols
+
+ docs/harfbuzz-sections.txt | 5 -----
+ 1 file changed, 5 deletions(-)
+
+commit 98e90cc67cdff8cee730e8459692bc4a07d9a279
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Thu Jun 30 08:43:57 2022 +0200
+
+    [docs] Reduce warnings
+    
+    Use markdown syntax for inline code blocks instead of %true, %false, and
+    %NULL.
+
+ src/hb-aat-layout.cc       |  6 +++---
+ src/hb-blob.cc             | 10 +++++-----
+ src/hb-buffer-serialize.cc | 24 ++++++++++++------------
+ src/hb-buffer.cc           | 38 +++++++++++++++++++-------------------
+ src/hb-buffer.h            |  6 +++---
+ src/hb-common.cc           | 26 +++++++++++++-------------
+ src/hb-deprecated.h        |  2 +-
+ src/hb-draw.cc             |  4 ++--
+ src/hb-face.cc             |  4 ++--
+ src/hb-font.cc             | 36 ++++++++++++++++++------------------
+ src/hb-font.h              | 14 +++++++-------
+ src/hb-ft.cc               |  4 ++--
+ src/hb-graphite2.cc        |  2 +-
+ src/hb-map.cc              | 10 +++++-----
+ src/hb-ot-color.cc         |  8 ++++----
+ src/hb-ot-layout.cc        | 40 ++++++++++++++++++++--------------------
+ src/hb-ot-math.cc          |  4 ++--
+ src/hb-ot-var.cc           |  4 ++--
+ src/hb-set.cc              | 20 ++++++++++----------
+ src/hb-shape-plan.cc       |  4 ++--
+ src/hb-shape.cc            | 12 ++++++------
+ src/hb-subset-input.cc     |  4 ++--
+ src/hb-subset-plan.cc      |  2 +-
+ src/hb-unicode.cc          |  8 ++++----
+ src/hb-unicode.h           |  4 ++--
+ 25 files changed, 148 insertions(+), 148 deletions(-)
+
+commit c69ec6f5bb42f9efe56e9c8086624458a359c5ae
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Jun 29 16:32:30 2022 -0600
+
+    [kern2] Fix sanitize issue on 32bit systems
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3483
+
+ src/hb-aat-layout-common.hh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 32e542d6f00992e0c2c1f51248242ab52ec278ab
+Author: Frédéric Wang <fwang@igalia.com>
+Date:   Wed Jun 29 06:45:38 2022 +0200
+
+    try & fix build errors on the bot
+
+ test/api/test-ot-face.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+commit 03d23767455539ebcaf01d4407a532c073d227ed
+Author: Frédéric Wang <fwang@igalia.com>
+Date:   Wed Jun 29 06:21:31 2022 +0200
+
+    [math] Improve fuzzing coverage
+    
+    Extend testing to cover parts that are missing according to the recent
+    oss-fuzz-coverage report:
+    - Retriving all constants from MathConstants.
+    - Retrieving entries from MathKern, MathGlyphPartRecord and
+      MathGlyphAssembly.
+    - Retrieving italic correction from MathGlyphAssembly.
+    - Choosing between horizontal/vertical offset in MathVariants.
+    
+    https://storage.googleapis.com/oss-fuzz-coverage/harfbuzz/reports/20220627/linux/src/harfbuzz/src/hb-ot-math-table.hh.html
+    https://github.com/harfbuzz/harfbuzz/issues/3688
+
+ test/api/test-ot-face.c | 37 +++++++++++++++++++++++++++++++------
+ 1 file changed, 31 insertions(+), 6 deletions(-)
+
+commit 22835dea292fb476dbce157d7dea5e57effcde47
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:49:28 2022 +0200
+
+    [docs] Add missing symbol
+
+ docs/harfbuzz-sections.txt | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 34d3d49e7898566b8a70177b8b8f934a485cc040
+Author: Khaled Hosny <khaled@aliftype.com>
+Date:   Wed Jun 29 07:46:21 2022 +0200
+
+    [docs] Fix Since annotation
+
+ src/hb-font.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
 commit 096aaa62a6e0d07c02a4894fc036efc927e5aaf9
 Author: Khaled Hosny <khaled@aliftype.com>
 Date:   Wed Jun 29 07:30:05 2022 +0200
diff --git a/source/libs/harfbuzz/harfbuzz-src/NEWS b/source/libs/harfbuzz/harfbuzz-src/NEWS
index b146f6a6f4955431c20c36d4f9391c8dd5c248c6..7de793e5bad07946cb0096245d96b840d826852f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/NEWS
+++ b/source/libs/harfbuzz/harfbuzz-src/NEWS
@@ -1,3 +1,50 @@
+Overview of changes leading to 5.0.1
+Saturday, July 23, 2022
+====================================
+- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
+
+
+Overview of changes leading to 5.0.0
+Saturday, July 23, 2022
+====================================
+- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
+  tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
+  extend OpenType in a backward-compatible way.
+  (Behdad Esfahbod, Garret Rieger)
+- Complete support for more than 65535 glyphs in “glyf” table that started in
+  4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
+- Support version 2 of “avar” table. Part of boring-expansion-spec.
+  (Behdad Esfahbod)
+- Fix mark attachment on multiple substitutions in some cases.
+  (Behdad Esfahbod)
+- Fix application of “calt”, “rclt”, and “ccmp” features to better match
+  Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
+- Improvement to interaction between multiple cursive attachments.
+  (Behdad Esfahbod)
+- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
+- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
+- Fix variation of “VORG” table. (Behdad Esfahbod)
+- Support for specific script tags to be retained in the subsetter, and add
+  “--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
+- Accept space as delimiter for --features/--variations in command line tools.
+- Improve subsetting of “COLR” table. (Qunxin Liu)
+- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
+- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
+  (Behdad Esfahbod)
+- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
+- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
+- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
+- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
+- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
+  (Luca Bacci)
+- Provide a single-file harfbuzz-subset.cc file for easier alternate building
+  of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
+
+- New API
++HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
++hb_language_matches()
+
+
 Overview of changes leading to 4.4.1
 Wednesday, June 29, 2022
 ====================================
diff --git a/source/libs/harfbuzz/harfbuzz-src/config.h.in b/source/libs/harfbuzz/harfbuzz-src/config.h.in
index 03db0581777b0685e26cb096e60a9438a180d26a..9ca8bb2c55d8f31561b62178d515344c1100970e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/config.h.in
+++ b/source/libs/harfbuzz/harfbuzz-src/config.h.in
@@ -31,8 +31,8 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
-/* Define to 1 if you have the <dwrite.h> header file. */
-#undef HAVE_DWRITE_H
+/* Define to 1 if you have the <dwrite_1.h> header file. */
+#undef HAVE_DWRITE_1_H
 
 /* Have FreeType 2 library */
 #undef HAVE_FREETYPE
@@ -40,6 +40,9 @@
 /* Define to 1 if you have the `FT_Done_MM_Var' function. */
 #undef HAVE_FT_DONE_MM_VAR
 
+/* Define to 1 if you have the `FT_Get_Transform' function. */
+#undef HAVE_FT_GET_TRANSFORM
+
 /* Define to 1 if you have the `FT_Get_Var_Blend_Coordinates' function. */
 #undef HAVE_FT_GET_VAR_BLEND_COORDINATES
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/configure.ac b/source/libs/harfbuzz/harfbuzz-src/configure.ac
index bc52d34f3f22144e28f780e7cabcc5dd019674b8..50fde646d7254a66588643cfafbb591045e2c853 100644
--- a/source/libs/harfbuzz/harfbuzz-src/configure.ac
+++ b/source/libs/harfbuzz/harfbuzz-src/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [4.4.1],
+        [5.0.1],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -308,7 +308,7 @@ if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
 	save_libs=$LIBS
 	LIBS="$LIBS $FREETYPE_LIBS"
-	AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
+	AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
 	LIBS=$save_libs
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@@ -366,17 +366,13 @@ AC_ARG_WITH(directwrite,
 have_directwrite=false
 AC_LANG_PUSH([C++])
 if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
-	AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
+	AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true)
 fi
 AC_LANG_POP([C++])
 if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
 	AC_MSG_ERROR([directwrite support requested but not found])
 fi
 if $have_directwrite; then
-	DIRECTWRITE_CXXFLAGS=
-	DIRECTWRITE_LIBS=-ldwrite
-	AC_SUBST(DIRECTWRITE_CXXFLAGS)
-	AC_SUBST(DIRECTWRITE_LIBS)
 	AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
 fi
 AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
diff --git a/source/libs/harfbuzz/harfbuzz-src/meson.build b/source/libs/harfbuzz/harfbuzz-src/meson.build
index 4a69d6d9ec3424884f6281b34968aa65096c8431..33908a2c320ac5ad1637b41e1e1a66f7fee785d8 100644
--- a/source/libs/harfbuzz/harfbuzz-src/meson.build
+++ b/source/libs/harfbuzz/harfbuzz-src/meson.build
@@ -1,6 +1,6 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.55.0',
-  version: '4.4.1',
+  version: '5.0.1',
   default_options: [
     'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway
     'cpp_std=c++11',
@@ -198,6 +198,7 @@ if freetype_dep.found()
     ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
     ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
     ['FT_Done_MM_Var', {'deps': freetype_dep}],
+    ['FT_Get_Transform', {'deps': freetype_dep}],
   ]
 
   if freetype_dep.type_name() == 'internal'
@@ -232,17 +233,12 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
 endif
 
 # DirectWrite (Windows)
-directwrite_dep = null_dep
 if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
   if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
     error('DirectWrite was enabled explicitly, but required header is missing.')
   endif
 
-  directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
-
-  if directwrite_dep.found()
-    conf.set('HAVE_DIRECTWRITE', 1)
-  endif
+  conf.set('HAVE_DIRECTWRITE', 1)
 endif
 
 # CoreText (macOS)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/Makefile.am b/source/libs/harfbuzz/harfbuzz-src/src/Makefile.am
index e1b56a5e9a7dcf703c2173f4dad03430ad782819..b0327368362c6cca8d5b84ba3ab11cd0fbe8a806 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/Makefile.am
+++ b/source/libs/harfbuzz/harfbuzz-src/src/Makefile.am
@@ -12,7 +12,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 TESTS =
 check_PROGRAMS =
 
-EXTRA_DIST += harfbuzz.cc
+EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
 EXTRA_DIST += meson.build
 EXTRA_DIST += fix_get_types.py
 
@@ -160,6 +160,17 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
 pkgconfig_DATA += harfbuzz-subset.pc
 EXTRA_DIST += harfbuzz-subset.pc.in
 
+harfbuzz-subset.cc: Makefile.sources
+	$(AM_V_GEN) \
+	for f in \
+		$(HB_BASE_sources) \
+		$(HB_SUBSET_sources) \
+		; do echo '#include "'$$f'"'; done | \
+	sort -u | \
+	grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
+	|| ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
+BUILT_SOURCES += harfbuzz-subset.cc
+
 if HAVE_ICU
 if HAVE_ICU_BUILTIN
 HBCFLAGS += $(ICU_CFLAGS)
@@ -294,6 +305,7 @@ harfbuzz.cc: Makefile.sources
 		$(HB_DIRECTWRITE_sources) \
 		$(HB_CORETEXT_sources) \
 		; do echo '#include "'$$f'"'; done | \
+	sort -u | \
 	grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
 	|| ($(RM) $(srcdir)/harfbuzz.cc; false)
 BUILT_SOURCES += harfbuzz.cc
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources b/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
index 7211fb0d5f220c544bccfbda99a87b64ff10863e..fbf9b9be863df1ac8374419f3489841c2aa5a84b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
+++ b/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
@@ -97,57 +97,65 @@ HB_BASE_sources = \
 	OT/glyf/SimpleGlyph.hh \
 	OT/glyf/CompositeGlyph.hh \
 	OT/glyf/SubsetGlyph.hh \
-	OT/Layout/GSUB/Common.hh \
-	OT/Layout/GSUB/Sequence.hh \
-	OT/Layout/GSUB/SingleSubstFormat1.hh \
-	OT/Layout/GSUB/SingleSubstFormat2.hh \
-	OT/Layout/GSUB/SingleSubst.hh \
-	OT/Layout/GSUB/MultipleSubstFormat1.hh \
-	OT/Layout/GSUB/MultipleSubst.hh \
-	OT/Layout/GSUB/AlternateSubstFormat1.hh \
-	OT/Layout/GSUB/AlternateSubst.hh \
-	OT/Layout/GSUB/AlternateSet.hh \
-	OT/Layout/GSUB/LigatureSubstFormat1.hh \
-	OT/Layout/GSUB/LigatureSubst.hh \
-	OT/Layout/GSUB/LigatureSet.hh \
-	OT/Layout/GSUB/Ligature.hh \
-	OT/Layout/GSUB/ReverseChainSingleSubst.hh \
-	OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
-	OT/Layout/GSUB/ContextSubst.hh \
-	OT/Layout/GSUB/ChainContextSubst.hh \
-	OT/Layout/GSUB/ExtensionSubst.hh \
-	OT/Layout/GSUB/SubstLookupSubTable.hh \
-	OT/Layout/GSUB/SubstLookup.hh \
-	OT/Layout/GSUB/GSUB.hh \
-	OT/Layout/GPOS.hh \
-	OT/Layout/GPOS/CursivePosFormat1.hh \
-	OT/Layout/GPOS/MarkLigPos.hh \
-	OT/Layout/GPOS/PairPos.hh \
-	OT/Layout/GPOS/Anchor.hh \
+	OT/Layout/types.hh \
+	OT/Layout/Common/Coverage.hh \
+	OT/Layout/Common/CoverageFormat1.hh \
+	OT/Layout/Common/CoverageFormat2.hh \
+	OT/Layout/Common/RangeRecord.hh \
 	OT/Layout/GPOS/AnchorFormat1.hh \
-	OT/Layout/GPOS/MarkLigPosFormat1.hh \
-	OT/Layout/GPOS/PairPosFormat1.hh \
-	OT/Layout/GPOS/ExtensionPos.hh \
+	OT/Layout/GPOS/AnchorFormat2.hh \
+	OT/Layout/GPOS/AnchorFormat3.hh \
+	OT/Layout/GPOS/Anchor.hh \
+	OT/Layout/GPOS/AnchorMatrix.hh \
 	OT/Layout/GPOS/ChainContextPos.hh \
 	OT/Layout/GPOS/Common.hh \
-	OT/Layout/GPOS/ValueFormat.hh \
-	OT/Layout/GPOS/AnchorMatrix.hh \
+	OT/Layout/GPOS/ContextPos.hh \
+	OT/Layout/GPOS/CursivePosFormat1.hh \
+	OT/Layout/GPOS/CursivePos.hh \
+	OT/Layout/GPOS/ExtensionPos.hh \
+	OT/Layout/GPOS/GPOS.hh \
+	OT/Layout/GPOS/LigatureArray.hh \
+	OT/Layout/GPOS/MarkArray.hh \
 	OT/Layout/GPOS/MarkBasePosFormat1.hh \
-	OT/Layout/GPOS/AnchorFormat3.hh \
-	OT/Layout/GPOS/PosLookup.hh \
-	OT/Layout/GPOS/MarkMarkPos.hh \
-	OT/Layout/GPOS/PairPosFormat2.hh \
 	OT/Layout/GPOS/MarkBasePos.hh \
+	OT/Layout/GPOS/MarkLigPosFormat1.hh \
+	OT/Layout/GPOS/MarkLigPos.hh \
 	OT/Layout/GPOS/MarkMarkPosFormat1.hh \
-	OT/Layout/GPOS/SinglePos.hh \
-	OT/Layout/GPOS/MarkArray.hh \
-	OT/Layout/GPOS/CursivePos.hh \
-	OT/Layout/GPOS/PosLookupSubTable.hh \
+	OT/Layout/GPOS/MarkMarkPos.hh \
 	OT/Layout/GPOS/MarkRecord.hh \
-	OT/Layout/GPOS/AnchorFormat2.hh \
-	OT/Layout/GPOS/ContextPos.hh \
-	OT/Layout/GPOS/SinglePosFormat2.hh \
+	OT/Layout/GPOS/PairPosFormat1.hh \
+	OT/Layout/GPOS/PairPosFormat2.hh \
+	OT/Layout/GPOS/PairPos.hh \
+	OT/Layout/GPOS/PairSet.hh \
+	OT/Layout/GPOS/PairValueRecord.hh \
+	OT/Layout/GPOS/PosLookup.hh \
+	OT/Layout/GPOS/PosLookupSubTable.hh \
 	OT/Layout/GPOS/SinglePosFormat1.hh \
+	OT/Layout/GPOS/SinglePosFormat2.hh \
+	OT/Layout/GPOS/SinglePos.hh \
+	OT/Layout/GPOS/ValueFormat.hh \
+	OT/Layout/GSUB/AlternateSet.hh \
+	OT/Layout/GSUB/AlternateSubstFormat1.hh \
+	OT/Layout/GSUB/AlternateSubst.hh \
+	OT/Layout/GSUB/ChainContextSubst.hh \
+	OT/Layout/GSUB/Common.hh \
+	OT/Layout/GSUB/ContextSubst.hh \
+	OT/Layout/GSUB/ExtensionSubst.hh \
+	OT/Layout/GSUB/GSUB.hh \
+	OT/Layout/GSUB/Ligature.hh \
+	OT/Layout/GSUB/LigatureSet.hh \
+	OT/Layout/GSUB/LigatureSubstFormat1.hh \
+	OT/Layout/GSUB/LigatureSubst.hh \
+	OT/Layout/GSUB/MultipleSubstFormat1.hh \
+	OT/Layout/GSUB/MultipleSubst.hh \
+	OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
+	OT/Layout/GSUB/ReverseChainSingleSubst.hh \
+	OT/Layout/GSUB/Sequence.hh \
+	OT/Layout/GSUB/SingleSubstFormat1.hh \
+	OT/Layout/GSUB/SingleSubstFormat2.hh \
+	OT/Layout/GSUB/SingleSubst.hh \
+	OT/Layout/GSUB/SubstLookup.hh \
+	OT/Layout/GSUB/SubstLookupSubTable.hh \
 	hb-ot-layout-gsubgpos.hh \
 	hb-ot-layout-jstf-table.hh \
 	hb-ot-layout.cc \
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh
deleted file mode 100644
index 224d6b746bdaf40212d758adf1d6daee20fe3df8..0000000000000000000000000000000000000000
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef OT_LAYOUT_GPOS_HH
-#define OT_LAYOUT_GPOS_HH
-
-#include "../../hb-ot-layout-common.hh"
-#include "../../hb-ot-layout-gsubgpos.hh"
-#include "GPOS/Common.hh"
-#include "GPOS/PosLookup.hh"
-
-namespace OT {
-namespace Layout {
-
-static void
-propagate_attachment_offsets (hb_glyph_position_t *pos,
-                              unsigned int len,
-                              unsigned int i,
-                              hb_direction_t direction,
-                              unsigned nesting_level = HB_MAX_NESTING_LEVEL);
-
-/*
- * GPOS -- Glyph Positioning
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
- */
-
-struct GPOS : GSUBGPOS
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
-
-  using Lookup = GPOS_impl::PosLookup;
-
-  const GPOS_impl::PosLookup& get_lookup (unsigned int i) const
-  { return static_cast<const GPOS_impl::PosLookup &> (GSUBGPOS::get_lookup (i)); }
-
-  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
-    return GSUBGPOS::subset<GPOS_impl::PosLookup> (&l);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<GPOS_impl::PosLookup> (c); }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-                                   hb_face_t *face) const;
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
-    {
-      if (!c->gpos_lookups->has (i)) continue;
-      const GPOS_impl::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<GPOS_impl::PosLookup> (face, glyphs, lookup_indexes); }
-
-  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
-};
-
-
-static void
-propagate_attachment_offsets (hb_glyph_position_t *pos,
-                              unsigned int len,
-                              unsigned int i,
-                              hb_direction_t direction,
-                              unsigned nesting_level)
-{
-  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
-   * offset of glyph they are attached to. */
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain))
-    return;
-
-  pos[i].attach_chain() = 0;
-
-  unsigned int j = (int) i + chain;
-
-  if (unlikely (j >= len))
-    return;
-
-  if (unlikely (!nesting_level))
-    return;
-
-  propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
-
-  assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
-
-  if (type & GPOS_impl::ATTACH_TYPE_CURSIVE)
-  {
-    if (HB_DIRECTION_IS_HORIZONTAL (direction))
-      pos[i].y_offset += pos[j].y_offset;
-    else
-      pos[i].x_offset += pos[j].x_offset;
-  }
-  else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/
-  {
-    pos[i].x_offset += pos[j].x_offset;
-    pos[i].y_offset += pos[j].y_offset;
-
-    assert (j < i);
-    if (HB_DIRECTION_IS_FORWARD (direction))
-      for (unsigned int k = j; k < i; k++) {
-        pos[i].x_offset -= pos[k].x_advance;
-        pos[i].y_offset -= pos[k].y_advance;
-      }
-    else
-      for (unsigned int k = j + 1; k < i + 1; k++) {
-        pos[i].x_offset += pos[k].x_advance;
-        pos[i].y_offset += pos[k].y_advance;
-      }
-  }
-}
-
-void
-GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
-}
-
-void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-  //_hb_buffer_assert_gsubgpos_vars (buffer);
-}
-
-void
-GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
-{
-  _hb_buffer_assert_gsubgpos_vars (buffer);
-
-  unsigned int len;
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
-  hb_direction_t direction = buffer->props.direction;
-
-  /* Handle attachments */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned i = 0; i < len; i++)
-      propagate_attachment_offsets (pos, len, i, direction);
-
-  if (unlikely (font->slant))
-  {
-    for (unsigned i = 0; i < len; i++)
-      if (unlikely (pos[i].y_offset))
-        pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
-  }
-}
-
-}
-
-struct GPOS_accelerator_t : Layout::GPOS::accelerator_t {
-  GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {}
-};
-
-}
-
-#endif  /* OT_LAYOUT_GPOS_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh
index e212fab976b1f6ead0133337ee98c6c6e490bd9b..7c34bb3c93de95ac6a3493e789d4eeb7860a7237 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -140,7 +140,7 @@ struct CursivePosFormat1
     unsigned int i = skippy_iter.idx;
     unsigned int j = buffer->idx;
 
-    buffer->unsafe_to_break (i, j);
+    buffer->unsafe_to_break (i, j + 1);
     float entry_x, entry_y, exit_x, exit_y;
     (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
     (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
@@ -223,7 +223,13 @@ struct CursivePosFormat1
      * https://github.com/harfbuzz/harfbuzz/issues/2469
      */
     if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+    {
       pos[parent].attach_chain() = 0;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+	pos[parent].y_offset = 0;
+      else
+	pos[parent].x_offset = 0;
+    }
 
     buffer->idx++;
     return_trace (true);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh
index e99e13ff84f3df29d1669058625caa47a50066ff..c99b6b2e4b72d3499c0cb4d5b5a91fd17f9512a7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh
@@ -11,8 +11,11 @@ struct MarkBasePos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkBasePosFormat1    format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkBasePosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkBasePosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkBasePos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
index a10b806fe5f7bb30d44d954d80e6c45fec83f9b3..ebb8c31c679ce16f6a7adfd0913b16a2dda14a03 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -12,26 +12,27 @@ typedef AnchorMatrix BaseArray;         /* base-major--
                                          * mark-minor--
                                          * ordered by class--zero-based. */
 
-struct MarkBasePosFormat1
+template <typename Types>
+struct MarkBasePosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 markCoverage;           /* Offset to MarkCoverage table--from
                                          * beginning of MarkBasePos subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 baseCoverage;           /* Offset to BaseCoverage table--from
                                          * beginning of MarkBasePos subtable */
   HBUINT16      classCount;             /* Number of classes defined for marks */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 markArray;              /* Offset to MarkArray table--from
                                          * beginning of MarkBasePos subtable */
-  Offset16To<BaseArray>
+  typename Types::template OffsetTo<BaseArray>
                 baseArray;              /* Offset to BaseArray table--from
                                          * beginning of MarkBasePos subtable */
 
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
     bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -117,6 +118,7 @@ struct MarkBasePosFormat1
           0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
           (skippy_iter.idx == 0 ||
            _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
+           !_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh
index 7e74aa73e0a39c432fd6eba396cda24dfbbb1e4f..8a4de9ffaa6bbd765659d72389cf8bdcfe4d2ebc 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh
@@ -11,8 +11,11 @@ struct MarkLigPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkLigPosFormat1     format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkLigPosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkLigPosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkLigPos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
index 4382aa6c6cb3d4a1e4f1304c8d5c8acf4d7dea7a..1a8021237e2bd06a95358a06521b77b69337fd46 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -1,72 +1,34 @@
 #ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
 #define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
 
+#include "LigatureArray.hh"
+
 namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-typedef AnchorMatrix LigatureAttach;    /* component-major--
-                                         * in order of writing direction--,
-                                         * mark-minor--
-                                         * ordered by class--zero-based. */
-
-/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : List16OfOffset16To<LigatureAttach>
-{
-  template <typename Iterator,
-            hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator             coverage,
-               unsigned             class_count,
-               const hb_map_t      *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    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
+template <typename Types>
+struct MarkLigPosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 markCoverage;           /* Offset to Mark Coverage table--from
                                          * beginning of MarkLigPos subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 ligatureCoverage;       /* Offset to Ligature Coverage
                                          * table--from beginning of MarkLigPos
                                          * subtable */
   HBUINT16      classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 markArray;              /* Offset to MarkArray table--from
                                          * beginning of MarkLigPos subtable */
-  Offset16To<LigatureArray>
+  typename Types::template OffsetTo<LigatureArray>
                 ligatureArray;          /* Offset to LigatureArray table--from
                                          * beginning of MarkLigPos subtable */
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh
index c0eee6d54cf8990d9989bdf8d9ef77f81360d2ae..74b5105c4234348eb04328f6e0a9b5d85c7589c3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh
@@ -11,8 +11,11 @@ struct MarkMarkPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkMarkPosFormat1    format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkMarkPosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkMarkPosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkMarkPos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index c48a74f77389b02283abe75afd63401aa257f259..fbcebb8044169af0ebe5fa3e4ad4fd730ceb43e2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -12,27 +12,28 @@ typedef AnchorMatrix Mark2Array;        /* mark2-major--
                                          * mark1-minor--
                                          * ordered by class--zero-based. */
 
-struct MarkMarkPosFormat1
+template <typename Types>
+struct MarkMarkPosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
                                          * table--from beginning of MarkMarkPos
                                          * subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
                                          * table--from beginning of MarkMarkPos
                                          * subtable */
   HBUINT16      classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 mark1Array;             /* Offset to Mark1Array table--from
                                          * beginning of MarkMarkPos subtable */
-  Offset16To<Mark2Array>
+  typename Types::template OffsetTo<Mark2Array>
                 mark2Array;             /* Offset to Mark2Array table--from
                                          * beginning of MarkMarkPos subtable */
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -100,7 +101,7 @@ struct MarkMarkPosFormat1
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+    skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
     unsigned unsafe_from;
     if (!skippy_iter.prev (&unsafe_from))
     {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh
index 8479178d384a52ebc24e5152a4e2a2de6871169d..72bfc43dc434554c612397cd1c91a31583b8404d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh
@@ -12,9 +12,13 @@ struct PairPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  PairPosFormat1        format1;
-  PairPosFormat2        format2;
+  HBUINT16			format;         /* Format identifier */
+  PairPosFormat1_3<SmallTypes>	format1;
+  PairPosFormat2_4<SmallTypes>	format2;
+#ifndef HB_NO_BORING_EXPANSION
+  PairPosFormat1_3<MediumTypes>	format3;
+  PairPosFormat2_4<MediumTypes>	format4;
+#endif
   } u;
 
   public:
@@ -26,6 +30,10 @@ struct PairPos
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh
index 35a2db2d45eb54335e9f0c452438c9dc08cb5c91..3cb207281d978a073e905b4eb182b2061ddb1b5d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -1,248 +1,22 @@
 #ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
 #define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
 
+#include "PairSet.hh"
+
 namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-struct PairValueRecord
-{
-  friend struct PairSet;
-
-  int cmp (hb_codepoint_t k) const
-  { return secondGlyph.cmp (k); }
-
-  struct context_t
-  {
-    const void          *base;
-    const ValueFormat   *valueFormats;
-    const ValueFormat   *newFormats;
-    unsigned            len1; /* valueFormats[0].get_len() */
-    const hb_map_t      *glyph_map;
-    const hb_map_t      *layout_variation_idx_map;
-  };
-
-  bool subset (hb_subset_context_t *c,
-               context_t *closure) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *s = c->serializer;
-    auto *out = s->start_embed (*this);
-    if (unlikely (!s->extend_min (out))) return_trace (false);
-
-    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
-
-    closure->valueFormats[0].copy_values (s,
-                                          closure->newFormats[0],
-                                          closure->base, &values[0],
-                                          closure->layout_variation_idx_map);
-    closure->valueFormats[1].copy_values (s,
-                                          closure->newFormats[1],
-                                          closure->base,
-                                          &values[closure->len1],
-                                          closure->layout_variation_idx_map);
-
-    return_trace (true);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                  const ValueFormat *valueFormats,
-                                  const void *base) const
-  {
-    unsigned record1_len = valueFormats[0].get_len ();
-    unsigned record2_len = valueFormats[1].get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
-
-    if (valueFormats[0].has_device ())
-      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
-
-    if (valueFormats[1].has_device ())
-      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
-  }
-
-  bool intersects (const hb_set_t& glyphset) const
-  {
-    return glyphset.has(secondGlyph);
-  }
-
-  const Value* get_values_1 () const
-  {
-    return &values[0];
-  }
-
-  const Value* get_values_2 (ValueFormat format1) const
-  {
-    return &values[format1.get_len ()];
-  }
 
-  protected:
-  HBGlyphID16   secondGlyph;            /* GlyphID of second glyph in the
-                                         * pair--first glyph is listed in the
-                                         * Coverage table */
-  ValueRecord   values;                 /* Positioning data for the first glyph
-                                         * followed by for second glyph */
-  public:
-  DEFINE_SIZE_ARRAY (2, values);
-};
-
-struct PairSet
+template <typename Types>
+struct PairPosFormat1_3
 {
-  friend struct PairPosFormat1;
-
-  bool intersects (const hb_set_t *glyphs,
-                   const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (glyphs->has (record->secondGlyph))
-        return true;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-    return false;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c,
-                       const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    c->input->add_array (&record->secondGlyph, len, record_size);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                  const ValueFormat *valueFormats) const
-  {
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (c->glyph_set->has (record->secondGlyph))
-      { record->collect_variation_indices (c, valueFormats, this); }
-
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-  }
+  using PairSet = GPOS_impl::PairSet<Types>;
+  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
 
-  bool apply (hb_ot_apply_context_t *c,
-              const ValueFormat *valueFormats,
-              unsigned int pos) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
-                                                &firstPairValueRecord,
-                                                len,
-                                                record_size);
-    if (record)
-    {
-      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
-      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
-      if (applied_first || applied_second)
-        buffer->unsafe_to_break (buffer->idx, pos + 1);
-      if (len2)
-        pos++;
-      buffer->idx = pos;
-      return_trace (true);
-    }
-    buffer->unsafe_to_concat (buffer->idx, pos + 1);
-    return_trace (false);
-  }
-
-  bool subset (hb_subset_context_t *c,
-               const ValueFormat valueFormats[2],
-               const ValueFormat newFormats[2]) const
-  {
-    TRACE_SUBSET (this);
-    auto snap = c->serializer->snapshot ();
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->len = 0;
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    PairValueRecord::context_t context =
-    {
-      this,
-      valueFormats,
-      newFormats,
-      len1,
-      &glyph_map,
-      c->plan->layout_variation_idx_map
-    };
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len, num = 0;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (glyphset.has (record->secondGlyph)
-         && record->subset (c, &context)) num++;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-
-    out->len = num;
-    if (!num) c->serializer->revert (snap);
-    return_trace (num);
-  }
-
-  struct sanitize_closure_t
-  {
-    const ValueFormat *valueFormats;
-    unsigned int len1; /* valueFormats[0].get_len() */
-    unsigned int stride; /* 1 + len1 + len2 */
-  };
-
-  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && c->check_range (&firstPairValueRecord,
-                          len,
-                          HBUINT16::static_size,
-                          closure->stride))) return_trace (false);
-
-    unsigned int count = len;
-    const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
-                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
-  }
-
-  protected:
-  HBUINT16              len;    /* Number of PairValueRecords */
-  PairValueRecord       firstPairValueRecord;
-                                /* Array of PairValueRecords--ordered
-                                 * by GlyphID of the second glyph */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct PairPosFormat1
-{
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of subtable */
   ValueFormat   valueFormat[2];         /* [0] Defines the types of data in
@@ -251,11 +25,11 @@ struct PairPosFormat1
                                         /* [1] Defines the types of data in
                                          * ValueRecord2--for the second glyph
                                          * in the pair--may be zero (0) */
-  Array16OfOffset16To<PairSet>
+  Array16Of<typename Types::template OffsetTo<PairSet>>
                 pairSet;                /* Array of PairSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (10, pairSet);
+  DEFINE_SIZE_ARRAY (8 + Types::size, pairSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -265,7 +39,7 @@ struct PairPosFormat1
 
     unsigned int len1 = valueFormat[0].get_len ();
     unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure =
+    typename PairSet::sanitize_closure_t closure =
     {
       valueFormat,
       len1,
@@ -275,14 +49,13 @@ struct PairPosFormat1
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
-
   bool intersects (const hb_set_t *glyphs) const
   {
     return
     + hb_zip (this+coverage, pairSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
+    | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
               { return (this+_).intersects (glyphs, valueFormat); })
     | hb_any
     ;
@@ -358,7 +131,7 @@ struct PairPosFormat1
 
     + hb_zip (this+coverage, pairSet)
     | hb_filter (glyphset, hb_first)
-    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
+    | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
                  {
                    auto snap = c->serializer->snapshot ();
                    auto *o = out->pairSet.serialize_append (c->serializer);
@@ -391,7 +164,7 @@ struct PairPosFormat1
 
     unsigned format1 = 0;
     unsigned format2 = 0;
-    for (const Offset16To<PairSet>& _ :
+    for (const auto & _ :
              + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
     {
       const PairSet& set = (this + _);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh
index 3f5f9959c4675f56e3637abdf97f635c19f467c8..f58bcb1b303788ad8423343ab50986f343ed439f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -7,11 +7,12 @@ namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-struct PairPosFormat2
+template <typename Types>
+struct PairPosFormat2_4
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of subtable */
   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
@@ -20,11 +21,11 @@ struct PairPosFormat2
   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
                                          * second glyph of the pair--may be
                                          * zero (0) */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                 classDef1;              /* Offset to ClassDef table--from
                                          * beginning of PairPos subtable--for
                                          * the first glyph of the pair */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                 classDef2;              /* Offset to ClassDef table--from
                                          * beginning of PairPos subtable--for
                                          * the second glyph of the pair */
@@ -36,7 +37,7 @@ struct PairPosFormat2
                                          * class1-major, class2-minor,
                                          * Each entry has value1 and value2 */
   public:
-  DEFINE_SIZE_ARRAY (16, values);
+  DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh
index 57e146befd62e2dc1e82545eeb32891625f868a7..702f578b3c7bc34a39b2e60e843cca2711e611ac 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh
@@ -45,10 +45,7 @@ struct SinglePos
     ValueFormat new_format = src->get_value_format ();
 
     if (glyph_val_iter_pairs)
-    {
       format = get_format (glyph_val_iter_pairs);
-      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
-    }
 
     u.format = format;
     switch (u.format) {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh
index 8b7840ed0ebfd039a72f1c8fab9e9e4855068155..c0e7d29ceabeacab17eb9140c11cc305b8f21328 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -104,9 +104,11 @@ struct SinglePosFormat1
     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
+
     auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
+    + hb_iter (intersection)
     | hb_map_retains_sorting (glyph_map)
     | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
     ;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSet.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSet.hh
index 484f3474686cf9acfd51f33313be958eababc2e6..a5dcb653599bc1ecf85f042743d1436474374770 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSet.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSet.hh
@@ -5,12 +5,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct AlternateSet
 {
   protected:
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 alternates;             /* Array of alternate GlyphIDs--in
                                          * arbitrary order */
   public:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubst.hh
index e5d999261fc582785d165acb9b6c665adaff18cc..37406179a286757cc53298449de10767481b831c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubst.hh
@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct AlternateSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  AlternateSubstFormat1 format1;
+  HBUINT16				format;         /* Format identifier */
+  AlternateSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  AlternateSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
   public:
 
@@ -24,10 +27,15 @@ struct AlternateSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+   * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
   bool serialize (hb_serialize_context_t *c,
                   hb_sorted_array_t<const HBGlyphID16> glyphs,
                   hb_array_t<const unsigned int> alternate_len_list,
@@ -42,6 +50,9 @@ struct AlternateSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
index af1cd7bedbad65d59a1ac9e7918329cab15ce58b..adec65d58646f72ec55db96e9f182ef857f61899 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct AlternateSubstFormat1
+template <typename Types>
+struct AlternateSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<AlternateSet>
+  Array16Of<typename Types::template OffsetTo<AlternateSet<Types>>>
                 alternateSet;           /* Array of AlternateSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, alternateSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -39,9 +40,8 @@ struct AlternateSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
     ;
-
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -52,7 +52,7 @@ struct AlternateSubstFormat1
     + hb_zip (this+coverage, alternateSet)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ChainContextSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ChainContextSubst.hh
index bbb88b222f8388667c4b6f0c232458eb40f23735..08fd779f73096c9c73ca5806a339553457e70d64 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ChainContextSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ChainContextSubst.hh
@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ChainContextSubst : ChainContext {};
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Common.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Common.hh
index f4c78a9f0205878b6c12f715e2d52d0aa9e80db0..968bba0481adf2f7d953c72ef9f7b1723d83ce15 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Common.hh
@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ContextSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ContextSubst.hh
index 2af54e8ff47acc34d94a81ab158338e8babbde43..9f8cb46b5e20960557fe59eacc9a71b91ac82318 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ContextSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ContextSubst.hh
@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ContextSubst : Context {};
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ExtensionSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ExtensionSubst.hh
index 40a3ff439f1b1c47acaa22af23e37b7fbc3168ca..831a7dfa2d1b79953272a54180b499592c0050ed 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ExtensionSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ExtensionSubst.hh
@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ExtensionSubst : Extension<ExtensionSubst>
 {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/GSUB.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/GSUB.hh
index 3f0c4b2ad9acb5c1824dcfa11bbdd33aae2d95d0..c0ff098f491e12dbad6e0ab50eb480ff035c6c9a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/GSUB.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/GSUB.hh
@@ -1,16 +1,15 @@
 #ifndef OT_LAYOUT_GSUB_GSUB_HH
 #define OT_LAYOUT_GSUB_GSUB_HH
 
-// TODO(garretrieger): move to new layout.
 #include "../../../hb-ot-layout-gsubgpos.hh"
 #include "Common.hh"
 #include "SubstLookup.hh"
 
-using OT::Layout::GSUB::SubstLookup;
-
 namespace OT {
+
+using Layout::GSUB_impl::SubstLookup;
+
 namespace Layout {
-namespace GSUB {
 
 /*
  * GSUB -- Glyph Substitution
@@ -33,7 +32,10 @@ struct GSUB : GSUBGPOS
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<SubstLookup> (c); }
+  {
+    TRACE_SANITIZE (this);
+    return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
+  }
 
   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
@@ -47,11 +49,10 @@ struct GSUB : GSUBGPOS
 };
 
 
-}
 }
 
-struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t {
-  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {}
+struct GSUB_accelerator_t : Layout::GSUB::accelerator_t {
+  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {}
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Ligature.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Ligature.hh
index 0448d925d125a7b850574dfaf65fad9b43327b68..22ed65f858ad30a744827d320aeaf4656b65639b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Ligature.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Ligature.hh
@@ -5,18 +5,20 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct Ligature
 {
   protected:
-  HBGlyphID16   ligGlyph;               /* GlyphID of ligature to substitute */
-  HeadlessArrayOf<HBGlyphID16>
-                component;              /* Array of component GlyphIDs--start
+  typename Types::HBGlyphID
+		ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArrayOf<typename Types::HBGlyphID>
+		component;              /* Array of component GlyphIDs--start
                                          * with the second  component--ordered
                                          * in writing direction */
   public:
-  DEFINE_SIZE_ARRAY (4, component);
+  DEFINE_SIZE_ARRAY (Types::size + 2, component);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSet.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSet.hh
index 185b324b35bc60819b00f89b299bf352a9d9f6f2..637cec713777f08f74a53d8639f03a9d419e4ecf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSet.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSet.hh
@@ -6,12 +6,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct LigatureSet
 {
   protected:
-  Array16OfOffset16To<Ligature>
+  Array16OfOffset16To<Ligature<Types>>
                 ligature;               /* Array LigatureSet tables
                                          * ordered by preference */
   public:
@@ -28,7 +29,7 @@ struct LigatureSet
     return
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
+    | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
     | hb_any
     ;
   }
@@ -37,7 +38,7 @@ struct LigatureSet
   {
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
+    | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
     ;
   }
 
@@ -45,7 +46,7 @@ struct LigatureSet
   {
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
@@ -54,7 +55,7 @@ struct LigatureSet
     return
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
+    | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
     | hb_any
     ;
   }
@@ -65,7 +66,7 @@ struct LigatureSet
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
-      const Ligature &lig = this+ligature[i];
+      const auto &lig = this+ligature[i];
       if (lig.apply (c)) return_trace (true);
     }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubst.hh
index a029bf5e9f47ffda31ab55a31c0408a77f2af99b..63707972a812741ba8927c2ee86b6c54c2ecac49 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubst.hh
@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct LigatureSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  LigatureSubstFormat1  format1;
+  HBUINT16				format;         /* Format identifier */
+  LigatureSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  LigatureSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -24,10 +27,16 @@ struct LigatureSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should
+   * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t
+   * instead. */
   bool serialize (hb_serialize_context_t *c,
                   hb_sorted_array_t<const HBGlyphID16> first_glyphs,
                   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
@@ -49,6 +58,9 @@ struct LigatureSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
index 19dfe984694777b0ba03434640a3cd4cf6a5822e..32b642c38ad7ee3cd8a8997b0036638d805c00ce 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct LigatureSubstFormat1
+template <typename Types>
+struct LigatureSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<LigatureSet>
+  Array16Of<typename Types::template OffsetTo<LigatureSet<Types>>>
                 ligatureSet;            /* Array LigatureSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ligatureSet);
+  DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -33,7 +34,7 @@ struct LigatureSubstFormat1
     + hb_zip (this+coverage, ligatureSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
+    | hb_map ([this, glyphs] (const typename Types::template OffsetTo<LigatureSet<Types>> &_)
               { return (this+_).intersects (glyphs); })
     | hb_any
     ;
@@ -48,7 +49,7 @@ struct LigatureSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.closure (c); })
     ;
 
   }
@@ -62,7 +63,7 @@ struct LigatureSubstFormat1
     + hb_zip (this+coverage, ligatureSet)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
@@ -73,7 +74,7 @@ struct LigatureSubstFormat1
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
     if (likely (index == NOT_COVERED)) return false;
 
-    const LigatureSet &lig_set = this+ligatureSet[index];
+    const auto &lig_set = this+ligatureSet[index];
     return lig_set.would_apply (c);
   }
 
@@ -84,7 +85,7 @@ struct LigatureSubstFormat1
     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];
+    const auto &lig_set = this+ligatureSet[index];
     return_trace (lig_set.apply (c));
   }
 
@@ -128,7 +129,7 @@ struct LigatureSubstFormat1
     hb_set_t new_coverage;
     + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
     | hb_filter (glyphset, hb_first)
-    | hb_filter ([&] (const LigatureSet& _) {
+    | hb_filter ([&] (const LigatureSet<Types>& _) {
       return _.intersects (&glyphset);
     }, hb_second)
     | hb_map (hb_first)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubst.hh
index b2891755048854702822c5732cb931af82a35213..98f2f5fe7a3af941dc5be95bd0a855d5a6fbed66 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubst.hh
@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct MultipleSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MultipleSubstFormat1  format1;
+  HBUINT16				format;         /* Format identifier */
+  MultipleSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MultipleSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -25,10 +28,15 @@ struct MultipleSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+   * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
   bool serialize (hb_serialize_context_t *c,
                   hb_sorted_array_t<const HBGlyphID16> glyphs,
                   hb_array_t<const unsigned int> substitute_len_list,
@@ -43,6 +51,9 @@ struct MultipleSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
index 54c6dc847835e417ab57441ead549c800fed1c43..89a04ec3b126d14d16d6ce73d526b7432314b2d4 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct MultipleSubstFormat1
+template <typename Types>
+struct MultipleSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<Sequence>
+  Array16Of<typename Types::template OffsetTo<Sequence<Types>>>
                 sequence;               /* Array of Sequence tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, sequence);
+  DEFINE_SIZE_ARRAY (4 + Types::size, sequence);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -39,7 +40,7 @@ struct MultipleSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
+    | hb_apply ([c] (const Sequence<Types> &_) { _.closure (c); })
     ;
   }
 
@@ -51,7 +52,7 @@ struct MultipleSubstFormat1
     + hb_zip (this+coverage, sequence)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const Sequence<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
index 435d80fd3104306363481c99ae5d8f36a91b1a9f..48e208efb9c6694d2cc0ca5101fe504c0e6494c2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ReverseChainSingleSubst
 {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 7a79a9df25edf4186662ef549881740c24da6cd0..1d27df95ddafdee071cfd7a1eb4586be490f4b2b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -5,7 +5,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ReverseChainSingleSubstFormat1
 {
@@ -33,10 +33,10 @@ struct ReverseChainSingleSubstFormat1
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
@@ -45,7 +45,7 @@ struct ReverseChainSingleSubstFormat1
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
 
     unsigned int count;
 
@@ -69,8 +69,8 @@ struct ReverseChainSingleSubstFormat1
   {
     if (!intersects (c->glyphs)) return;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     + hb_zip (this+coverage, substitute)
     | hb_filter (c->parent_active_glyphs (), hb_first)
@@ -91,12 +91,12 @@ struct ReverseChainSingleSubstFormat1
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
 
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -115,8 +115,8 @@ struct ReverseChainSingleSubstFormat1
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
@@ -206,8 +206,8 @@ struct ReverseChainSingleSubstFormat1
     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);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     auto it =
     + hb_zip (this+coverage, substitute)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Sequence.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Sequence.hh
index ebd451e6ba31e8e09777f238b7326b5fdd9653ac..c5cd15bb23d3c9dd3aaf24d621a057e0a48a7d89 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Sequence.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/Sequence.hh
@@ -5,12 +5,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct Sequence
 {
   protected:
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 substitute;             /* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubst.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubst.hh
index 786428fe453e72df817d0d0a7c5ceb0fcfa7c58e..6942e6997f697437221d4a6e02327e0601948ad6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubst.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubst.hh
@@ -7,15 +7,19 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SingleSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  SingleSubstFormat1    format1;
-  SingleSubstFormat2    format2;
+  HBUINT16				format;         /* Format identifier */
+  SingleSubstFormat1_3<SmallTypes>	format1;
+  SingleSubstFormat2_4<SmallTypes>	format2;
+#ifndef HB_NO_BORING_EXPANSION
+  SingleSubstFormat1_3<MediumTypes>	format3;
+  SingleSubstFormat2_4<MediumTypes>	format4;
+#endif
   } u;
 
   public:
@@ -28,6 +32,10 @@ struct SingleSubst
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
@@ -45,11 +53,24 @@ struct SingleSubst
     if (glyphs)
     {
       format = 1;
+      hb_codepoint_t mask = 0xFFFFu;
+
+#ifndef HB_NO_BORING_EXPANSION
+       if (+ glyphs
+	   | hb_map_retains_sorting (hb_first)
+	   | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
+       {
+	 format += 2;
+	 mask = 0xFFFFFFu;
+       }
+#endif
+
       auto get_delta = [=] (hb_codepoint_pair_t _)
-                       { return (unsigned) (_.second - _.first) & 0xFFFF; };
+                       { return (unsigned) (_.second - _.first) & mask; };
       delta = get_delta (*glyphs);
-      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
+      if (!hb_all (++(+glyphs), delta, get_delta)) format += 1;
     }
+
     u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c,
@@ -57,6 +78,13 @@ struct SingleSubst
                                                | hb_map_retains_sorting (hb_first),
                                                delta));
     case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (u.format3.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
     default:return_trace (false);
     }
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index 3c6b2954cecd8a1be9c08f004d75b6d6ad63a47b..dd4459574175a87ceeed14427d7b845861d9cbcf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -5,20 +5,22 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct SingleSubstFormat1
+template <typename Types>
+struct SingleSubstFormat1_3
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  HBUINT16      deltaGlyphID;           /* Add to original GlyphID to get
+  typename Types::HBUINT
+                deltaGlyphID;           /* Add to original GlyphID to get
                                          * substitute GlyphID, modulo 0x10000 */
 
   public:
-  DEFINE_SIZE_STATIC (6);
+  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -26,6 +28,9 @@ struct SingleSubstFormat1
     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
+  hb_codepoint_t get_mask () const
+  { return (1 << (8 * Types::size)) - 1; }
+
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
@@ -34,14 +39,16 @@ struct SingleSubstFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned d = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
 
-    + hb_iter (this+coverage)
-    | hb_filter (c->parent_active_glyphs ())
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    hb_set_t intersection;
+    (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
+
+    + hb_iter (intersection)
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     | hb_sink (c->output)
     ;
-
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -49,9 +56,11 @@ struct SingleSubstFormat1
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned d = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
     + hb_iter (this+coverage)
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     | hb_sink (c->output)
     ;
   }
@@ -68,9 +77,11 @@ struct SingleSubstFormat1
     unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    /* According to the Adobe Annotated OpenType Suite, result is always
-     * limited to 16bit. */
-    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    glyph_id = (glyph_id + d) & mask;
+
     c->replace_glyph (glyph_id);
 
     return_trace (true);
@@ -95,14 +106,17 @@ struct SingleSubstFormat1
     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
-    hb_codepoint_t delta = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
 
     auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
+    + hb_iter (intersection)
+    | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
                                 return hb_codepoint_pair_t (g,
-                                                            (g + delta) & 0xFFFF); })
+                                                            (g + d) & mask); })
     | hb_filter (glyphset, hb_second)
     | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
                               { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index df75bb52bbc24a29565274fc87e97162a7c10b76..386419a2a5bb0e39da388f7739d8941783fd20c0 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -5,21 +5,22 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct SingleSubstFormat2
+template <typename Types>
+struct SingleSubstFormat2_4
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 substitute;             /* Array of substitute
                                          * GlyphIDs--ordered by Coverage Index */
 
   public:
-  DEFINE_SIZE_ARRAY (6, substitute);
+  DEFINE_SIZE_ARRAY (4 + Types::size, substitute);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -103,7 +104,7 @@ struct SingleSubstFormat2
     + 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
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const typename Types::HBGlyphID &> p) -> hb_codepoint_pair_t
                               { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
     ;
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookup.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookup.hh
index 8fb3b550976a20d5c615e18de86537d6a407b6e3..320685b868b3a2ff874be565e52ef835bfb5919c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookup.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookup.hh
@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SubstLookup : Lookup
 {
@@ -25,7 +25,7 @@ struct SubstLookup : Lookup
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubTable::Extension))
-      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
+      return get_subtable (0).u.extension.is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
@@ -98,10 +98,15 @@ struct SubstLookup : Lookup
       return dispatch (c);
   }
 
+  template<typename Glyphs, typename Substitutes,
+	   hb_requires (hb_is_sorted_source_of (Glyphs,
+						const hb_codepoint_t) &&
+			hb_is_source_of (Substitutes,
+					 const hb_codepoint_t))>
   bool serialize_single (hb_serialize_context_t *c,
                          uint32_t lookup_props,
-                         hb_sorted_array_t<const HBGlyphID16> glyphs,
-                         hb_array_t<const HBGlyphID16> substitutes)
+                         Glyphs glyphs,
+                         Substitutes substitutes)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookupSubTable.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookupSubTable.hh
index 53e963e2a2918a8754a0cdc14bfe0ffe3bc9e5f9..a525fba039971fad10378cf13441d217dcbb053f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookupSubTable.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GSUB/SubstLookupSubTable.hh
@@ -13,7 +13,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SubstLookupSubTable
 {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/CompositeGlyph.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/CompositeGlyph.hh
index c145beaa49adb53d3f1167bdd399e5119b061845..abe4c8330c0a12bd5a308e7ebc1197c67fd64942 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/CompositeGlyph.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/CompositeGlyph.hh
@@ -25,13 +25,16 @@ struct CompositeGlyphRecord
     USE_MY_METRICS		= 0x0200,
     OVERLAP_COMPOUND		= 0x0400,
     SCALED_COMPONENT_OFFSET	= 0x0800,
-    UNSCALED_COMPONENT_OFFSET	= 0x1000
+    UNSCALED_COMPONENT_OFFSET	= 0x1000,
+    GID_IS_24BIT		= 0x2000
   };
 
   public:
   unsigned int get_size () const
   {
     unsigned int size = min_size;
+    /* glyphIndex is 24bit instead of 16bit */
+    if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
     /* arg1 and 2 are int16 */
     if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
     /* arg1 and 2 are int8 */
@@ -60,7 +63,11 @@ struct CompositeGlyphRecord
   bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
   void get_anchor_points (unsigned int &point1, unsigned int &point2) const
   {
-    const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
+    const auto *p = &StructAfter<const HBUINT8> (flags);
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+      p += HBGlyphID16::static_size;
     if (flags & ARG_1_AND_2_ARE_WORDS)
     {
       point1 = ((const HBUINT16 *) p)[0];
@@ -101,8 +108,12 @@ struct CompositeGlyphRecord
     matrix[0] = matrix[3] = 1.f;
     matrix[1] = matrix[2] = 0.f;
 
+    const auto *p = &StructAfter<const HBINT8> (flags);
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+      p += HBGlyphID16::static_size;
     int tx, ty;
-    const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
     if (flags & ARG_1_AND_2_ARE_WORDS)
     {
       tx = *(const HBINT16 *) p;
@@ -145,8 +156,25 @@ struct CompositeGlyphRecord
   }
 
   public:
+  hb_codepoint_t get_gid () const
+  {
+    if (flags & GID_IS_24BIT)
+      return StructAfter<const HBGlyphID24> (flags);
+    else
+      return StructAfter<const HBGlyphID16> (flags);
+  }
+  void set_gid (hb_codepoint_t gid)
+  {
+    if (flags & GID_IS_24BIT)
+      StructAfter<HBGlyphID24> (flags) = gid;
+    else
+      /* TODO assert? */
+      StructAfter<HBGlyphID16> (flags) = gid;
+  }
+
+  protected:
   HBUINT16	flags;
-  HBGlyphID16	glyphIndex;
+  HBUINT24	pad;
   public:
   DEFINE_SIZE_MIN (4);
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh
index 2199d2c48b8c29adea2ba1a0ebe550707b076bf9..3efe538f370391f9ea446f45631db5ca63981bbf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh
@@ -105,19 +105,21 @@ struct Glyph
     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);
     {
-      int h_delta = (int) header->xMin -
-		    glyf_accelerator.hmtx->get_side_bearing (gid);
+      int lsb = 0;
+      int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+		    (int) header->xMin - lsb : 0;
+      int tsb = 0;
       int v_orig  = (int) header->yMax +
 #ifndef HB_NO_VERTICAL
-		    glyf_accelerator.vmtx->get_side_bearing (gid)
+		    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
 #else
 		    0
 #endif
 		    ;
-      unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
+      unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
       unsigned v_adv =
 #ifndef HB_NO_VERTICAL
-		       glyf_accelerator.vmtx->get_advance (gid)
+		       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
 #else
 		       - font->face->get_upem ()
 #endif
@@ -144,7 +146,7 @@ struct Glyph
       for (auto &item : get_composite_iterator ())
       {
         comp_points.reset ();
-	if (unlikely (!glyf_accelerator.glyph_for_gid (item.glyphIndex)
+	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 				       .get_points (font, glyf_accelerator, comp_points,
 						    phantom_only, depth + 1)))
 	  return false;
@@ -198,11 +200,11 @@ struct Glyph
     return !all_points.in_error ();
   }
 
-  bool get_extents (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
-		    hb_glyph_extents_t *extents) const
+  bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
+				       hb_glyph_extents_t *extents) const
   {
     if (type == EMPTY) return true; /* Empty glyph; zero extents. */
-    return header->get_extents (font, glyf_accelerator, gid, extents);
+    return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
   }
 
   hb_bytes_t get_bytes () const { return bytes; }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/GlyphHeader.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/GlyphHeader.hh
index 792bd5478f59e2bda40f4c72751f30993780e443..e4a9168b79f0c703c4ae45c3f2db0887ca8bbbc9 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/GlyphHeader.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/GlyphHeader.hh
@@ -14,12 +14,14 @@ struct GlyphHeader
   bool has_data () const { return numberOfContours; }
 
   template <typename accelerator_t>
-  bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
-		    hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+  bool get_extents_without_var_scaled (hb_font_t *font, const accelerator_t &glyf_accelerator,
+				       hb_codepoint_t gid, hb_glyph_extents_t *extents) const
   {
     /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
     /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
-    extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
+    int lsb = hb_min (xMin, xMax);
+    (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+    extents->x_bearing = font->em_scale_x (lsb);
     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));
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SubsetGlyph.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SubsetGlyph.hh
index ebe437204750995dd48d8745acbf182b2d1d06e5..7ae8fe307807351684d86120f77fcc500f8802a3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SubsetGlyph.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SubsetGlyph.hh
@@ -42,8 +42,8 @@ struct SubsetGlyph
     for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
     {
       hb_codepoint_t new_gid;
-      if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid))
-	const_cast<CompositeGlyphRecord &> (_).glyphIndex = new_gid;
+      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
+	const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
     }
 
     if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
index f74513cb968bcc4e34c0b73eca54333345163bb9..bcaf44fc1e7e4733591a41b3dc99816b843c3ace 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/glyf.hh
@@ -194,6 +194,7 @@ struct glyf_accelerator_t
     hb_font_t *font;
     hb_glyph_extents_t *extents;
     contour_point_t *phantoms;
+    bool scaled;
 
     struct contour_bounds_t
     {
@@ -209,7 +210,7 @@ struct glyf_accelerator_t
 
       bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
 
-      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
+      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled)
       {
 	if (unlikely (empty ()))
 	{
@@ -219,26 +220,37 @@ struct glyf_accelerator_t
 	  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;
+	if (scaled)
+	{
+	  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;
+	}
+	else
+	{
+	  extents->x_bearing = roundf (min_x);
+	  extents->width = roundf (max_x - extents->x_bearing);
+	  extents->y_bearing = roundf (max_y);
+	  extents->height = roundf (min_y - extents->y_bearing);
+	}
       }
 
       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_)
+    points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_)
     {
       font = font_;
       extents = extents_;
       phantoms = phantoms_;
+      scaled = scaled_;
       if (extents) bounds = contour_bounds_t ();
     }
 
     void consume_point (const contour_point_t &point) { bounds.add (point); }
-    void points_end () { bounds.get_extents (font, extents); }
+    void points_end () { bounds.get_extents (font, extents, scaled); }
 
     bool is_consuming_contour_points () { return extents; }
     contour_point_t *get_phantoms_sink () { return phantoms; }
@@ -246,22 +258,22 @@ struct glyf_accelerator_t
 
   public:
   unsigned
-  get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+  get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
   {
     if (unlikely (gid >= num_glyphs)) return 0;
 
     bool success = false;
 
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (likely (font->num_coords == gvar->get_axis_count ()))
-      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
+    if (font->num_coords)
+      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
 
     if (unlikely (!success))
       return
 #ifndef HB_NO_VERTICAL
-	is_vertical ? vmtx->get_advance (gid) :
+	is_vertical ? vmtx->get_advance_without_var_unscaled (gid) :
 #endif
-	hmtx->get_advance (gid);
+	hmtx->get_advance_without_var_unscaled (gid);
 
     float result = is_vertical
 		 ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
@@ -269,23 +281,20 @@ struct glyf_accelerator_t
     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
+  bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const
   {
-    if (unlikely (gid >= num_glyphs)) return 0;
+    if (unlikely (gid >= num_glyphs)) return false;
 
     hb_glyph_extents_t extents;
 
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
-      return
-#ifndef HB_NO_VERTICAL
-	is_vertical ? vmtx->get_side_bearing (gid) :
-#endif
-	hmtx->get_side_bearing (gid);
+    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
+      return false;
 
-    return is_vertical
-	 ? ceilf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
-	 : floorf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+    *lsb = is_vertical
+	 ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
+	 : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+    return true;
   }
 #endif
 
@@ -296,9 +305,9 @@ struct glyf_accelerator_t
 
 #ifndef HB_NO_VAR
     if (font->num_coords)
-      return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
+      return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
 #endif
-    return glyph_for_gid (gid).get_extents (font, *this, extents);
+    return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
   }
 
   const glyf_impl::Glyph
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/gen-def.py b/source/libs/harfbuzz/harfbuzz-src/src/gen-def.py
index 205ed7ebdb4500bed26f7b535cdc9db9f62931d5..47b7b479df47cabeabdca9ad16bd4c5c230a1a3f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/gen-def.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/gen-def.py
@@ -19,7 +19,9 @@ symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re
 if '--experimental-api' not in sys.argv:
 	# Move these to harfbuzz-sections.txt when got stable
 	experimental_symbols = \
-"""hb_subset_repack_or_fail""".splitlines ()
+"""hb_subset_repack_or_fail
+hb_subset_input_pin_axis_location
+hb_subset_input_pin_axis_to_default""".splitlines ()
 	symbols = [x for x in symbols if x not in experimental_symbols]
 symbols = "\n".join (symbols)
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/gen-harfbuzzcc.py b/source/libs/harfbuzz/harfbuzz-src/src/gen-harfbuzzcc.py
index 6801281a68c79539cdbcf3f0c646a46d4676caa4..1a492d47a69dfdf268cda9d2722da5b17ae3f389 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/gen-harfbuzzcc.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/gen-harfbuzzcc.py
@@ -9,7 +9,9 @@ if len (sys.argv) < 3:
 
 OUTPUT = sys.argv[1]
 CURRENT_SOURCE_DIR = sys.argv[2]
-sources = sys.argv[3:]
+
+# make sure input files are unique
+sources = sorted(set(sys.argv[3:]))
 
 with open (OUTPUT, "wb") as f:
 	f.write ("".join ('#include "{}"\n'.format (os.path.basename (x)) for x in sources if x.endswith (".cc")).encode ())
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/gen-use-table.py b/source/libs/harfbuzz/harfbuzz-src/src/gen-use-table.py
index 5daab7063ab50a0af798f070c73347aaa6654002..5e6a3b02f3246ce96d051c3fed966d6c3fe913ab 100755
--- a/source/libs/harfbuzz/harfbuzz-src/src/gen-use-table.py
+++ b/source/libs/harfbuzz/harfbuzz-src/src/gen-use-table.py
@@ -478,64 +478,15 @@ for k,v in sorted(use_positions.items()):
 		print ("#define %s	USE(%s)" % (tag, tag))
 print ('#pragma GCC diagnostic pop')
 print ("")
-print ("static const uint8_t use_table[] = {")
-for u in uu:
-	if u <= last:
-		continue
-	if use_data[u][0] == 'O':
-		continue
-	block = use_data[u][1]
-
-	start = u//8*8
-	end = start+1
-	while end in uu and block == use_data[end][1]:
-		end += 1
-	end = (end-1)//8*8 + 7
-
-	if start != last + 1:
-		if start - last <= 1+16*3:
-			print_block (None, last+1, start-1, use_data)
-		else:
-			if last >= 0:
-				ends.append (last + 1)
-				offset += ends[-1] - starts[-1]
-			print ()
-			print ()
-			print ("#define use_offset_0x%04xu %d" % (start, offset))
-			starts.append (start)
 
-	print_block (block, start, end, use_data)
-	last = end
-ends.append (last + 1)
-offset += ends[-1] - starts[-1]
-print ()
-print ()
-occupancy = used * 100. / total
-page_bits = 12
-print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
-print ()
-print ("static inline uint8_t")
-print ("hb_use_get_category (hb_glyph_info_t info)")
-print ("{")
-print ("  hb_codepoint_t u = info.codepoint;")
-print ("  switch (u >> %d)" % page_bits)
-print ("  {")
-pages = set([u>>page_bits for u in starts+ends])
-for p in sorted(pages):
-	print ("    case 0x%0Xu:" % p)
-	for (start,end) in zip (starts, ends):
-		if p not in [start>>page_bits, end>>page_bits]: continue
-		offset = "use_offset_0x%04xu" % start
-		print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
-	print ("      break;")
-	print ("")
-print ("    default:")
-print ("      break;")
-print ("  }")
-print ("  if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED)")
-print ("    return WJ;")
-print ("  return O;")
-print ("}")
+
+import packTab
+data = {u:v[0] for u,v in use_data.items()}
+code = packTab.Code('hb_use')
+sol = packTab.pack_table(data, compression=5, default='O')
+sol.genCode(code, f'get_category')
+code.print_c(linkage='static inline')
+
 print ()
 for k in sorted(use_mapping.keys()):
 	if k in use_positions and use_positions[k]: continue
@@ -549,7 +500,3 @@ print ()
 print ()
 print ("#endif /* HB_OT_SHAPER_USE_TABLE_HH */")
 print ("/* == End of generated table == */")
-
-# Maintain at least 50% occupancy in the table */
-if occupancy < 50:
-	raise Exception ("Table too sparse, please investigate: ", occupancy)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/graph/graph.hh b/source/libs/harfbuzz/harfbuzz-src/src/graph/graph.hh
index 52ca9dd142e238b25271241afdd63f4570fb7497..49638f34a72259cf89d520b49c3536686cebe634 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/graph/graph.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/graph/graph.hh
@@ -265,28 +265,64 @@ struct graph_t
   }
 
   /*
-   * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
+   * Finds the set of nodes (placed into roots) that should be assigned unique spaces.
+   * More specifically this looks for the top most 24 bit or 32 bit links in the graph.
+   * Some special casing is done that is specific to the layout of GSUB/GPOS tables.
    */
-  bool assign_32bit_spaces ()
+  void find_space_roots (hb_set_t& visited, hb_set_t& roots)
   {
-    unsigned root_index = root_idx ();
-    hb_set_t visited;
-    hb_set_t roots;
-    for (unsigned i = 0; i <= root_index; i++)
+    int root_index = (int) root_idx ();
+    for (int i = root_index; i >= 0; i--)
     {
+      if (visited.has (i)) continue;
+
       // Only real links can form 32 bit spaces
       for (auto& l : vertices_[i].obj.real_links)
       {
-        if (l.width == 4 && !l.is_signed)
+        if (l.is_signed || l.width < 3)
+          continue;
+
+        if (i == root_index && l.width == 3)
+          // Ignore 24bit links from the root node, this skips past the single 24bit
+          // pointer to the lookup list.
+          continue;
+
+        if (l.width == 3)
         {
-          roots.add (l.objidx);
-          find_subgraph (l.objidx, visited);
+          // A 24bit offset forms a root, unless there is 32bit offsets somewhere
+          // in it's subgraph, then those become the roots instead. This is to make sure
+          // that extension subtables beneath a 24bit lookup become the spaces instead
+          // of the offset to the lookup.
+          hb_set_t sub_roots;
+          find_32bit_roots (l.objidx, sub_roots);
+          if (sub_roots) {
+            for (unsigned sub_root_idx : sub_roots) {
+              roots.add (sub_root_idx);
+              find_subgraph (sub_root_idx, visited);
+            }
+            continue;
+          }
         }
+
+        roots.add (l.objidx);
+        find_subgraph (l.objidx, visited);
       }
     }
+  }
 
-    // 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.
+  /*
+   * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
+   * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
+   * (including with 24bit offsets) table.
+   */
+  bool assign_spaces ()
+  {
+    hb_set_t visited;
+    hb_set_t roots;
+    find_space_roots (visited, roots);
+
+    // Mark everything not in the subgraphs of the roots as visited. This prevents
+    // subgraphs from being connected via nodes not in those subgraphs.
     visited.invert ();
 
     if (!roots) return false;
@@ -422,6 +458,22 @@ struct graph_t
       find_subgraph (link.objidx, subgraph);
   }
 
+  /*
+   * Finds the topmost children of 32bit offsets in the subgraph starting
+   * at node_idx. Found indices are placed into 'found'.
+   */
+  void find_32bit_roots (unsigned node_idx, hb_set_t& found)
+  {
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
+    {
+      if (!link.is_signed && link.width == 4) {
+        found.add (link.objidx);
+        continue;
+      }
+      find_32bit_roots (link.objidx, found);
+    }
+  }
+
   /*
    * 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
@@ -622,7 +674,7 @@ struct graph_t
  private:
 
   /*
-   * Returns the numbers of incoming edges that are 32bits wide.
+   * Returns the numbers of incoming edges that are 24 or 32 bits wide.
    */
   unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
   {
@@ -636,7 +688,9 @@ struct graph_t
       // Only real links can be wide
       for (const auto& l : vertices_[p].obj.real_links)
       {
-        if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
+        if (l.objidx == node_idx
+            && (l.width == 3 || l.width == 4)
+            && !l.is_signed)
         {
           count++;
           parents.add (p);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc b/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
index 05a864ae11f93e5531e0c914327a6638e2685a04..fe4e21db07ff41a9bcad8f6286a00b995662ee3d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/harfbuzz.cc
@@ -5,10 +5,16 @@
 #include "hb-buffer-verify.cc"
 #include "hb-buffer.cc"
 #include "hb-common.cc"
+#include "hb-coretext.cc"
+#include "hb-directwrite.cc"
 #include "hb-draw.cc"
 #include "hb-face.cc"
 #include "hb-fallback-shape.cc"
 #include "hb-font.cc"
+#include "hb-ft.cc"
+#include "hb-gdi.cc"
+#include "hb-glib.cc"
+#include "hb-graphite2.cc"
 #include "hb-map.cc"
 #include "hb-number.cc"
 #include "hb-ot-cff1-table.cc"
@@ -22,6 +28,9 @@
 #include "hb-ot-meta.cc"
 #include "hb-ot-metrics.cc"
 #include "hb-ot-name.cc"
+#include "hb-ot-shape-fallback.cc"
+#include "hb-ot-shape-normalize.cc"
+#include "hb-ot-shape.cc"
 #include "hb-ot-shaper-arabic.cc"
 #include "hb-ot-shaper-default.cc"
 #include "hb-ot-shaper-hangul.cc"
@@ -34,9 +43,6 @@
 #include "hb-ot-shaper-thai.cc"
 #include "hb-ot-shaper-use.cc"
 #include "hb-ot-shaper-vowel-constraints.cc"
-#include "hb-ot-shape-fallback.cc"
-#include "hb-ot-shape-normalize.cc"
-#include "hb-ot-shape.cc"
 #include "hb-ot-tag.cc"
 #include "hb-ot-var.cc"
 #include "hb-set.cc"
@@ -47,10 +53,4 @@
 #include "hb-style.cc"
 #include "hb-ucd.cc"
 #include "hb-unicode.cc"
-#include "hb-glib.cc"
-#include "hb-ft.cc"
-#include "hb-graphite2.cc"
 #include "hb-uniscribe.cc"
-#include "hb-gdi.cc"
-#include "hb-directwrite.cc"
-#include "hb-coretext.cc"
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-bsln-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-bsln-table.hh
index b52844e75d69b621d9a87a875a71e27fe5a0dc72..bf12d2e699f2632efd1a4aa45ca71f95995b2bfd 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-bsln-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-bsln-table.hh
@@ -42,7 +42,7 @@ struct BaselineTableFormat0Part
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -78,7 +78,7 @@ struct BaselineTableFormat2Part
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
index 1db0f1df9286128fe6b2d816b923ad7ee73a8d01..6cbed826921dd60ebadb34d7448d7ba6d401e921 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-common.hh
@@ -415,18 +415,7 @@ struct Lookup
   public:
   DEFINE_SIZE_UNION (2, format);
 };
-/* Lookup 0 has unbounded size (dependant on num_glyphs).  So we need to defined
- * special NULL objects for Lookup<> objects, but since it's template our macros
- * don't work.  So we have to hand-code them here.  UGLY. */
-} /* Close namespace. */
-/* Ugly hand-coded null objects for template Lookup<> :(. */
-extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
-template <typename T>
-struct Null<AAT::Lookup<T>> {
-  static AAT::Lookup<T> const & get_null ()
-  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
-};
-namespace AAT {
+DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
 
 enum { DELETED_GLYPH = 0xFFFF };
 
@@ -681,6 +670,13 @@ struct ObsoleteTypes
 				     const void *base,
 				     const T *array)
   {
+    /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
+    /* If offset is less than base, return an offset that would
+     * result in an address half a 32bit address-space away,
+     * to make sure sanitize fails even on 32bit builds. */
+    if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
+      return INT_MAX / T::static_size;
+
     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
   }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-feat-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-feat-table.hh
index 573f0cf9f6be2ce3168f2ff960267c29f6d99cb0..815a1fd2aa975d9dedde1f7804b6e4aef01c8db0 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-feat-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-feat-table.hh
@@ -62,7 +62,7 @@ struct SettingName
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-just-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-just-table.hh
index 0bf9bd29126232709d53a57455a6ab60cfced31c..57c105967de5167c5863da026f675aa6cea7d790 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-just-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-just-table.hh
@@ -48,7 +48,7 @@ struct ActionSubrecordHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   HBUINT16	actionClass;	/* The JustClass value associated with this
@@ -65,7 +65,7 @@ struct DecompositionAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   ActionSubrecordHeader
@@ -112,7 +112,7 @@ struct ConditionalAddGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -137,7 +137,7 @@ struct DuctileGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -163,7 +163,7 @@ struct RepeatedAddGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -294,7 +294,7 @@ struct WidthDeltaPair
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
index 6a24c90c3126ea1f299b9189497b61031e0e894b..995492cd5a703b5f41c182f1fded5efbebbd50d7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
@@ -751,7 +751,7 @@ struct KerxSubTableHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
index 3d053cb13e59247657d8f38b7aaa0487e9173016..aa4ad4cf3c196a08560976b82ffcb30e935f07f6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
@@ -980,6 +980,15 @@ struct Chain
 	  setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
 	  goto retry;
 	}
+#ifndef HB_NO_AAT
+	else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
+		 /* TODO: Rudimentary language matching. */
+		 hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
+	{
+	  flags &= feature.disableFlags;
+	  flags |= feature.enableFlags;
+	}
+#endif
       }
     }
     return flags;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-opbd-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-opbd-table.hh
index b1a1512821d8cb355a1b48c2baf99650a2d1e1ca..51b650fc33c67ef35746d457d078a6d6ca0143e7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-opbd-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-opbd-table.hh
@@ -42,7 +42,7 @@ struct OpticalBounds
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   FWORD		leftSide;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
index caff204d67d38dee1e6dc788131bdda8b3b4ba70..e06d286ff09e7e8bf0416daf9f54e86421ddf714 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout.cc
@@ -229,7 +229,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
  *
  * <note>Note: does not examine the `GSUB` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -300,7 +300,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
  *
  * <note>Note: does not examine the `GPOS` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -333,7 +333,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
  * Tests whether the specified face includes any tracking information
  * in the `trak` table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.hh
index 5a0fa7054453c53aeb05710b25d73e0b6ba8e2dd..c914f58d707ad6f0621f7a32204f90b07fee84bb 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-map.hh
@@ -52,8 +52,9 @@ struct hb_aat_map_builder_t
   public:
 
   HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
-				    const hb_segment_properties_t *props_ HB_UNUSED) :
-				      face (face_) {}
+				    const hb_segment_properties_t props_) :
+				      face (face_),
+				      props (props_) {}
 
   HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
 
@@ -87,6 +88,7 @@ struct hb_aat_map_builder_t
 
   public:
   hb_face_t *face;
+  hb_segment_properties_t props;
 
   public:
   hb_sorted_vector_t<feature_info_t> features;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh
index f1633d886a741a061a596ac103c95d8ebe3c099d..cc37c073da120e6f861a7bbafdec7e7be9ae8836 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh
@@ -109,15 +109,16 @@ struct BEInt<Type, 2>
   struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
   constexpr operator Type () const
   {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+    ((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);
+    return __builtin_bswap16 (((packed_uint16_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
+    return ((packed_uint16_t *) v)->v;
 #endif
 #else
     return (v[0] <<  8)
@@ -153,15 +154,16 @@ struct BEInt<Type, 4>
 
   struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
   constexpr operator Type () const {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+    ((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_bswap32 (((packed_uint32_t *) this)->v);
+    return __builtin_bswap32 (((packed_uint32_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint32_t *) this)->v;
+    return ((packed_uint32_t *) v)->v;
 #endif
 #else
     return (v[0] << 24)
@@ -525,7 +527,6 @@ struct hb_pair_t
   T1 first;
   T2 second;
 };
-#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
 template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
 hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
 
@@ -551,14 +552,14 @@ struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a <= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a <= b ? a : b)
 }
 HB_FUNCOBJ (hb_min);
 struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a >= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a >= b ? a : b)
 }
 HB_FUNCOBJ (hb_max);
 struct
@@ -972,7 +973,7 @@ void hb_qsort(void *base, size_t nel, size_t width,
               [void *arg]);
 */
 
-#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp))
 
 /* swap a and b */
 /* a and b must not be equal! */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-array.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-array.hh
index 5baeb6f7fef153ef73ccc2d287b9d3af7de788f2..826a90181962381be2e064acf238418d372b1175 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-array.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-array.hh
@@ -100,10 +100,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
    * it's best if we can just compare arrayZ, though comparing contents is still fast,
    * but also would require that Type has operator==.  As such, we optimize this operator
-   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
-   * assume we're only compared to .end(). */
+   * for range-based for loop and just compare arrayZ and length. */
   bool operator != (const hb_array_t& o) const
-  { return arrayZ != o.arrayZ; }
+  { return this->arrayZ != o.arrayZ || this->length != o.length; }
 
   /* Extra operators.
    */
@@ -220,11 +219,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
     if (end < start + 2)
       return;
 
-    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
-      Type temp = arrayZ[rhs];
-      arrayZ[rhs] = arrayZ[lhs];
-      arrayZ[lhs] = temp;
-    }
+    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
+      hb_swap (arrayZ[rhs], arrayZ[lhs]);
   }
 
   hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
@@ -328,6 +324,8 @@ struct hb_sorted_array_t :
   { hb_array_t<Type> (*this) = o; return *this; }
 
   /* Iterator implementation. */
+
+  /* See comment in hb_array_of::operator != */
   bool operator != (const hb_sorted_array_t& o) const
   { return this->arrayZ != o.arrayZ || this->length != o.length; }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
index e640d1b5868b5a9b72f3f9bbe0e090bf69f95246..d6dfb0f57a17505ba7b35d9eb36081c467281d65 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-atomic.hh
@@ -111,6 +111,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 
 
+#ifndef _hb_compiler_memory_r_barrier
+/* This we always use std::atomic for; and should never be disabled...
+ * except that MSVC gives me an internal compiler error on it. */
+#if !defined(_MSC_VER)
+#include <atomic>
+#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
+#else
+#define _hb_compiler_memory_r_barrier() do {} while (0)
+#endif
+#endif
+
+
+
 #ifndef _hb_memory_r_barrier
 #define _hb_memory_r_barrier()			_hb_memory_barrier ()
 #endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh
index cbe918ee401a8b27c4d98cb20912cb75fe98f70f..95ae1b7bf98618ff78fda1cbfba37d8cdee44bab 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh
@@ -55,7 +55,7 @@ struct hb_bit_page_t
 
   void add (hb_codepoint_t g) { elt (g) |= mask (g); }
   void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-  void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+  void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
   bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
   void add_range (hb_codepoint_t a, hb_codepoint_t b)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
index 438fb66a2cdb41fedd7114325c22dbdc4feee345..4765af67ce96dc7291f47608e1e8d89fc675b230 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
@@ -465,12 +465,10 @@ struct hb_bit_set_t
   }
   public:
 
-  template <typename Op>
-  void process (const Op& op, const hb_bit_set_t &other)
+  void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
+		 bool passthru_left, bool passthru_right,
+		 const hb_bit_set_t &other)
   {
-    const bool passthru_left = op (1, 0);
-    const bool passthru_right = op (0, 1);
-
     if (unlikely (!successful)) return;
 
     dirty ();
@@ -590,6 +588,15 @@ struct hb_bit_set_t
     assert (!count);
     resize (newCount);
   }
+  template <typename Op>
+  static hb_bit_page_t::vector_t
+  op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
+  { return Op{} (a, b); }
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_t &other)
+  {
+    process_ (op_<Op>, op (1, 0), op (0, 1), other);
+  }
 
   void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
   void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.cc
index b561a9374e37bb1a0c5ea09b432d0ca6c4ce02f3..47062eab9a7266a358e3fded9b2b87bd0ebf7c44 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.cc
@@ -99,7 +99,7 @@ hb_blob_create (const char        *data,
  * is zero. This is in contrast to hb_blob_create(), which returns the singleton
  * empty blob (as returned by hb_blob_get_empty()) if @length is zero.
  *
- * Return value: New blob, or %NULL if failed.  Destroy with hb_blob_destroy().
+ * Return value: New blob, or `NULL` if failed.  Destroy with hb_blob_destroy().
  *
  * Since: 2.8.2
  **/
@@ -263,8 +263,6 @@ hb_blob_destroy (hb_blob_t *blob)
 {
   if (!hb_object_destroy (blob)) return;
 
-  blob->fini_shallow ();
-
   hb_free (blob);
 }
 
@@ -278,7 +276,7 @@ hb_blob_destroy (hb_blob_t *blob)
  *
  * Attaches a user-data key/data pair to the specified blob.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -335,7 +333,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
  *
  * Tests whether a blob is immutable.
  *
- * Return value: %true if @blob is immutable, %false otherwise
+ * Return value: `true` if @blob is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -394,7 +392,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
  * fails.
  *
  * Returns: (transfer none) (array length=length): Writable blob data,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 0.9.2
  **/
@@ -620,7 +618,7 @@ hb_blob_create_from_file (const char *file_name)
  * specified binary font file.
  *
  * Returns: An #hb_blob_t pointer with the content of the file,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 2.8.2
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.hh
index a3683a681e78bfd4b389e78732a95e841a11e62a..b1b3b94d3ddc6903faaf4917887abf4b6c853849 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-blob.hh
@@ -38,7 +38,7 @@
 
 struct hb_blob_t
 {
-  void fini_shallow () { destroy_user_data (); }
+  ~hb_blob_t () { destroy_user_data (); }
 
   void destroy_user_data ()
   {
@@ -61,12 +61,12 @@ struct hb_blob_t
   public:
   hb_object_header_t header;
 
-  const char *data;
-  unsigned int length;
-  hb_memory_mode_t mode;
+  const char *data = nullptr;
+  unsigned int length = 0;
+  hb_memory_mode_t mode = (hb_memory_mode_t) 0;
 
-  void *user_data;
-  hb_destroy_func_t destroy;
+  void *user_data = nullptr;
+  hb_destroy_func_t destroy = nullptr;
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
index e80cfea6e7ac3d7dea4054187301b4c8bbde3a5f..44c802a00c2f09d635eee957ea8cb13c49e18e0d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.hh
@@ -32,15 +32,16 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-json.hh"
+#line 33 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
 	0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
 	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
 	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
 	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
-	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 
+	9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 
+	34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, 
+	9u, 123u, 0u, 0u, 0
 };
 
 static const char _deserialize_json_key_spans[] = {
@@ -48,9 +49,10 @@ static const char _deserialize_json_key_spans[] = {
 	10, 117, 117, 117, 1, 50, 49, 10, 
 	117, 117, 1, 1, 50, 49, 117, 117, 
 	2, 1, 50, 49, 10, 117, 117, 1, 
-	50, 49, 10, 117, 117, 1, 50, 49, 
-	59, 117, 59, 117, 117, 1, 50, 49, 
-	117, 85, 115, 0
+	50, 49, 10, 117, 117, 1, 1, 50, 
+	49, 117, 117, 1, 50, 49, 59, 117, 
+	59, 117, 117, 1, 50, 49, 117, 85, 
+	115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
@@ -58,9 +60,10 @@ static const short _deserialize_json_index_offsets[] = {
 	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
+	1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, 
+	2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, 
+	2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, 
+	3255, 3371
 };
 
 static const char _deserialize_json_indicies[] = {
@@ -82,28 +85,28 @@ static const char _deserialize_json_indicies[] = {
 	3, 3, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 3, 1, 4, 1, 
-	5, 1, 6, 7, 1, 1, 8, 1, 
+	5, 1, 6, 7, 1, 8, 9, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 9, 1, 10, 11, 
-	1, 12, 1, 12, 12, 12, 12, 12, 
+	1, 1, 1, 1, 10, 1, 11, 12, 
+	1, 13, 1, 13, 13, 13, 13, 13, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 12, 1, 1, 1, 1, 1, 
+	1, 1, 13, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 13, 1, 13, 13, 
-	13, 13, 13, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 14, 1, 14, 14, 
+	14, 14, 14, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 13, 1, 1, 
+	1, 1, 1, 1, 1, 14, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 14, 1, 1, 15, 16, 16, 
-	16, 16, 16, 16, 16, 16, 16, 1, 
-	17, 18, 18, 18, 18, 18, 18, 18, 
-	18, 18, 1, 19, 19, 19, 19, 19, 
+	1, 1, 15, 1, 1, 16, 17, 17, 
+	17, 17, 17, 17, 17, 17, 17, 1, 
+	18, 19, 19, 19, 19, 19, 19, 19, 
+	19, 19, 1, 20, 20, 20, 20, 20, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 19, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 20, 1, 
+	1, 1, 20, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 21, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -113,11 +116,11 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 21, 
-	1, 22, 22, 22, 22, 22, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 22, 
+	1, 23, 23, 23, 23, 23, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	22, 1, 1, 1, 1, 1, 1, 1, 
+	23, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -128,41 +131,58 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 23, 1, 19, 
-	19, 19, 19, 19, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 24, 1, 20, 
+	20, 20, 20, 20, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 20, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 21, 1, 1, 1, 19, 19, 
+	19, 19, 19, 19, 19, 19, 19, 19, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 25, 1, 25, 
+	25, 25, 25, 25, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 25, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 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, 18, 18, 
-	18, 18, 18, 18, 18, 18, 18, 18, 
+	26, 1, 26, 26, 26, 26, 26, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 26, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 27, 1, 
+	1, 28, 29, 29, 29, 29, 29, 29, 
+	29, 29, 29, 1, 30, 31, 31, 31, 
+	31, 31, 31, 31, 31, 31, 1, 32, 
+	32, 32, 32, 32, 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, 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, 1, 1, 
-	1, 1, 1, 21, 1, 24, 1, 24, 
-	24, 24, 24, 24, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 24, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	25, 1, 25, 25, 25, 25, 25, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 34, 1, 32, 32, 32, 
+	32, 32, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 25, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 26, 1, 
-	1, 27, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 1, 29, 30, 30, 30, 
-	30, 30, 30, 30, 30, 30, 1, 31, 
-	31, 31, 31, 31, 1, 1, 1, 1, 
+	1, 1, 1, 1, 32, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 31, 1, 
+	33, 1, 1, 1, 31, 31, 31, 31, 
+	31, 31, 31, 31, 31, 31, 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, 
@@ -170,41 +190,41 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 34, 1, 35, 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, 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, 
+	37, 1, 37, 37, 37, 37, 37, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 37, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 38, 39, 39, 39, 39, 39, 39, 
+	39, 39, 39, 1, 40, 40, 40, 40, 
+	40, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 40, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 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, 33, 1, 34, 1, 35, 1, 35, 
-	35, 35, 35, 35, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 35, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	36, 1, 36, 36, 36, 36, 36, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 36, 1, 1, 1, 1, 1, 1, 
+	42, 1, 40, 40, 40, 40, 40, 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, 40, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 41, 1, 1, 
+	1, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 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, 
@@ -212,137 +232,130 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 42, 1, 
+	44, 45, 1, 46, 1, 46, 46, 46, 
+	46, 46, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	41, 1, 39, 39, 39, 39, 39, 1, 
+	1, 1, 1, 1, 1, 1, 47, 1, 
+	47, 47, 47, 47, 47, 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, 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, 48, 1, 1, 49, 
+	50, 50, 50, 50, 50, 50, 50, 50, 
+	50, 1, 51, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 1, 53, 53, 53, 
+	53, 53, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 53, 1, 1, 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, 1, 1, 1, 1, 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, 1, 1, 1, 1, 46, 1, 
-	46, 46, 46, 46, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 46, 
+	1, 55, 1, 53, 53, 53, 53, 53, 
 	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, 53, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 54, 1, 
+	1, 1, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 1, 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, 55, 
+	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, 1, 
-	1, 54, 1, 52, 52, 52, 52, 52, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 57, 1, 57, 57, 
+	57, 57, 57, 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, 57, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 58, 1, 1, 59, 60, 60, 
+	60, 60, 60, 60, 60, 60, 60, 1, 
+	61, 62, 62, 62, 62, 62, 62, 62, 
+	62, 62, 1, 63, 63, 63, 63, 63, 
 	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, 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, 
 	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, 65, 
+	1, 63, 63, 63, 63, 63, 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, 
+	63, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 64, 1, 1, 1, 
+	62, 62, 62, 62, 62, 62, 62, 62, 
+	62, 62, 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, 
 	1, 1, 1, 1, 1, 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, 66, 
+	1, 67, 1, 67, 67, 67, 67, 67, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 67, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 64, 
-	1, 62, 62, 62, 62, 62, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 68, 1, 68, 68, 
+	68, 68, 68, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	62, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 63, 1, 1, 1, 
-	61, 61, 61, 61, 61, 61, 61, 61, 
-	61, 61, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 68, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 69, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 1, 
+	71, 71, 71, 71, 71, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 71, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 72, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 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, 73, 1, 71, 71, 
+	71, 71, 71, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 68, 69, 69, 69, 69, 
-	69, 69, 69, 69, 69, 1, 71, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	72, 70, 73, 73, 73, 73, 73, 1, 
+	1, 1, 1, 1, 1, 71, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 72, 1, 1, 1, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 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, 
@@ -350,21 +363,33 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 73, 1, 75, 1, 75, 75, 
+	75, 75, 75, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 75, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 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, 76, 
+	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, 77, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	78, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 1, 81, 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, 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, 82, 80, 83, 
+	83, 83, 83, 83, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 83, 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, 84, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 76, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 77, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -373,67 +398,85 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 85, 1, 80, 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, 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, 80, 
+	1, 86, 86, 86, 86, 86, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	86, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 87, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 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, 88, 1, 86, 
+	86, 86, 86, 86, 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, 86, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 81, 1, 1, 1, 
+	1, 1, 87, 1, 1, 1, 89, 89, 
+	89, 89, 89, 89, 89, 89, 89, 89, 
 	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, 88, 1, 90, 1, 90, 
+	90, 90, 90, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 90, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 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, 
+	91, 1, 91, 91, 91, 91, 91, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 91, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 92, 93, 93, 93, 93, 93, 93, 
+	93, 93, 93, 1, 86, 86, 86, 86, 
 	86, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 86, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 87, 
+	1, 1, 1, 94, 94, 94, 94, 94, 
+	94, 94, 94, 94, 94, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	88, 1, 95, 95, 95, 95, 95, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 95, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 96, 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, 97, 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, 
@@ -442,46 +485,52 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 1, 
-	0
+	1, 1, 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, 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
+	37, 43, 51, 5, 12, 6, 7, 8, 
+	9, 11, 9, 11, 10, 2, 55, 10, 
+	55, 13, 14, 15, 16, 17, 16, 17, 
+	10, 2, 55, 19, 20, 21, 22, 23, 
+	10, 2, 55, 23, 25, 31, 26, 27, 
+	28, 29, 30, 29, 30, 10, 2, 55, 
+	32, 33, 34, 35, 36, 35, 36, 10, 
+	2, 55, 38, 39, 40, 41, 42, 10, 
+	2, 55, 42, 44, 45, 46, 49, 50, 
+	46, 47, 48, 10, 2, 55, 10, 2, 
+	55, 50, 52, 53, 49, 54, 54, 55, 
+	56, 57
 };
 
 static const char _deserialize_json_trans_actions[] = {
 	0, 0, 1, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 2, 2, 
-	2, 0, 0, 3, 3, 4, 0, 5, 
-	0, 0, 2, 2, 2, 0, 0, 6, 
-	6, 7, 0, 0, 0, 2, 2, 8, 
-	8, 9, 0, 0, 0, 0, 0, 2, 
-	2, 2, 0, 0, 10, 10, 11, 0, 
-	0, 2, 2, 2, 0, 0, 12, 12, 
-	13, 0, 0, 2, 14, 14, 0, 15, 
-	0, 16, 16, 17, 18, 18, 19, 15, 
-	0, 0, 20, 20, 21, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 2, 
+	2, 2, 0, 0, 3, 3, 4, 0, 
+	5, 0, 0, 2, 2, 2, 0, 0, 
+	6, 6, 7, 0, 0, 0, 2, 2, 
+	8, 8, 9, 0, 0, 0, 0, 0, 
+	2, 2, 2, 0, 0, 10, 10, 11, 
+	0, 0, 2, 2, 2, 0, 0, 12, 
+	12, 13, 0, 0, 0, 2, 2, 14, 
+	14, 15, 0, 0, 0, 2, 16, 16, 
+	0, 17, 0, 18, 18, 19, 20, 20, 
+	21, 17, 0, 0, 22, 22, 23, 0, 
+	0, 0
 };
 
 static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 49;
+static const int deserialize_json_first_final = 55;
 static const int deserialize_json_error = 0;
 
 static const int deserialize_json_en_main = 1;
 
 
-#line 108 "hb-buffer-deserialize-json.rl"
+#line 111 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
@@ -508,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 512 "hb-buffer-deserialize-json.hh"
+#line 554 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
-#line 517 "hb-buffer-deserialize-json.hh"
+#line 557 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
 	int _trans;
@@ -561,25 +610,25 @@ _resume:
 	tok = p;
 }
 	break;
-	case 15:
+	case 17:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 21:
+	case 23:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 16:
+	case 18:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
+					tok+1, p - tok - 2, /* Skip "" */
 					&info.codepoint))
 	  return false;
 }
 	break;
-	case 18:
+	case 20:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
@@ -604,6 +653,10 @@ _resume:
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
 	case 14:
+#line 72 "hb-buffer-deserialize-json.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+	break;
+	case 16:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -611,7 +664,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 20:
+	case 22:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -619,12 +672,12 @@ _resume:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 17:
+	case 19:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
+					tok+1, p - tok - 2, /* Skip "" */
 					&info.codepoint))
 	  return false;
 }
@@ -637,7 +690,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
@@ -709,7 +762,19 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-#line 713 "hb-buffer-deserialize-json.hh"
+	case 15:
+#line 72 "hb-buffer-deserialize-json.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 735 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -721,7 +786,7 @@ _again:
 	_out: {}
 	}
 
-#line 136 "hb-buffer-deserialize-json.rl"
+#line 139 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
index 382423f6c7da8310a31677e97fe46a7ad159546c..d5e3c138db16a4ebe2e546fb59dd4b7863291e25 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-json.rl
@@ -58,17 +58,18 @@ action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false;
 action parse_glyph_name {
 	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
+					tok+1, p - tok - 2, /* Skip "" */
 					&info.codepoint))
 	  return false;
 }
 
-action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; }
-action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_codepoint	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
+action parse_cluster	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 
 unum	= '0' | [1-9] digit*;
 num	= '-'? unum;
@@ -82,13 +83,14 @@ glyph_name = '"' ([^\\"] | '\\' [\\"])* '"';
 parse_glyph_name   = (glyph_name >tok %parse_glyph_name);
 parse_codepoint = (codepoint >tok %parse_codepoint);
 
-glyph	= "\"g\""  colon (parse_glyph_name | parse_codepoint);
-unicode	= "\"u\""  colon parse_codepoint;
-cluster	= "\"cl\"" colon (unum >tok %parse_cluster);
-xoffset	= "\"dx\"" colon (num >tok %parse_x_offset);
-yoffset	= "\"dy\"" colon (num >tok %parse_y_offset);
-xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
-yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+glyph	=  "\"g\""  colon (parse_glyph_name | parse_codepoint);
+unicode	=  "\"u\""  colon parse_codepoint;
+cluster	=  "\"cl\"" colon (unum >tok %parse_cluster);
+xoffset	=  "\"dx\"" colon (num  >tok %parse_x_offset);
+yoffset	=  "\"dy\"" colon (num  >tok %parse_y_offset);
+xadvance=  "\"ax\"" colon (num  >tok %parse_x_advance);
+yadvance=  "\"ay\"" colon (num  >tok %parse_y_advance);
+glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
 
 element = glyph @ensure_glyphs
 	| unicode @ensure_unicode
@@ -96,7 +98,8 @@ element = glyph @ensure_glyphs
 	| xoffset
 	| yoffset
 	| xadvance
-	| yadvance;
+	| yadvance
+	| glyphflags;
 item	=
 	( '{' space* element (comma element)* space* '}')
 	>clear_item
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.hh
index 06a605e225eb007df8c217ba9e3381a24182c763..8fbcdcc18cb894607cfbc47e3f2e1450d0e52bf2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.hh
@@ -32,29 +32,32 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-text.hh"
+#line 33 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
 	0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, 
-	48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 
-	43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 9u, 124u, 
+	48u, 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, 0
+	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
+	9u, 124u, 9u, 124u, 9u, 124u, 0
 };
 
 static const char _deserialize_text_key_spans[] = {
 	0, 83, 1, 1, 55, 77, 10, 13, 
-	10, 10, 13, 10, 1, 13, 10, 14, 
-	82, 13, 10, 116, 116, 0, 77, 116, 
+	10, 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, 116, 116, 
-	116, 116, 116, 116, 116
+	116, 116, 116
 };
 
 static const short _deserialize_text_index_offsets[] = {
 	0, 0, 84, 86, 88, 144, 222, 233, 
-	247, 258, 269, 283, 294, 296, 310, 321, 
-	336, 419, 433, 444, 561, 678, 679, 757, 
-	874, 991, 1108, 1225, 1342, 1459, 1576, 1693, 
-	1810, 1927, 2044, 2161, 2278
+	247, 258, 269, 280, 294, 305, 307, 321, 
+	332, 347, 430, 444, 455, 572, 689, 690, 
+	768, 885, 1002, 1119, 1236, 1353, 1470, 1587, 
+	1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523, 
+	2640, 2757, 2874
 };
 
 static const char _deserialize_text_indicies[] = {
@@ -91,50 +94,52 @@ static const char _deserialize_text_indicies[] = {
 	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, 
+	16, 16, 16, 16, 16, 1, 17, 18, 
+	18, 18, 18, 18, 18, 18, 18, 18, 
+	1, 19, 1, 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, 
+	23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 1, 24, 1, 25, 1, 1, 26, 
 	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 1, 22, 1, 1, 1, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	1, 28, 28, 1, 1, 1, 1, 1, 
+	27, 1, 28, 29, 29, 29, 29, 29, 
+	29, 29, 29, 29, 1, 24, 1, 1, 
+	1, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 1, 30, 30, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 28, 1, 1, 28, 1, 
+	1, 1, 1, 1, 1, 1, 30, 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, 30, 30, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 28, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 30, 1, 31, 
+	1, 1, 32, 33, 33, 33, 33, 33, 
+	33, 33, 33, 33, 1, 34, 35, 35, 
+	35, 35, 35, 35, 35, 35, 35, 1, 
+	36, 36, 36, 36, 36, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 1, 29, 1, 1, 30, 
-	31, 31, 31, 31, 31, 31, 31, 31, 
-	31, 1, 32, 33, 33, 33, 33, 33, 
-	33, 33, 33, 33, 1, 34, 34, 34, 
-	34, 34, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 36, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 34, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 37, 
+	37, 37, 37, 37, 37, 37, 37, 37, 
+	37, 1, 1, 1, 38, 39, 1, 1, 
+	37, 37, 37, 37, 37, 37, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 1, 1, 
-	1, 36, 37, 1, 1, 35, 35, 35, 
-	35, 35, 35, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 35, 35, 35, 
-	35, 35, 35, 1, 1, 1, 1, 1, 
+	37, 37, 37, 37, 37, 37, 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, 40, 1, 41, 41, 41, 
+	41, 41, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 41, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 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, 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, 
@@ -142,24 +147,23 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 41, 1, 1, 
-	7, 7, 7, 7, 7, 1, 1, 1, 
+	43, 1, 1, 7, 7, 7, 7, 7, 
 	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, 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, 4, 1, 42, 42, 
-	42, 42, 42, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 4, 
+	1, 44, 44, 44, 44, 44, 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, 
+	44, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 43, 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, 1, 1, 1, 1, 
@@ -167,68 +171,83 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 44, 1, 42, 42, 42, 42, 42, 
+	1, 1, 1, 1, 46, 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, 42, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 47, 47, 47, 
+	47, 47, 47, 47, 47, 47, 47, 1, 
+	1, 1, 1, 45, 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, 46, 1, 49, 49, 49, 49, 49, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 49, 48, 48, 50, 48, 48, 
+	48, 48, 48, 48, 48, 51, 1, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 52, 
+	48, 48, 53, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 54, 55, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 56, 48, 
+	57, 57, 57, 57, 57, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 57, 
+	30, 30, 58, 30, 30, 30, 30, 30, 
+	30, 30, 59, 1, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 60, 30, 30, 61, 
+	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, 30, 30, 62, 63, 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, 30, 30, 
+	30, 30, 30, 64, 30, 57, 57, 57, 
+	57, 57, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 57, 30, 30, 58, 
+	30, 30, 30, 30, 30, 30, 30, 59, 
+	1, 30, 30, 30, 65, 66, 66, 66, 
+	66, 66, 66, 66, 66, 66, 30, 30, 
+	30, 60, 30, 30, 61, 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, 30, 30, 
+	62, 63, 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, 30, 30, 30, 30, 30, 
+	64, 30, 67, 67, 67, 67, 67, 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, 67, 1, 1, 68, 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, 1, 1, 1, 1, 63, 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, 1, 1, 64, 1, 65, 
-	65, 65, 65, 65, 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, 65, 1, 
+	1, 1, 1, 1, 1, 1, 72, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -236,172 +255,238 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 40, 1, 1, 1, 1, 
+	1, 1, 1, 42, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 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, 73, 1, 74, 74, 74, 74, 
+	74, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 74, 48, 48, 50, 48, 
+	48, 48, 48, 48, 48, 48, 51, 1, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	52, 48, 48, 53, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 54, 
+	55, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 56, 
+	48, 75, 75, 75, 75, 75, 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, 
+	75, 1, 1, 76, 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, 
-	70, 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, 43, 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, 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, 79, 1, 80, 80, 
+	80, 80, 80, 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, 80, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	73, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 74, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 81, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 75, 1, 72, 72, 72, 72, 72, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 82, 1, 80, 80, 80, 80, 80, 
 	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, 80, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 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, 81, 
 	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, 82, 1, 
+	84, 84, 84, 84, 84, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 84, 
+	1, 1, 85, 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, 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, 87, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 88, 1, 84, 84, 84, 
+	84, 84, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 84, 1, 1, 85, 
+	1, 1, 1, 1, 1, 1, 1, 86, 
+	1, 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, 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, 87, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	88, 1, 75, 75, 75, 75, 75, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 75, 1, 1, 76, 1, 1, 1, 
+	1, 1, 1, 1, 77, 1, 1, 1, 
+	1, 89, 89, 89, 89, 89, 89, 89, 
+	89, 89, 89, 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, 45, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	79, 1, 77, 77, 77, 77, 77, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 77, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 79, 1, 90, 
+	90, 90, 90, 90, 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, 90, 1, 
+	1, 91, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 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, 92, 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, 93, 1, 90, 90, 90, 90, 
+	90, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 90, 1, 1, 91, 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, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 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, 
+	92, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 93, 
+	1, 67, 67, 67, 67, 67, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 64, 1, 0
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	67, 1, 1, 68, 1, 1, 1, 1, 
+	1, 1, 1, 1, 69, 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, 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, 71, 1, 94, 94, 
+	94, 94, 94, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 94, 30, 30, 
+	58, 30, 30, 30, 30, 30, 30, 30, 
+	59, 1, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 60, 30, 30, 61, 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, 30, 
+	30, 62, 95, 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, 30, 30, 30, 30, 
+	30, 96, 30, 94, 94, 94, 94, 94, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 94, 30, 30, 58, 30, 30, 
+	30, 30, 30, 30, 30, 59, 1, 30, 
+	30, 30, 97, 97, 97, 97, 97, 97, 
+	97, 97, 97, 97, 30, 30, 30, 60, 
+	30, 30, 61, 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, 30, 30, 62, 95, 
+	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, 30, 30, 30, 30, 30, 96, 30, 
+	0
 };
 
 static const char _deserialize_text_trans_targs[] = {
-	1, 0, 2, 25, 3, 4, 19, 5, 
-	23, 24, 8, 27, 36, 27, 36, 30, 
-	33, 11, 12, 15, 12, 15, 13, 14, 
-	31, 32, 31, 32, 26, 18, 34, 35, 
-	34, 35, 20, 19, 6, 21, 22, 20, 
-	21, 22, 20, 21, 22, 24, 26, 26, 
-	7, 9, 10, 16, 21, 29, 26, 7, 
-	9, 10, 16, 21, 29, 28, 17, 21, 
-	29, 28, 29, 29, 28, 7, 10, 29, 
-	28, 7, 21, 29, 33, 28, 21, 29
+	1, 0, 2, 26, 3, 4, 20, 5, 
+	24, 25, 8, 29, 40, 29, 40, 32, 
+	37, 33, 34, 12, 13, 16, 13, 16, 
+	14, 15, 35, 36, 35, 36, 27, 19, 
+	38, 39, 38, 39, 21, 20, 6, 22, 
+	23, 21, 22, 23, 21, 22, 23, 25, 
+	27, 27, 28, 7, 9, 11, 17, 22, 
+	31, 27, 28, 7, 9, 11, 17, 22, 
+	31, 41, 42, 30, 10, 18, 22, 31, 
+	30, 31, 31, 30, 10, 7, 11, 31, 
+	30, 22, 31, 34, 30, 10, 7, 22, 
+	31, 37, 30, 10, 22, 31, 27, 22, 
+	31, 42
 };
 
 static const char _deserialize_text_trans_actions[] = {
 	0, 0, 0, 0, 1, 0, 2, 0, 
 	2, 2, 3, 4, 4, 5, 5, 4, 
-	4, 3, 3, 3, 0, 0, 6, 3, 
-	4, 4, 5, 5, 5, 3, 4, 4, 
-	5, 5, 7, 8, 9, 7, 7, 0, 
-	0, 0, 10, 10, 10, 8, 12, 13, 
-	14, 14, 14, 15, 11, 11, 17, 18, 
-	18, 18, 0, 16, 16, 19, 20, 19, 
-	19, 0, 0, 13, 10, 21, 21, 10, 
-	22, 23, 22, 22, 5, 24, 24, 24
+	4, 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, 15, 15, 15, 16, 11, 
+	11, 18, 19, 20, 20, 20, 0, 17, 
+	17, 4, 4, 21, 22, 22, 21, 21, 
+	0, 0, 13, 10, 23, 23, 23, 10, 
+	24, 24, 24, 5, 25, 26, 26, 25, 
+	25, 5, 27, 28, 27, 27, 30, 29, 
+	29, 5
 };
 
 static const char _deserialize_text_eof_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 7, 0, 0, 0, 10, 
-	10, 11, 16, 19, 0, 11, 10, 22, 
-	22, 10, 24, 24, 19
+	0, 0, 0, 0, 7, 0, 0, 0, 
+	10, 10, 11, 17, 17, 21, 0, 11, 
+	10, 24, 24, 25, 25, 10, 27, 27, 
+	21, 29, 29
 };
 
 static const int deserialize_text_start = 1;
-static const int deserialize_text_first_final = 19;
+static const int deserialize_text_first_final = 20;
 static const int deserialize_text_error = 0;
 
 static const int deserialize_text_en_main = 1;
 
 
-#line 114 "hb-buffer-deserialize-text.rl"
+#line 117 "hb-buffer-deserialize-text.rl"
 
 
 static hb_bool_t
@@ -424,12 +509,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 428 "hb-buffer-deserialize-text.hh"
+#line 506 "hb-buffer-deserialize-text.hh"
 	{
 	cs = deserialize_text_start;
 	}
 
-#line 433 "hb-buffer-deserialize-text.hh"
+#line 509 "hb-buffer-deserialize-text.hh"
 	{
 	int _slen;
 	int _trans;
@@ -475,7 +560,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 18:
+	case 20:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -489,7 +574,7 @@ _resume:
 #line 66 "hb-buffer-deserialize-text.rl"
 	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
 	break;
-	case 21:
+	case 23:
 #line 68 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
@@ -497,15 +582,19 @@ _resume:
 #line 69 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 23:
+	case 26:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 20:
+	case 22:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 15:
+	case 28:
+#line 72 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+	break;
+	case 16:
 #line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
@@ -532,7 +621,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 16:
+	case 17:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -549,6 +638,18 @@ _resume:
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
+	break;
+	case 19:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	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; }
 	break;
 	case 7:
 #line 66 "hb-buffer-deserialize-text.rl"
@@ -574,7 +675,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 22:
+	case 25:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -586,7 +687,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -598,7 +699,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 24:
+	case 27:
 #line 72 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -608,6 +709,18 @@ _resume:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 24:
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
 }
 	break;
 	case 12:
@@ -623,7 +736,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 14:
+	case 15:
 #line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
@@ -642,7 +755,7 @@ _resume:
 	  return false;
 }
 	break;
-	case 17:
+	case 18:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -660,6 +773,26 @@ _resume:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 29:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) 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:
@@ -680,6 +813,49 @@ _resume:
 					&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 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 delimiters. */
+	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; }
+	break;
+	case 30:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) 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);
@@ -718,7 +894,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-#line 722 "hb-buffer-deserialize-text.hh"
+#line 826 "hb-buffer-deserialize-text.hh"
 	}
 
 _again:
@@ -730,7 +906,7 @@ _again:
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_eof_actions[cs] ) {
-	case 16:
+	case 17:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -772,7 +948,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 22:
+	case 25:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -784,7 +960,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -796,7 +972,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 24:
+	case 27:
 #line 72 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -806,6 +982,38 @@ _again:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 24:
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) 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 29:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) 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:
@@ -835,14 +1043,14 @@ _again:
 	*end_ptr = p;
 }
 	break;
-#line 839 "hb-buffer-deserialize-text.hh"
+#line 953 "hb-buffer-deserialize-text.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 138 "hb-buffer-deserialize-text.rl"
+#line 141 "hb-buffer-deserialize-text.rl"
 
 
   *end_ptr = p;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.rl b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.rl
index 73b007b98e78236a3403f2f1215567e041342d68..0f33eb89d44487a0c91d20dd92991b107e6a92bf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.rl
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-deserialize-text.rl
@@ -65,11 +65,12 @@ action parse_glyph {
 
 action parse_hexdigits  {if (!parse_hex (tok, p, &info.codepoint )) return false; }
 
-action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
-action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_cluster	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+action parse_glyph_flags{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 
 unum  = '0' | [1-9] digit*;
 num	= '-'? unum;
@@ -81,6 +82,7 @@ glyph	= (glyph_id | glyph_name) >tok %parse_glyph;
 cluster	= '=' (unum >tok %parse_cluster);
 offsets	= '@' (num >tok %parse_x_offset)   ',' (num >tok %parse_y_offset );
 advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
+glyphflags= '#' (unum >tok %parse_glyph_flags);
 
 glyph_item	=
 	(
@@ -88,6 +90,7 @@ glyph_item	=
 		cluster?
 		offsets?
 		advances?
+		glyphflags?
 	)
 	>clear_item
 	@ensure_glyphs
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
index 3f619a113e8e0b28966e8fbc412861a9a223e082..d1e177543033c56e51fcfc547ada0abd38fd8b28 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer-serialize.cc
@@ -56,7 +56,7 @@ hb_buffer_serialize_list_formats ()
 /**
  * hb_buffer_serialize_format_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  *
  * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
  * @str is a valid buffer serialization format, use
@@ -78,11 +78,11 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
  * hb_buffer_serialize_format_to_string:
  * @format: an #hb_buffer_serialize_format_t to convert.
  *
- * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * Converts @format to the string corresponding it, or `NULL` if it is not a valid
  * #hb_buffer_serialize_format_t.
  *
  * Return value: (transfer none):
- * A %NULL terminated string corresponding to @format. Should not be freed.
+ * A `NULL` terminated string corresponding to @format. Should not be freed.
  *
  * Since: 0.9.7
  **/
@@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, an empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, an empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -727,7 +727,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * hb_buffer_deserialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @font: (nullable): font for getting glyph IDs
@@ -736,7 +736,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -800,7 +800,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * hb_buffer_deserialize_unicode:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @format: the #hb_buffer_serialize_format_t of the input @buf
@@ -808,7 +808,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
  *
  * Since: 2.7.3
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
index 2272ecf09b51abbf7cf62273f614c318c8cda2e3..fddda23304498320211c74a1ffb75a6fc8e3d7b6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
@@ -51,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
  **/
@@ -643,9 +643,9 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
  * Return value: (transfer full):
  * A newly allocated #hb_buffer_t with a reference count of 1. The initial
  * reference count should be released with hb_buffer_destroy() when you are done
- * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
  * be allocated, a special #hb_buffer_t object will be returned on which
- * hb_buffer_allocation_successful() returns %false.
+ * hb_buffer_allocation_successful() returns `false`.
  *
  * Since: 0.9.2
  **/
@@ -775,7 +775,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
  *
  * Attaches a user-data key/data pair to the specified buffer. 
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1278,7 +1278,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer)
  * Pre allocates memory for @buffer to fit at least @size number of items.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise
+ * `true` if @buffer memory allocation succeeded, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1295,7 +1295,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
  * Check if allocating memory for the buffer succeeded.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1340,7 +1340,7 @@ hb_buffer_add (hb_buffer_t    *buffer,
  * end.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1426,7 +1426,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  * If buffer did not have positions before, the positions will be
  * initialized to zeros, unless this function is called from
  * within a buffer message callback (see hb_buffer_set_message_func()),
- * in which case %NULL is returned.
+ * in which case `NULL` is returned.
  *
  * Return value: (transfer none) (array length=length):
  * The @buffer glyph position array.
@@ -1461,7 +1461,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
  * and cleared of position data when hb_buffer_clear_contents() is called.
  *
  * Return value:
- * %true if the @buffer has position array, %false otherwise.
+ * `true` if the @buffer has position array, `false` otherwise.
  *
  * Since: 2.7.3
  **/
@@ -1645,10 +1645,10 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
  *               characters to append.
- * @text_length: The length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: The offset of the first character to add to the @buffer.
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1671,10 +1671,10 @@ hb_buffer_add_utf8 (hb_buffer_t  *buffer,
  * hb_buffer_add_utf16:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-16 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1697,10 +1697,10 @@ hb_buffer_add_utf16 (hb_buffer_t    *buffer,
  * hb_buffer_add_utf32:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-32 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1724,10 +1724,10 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
  *               characters to append
- * @text_length: the length of the @text, or -1 if it is %NULL terminated
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: the offset of the first character to add to the @buffer
  * @item_length: the number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
  * Unicode code points that can fit in 8-bit strings.
@@ -1750,10 +1750,10 @@ hb_buffer_add_latin1 (hb_buffer_t   *buffer,
  * hb_buffer_add_codepoints:
  * @buffer: a #hb_buffer_t to append characters to.
  * @text: (array length=text_length): an array of Unicode code points to append.
- * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: the offset of the first code point to add to the @buffer.
  * @item_length: the number of code points to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * Appends characters from @text array to @buffer. The @item_offset is the
  * position of the first character from @text that will be appended, and
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
index 22fb3496f2ec7cbebab87bcd26b0100e73310ac8..e095c5344cec6807e5c41c28a591b47712b5aa3b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.h
@@ -755,16 +755,16 @@ hb_buffer_diff (hb_buffer_t *buffer,
  * hb_buffer_message_func_t:
  * @buffer: An #hb_buffer_t to work upon
  * @font: The #hb_font_t the @buffer is shaped with
- * @message: %NULL-terminated message passed to the function
+ * @message: `NULL`-terminated message passed to the function
  * @user_data: User data pointer passed by the caller
  *
  * A callback method for #hb_buffer_t. The method gets called with the
  * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
  * message describing what step of the shaping process will be performed.
- * Returning %false from this method will skip this shaping step and move to
+ * Returning `false` from this method will skip this shaping step and move to
  * the next one.
  *
- * Return value: %true to perform the shaping step, %false to skip it.
+ * Return value: `true` to perform the shaping step, `false` to skip it.
  *
  * Since: 1.1.3
  */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-cff-interp-cs-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-cff-interp-cs-common.hh
index 2983ae54a1ed3efc65c47a276cbb570dc406f846..f93c83ab459249e6da53248c8d89a030a5689a62 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-cff-interp-cs-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-cff-interp-cs-common.hh
@@ -57,6 +57,7 @@ struct call_context_t
 
 /* call stack */
 const unsigned int kMaxCallLimit = 10;
+const unsigned int kMaxOps = 10000;
 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 
 template <typename SUBRS>
@@ -881,7 +882,13 @@ struct cs_interpreter_t : interpreter_t<ENV>
   {
     SUPER::env.set_endchar (false);
 
+    unsigned max_ops = kMaxOps;
     for (;;) {
+      if (unlikely (!--max_ops))
+      {
+	SUPER::env.set_error ();
+	break;
+      }
       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
       if (unlikely (SUPER::env.in_error ()))
 	return false;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
index 7266d9b01f4430d621e89f08d829d0802737e8ea..e6512872e87294af7cb42f6064a77901cb7ea05b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.cc
@@ -108,7 +108,7 @@ _hb_options_init ()
 /**
  * hb_tag_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string into an #hb_tag_t. Valid tags
  * are four characters. Shorter input strings will be
@@ -170,7 +170,7 @@ static const char direction_strings[][4] = {
 /**
  * hb_direction_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string to an #hb_direction_t.
  *
@@ -357,7 +357,7 @@ retry:
  * hb_language_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing
  *       a BCP 47 language tag
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts @str representing a BCP 47 language tag to the corresponding
  * #hb_language_t.
@@ -396,7 +396,7 @@ hb_language_from_string (const char *str, int len)
  * Converts an #hb_language_t to a string.
  *
  * Return value: (transfer none):
- * A %NULL-terminated string representing the @language. Must not be freed by
+ * A `NULL`-terminated string representing the @language. Must not be freed by
  * the caller.
  *
  * Since: 0.9.2
@@ -441,6 +441,38 @@ hb_language_get_default ()
   return language;
 }
 
+/**
+ * hb_language_matches:
+ * @language: The #hb_language_t to work on
+ * @specific: Another #hb_language_t
+ *
+ * Check whether a second language tag is the same or a more
+ * specific version of the provided language tag.  For example,
+ * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".
+ *
+ * Return value: `true` if languages match, `false` otherwise.
+ *
+ * Since: 5.0.0
+ **/
+hb_bool_t
+hb_language_matches (hb_language_t language,
+		     hb_language_t specific)
+{
+  if (language == specific) return true;
+  if (!language || !specific) return false;
+
+  const char *l = language->s;
+  const char *s = specific->s;
+  unsigned ll = strlen (l);
+  unsigned sl = strlen (s);
+
+  if (ll > sl)
+    return false;
+
+  return strncmp (l, s, ll) == 0 &&
+	 (s[ll] == '\0' || s[ll] == '-');
+}
+
 
 /* hb_script_t */
 
@@ -498,7 +530,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
  * hb_script_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing an
  *       ISO 15924 tag.
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts a string @str representing an ISO 15924 script tag to a
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
@@ -693,8 +725,8 @@ hb_version_string ()
  * Tests the library version against a minimum value,
  * as three integer components.
  *
- * Return value: %true if the library is equal to or greater than
- * the test value, %false otherwise
+ * Return value: `true` if the library is equal to or greater than
+ * the test value, `false` otherwise
  *
  * Since: 0.9.30
  **/
@@ -881,7 +913,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
 /**
  * hb_feature_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @feature: (out): the #hb_feature_t to initialize with the parsed values
  *
  * Parses a string into a #hb_feature_t.
@@ -923,7 +955,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
  * </informaltable>
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 0.9.5
  **/
@@ -954,7 +986,7 @@ hb_feature_from_string (const char *str, int len,
  * @buf: (array length=size) (out): output string
  * @size: the allocated size of @buf
  *
- * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * Converts a #hb_feature_t into a `NULL`-terminated string in the format
  * understood by hb_feature_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
@@ -1022,7 +1054,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
 /**
  * hb_variation_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @variation: (out): the #hb_variation_t to initialize with the parsed values
  *
  * Parses a string into a #hb_variation_t.
@@ -1035,7 +1067,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
  * number. For example `wght=500`, or `slnt=-7.5`.
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 1.4.2
  */
@@ -1107,7 +1139,7 @@ get_C_locale ()
  * @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
+ * 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.
  *
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
index 7b897a6c511d7dc2db7807c48d95d18e993fac7e..7c7ad87c7caff63955efff45a372d504d9091dd3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-common.h
@@ -326,6 +326,9 @@ hb_language_to_string (hb_language_t language);
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
+HB_EXTERN hb_bool_t
+hb_language_matches (hb_language_t language,
+		     hb_language_t specific);
 
 /**
  * hb_script_t:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh
index 2578231d2388997b2042377e12a6a1e7bd69054a..db8ec0e908cd3e367ea49349ce36522a0da86ac3 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh
@@ -98,6 +98,11 @@
 
 /* Closure of options. */
 
+#ifdef HB_NO_BORING_EXPANSION
+#define HB_NO_BEYOND_64K
+#define HB_NO_VARIATIONS2
+#endif
+
 #ifdef HB_DISABLE_DEPRECATED
 #define HB_IF_NOT_DEPRECATED(x)
 #else
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-cplusplus.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-cplusplus.hh
index c79d1550649a07fd45e46f27b4312d072e302625..f06a32d912fb5c968f8b3fdfefa92af94bcacf36 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-cplusplus.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-cplusplus.hh
@@ -166,14 +166,18 @@ HB_DEFINE_VTABLE (unicode_funcs);
 
 } // namespace hb
 
+/* Workaround for GCC < 7, see:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+ * https://stackoverflow.com/a/25594741 */
 namespace std {
 
+
 template<typename T>
 struct hash<hb::shared_ptr<T>>
 {
-    size_t operator()(const hb::shared_ptr<T>& v) const noexcept
+    std::size_t operator()(const hb::shared_ptr<T>& v) const noexcept
     {
-        size_t h = hash<decltype (v.get ())>{}(v.get ());
+        std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
         return h;
     }
 };
@@ -181,13 +185,14 @@ struct hash<hb::shared_ptr<T>>
 template<typename T>
 struct hash<hb::unique_ptr<T>>
 {
-    size_t operator()(const hb::unique_ptr<T>& v) const noexcept
+    std::size_t operator()(const hb::unique_ptr<T>& v) const noexcept
     {
-        size_t h = hash<decltype (v.get ())>{}(v.get ());
+        std::size_t h = std::hash<decltype (v.get ())>{}(v.get ());
         return h;
     }
 };
 
+
 } // namespace std
 
 #endif /* __cplusplus */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h
index a130d77f77079b1c013d6cabca849033d99ed97d..333dc3cd4c3572899411f7ab0aab0a3ef612aaff 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h
@@ -93,7 +93,7 @@ HB_BEGIN_DECLS
  * This method should retrieve the glyph ID for a specified Unicode code point
  * font, with an optional variation selector.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * Deprecated: 1.2.3
  *
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
index ce04f5bab1898f2242a6905ea85f453ba5fab3b8..de05b7d871a1099217c97578adab2cea3f24b2d4 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
@@ -43,6 +43,14 @@
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
+
 /*
  * DirectWrite font stream helpers
  */
@@ -137,6 +145,7 @@ public:
 
 struct hb_directwrite_face_data_t
 {
+  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   DWriteFontFileStream *fontFileStream;
@@ -158,12 +167,33 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
     return nullptr; \
   } HB_STMT_END
 
+  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
+  if (unlikely (!data->dwrite_dll))
+    FAIL ("Cannot find DWrite.DLL");
+
+  t_DWriteCreateFactory p_DWriteCreateFactory;
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+  p_DWriteCreateFactory = (t_DWriteCreateFactory)
+			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+  if (unlikely (!p_DWriteCreateFactory))
+    FAIL ("Cannot find DWriteCreateFactory().");
+
   HRESULT hr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
-  hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-			    (IUnknown**) &dwriteFactory);
+  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+			      (IUnknown**) &dwriteFactory);
 
   if (unlikely (hr != S_OK))
     FAIL ("Failed to run DWriteCreateFactory().");
@@ -227,6 +257,8 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
+  if (data->dwrite_dll)
+    FreeLibrary (data->dwrite_dll);
   if (data)
     delete data;
 }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.cc
index fdc71102d6499f42e8a497b14938d04be19d12d4..46797e64e62dd546f1ecdc5bc03053d2c06f4357 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-draw.cc
@@ -120,6 +120,7 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t	 *dfuncs,		\
     if (dfuncs->destroy)						\
       dfuncs->destroy->name = nullptr;					\
   }									\
+  return;                                                                \
                                                                          \
 fail:                                                                    \
   if (destroy)                                                           \
@@ -137,7 +138,7 @@ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
  * Return value: (transfer full):
  * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
  * reference count should be released with hb_draw_funcs_destroy when you are
- * done using the #hb_draw_funcs_t. This function never returns %NULL. If
+ * done using the #hb_draw_funcs_t. This function never returns `NULL`. If
  * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
  * be returned.
  *
@@ -208,6 +209,9 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
 #undef HB_DRAW_FUNC_IMPLEMENT
   }
 
+  hb_free (dfuncs->destroy);
+  hb_free (dfuncs->user_data);
+
   hb_free (dfuncs);
 }
 
@@ -234,7 +238,7 @@ hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
  *
  * Checks whether @dfuncs is immutable.
  *
- * Return value: %true if @dfuncs is immutable, %false otherwise
+ * Return value: `true` if @dfuncs is immutable, `false` otherwise
  *
  * Since: 4.0.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
index 7cdd6cb49fb84c15443b00f0047cb291a8115dbd..8f8b1a6d148e9137a3042bf3e421913a0bfffebb 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-face.cc
@@ -315,7 +315,7 @@ hb_face_destroy (hb_face_t *face)
  *
  * Attaches a user-data key/data pair to the given face object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -371,7 +371,7 @@ hb_face_make_immutable (hb_face_t *face)
  *
  * Tests whether the given face object is immutable.
  *
- * Return value: %true is @face is immutable, %false otherwise
+ * Return value: `true` is @face is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
index 8c4fe863b65d2be608008d46e00a70a61c28d683..fd9073c33e7ee4d00aa942fd4b337ae4ff9d8a01 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
@@ -754,7 +754,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
  *
  * Attaches a user-data key/data pair to the specified font-functions structure.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -811,7 +811,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
  *
  * Tests whether a font-functions structure is immutable.
  *
- * Return value: %true if @ffuncs is immutable, %false otherwise
+ * Return value: `true` if @ffuncs is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -903,7 +903,7 @@ hb_font_t::has_func (unsigned int i)
  * Fetches the extents for a specified font, for horizontal
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -922,7 +922,7 @@ hb_font_get_h_extents (hb_font_t         *font,
  * Fetches the extents for a specified font, for vertical
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -946,7 +946,7 @@ hb_font_get_v_extents (hb_font_t         *font,
  * If @variation_selector is 0, calls hb_font_get_nominal_glyph();
  * otherwise calls hb_font_get_variation_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -974,7 +974,7 @@ hb_font_get_glyph (hb_font_t      *font,
  * for code points modified by variation selectors. For variation-selector
  * support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -1026,7 +1026,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
  * by the specified variation-selector code point, in the specified
  * font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -1136,7 +1136,7 @@ hb_font_get_glyph_v_advances (hb_font_t*            font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for horizontal text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1159,7 +1159,7 @@ hb_font_get_glyph_h_origin (hb_font_t      *font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for vertical text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1232,7 +1232,7 @@ hb_font_get_glyph_v_kerning (hb_font_t      *font,
  * Fetches the #hb_glyph_extents_t data for a glyph ID
  * in the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1255,7 +1255,7 @@ hb_font_get_glyph_extents (hb_font_t          *font,
  * Fetches the (x,y) coordinates of a specified contour-point index
  * in the specified glyph, within the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1278,7 +1278,7 @@ hb_font_get_glyph_contour_point (hb_font_t      *font,
  *
  * Fetches the glyph-name string for a glyph ID in the specified @font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1302,7 +1302,7 @@ hb_font_get_glyph_name (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the name string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1537,7 +1537,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t      *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1566,7 +1566,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t          *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1617,7 +1617,7 @@ hb_font_glyph_to_string (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1675,6 +1675,7 @@ _hb_font_create (hb_face_t *face)
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
+
   if (!(font = hb_object_create<hb_font_t> ()))
     return hb_font_get_empty ();
 
@@ -1866,7 +1867,7 @@ hb_font_destroy (hb_font_t *font)
  *
  * Attaches a user-data key/data pair to the specified font object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1928,7 +1929,7 @@ hb_font_make_immutable (hb_font_t *font)
  *
  * Tests whether a font object is immutable.
  *
- * Return value: %true if @font is immutable, %false otherwise
+ * Return value: `true` if @font is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1948,7 +1949,7 @@ hb_font_is_immutable (hb_font_t *font)
  *
  * Return value: serial number
  *
- * Since: 4.4.0.
+ * Since: 4.4.0
  **/
 unsigned int
 hb_font_get_serial (hb_font_t *font)
@@ -1964,7 +1965,7 @@ hb_font_get_serial (hb_font_t *font)
  * This has the effect of increasing the serial as returned
  * by hb_font_get_serial(), which invalidates internal caches.
  *
- * Since: 4.4.0.
+ * Since: 4.4.0
  **/
 void
 hb_font_changed (hb_font_t *font)
@@ -2386,6 +2387,10 @@ hb_font_set_variations (hb_font_t            *font,
     return;
   }
 
+  /* Initialize design coords to default from fvar. */
+  for (unsigned int i = 0; i < coords_length; i++)
+    design_coords[i] = axes[i].get_default ();
+
   for (unsigned int i = 0; i < variations_length; i++)
   {
     const auto tag = variations[i].tag;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
index ca6ecf79634ae5d9b723c49196932b1b432364ed..3f27bca2881f75966660341189b8d262bce2ade6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-font.h
@@ -198,7 +198,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
  * This method should retrieve the nominal glyph ID for a specified Unicode code
  * point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -221,7 +221,7 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
  * followed by a specified Variation Selector code point. Glyph IDs must be
  * returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -362,7 +362,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
  * origin for a glyph. Each coordinate must be returned in an #hb_position_t
  * output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -434,7 +434,7 @@ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
  * This method should retrieve the extents for a specified glyph. Extents must be 
  * returned in an #hb_glyph_extents output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -458,7 +458,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
  * specified contour point in a glyph. Each coordinate must be returned as
  * an #hb_position_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
@@ -481,7 +481,7 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
  * This method should retrieve the glyph name that corresponds to a
  * glyph ID. The name should be returned in a string output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
@@ -503,7 +503,7 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
  * This method should retrieve the glyph ID that corresponds to a glyph-name
  * string. 
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
index b526a828657b57e596dc5aa37872d0adce15d410..5c88a7f3bd377548eaf33d2cae0baa24a1346c57 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
@@ -136,32 +136,56 @@ _hb_ft_font_destroy (void *data)
 /* hb_font changed, update FT_Face. */
 static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
 {
+  float x_mult = 1.f, y_mult = 1.f;
 
-  FT_Set_Char_Size (ft_face,
-		    abs (font->x_scale), abs (font->y_scale),
-		    0, 0);
+  if (font->x_scale < 0) x_mult = -x_mult;
+  if (font->y_scale < 0) y_mult = -y_mult;
+
+  if (FT_Set_Char_Size (ft_face,
+			abs (font->x_scale), abs (font->y_scale),
+			0, 0
 #if 0
 		    font->x_ppem * 72 * 64 / font->x_scale,
-		    font->y_ppem * 72 * 64 / font->y_scale);
+		    font->y_ppem * 72 * 64 / font->y_scale
+#endif
+     ) && ft_face->num_fixed_sizes)
+  {
+#ifdef HAVE_FT_GET_TRANSFORM
+    /* Bitmap font, eg. bitmap color emoji. */
+    /* TODO Pick largest size? */
+    int x_scale  = ft_face->available_sizes[0].x_ppem;
+    int y_scale = ft_face->available_sizes[0].y_ppem;
+    FT_Set_Char_Size (ft_face,
+		      x_scale, y_scale,
+		      0, 0);
+
+    /* This contains the sign that was previously in x_mult/y_mult. */
+    x_mult = (float) font->x_scale / x_scale;
+    y_mult = (float) font->y_scale / y_scale;
 #endif
-  if (font->x_scale < 0 || font->y_scale < 0)
+  }
+  else
+  { /* Shrug */ }
+
+
+  if (x_mult != 1.f || y_mult != 1.f)
   {
-    FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
-			  0, font->y_scale < 0 ? -1 : +1};
+    FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
+			  0, (int) roundf (y_mult * (1<<16))};
     FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
   unsigned int num_coords;
-  const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
+  const float *coords = hb_font_get_var_coords_design (font, &num_coords);
   if (num_coords)
   {
     FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
     if (ft_coords)
     {
       for (unsigned int i = 0; i < num_coords; i++)
-	ft_coords[i] = coords[i] * 4;
-      FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
+	  ft_coords[i] = coords[i] * 65536.f;
+      FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
       hb_free (ft_coords);
     }
   }
@@ -241,7 +265,7 @@ hb_ft_font_get_load_flags (hb_font_t *font)
  * Fetches the FT_Face associated with the specified #hb_font_t
  * font object.
  *
- * Return value: (nullable): the FT_Face found or %NULL
+ * Return value: (nullable): the FT_Face found or `NULL`
  *
  * Since: 0.9.2
  **/
@@ -263,7 +287,7 @@ hb_ft_font_get_face (hb_font_t *font)
  * 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
+ * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
  * Since: 2.6.5
  **/
 FT_Face
@@ -280,7 +304,7 @@ hb_ft_font_lock_face (hb_font_t *font)
 }
 
 /**
- * hb_ft_font_unlock_face:
+ * hb_ft_font_unlock_face: (skip)
  * @font: #hb_font_t to work upon
  *
  * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
@@ -404,7 +428,13 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   int load_flags = ft_font->load_flags;
-  int mult = font->x_scale < 0 ? -1 : +1;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float mult = matrix.xx / 65536.f;
+#else
+  float mult = font->x_scale < 0 ? -1 : +1;
+#endif
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -420,7 +450,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
       ft_font->advance_cache.set (glyph, v);
     }
 
-    *first_advance = (v * mult + (1<<9)) >> 10;
+    *first_advance = (int) (v * mult + (1<<9)) >> 10;
     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
@@ -436,12 +466,18 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Fixed v;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
     return 0;
 
-  if (font->y_scale < 0)
-    v = -v;
+  v = (int) (y_mult * v);
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
@@ -462,6 +498,15 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float x_mult = matrix.xx / 65536.f;
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float x_mult = font->x_scale < 0 ? -1 : +1;
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
@@ -471,10 +516,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 
-  if (font->x_scale < 0)
-    *x = -*x;
-  if (font->y_scale < 0)
-    *y = -*y;
+  *x = (hb_position_t) (x_mult * *x);
+  *y = (hb_position_t) (y_mult * *y);
 
   return true;
 }
@@ -510,24 +553,24 @@ hb_ft_get_glyph_extents (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float x_mult = matrix.xx / 65536.f;
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float x_mult = font->x_scale < 0 ? -1 : +1;
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
-  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
-  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
-  extents->width = ft_face->glyph->metrics.width;
-  extents->height = -ft_face->glyph->metrics.height;
-  if (font->x_scale < 0)
-  {
-    extents->x_bearing = -extents->x_bearing;
-    extents->width = -extents->width;
-  }
-  if (font->y_scale < 0)
-  {
-    extents->y_bearing = -extents->y_bearing;
-    extents->height = -extents->height;
-  }
+  extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX);
+  extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY);
+  extents->width  = (hb_position_t) (x_mult *  ft_face->glyph->metrics.width);
+  extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height);
+
   return true;
 }
 
@@ -620,16 +663,32 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
-  metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
-  metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
-  metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
-  if (font->y_scale < 0)
+  if (ft_face->units_per_EM != 0)
+  {
+    metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
+    metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
+    metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
+  }
+  else
   {
-    metrics->ascender = -metrics->ascender;
-    metrics->descender = -metrics->descender;
-    metrics->line_gap = -metrics->line_gap;
+    /* Bitmap-only font, eg. color bitmap font. */
+    metrics->ascender = ft_face->size->metrics.ascender;
+    metrics->descender = ft_face->size->metrics.descender;
+    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
   }
+
+  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
+  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
+  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
+
   return true;
 }
 
@@ -684,8 +743,6 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
-  _hb_ft_hb_font_check_changed (font, ft_font);
-
   if (unlikely (FT_Load_Glyph (ft_face, glyph,
 			       FT_LOAD_NO_BITMAP | ft_font->load_flags)))
     return;
@@ -1028,6 +1085,8 @@ hb_ft_font_changed (hb_font_t *font)
 #endif
   }
 #endif
+
+  _hb_ft_hb_font_check_changed (font, ft_font);
 }
 
 /**
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
index 63dc18b466d0f3f535251aac2d1a8592e801db76..4d0e687c7553c34f0892e6a45469ebe5b2cc152f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
@@ -158,7 +158,7 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
 }
 
 /**
- * hb_graphite2_face_get_gr_face:
+ * hb_graphite2_face_get_gr_face: (skip)
  * @face: @hb_face_t to query
  *
  * Fetches the Graphite2 gr_face corresponding to the specified
@@ -195,10 +195,10 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
 
 #ifndef HB_DISABLE_DEPRECATED
 /**
- * hb_graphite2_font_get_gr_font:
+ * hb_graphite2_font_get_gr_font: (skip)
  * @font: An #hb_font_t
  *
- * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ * Always returns `NULL`. Use hb_graphite2_face_get_gr_face() instead.
  *
  * Return value: (nullable): Graphite2 font associated with @font.
  *
@@ -223,7 +223,7 @@ struct hb_graphite2_cluster_t {
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
-  unsigned int advance;
+  int advance;
 };
 
 hb_bool_t
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh
index d4461f166cc5395360689b2a21a53e9916de1ad0..1a3ab43de03ebb77d489bc7fd6e138d5e6d8a66d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh
@@ -253,6 +253,8 @@ struct hb_is_iterator_of
 };
 #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
 #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+#define hb_is_sorted_iterator_of(Iter, Item) (hb_is_iterator_of<Iter, Item>::value && Iter::is_sorted_iterator)
+#define hb_is_sorted_iterator(Iter) hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
 
 /* hb_is_iterable() */
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc
index 089615c72a0dab46008efd8305aaa355ad1a08c5..a29fa1a31368f4204b30f969d79a4b47c1a5dc8b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc
@@ -56,8 +56,6 @@ hb_map_create ()
   if (!(map = hb_object_create<hb_map_t> ()))
     return hb_map_get_empty ();
 
-  map->init_shallow ();
-
   return map;
 }
 
@@ -107,8 +105,6 @@ hb_map_destroy (hb_map_t *map)
 {
   if (!hb_object_destroy (map)) return;
 
-  map->fini_shallow ();
-
   hb_free (map);
 }
 
@@ -122,7 +118,7 @@ hb_map_destroy (hb_map_t *map)
  *
  * Attaches a user-data key/data pair to the specified map.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -162,7 +158,7 @@ hb_map_get_user_data (hb_map_t           *map,
  *
  * Tests whether memory allocation for a set was successful.
  *
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -251,7 +247,7 @@ hb_map_del (hb_map_t       *map,
  *
  * Tests whether @key is an element of @map.
  *
- * Return value: %true if @key is found in @map, %false otherwise
+ * Return value: `true` if @key is found in @map, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -283,7 +279,7 @@ hb_map_clear (hb_map_t *map)
  *
  * Tests whether @map is empty (contains no elements).
  *
- * Return value: %true if @map is empty
+ * Return value: `true` if @map is empty
  *
  * Since: 1.7.7
  **/
@@ -317,7 +313,7 @@ hb_map_get_population (const hb_map_t *map)
  * Tests whether @map and @other are equal (contain the same
  * elements).
  *
- * Return value: %true if the two maps are equal, %false otherwise.
+ * Return value: `true` if the two maps are equal, `false` otherwise.
  *
  * Since: 4.3.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
index 5efad8d20cd2daeb6cb3b80da1e5d497355d2c35..8302e3f8c7a3e23f6108ff9fe9494238dc80e225 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
@@ -124,21 +124,20 @@ struct hb_hashmap_t
     hb_swap (a.prime, b.prime);
     hb_swap (a.items, b.items);
   }
-  void init_shallow ()
+  void init ()
   {
+    hb_object_init (this);
+
     successful = true;
     population = occupancy = 0;
     mask = 0;
     prime = 0;
     items = nullptr;
   }
-  void init ()
-  {
-    hb_object_init (this);
-    init_shallow ();
-  }
-  void fini_shallow ()
+  void fini ()
   {
+    hb_object_fini (this);
+
     if (likely (items)) {
       unsigned size = mask + 1;
       for (unsigned i = 0; i < size; i++)
@@ -148,11 +147,6 @@ struct hb_hashmap_t
     }
     population = occupancy = 0;
   }
-  void fini ()
-  {
-    hb_object_fini (this);
-    fini_shallow ();
-  }
 
   void reset ()
   {
@@ -219,13 +213,11 @@ struct hb_hashmap_t
   /* Has interface. */
   typedef const V& value_t;
   value_t operator [] (K k) const { return get (k); }
-  bool has (K key, const V **vp = nullptr) const
+  template <typename VV=V>
+  bool has (K key, VV **vp = nullptr) const
   {
     if (unlikely (!items))
-    {
-      if (vp) *vp = &item_t::default_value ();
       return false;
-    }
     unsigned int i = bucket_for (key);
     if (items[i].is_real () && items[i] == key)
     {
@@ -233,10 +225,7 @@ struct hb_hashmap_t
       return true;
     }
     else
-    {
-      if (vp) *vp = &item_t::default_value ();
       return false;
-    }
   }
   /* Projection. */
   V operator () (K k) const { return get (k); }
@@ -301,6 +290,12 @@ struct hb_hashmap_t
     | hb_map (&item_t::key)
     | hb_map (hb_ridentity)
   )
+  auto keys_ref () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::key)
+  )
   auto values () const HB_AUTO_RETURN
   (
     + hb_array (items, mask ? mask + 1 : 0)
@@ -308,6 +303,12 @@ struct hb_hashmap_t
     | hb_map (&item_t::value)
     | hb_map (hb_ridentity)
   )
+  auto values_ref () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::value)
+  )
 
   /* Sink interface. */
   hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
@@ -443,4 +444,37 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
   hb_map_t (const Iterable &o) : hashmap (o) {}
 };
 
+template <typename K, typename V>
+static inline
+hb_hashmap_t<K, V>* hb_hashmap_create ()
+{
+  using hashmap = hb_hashmap_t<K, V>;
+  hashmap* map;
+  if (!(map = hb_object_create<hashmap> ()))
+    return nullptr;
+
+  return map;
+}
+
+template <typename K, typename V>
+static inline
+void hb_hashmap_destroy (hb_hashmap_t<K, V>* map)
+{
+  if (!hb_object_destroy (map))
+    return;
+
+  hb_free (map);
+}
+
+namespace hb {
+
+template <typename K, typename V>
+struct vtable<hb_hashmap_t<K, V>>
+{
+  static constexpr auto destroy = hb_hashmap_destroy<K,V>;
+};
+
+}
+
+
 #endif /* HB_MAP_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-meta.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-meta.hh
index e97d790fc362d7bb26570bd09000fe14aaa7ed6f..1921ccbb6d12fb3cefd3313205f84b3b93383adf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-meta.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-meta.hh
@@ -188,7 +188,7 @@ template <> struct hb_int_max<signed long long>		: hb_integral_constant<signed l
 template <> struct hb_int_max<unsigned long long>	: hb_integral_constant<unsigned long long,	ULLONG_MAX>	{};
 #define hb_int_max(T) hb_int_max<T>::value
 
-#if defined(__GNUC__) && __GNUC__ < 5
+#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
 #define hb_is_trivially_copyable(T) __has_trivial_copy(T)
 #define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T)
 #define hb_is_trivially_constructible(T) __has_trivial_constructor(T)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-null.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-null.hh
index 78eb6474d577e08b527b6fc05cd9dccd36eee527..0d7f4da79e7b1d1216dc3dfa38e63570b7c03b20 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-null.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-null.hh
@@ -39,6 +39,24 @@
 
 #define HB_NULL_POOL_SIZE 448
 
+template <typename T, typename>
+struct _hb_has_min_size : hb_false_type {};
+template <typename T>
+struct _hb_has_min_size<T, hb_void_t<decltype (T::min_size)>>
+	: hb_true_type {};
+template <typename T>
+using hb_has_min_size = _hb_has_min_size<T, void>;
+#define hb_has_min_size(T) hb_has_min_size<T>::value
+
+template <typename T, typename>
+struct _hb_has_null_size : hb_false_type {};
+template <typename T>
+struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>>
+	: hb_true_type {};
+template <typename T>
+using hb_has_null_size = _hb_has_null_size<T, void>;
+#define hb_has_null_size(T) hb_has_null_size<T>::value
+
 /* Use SFINAE to sniff whether T has min_size; in which case return the larger
  * of sizeof(T) and T::null_size, otherwise return sizeof(T).
  *
@@ -117,8 +135,19 @@ struct NullHelper
 	}; \
 	namespace Namespace { \
 	static_assert (true, "") /* Require semicolon after. */
+#define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \
+	} /* Close namespace. */ \
+	extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \
+	template <typename Spec> \
+	struct Null<Namespace::Type<Spec>> { \
+	  static Namespace::Type<Spec> const & get_null () { \
+	    return *reinterpret_cast<const Namespace::Type<Spec> *> (_hb_Null_##Namespace##_##Type); \
+	  } \
+	}; \
+	namespace Namespace { \
+	static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-	const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]
+	const unsigned char _hb_Null_##Namespace##_##Type[sizeof (_hb_Null_##Namespace##_##Type)]
 
 /* Specializations for arbitrary-content Null objects expressed as struct initializer. */
 #define DECLARE_NULL_INSTANCE(Type) \
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-number-parser.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-number-parser.hh
index 1a9dbba6dd3dc9766ff134c5bc53512a38d6affa..ec68c3a7281a0059ef88260bd0164c3e1084f29b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-number-parser.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-number-parser.hh
@@ -31,7 +31,7 @@
 #include "hb.hh"
 
 
-#line 35 "hb-number-parser.hh"
+#line 32 "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
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 
   int cs;
   
-#line 139 "hb-number-parser.hh"
+#line 132 "hb-number-parser.hh"
 	{
 	cs = double_parser_start;
 	}
 
-#line 144 "hb-number-parser.hh"
+#line 135 "hb-number-parser.hh"
 	{
 	int _slen;
 	int _trans;
@@ -198,7 +198,7 @@ _resume:
 	  exp_overflow = true;
 }
 	break;
-#line 202 "hb-number-parser.hh"
+#line 187 "hb-number-parser.hh"
 	}
 
 _again:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
index 4b5bc32ade7e499947d5427b45f942a90217a832..f6c7a569914d27fa9871d5e1a12abfd1b31c889f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
@@ -222,8 +222,11 @@ static inline Type *hb_object_create ()
   if (unlikely (!obj))
     return obj;
 
+  new (obj) Type;
+
   hb_object_init (obj);
   hb_object_trace (obj, HB_FUNC);
+
   return obj;
 }
 template <typename Type>
@@ -269,6 +272,9 @@ static inline bool hb_object_destroy (Type *obj)
     return false;
 
   hb_object_fini (obj);
+
+  obj->~Type ();
+
   return true;
 }
 template <typename Type>
@@ -280,7 +286,7 @@ static inline void hb_object_fini (Type *obj)
   {
     user_data->fini ();
     hb_free (user_data);
-    user_data = nullptr;
+    obj->header.user_data.set_relaxed (nullptr);
   }
 }
 template <typename Type>
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
index aee7064be3ee905333e78b90b8135c7dfc62a804..d0d01a68c52216a0911486768cccdcbc74762dc7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-open-type.hh
@@ -105,7 +105,7 @@ struct IntType
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
   protected:
   BEInt<Type, Size> v;
@@ -170,7 +170,7 @@ struct LONGDATETIME
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
   protected:
   HBINT32 major;
@@ -196,6 +196,10 @@ struct HBGlyphID16 : HBUINT16
 {
   HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
+struct HBGlyphID24 : HBUINT24
+{
+  HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
@@ -300,6 +304,10 @@ struct _hb_has_null<Type, true>
 template <typename Type, typename OffsetType, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
+  // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
+  static_assert (has_null == false ||
+		 (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
+
   HB_DELETE_COPY_ASSIGN (OffsetTo);
   OffsetTo () = default;
 
@@ -450,14 +458,16 @@ struct UnsizedArrayOf
   {
     unsigned int i = (unsigned int) i_;
     const Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return *p;
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return *p;
   }
 
@@ -550,14 +560,16 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
   {
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
-    if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return this+*p;
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
-    if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return this+*p;
   }
 
@@ -608,12 +620,14 @@ struct ArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
 
@@ -729,6 +743,7 @@ struct ArrayOf
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
@@ -738,26 +753,28 @@ template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUI
 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
-template <typename Type>
-struct List16OfOffset16To : Array16OfOffset16To<Type>
+template <typename Type, typename OffsetType>
+struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
 {
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
   const Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
+    struct List16OfOffsetTo *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
@@ -769,10 +786,13 @@ struct List16OfOffset16To : Array16OfOffset16To<Type>
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
+    return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
   }
 };
 
+template <typename Type>
+using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
+
 /* An array starting at second element. */
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
@@ -785,12 +805,14 @@ struct HeadlessArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   unsigned int get_size () const
@@ -869,12 +891,14 @@ struct ArrayOfM1
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   unsigned int get_size () const
@@ -961,6 +985,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
 };
 
 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
 
 /*
@@ -1053,12 +1078,14 @@ struct VarSizedBinSearchArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   unsigned int get_length () const
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh
index dac755c02ca8ca75e045eb9fa4b9ea056136919e..f01d383bdcd809cc978ad437dcdf1fb13349156a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh
@@ -145,7 +145,7 @@ struct BaseGlyphRecord
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:
@@ -524,6 +524,7 @@ struct PaintSweepGradient
 };
 
 struct Paint;
+
 // Paint a non-COLR glyph, filled as indicated by paint.
 struct PaintGlyph
 {
@@ -1152,6 +1153,8 @@ struct Paint
   Variable<PaintSkewAroundCenter>		paintformat31;
   PaintComposite				paintformat32;
   } u;
+  public:
+  DEFINE_SIZE_MIN (2);
 };
 
 struct BaseGlyphPaintRecord
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
index 16077765bdd66a632ed14bb96c39aae7bbeb7ed6..a9ae01368244a2f23c43f9924441fb2db3c1499d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.cc
@@ -61,7 +61,7 @@
  *
  * Tests whether a face includes a `CPAL` color-palette table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
@@ -192,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t     *face,
  *
  * 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
  */
@@ -239,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
  *
  * Tests whether a face includes any `SVG` glyph images.
  *
- * Return value: %true if data found, %false otherwise.
+ * Return value: `true` if data found, `false` otherwise.
  *
  * Since: 2.1.0
  */
@@ -279,7 +279,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
  *
  * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.h
index c23ce4de44f3f9a29f9ec17de1044f07d3ad15db..d11e07e2309ad0f23edd6b906e54bbd04f487733 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color.h
@@ -102,6 +102,10 @@ hb_ot_color_has_layers (hb_face_t *face);
  *
  * Pairs of glyph and color index.
  *
+ * A color index of 0xFFFF does not refer to a palette
+ * color, but indicates that the foreground color should
+ * be used.
+ *
  * Since: 2.1.0
  **/
 typedef struct hb_ot_color_layer_t {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
index af1bc86d4886069aae2a6ebeec2063301e139a5d..3f13b9994a63e53f3be0c09c5967e7a863c9ce9e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
@@ -151,7 +151,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
 #ifndef HB_NO_VAR
-  const OT::HVARVVAR &HVAR = *hmtx.var_table;
+  const OT::HVAR &HVAR = *hmtx.var_table;
   const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
   OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
 
@@ -190,7 +190,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   {
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, varStore_cache));
+      *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -211,7 +211,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
 	v = cv;
       else
       {
-        v = hmtx.get_advance (*first_glyph, font, varStore_cache);
+        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
 	ot_font->advance_cache->set (*first_glyph, v);
       }
       *first_advance = font->em_scale_x (v);
@@ -242,7 +242,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
   if (vmtx.has_data ())
   {
 #ifndef HB_NO_VAR
-    const OT::HVARVVAR &VVAR = *vmtx.var_table;
+    const OT::VVAR &VVAR = *vmtx.var_table;
     const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
     OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
 #else
@@ -251,7 +251,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
 
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, varStore_cache));
+      *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -293,17 +293,28 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
   const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
-    *y = font->em_scale_y (VORG.get_y_origin (glyph));
+    float delta = 0;
+
+#ifndef HB_NO_VAR
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+    const OT::VVAR &VVAR = *vmtx.var_table;
+    if (font->num_coords)
+      VVAR.get_vorg_delta_unscaled (glyph,
+				    font->coords, font->num_coords,
+				    &delta);
+#endif
+
+    *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
     return true;
   }
 
   hb_glyph_extents_t extents = {0};
   if (ot_face->glyf->get_extents (font, glyph, &extents))
   {
-    if (ot_face->vmtx->has_data ())
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+    int tsb = 0;
+    if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
     {
-      const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-      hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
       *y = extents.y_bearing + font->em_scale_y (tsb);
       return true;
     }
@@ -503,16 +514,17 @@ hb_ot_font_set_funcs (hb_font_t *font)
 }
 
 #ifndef HB_NO_VAR
-int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
+					     int *lsb)
 {
-  return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
+  return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
 }
 
 unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
 {
-  return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+  return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
 }
 #endif
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh
index d0e46e0b0fcf045458662a618e282a0719b0ec4b..50e4b54fded245a9769772960760dba55474cd0f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh
@@ -43,11 +43,11 @@
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
-HB_INTERNAL int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+HB_INTERNAL bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
 
 HB_INTERNAL unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
 
 
 namespace OT {
@@ -62,7 +62,7 @@ struct LongMetric
 };
 
 
-template <typename T, typename H>
+template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
 struct hmtxvmtx
 {
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
@@ -135,9 +135,9 @@ struct hmtxvmtx
       auto& plan = c->plan;
       num_long_metrics = plan->num_output_glyphs ();
       hb_codepoint_t old_gid = 0;
-      unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
+      unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0;
       while (num_long_metrics > 1 &&
-	     last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
+	     last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0))
       {
 	num_long_metrics--;
       }
@@ -150,7 +150,9 @@ struct hmtxvmtx
 		hb_codepoint_t old_gid;
 		if (!c->plan->old_gid_for_new_gid (_, &old_gid))
 		  return hb_pair (0u, 0);
-		return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+		int lsb = 0;
+		(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
+		return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
 	      })
     ;
 
@@ -173,7 +175,7 @@ struct hmtxvmtx
     accelerator_t (hb_face_t *face)
     {
       table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
-      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
 
       default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
 
@@ -221,36 +223,46 @@ struct hmtxvmtx
 
     bool has_data () const { return (bool) num_bearings; }
 
-    int get_side_bearing (hb_codepoint_t glyph) const
+    bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
+						   int *lsb) const
     {
       if (glyph < num_long_metrics)
-	return table->longMetricZ[glyph].sb;
+      {
+	*lsb = table->longMetricZ[glyph].sb;
+	return true;
+      }
 
       if (unlikely (glyph >= num_bearings))
-	return 0;
+	return false;
 
       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
-      return bearings[glyph - num_long_metrics];
+      *lsb = bearings[glyph - num_long_metrics];
+      return true;
     }
 
-    int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+    bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
+						hb_codepoint_t glyph,
+						int *lsb) const
     {
-      int side_bearing = get_side_bearing (glyph);
+      if (!font->num_coords)
+	return get_leading_bearing_without_var_unscaled (glyph, lsb);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_bearings) || !font->num_coords)
-	return side_bearing;
-
-      if (var_table.get_length ())
-	return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords);
+      float delta;
+      if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
+	  get_leading_bearing_without_var_unscaled (glyph, lsb))
+      {
+	*lsb += roundf (delta);
+	return true;
+      }
 
-      return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
 #else
-      return side_bearing;
+      return false;
 #endif
     }
 
-    unsigned int get_advance (hb_codepoint_t glyph) const
+    unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
     {
       /* OpenType case. */
       if (glyph < num_bearings)
@@ -262,7 +274,7 @@ struct hmtxvmtx
       if (unlikely (!num_advances))
 	return default_advance;
 
-#ifdef HB_NO_BORING_EXPANSION
+#ifdef HB_NO_BEYOND_64K
       return 0;
 #endif
 
@@ -275,7 +287,7 @@ struct hmtxvmtx
       /* TODO Optimize */
 
       if (num_bearings == num_advances)
-        return get_advance (num_bearings - 1);
+        return get_advance_without_var_unscaled (num_bearings - 1);
 
       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
       const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
@@ -283,20 +295,22 @@ struct hmtxvmtx
       return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
     }
 
-    unsigned int get_advance (hb_codepoint_t  glyph,
-			      hb_font_t      *font,
-			      VariationStore::cache_t *store_cache = nullptr) const
+    unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
+					    hb_font_t      *font,
+					    VariationStore::cache_t *store_cache = nullptr) const
     {
-      unsigned int advance = get_advance (glyph);
+      unsigned int advance = get_advance_without_var_unscaled (glyph);
 
 #ifndef HB_NO_VAR
       if (unlikely (glyph >= num_bearings) || !font->num_coords)
 	return advance;
 
       if (var_table.get_length ())
-	return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?!
+	return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
+									font->coords, font->num_coords,
+									store_cache)); // TODO Optimize?!
 
-      return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
 #else
       return advance;
 #endif
@@ -313,7 +327,7 @@ struct hmtxvmtx
 
     public:
     hb_blob_ptr_t<hmtxvmtx> table;
-    hb_blob_ptr_t<HVARVVAR> var_table;
+    hb_blob_ptr_t<V> var_table;
   };
 
   protected:
@@ -346,12 +360,12 @@ struct hmtxvmtx
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };
 
-struct hmtx : hmtxvmtx<hmtx, hhea> {
+struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
   static constexpr bool is_horizontal = true;
 };
-struct vmtx : hmtxvmtx<vmtx, vhea> {
+struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
   static constexpr bool is_horizontal = false;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-base-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-base-table.hh
index 1b9dfcd3f54bf309d15a93acc58804c8114079d8..8179e5acd52e4fd8ba3a6f0f775b19fd9b78b2c9 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-base-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-base-table.hh
@@ -49,7 +49,7 @@ struct BaseCoordFormat1
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
index d3438053468e09b1791ff007b1d54fa16b8a1149..9a4157b21ffa462b4ace4e6b50f66b013a1dcfc7 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
@@ -35,6 +35,14 @@
 #include "hb-set.hh"
 #include "hb-bimap.hh"
 
+#include "OT/Layout/Common/Coverage.hh"
+#include "OT/Layout/types.hh"
+
+// TODO(garretrieger): cleanup these after migration.
+using OT::Layout::Common::Coverage;
+using OT::Layout::Common::RangeRecord;
+using OT::Layout::SmallTypes;
+using OT::Layout::MediumTypes;
 
 #ifndef HB_MAX_NESTING_LEVEL
 #define HB_MAX_NESTING_LEVEL	64
@@ -46,10 +54,10 @@
 /*
  * The maximum number of times a lookup can be applied during shaping.
  * Used to limit the number of iterations of the closure algorithm.
- * This must be larger than the number of times add_pause() is
+ * This must be larger than the number of times add_gsub_pause() is
  * called in a collect_features call of any shaper.
  */
-#define HB_CLOSURE_MAX_STAGES	32
+#define HB_CLOSURE_MAX_STAGES	12
 #endif
 
 #ifndef HB_MAX_SCRIPTS
@@ -79,14 +87,6 @@
 
 namespace OT {
 
-
-#define NOT_COVERED		((unsigned int) -1)
-
-
-template<typename Iterator>
-static inline void Coverage_serialize (hb_serialize_context_t *c,
-				       Iterator it);
-
 template<typename Iterator>
 static inline void ClassDef_serialize (hb_serialize_context_t *c,
 				       Iterator it);
@@ -377,6 +377,51 @@ HB_FUNCOBJ (serialize_math_record_array);
  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
  */
 
+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)
+    {
+      + 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 (as_array ());
+  }
+};
+
+
 struct Record_sanitize_closure_t {
   hb_tag_t tag;
   const void *list_base;
@@ -465,122 +510,405 @@ struct RecordListOf : RecordArrayOf<Type>
   }
 };
 
-struct Feature;
-
-struct RecordListOfFeature : RecordListOf<Feature>
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
+struct FeatureParamsSize
 {
-  bool subset (hb_subset_context_t *c,
-	       hb_subset_layout_context_t *l) const
+  bool sanitize (hb_sanitize_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);
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) 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);
+    /* This subtable has some "history", if you will.  Some earlier versions of
+     * Adobe tools calculated the offset of the FeatureParams subtable from the
+     * beginning of the FeatureList table!  Now, that is dealt with in the
+     * Feature implementation.  But we still need to be able to tell junk from
+     * real data.  Note: We don't check that the nameID actually exists.
+     *
+     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
+     *
+     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
+     * coming out soon, and that the makeotf program will build a font with a
+     * 'size' feature that is correct by the specification.
+     *
+     * The specification for this feature tag is in the "OpenType Layout Tag
+     * Registry". You can see a copy of this at:
+     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
+     *
+     * Here is one set of rules to determine if the 'size' feature is built
+     * correctly, or as by the older versions of MakeOTF. You may be able to do
+     * better.
+     *
+     * Assume that the offset to the size feature is according to specification,
+     * and make the following value checks. If it fails, assume the size
+     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
+     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
+     * offset from the beginning of the FeatureList table, rather than from the
+     * beginning of the 'size' Feature table.
+     *
+     * If "design size" == 0:
+     *     fails check
+     *
+     * Else if ("subfamily identifier" == 0 and
+     *     "range start" == 0 and
+     *     "range end" == 0 and
+     *     "range start" == 0 and
+     *     "menu name ID" == 0)
+     *     passes check: this is the format used when there is a design size
+     * specified, but there is no recommended size range.
+     *
+     * Else if ("design size" <  "range start" or
+     *     "design size" >   "range end" or
+     *     "range end" <= "range start" or
+     *     "menu name ID"  < 256 or
+     *     "menu name ID"  > 32767 or
+     *     menu name ID is not a name ID which is actually in the name table)
+     *     fails test
+     * Else
+     *     passes test.
+     */
+
+    if (!designSize)
+      return_trace (false);
+    else if (subfamilyID == 0 &&
+	     subfamilyNameID == 0 &&
+	     rangeStart == 0 &&
+	     rangeEnd == 0)
+      return_trace (true);
+    else if (designSize < rangeStart ||
+	     designSize > rangeEnd ||
+	     subfamilyNameID < 256 ||
+	     subfamilyNameID > 32767)
+      return_trace (false);
+    else
+      return_trace (true);
   }
-};
 
-struct Script;
-struct RecordListOfScript : RecordListOf<Script>
-{
-  bool subset (hb_subset_context_t *c,
-               hb_subset_layout_context_t *l) const
+  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);
-
-    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);
+    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
+				 * size but no recommended size range, the
+				 * rest of the array will consist of zeros. */
+  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
+				 * as an identifier that associates fonts
+				 * in a subfamily. All fonts which share a
+				 * Preferred or Font Family name and which
+				 * differ only by size range shall have the
+				 * same subfamily value, and no fonts which
+				 * differ in weight or style shall have the
+				 * same subfamily value. If this value is
+				 * zero, the remaining fields in the array
+				 * will be ignored. */
+  NameID	subfamilyNameID;/* If the preceding value is non-zero, this
+				 * value must be set in the range 256 - 32767
+				 * (inclusive). It records the value of a
+				 * field in the name table, which must
+				 * contain English-language strings encoded
+				 * in Windows Unicode and Macintosh Roman,
+				 * and may contain additional strings
+				 * localized to other scripts and languages.
+				 * Each of these strings is the name an
+				 * application should use, in combination
+				 * with the family name, to represent the
+				 * subfamily in a menu.  Applications will
+				 * choose the appropriate version based on
+				 * their selection criteria. */
+  HBUINT16	rangeStart;	/* Large end of the recommended usage range
+				 * (inclusive), stored in 720/inch units
+				 * (decipoints). */
+  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
+				   (exclusive), stored in 720/inch units
+				 * (decipoints). */
+  public:
+  DEFINE_SIZE_STATIC (10);
 };
 
-struct RangeRecord
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
+struct FeatureParamsStylisticSet
 {
-  int cmp (hb_codepoint_t g) const
-  { return g < first ? -1 : g <= last ? 0 : +1; }
-
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
+    /* Right now minorVersion is at zero.  Which means, any table supports
+     * the uiNameID field. */
     return_trace (c->check_struct (this));
   }
 
-  bool intersects (const hb_set_t *glyphs) const
-  { return glyphs->intersects (first, last); }
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
 
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  { return glyphs->add_range (first, last); }
+  HBUINT16	version;	/* (set to 0): This corresponds to a “minor”
+				 * version number. Additional data may be
+				 * added to the end of this Feature Parameters
+				 * table in the future. */
 
-  HBGlyphID16	first;		/* First GlyphID in the range */
-  HBGlyphID16	last;		/* Last GlyphID in the range */
-  HBUINT16	value;		/* Value */
+  NameID	uiNameID;	/* The 'name' table name ID that specifies a
+				 * string (or strings, for multiple languages)
+				 * for a user-interface label for this
+				 * feature.  The values of uiLabelNameId and
+				 * sampleTextNameId are expected to be in the
+				 * font-specific name ID range (256-32767),
+				 * though that is not a requirement in this
+				 * Feature Parameters specification. The
+				 * user-interface label for the feature can
+				 * be provided in multiple languages. An
+				 * English string should be included as a
+				 * fallback. The string should be kept to a
+				 * minimal length to fit comfortably with
+				 * different application interfaces. */
   public:
-  DEFINE_SIZE_STATIC (6);
+  DEFINE_SIZE_STATIC (4);
 };
-DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
 
-
-struct IndexArray : Array16Of<Index>
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
+struct FeatureParamsCharacterVariants
 {
-  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)
+  unsigned
+  get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const
   {
-    if (!it) return;
-    if (unlikely (!c->extend_min ((*this)))) return;
-
-    for (const auto _ : it)
+    if (char_count)
     {
-      if (!l->visitLookupIndex()) break;
-
-      Index i;
-      i = _;
-      c->copy (i);
-      this->len++;
+      + characters.sub_array (start_offset, char_count)
+      | hb_sink (hb_array (chars, *char_count))
+      ;
     }
+    return characters.len;
   }
 
-  unsigned int get_indexes (unsigned int start_offset,
-			    unsigned int *_count /* IN/OUT */,
-			    unsigned int *_indexes /* OUT */) const
+  unsigned get_size () const
+  { return min_size + characters.len * HBUINT24::static_size; }
+
+  bool subset (hb_subset_context_t *c) const
   {
-    if (_count)
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  characters.sanitize (c));
+  }
+
+  HBUINT16	format;			/* Format number is set to 0. */
+  NameID	featUILableNameID;	/* The ‘name’ table name ID that
+					 * specifies a string (or strings,
+					 * for multiple languages) for a
+					 * user-interface label for this
+					 * feature. (May be NULL.) */
+  NameID	featUITooltipTextNameID;/* The ‘name’ table name ID that
+					 * specifies a string (or strings,
+					 * for multiple languages) that an
+					 * application can use for tooltip
+					 * text for this feature. (May be
+					 * nullptr.) */
+  NameID	sampleTextNameID;	/* The ‘name’ table name ID that
+					 * specifies sample text that
+					 * illustrates the effect of this
+					 * feature. (May be NULL.) */
+  HBUINT16	numNamedParameters;	/* Number of named parameters. (May
+					 * be zero.) */
+  NameID	firstParamUILabelNameID;/* 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.) */
+  Array16Of<HBUINT24>
+		characters;		/* Array of the Unicode Scalar Value
+					 * of the characters for which this
+					 * feature provides glyph variants.
+					 * (May be zero.) */
+  public:
+  DEFINE_SIZE_ARRAY (14, characters);
+};
+
+struct FeatureParams
+{
+  bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+  {
+#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
+    return true;
+#endif
+    TRACE_SANITIZE (this);
+    if (tag == HB_TAG ('s','i','z','e'))
+      return_trace (u.size.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return_trace (u.stylisticSet.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return_trace (u.characterVariants.sanitize (c));
+    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
+  {
+    if (tag == HB_TAG ('s','i','z','e'))
+      return u.size;
+    return Null (FeatureParamsSize);
+  }
+  const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
+  {
+    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return u.stylisticSet;
+    return Null (FeatureParamsStylisticSet);
+  }
+  const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
+  {
+    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return u.characterVariants;
+    return Null (FeatureParamsCharacterVariants);
+  }
+#endif
+
+  private:
+  union {
+  FeatureParamsSize			size;
+  FeatureParamsStylisticSet		stylisticSet;
+  FeatureParamsCharacterVariants	characterVariants;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+};
+
+
+struct Feature
+{
+  unsigned int get_lookup_count () const
+  { return lookupIndex.len; }
+  hb_tag_t get_lookup_index (unsigned int i) const
+  { return lookupIndex[i]; }
+  unsigned int get_lookup_indexes (unsigned int start_index,
+				   unsigned int *lookup_count /* IN/OUT */,
+				   unsigned int *lookup_tags /* OUT */) const
+  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
+  void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
+  { lookupIndex.add_indexes_to (lookup_indexes); }
+
+  const FeatureParams &get_feature_params () const
+  { return this+featureParams; }
+
+  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->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);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c,
+		 const Record_sanitize_closure_t *closure = nullptr) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+      return_trace (false);
+
+    /* Some earlier versions of Adobe tools calculated the offset of the
+     * FeatureParams subtable from the beginning of the FeatureList table!
+     *
+     * If sanitizing "failed" for the FeatureParams subtable, try it with the
+     * alternative location.  We would know sanitize "failed" if old value
+     * of the offset was non-zero, but it's zeroed now.
+     *
+     * Only do this for the 'size' feature, since at the time of the faulty
+     * Adobe tools, only the 'size' feature had FeatureParams defined.
+     */
+
+    if (likely (featureParams.is_null ()))
+      return_trace (true);
+
+    unsigned int orig_offset = featureParams;
+    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+      return_trace (false);
+
+    if (featureParams == 0 && closure &&
+	closure->tag == HB_TAG ('s','i','z','e') &&
+	closure->list_base && closure->list_base < this)
     {
-      + this->sub_array (start_offset, _count)
-      | hb_sink (hb_array (_indexes, *_count))
-      ;
+      unsigned int new_offset_int = orig_offset -
+				    (((char *) this) - ((char *) closure->list_base));
+
+      Offset16To<FeatureParams> new_offset;
+      /* Check that it would not overflow. */
+      new_offset = new_offset_int;
+      if (new_offset == new_offset_int &&
+	  c->try_set (&featureParams, new_offset_int) &&
+	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+	return_trace (false);
     }
-    return this->len;
+
+    return_trace (true);
   }
 
-  void add_indexes_to (hb_set_t* output /* OUT */) const
+  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
+				 * if not required */
+  IndexArray	 lookupIndex;	/* Array of LookupList indices */
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
+};
+
+struct RecordListOfFeature : RecordListOf<Feature>
+{
+  bool subset (hb_subset_context_t *c,
+	       hb_subset_layout_context_t *l) const
   {
-    output->add_array (as_array ());
+    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);
   }
 };
 
+typedef RecordListOf<Feature> FeatureList;
+
 
 struct LangSys
 {
@@ -764,6 +1092,8 @@ struct Script
   {
     TRACE_SUBSET (this);
     if (!l->visitScript ()) return_trace (false);
+    if (tag && !c->plan->layout_scripts->has (*tag))
+      return false;
 
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
@@ -819,390 +1149,34 @@ struct Script
   DEFINE_SIZE_ARRAY_SIZED (4, langSys);
 };
 
+struct RecordListOfScript : RecordListOf<Script>
+{
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!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);
+  }
+};
+
 typedef RecordListOfScript ScriptList;
 
 
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
-struct FeatureParamsSize
-{
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return_trace (false);
-
-    /* This subtable has some "history", if you will.  Some earlier versions of
-     * Adobe tools calculated the offset of the FeatureParams subtable from the
-     * beginning of the FeatureList table!  Now, that is dealt with in the
-     * Feature implementation.  But we still need to be able to tell junk from
-     * real data.  Note: We don't check that the nameID actually exists.
-     *
-     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
-     *
-     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
-     * coming out soon, and that the makeotf program will build a font with a
-     * 'size' feature that is correct by the specification.
-     *
-     * The specification for this feature tag is in the "OpenType Layout Tag
-     * Registry". You can see a copy of this at:
-     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
-     *
-     * Here is one set of rules to determine if the 'size' feature is built
-     * correctly, or as by the older versions of MakeOTF. You may be able to do
-     * better.
-     *
-     * Assume that the offset to the size feature is according to specification,
-     * and make the following value checks. If it fails, assume the size
-     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
-     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
-     * offset from the beginning of the FeatureList table, rather than from the
-     * beginning of the 'size' Feature table.
-     *
-     * If "design size" == 0:
-     *     fails check
-     *
-     * Else if ("subfamily identifier" == 0 and
-     *     "range start" == 0 and
-     *     "range end" == 0 and
-     *     "range start" == 0 and
-     *     "menu name ID" == 0)
-     *     passes check: this is the format used when there is a design size
-     * specified, but there is no recommended size range.
-     *
-     * Else if ("design size" <  "range start" or
-     *     "design size" >   "range end" or
-     *     "range end" <= "range start" or
-     *     "menu name ID"  < 256 or
-     *     "menu name ID"  > 32767 or
-     *     menu name ID is not a name ID which is actually in the name table)
-     *     fails test
-     * Else
-     *     passes test.
-     */
-
-    if (!designSize)
-      return_trace (false);
-    else if (subfamilyID == 0 &&
-	     subfamilyNameID == 0 &&
-	     rangeStart == 0 &&
-	     rangeEnd == 0)
-      return_trace (true);
-    else if (designSize < rangeStart ||
-	     designSize > rangeEnd ||
-	     subfamilyNameID < 256 ||
-	     subfamilyNameID > 32767)
-      return_trace (false);
-    else
-      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
-				 * size but no recommended size range, the
-				 * rest of the array will consist of zeros. */
-  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
-				 * as an identifier that associates fonts
-				 * in a subfamily. All fonts which share a
-				 * Preferred or Font Family name and which
-				 * differ only by size range shall have the
-				 * same subfamily value, and no fonts which
-				 * differ in weight or style shall have the
-				 * same subfamily value. If this value is
-				 * zero, the remaining fields in the array
-				 * will be ignored. */
-  NameID	subfamilyNameID;/* If the preceding value is non-zero, this
-				 * value must be set in the range 256 - 32767
-				 * (inclusive). It records the value of a
-				 * field in the name table, which must
-				 * contain English-language strings encoded
-				 * in Windows Unicode and Macintosh Roman,
-				 * and may contain additional strings
-				 * localized to other scripts and languages.
-				 * Each of these strings is the name an
-				 * application should use, in combination
-				 * with the family name, to represent the
-				 * subfamily in a menu.  Applications will
-				 * choose the appropriate version based on
-				 * their selection criteria. */
-  HBUINT16	rangeStart;	/* Large end of the recommended usage range
-				 * (inclusive), stored in 720/inch units
-				 * (decipoints). */
-  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
-				   (exclusive), stored in 720/inch units
-				 * (decipoints). */
-  public:
-  DEFINE_SIZE_STATIC (10);
-};
-
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
-struct FeatureParamsStylisticSet
-{
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    /* Right now minorVersion is at zero.  Which means, any table supports
-     * the uiNameID field. */
-    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
-				 * table in the future. */
-
-  NameID	uiNameID;	/* The 'name' table name ID that specifies a
-				 * string (or strings, for multiple languages)
-				 * for a user-interface label for this
-				 * feature.  The values of uiLabelNameId and
-				 * sampleTextNameId are expected to be in the
-				 * font-specific name ID range (256-32767),
-				 * though that is not a requirement in this
-				 * Feature Parameters specification. The
-				 * user-interface label for the feature can
-				 * be provided in multiple languages. An
-				 * English string should be included as a
-				 * fallback. The string should be kept to a
-				 * minimal length to fit comfortably with
-				 * different application interfaces. */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-/* 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);
-    return_trace (c->check_struct (this) &&
-		  characters.sanitize (c));
-  }
-
-  HBUINT16	format;			/* Format number is set to 0. */
-  NameID	featUILableNameID;	/* The ‘name’ table name ID that
-					 * specifies a string (or strings,
-					 * for multiple languages) for a
-					 * user-interface label for this
-					 * feature. (May be NULL.) */
-  NameID	featUITooltipTextNameID;/* The ‘name’ table name ID that
-					 * specifies a string (or strings,
-					 * for multiple languages) that an
-					 * application can use for tooltip
-					 * text for this feature. (May be
-					 * nullptr.) */
-  NameID	sampleTextNameID;	/* The ‘name’ table name ID that
-					 * specifies sample text that
-					 * illustrates the effect of this
-					 * feature. (May be NULL.) */
-  HBUINT16	numNamedParameters;	/* Number of named parameters. (May
-					 * be zero.) */
-  NameID	firstParamUILabelNameID;/* 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.) */
-  Array16Of<HBUINT24>
-		characters;		/* Array of the Unicode Scalar Value
-					 * of the characters for which this
-					 * feature provides glyph variants.
-					 * (May be zero.) */
-  public:
-  DEFINE_SIZE_ARRAY (14, characters);
-};
-
-struct FeatureParams
-{
-  bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
-  {
-#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
-    return true;
-#endif
-    TRACE_SANITIZE (this);
-    if (tag == HB_TAG ('s','i','z','e'))
-      return_trace (u.size.sanitize (c));
-    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
-      return_trace (u.stylisticSet.sanitize (c));
-    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
-      return_trace (u.characterVariants.sanitize (c));
-    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
-  {
-    if (tag == HB_TAG ('s','i','z','e'))
-      return u.size;
-    return Null (FeatureParamsSize);
-  }
-  const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
-  {
-    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
-      return u.stylisticSet;
-    return Null (FeatureParamsStylisticSet);
-  }
-  const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
-  {
-    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
-      return u.characterVariants;
-    return Null (FeatureParamsCharacterVariants);
-  }
-#endif
-
-  private:
-  union {
-  FeatureParamsSize			size;
-  FeatureParamsStylisticSet		stylisticSet;
-  FeatureParamsCharacterVariants	characterVariants;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (0);
-};
-
-struct Feature
-{
-  unsigned int get_lookup_count () const
-  { return lookupIndex.len; }
-  hb_tag_t get_lookup_index (unsigned int i) const
-  { return lookupIndex[i]; }
-  unsigned int get_lookup_indexes (unsigned int start_index,
-				   unsigned int *lookup_count /* IN/OUT */,
-				   unsigned int *lookup_tags /* OUT */) const
-  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
-  void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
-  { lookupIndex.add_indexes_to (lookup_indexes); }
-
-  const FeatureParams &get_feature_params () const
-  { return this+featureParams; }
-
-  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->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);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c,
-		 const Record_sanitize_closure_t *closure = nullptr) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
-      return_trace (false);
-
-    /* Some earlier versions of Adobe tools calculated the offset of the
-     * FeatureParams subtable from the beginning of the FeatureList table!
-     *
-     * If sanitizing "failed" for the FeatureParams subtable, try it with the
-     * alternative location.  We would know sanitize "failed" if old value
-     * of the offset was non-zero, but it's zeroed now.
-     *
-     * Only do this for the 'size' feature, since at the time of the faulty
-     * Adobe tools, only the 'size' feature had FeatureParams defined.
-     */
-
-    if (likely (featureParams.is_null ()))
-      return_trace (true);
-
-    unsigned int orig_offset = featureParams;
-    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
-      return_trace (false);
-
-    if (featureParams == 0 && closure &&
-	closure->tag == HB_TAG ('s','i','z','e') &&
-	closure->list_base && closure->list_base < this)
-    {
-      unsigned int new_offset_int = orig_offset -
-				    (((char *) this) - ((char *) closure->list_base));
-
-      Offset16To<FeatureParams> new_offset;
-      /* Check that it would not overflow. */
-      new_offset = new_offset_int;
-      if (new_offset == new_offset_int &&
-	  c->try_set (&featureParams, new_offset_int) &&
-	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
-	return_trace (false);
-    }
-
-    return_trace (true);
-  }
-
-  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
-				 * if not required */
-  IndexArray	 lookupIndex;	/* Array of LookupList indices */
-  public:
-  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
-};
-
-typedef RecordListOf<Feature> FeatureList;
-
-
-struct LookupFlag : HBUINT16
+
+struct LookupFlag : HBUINT16
 {
   enum Flags {
     RightToLeft		= 0x0001u,
@@ -1249,629 +1223,166 @@ struct Lookup
     return (const char *) &markFilteringSet - (const char *) this;
   }
 
-  unsigned int get_type () const { return lookupType; }
-
-  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
-   * higher 16-bit is mark-filtering-set if the lookup uses one.
-   * Not to be confused with glyph_props which is very similar. */
-  uint32_t get_props () const
-  {
-    unsigned int flag = lookupFlag;
-    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
-    {
-      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
-      flag += (markFilteringSet << 16);
-    }
-    return flag;
-  }
-
-  template <typename TSubTable, typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    unsigned int lookup_type = get_type ();
-    TRACE_DISPATCH (this, lookup_type);
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...);
-      if (c->stop_sublookup_iteration (r))
-	return_trace (r);
-    }
-    return_trace (c->default_return_value ());
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-		  unsigned int lookup_type,
-		  uint32_t lookup_props,
-		  unsigned int num_subtables)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    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);
-      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
-      markFilteringSet = lookup_props >> 16;
-    }
-    return_trace (true);
-  }
-
-  template <typename TSubTable>
-  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->lookupType = lookupType;
-    out->lookupFlag = lookupFlag;
-
-    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))
-    ;
-
-    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>
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    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);
-      if (!markFilteringSet.sanitize (c)) return_trace (false);
-    }
-
-    if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
-      return_trace (false);
-
-    if (unlikely (get_type () == TSubTable::Extension && subtables && !c->get_edit_count ()))
-    {
-      /* The spec says all subtables of an Extension lookup should
-       * have the same type, which shall not be the Extension type
-       * itself (but we already checked for that).
-       * This is specially important if one has a reverse type!
-       *
-       * We only do this if sanitizer edit_count is zero.  Otherwise,
-       * some of the subtables might have become insane after they
-       * were sanity-checked by the edits of subsequent subtables.
-       * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
-       */
-      unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
-      for (unsigned int i = 1; i < subtables; i++)
-	if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
-	  return_trace (false);
-    }
-    return_trace (true);
-  }
-
-  private:
-  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
-  HBUINT16	lookupFlag;		/* Lookup qualifiers */
-  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
-					 * UseMarkFilteringSet of lookup flags is set. */
-  public:
-  DEFINE_SIZE_ARRAY (6, subTable);
-};
-
-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));
-  }
-};
-
-
-/*
- * Coverage Table
- */
-
-struct CoverageFormat1
-{
-  friend struct Coverage;
-
-  private:
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    unsigned int i;
-    glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
-    return i;
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (glyphArray.serialize (c, glyphs));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (glyphArray.sanitize (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    /* TODO Speed up, using hb_set_next() and bsearch()? */
-    for (const auto& g : glyphArray.as_array ())
-      if (glyphs->has (g))
-	return true;
-    return false;
-  }
-  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
-  { return glyphs->has (glyphArray[index]); }
-
-  void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
-  {
-    unsigned count = glyphArray.len;
-    for (unsigned i = 0; i < count; i++)
-      if (glyphs->has (glyphArray[i]))
-        intersect_glyphs->add (glyphArray[i]);
-  }
-
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  { return glyphs->add_sorted_array (glyphArray.as_array ()); }
-
-  public:
-  /* Older compilers need this to be public. */
-  struct iter_t
-  {
-    void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
-    void fini () {}
-    bool more () const { return i < c->glyphArray.len; }
-    void next () { i++; }
-    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
-    bool operator != (const iter_t& o) const
-    { return i != o.i; }
-    iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; }
-
-    private:
-    const struct CoverageFormat1 *c;
-    unsigned int i;
-  };
-  private:
-
-  protected:
-  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
-  SortedArray16Of<HBGlyphID16>
-		glyphArray;	/* Array of GlyphIDs--in numerical order */
-  public:
-  DEFINE_SIZE_ARRAY (4, glyphArray);
-};
-
-struct CoverageFormat2
-{
-  friend struct Coverage;
-
-  private:
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    const RangeRecord &range = rangeRecord.bsearch (glyph_id);
-    return likely (range.first <= range.last)
-	 ? (unsigned int) range.value + (glyph_id - range.first)
-	 : NOT_COVERED;
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-
-    /* TODO(iter) Write more efficiently? */
-
-    unsigned num_ranges = 0;
-    hb_codepoint_t last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-	num_ranges++;
-      last = g;
-    }
-
-    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
-    if (!num_ranges) return_trace (true);
-
-    unsigned count = 0;
-    unsigned range = (unsigned) -1;
-    last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-      {
-	range++;
-	rangeRecord[range].first = g;
-	rangeRecord[range].value = count;
-      }
-      rangeRecord[range].last = g;
-      last = g;
-      count++;
-    }
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (rangeRecord.sanitize (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return hb_any (+ hb_iter (rangeRecord.as_array ())
-		   | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (glyphs); }));
-  }
-  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
-  {
-    auto cmp = [] (const void *pk, const void *pr) -> int
-    {
-      unsigned index = * (const unsigned *) pk;
-      const RangeRecord &range = * (const RangeRecord *) pr;
-      if (index < range.value) return -1;
-      if (index > (unsigned int) range.value + (range.last - range.first)) return +1;
-      return 0;
-    };
-
-    auto arr = rangeRecord.as_array ();
-    unsigned idx;
-    if (hb_bsearch_impl (&idx, index,
-			 arr.arrayZ, arr.length, sizeof (arr[0]),
-			 (int (*)(const void *_key, const void *_item)) cmp))
-      return arr.arrayZ[idx].intersects (glyphs);
-    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;
-      unsigned last = range.last;
-      for (hb_codepoint_t g = range.first - 1;
-	   glyphs->next (&g) && g <= last;)
-        intersect_glyphs->add (g);
-    }
-  }
-
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  {
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
-	return false;
-    return true;
-  }
+  unsigned int get_type () const { return lookupType; }
 
-  public:
-  /* Older compilers need this to be public. */
-  struct iter_t
+  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
+   * higher 16-bit is mark-filtering-set if the lookup uses one.
+   * Not to be confused with glyph_props which is very similar. */
+  uint32_t get_props () const
   {
-    void init (const CoverageFormat2 &c_)
-    {
-      c = &c_;
-      coverage = 0;
-      i = 0;
-      j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
-      if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
-      {
-	/* Broken table. Skip. */
-	i = c->rangeRecord.len;
-      }
-    }
-    void fini () {}
-    bool more () const { return i < c->rangeRecord.len; }
-    void next ()
-    {
-      if (j >= c->rangeRecord[i].last)
-      {
-	i++;
-	if (more ())
-	{
-	  unsigned int old = coverage;
-	  j = c->rangeRecord[i].first;
-	  coverage = c->rangeRecord[i].value;
-	  if (unlikely (coverage != old + 1))
-	  {
-	    /* Broken table. Skip. Important to avoid DoS.
-	     * Also, our callers depend on coverage being
-	     * consecutive and monotonically increasing,
-	     * ie. iota(). */
-	   i = c->rangeRecord.len;
-	   return;
-	  }
-	}
-	else
-	  j = 0;
-	return;
-      }
-      coverage++;
-      j++;
-    }
-    hb_codepoint_t get_glyph () const { return j; }
-    bool operator != (const iter_t& o) const
-    { return i != o.i || j != o.j; }
-    iter_t __end__ () const
+    unsigned int flag = lookupFlag;
+    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
     {
-      iter_t it;
-      it.init (*c);
-      it.i = c->rangeRecord.len;
-      it.j = 0;
-      return it;
+      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
+      flag += (markFilteringSet << 16);
     }
+    return flag;
+  }
 
-    private:
-    const struct CoverageFormat2 *c;
-    unsigned int i, coverage;
-    hb_codepoint_t j;
-  };
-  private:
-
-  protected:
-  HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
-  SortedArray16Of<RangeRecord>
-		rangeRecord;	/* Array of glyph ranges--ordered by
-				 * Start GlyphID. rangeCount entries
-				 * long */
-  public:
-  DEFINE_SIZE_ARRAY (4, rangeRecord);
-};
-
-struct Coverage
-{
-  /* Has interface. */
-  static constexpr unsigned SENTINEL = NOT_COVERED;
-  typedef unsigned int value_t;
-  value_t operator [] (hb_codepoint_t k) const { return get (k); }
-  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
-  /* Predicate. */
-  bool operator () (hb_codepoint_t k) const { return has (k); }
-
-  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
-  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  template <typename TSubTable, typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage (glyph_id);
-    case 2: return u.format2.get_coverage (glyph_id);
-    default:return NOT_COVERED;
+    unsigned int lookup_type = get_type ();
+    TRACE_DISPATCH (this, lookup_type);
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...);
+      if (c->stop_sublookup_iteration (r))
+	return_trace (r);
     }
+    return_trace (c->default_return_value ());
   }
 
-  template <typename Iterator,
-      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  bool serialize (hb_serialize_context_t *c,
+		  unsigned int lookup_type,
+		  uint32_t lookup_props,
+		  unsigned int num_subtables)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (this))) return_trace (false);
-
-    unsigned count = 0;
-    unsigned num_ranges = 0;
-    hb_codepoint_t last = (hb_codepoint_t) -2;
-    for (auto g: glyphs)
-    {
-      if (last + 1 != g)
-	num_ranges++;
-      last = g;
-      count++;
-    }
-    u.format = count <= num_ranges * 3 ? 1 : 2;
-
-    switch (u.format)
+    lookupType = lookup_type;
+    lookupFlag = lookup_props & 0xFFFFu;
+    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-    case 1: return_trace (u.format1.serialize (c, glyphs));
-    case 2: return_trace (u.format2.serialize (c, glyphs));
-    default:return_trace (false);
+      if (unlikely (!c->extend (this))) return_trace (false);
+      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
+      markFilteringSet = lookup_props >> 16;
     }
+    return_trace (true);
   }
 
+  template <typename TSubTable>
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    auto it =
-    + iter ()
-    | hb_filter (c->plan->glyph_map_gsub)
-    | hb_map_retains_sorting (c->plan->glyph_map_gsub)
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    out->lookupType = lookupType;
+    out->lookupFlag = lookupFlag;
+
+    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))
     ;
 
-    // Cache the iterator result as it will be iterated multiple times
-    // by the serialize code below.
-    hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
-    Coverage_serialize (c->serializer, glyphs.iter ());
-    return_trace (bool (glyphs));
+    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>
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
-    switch (u.format)
-    {
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    default:return_trace (true);
-    }
-  }
+    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
 
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    switch (u.format)
-    {
-    case 1: return u.format1.intersects (glyphs);
-    case 2: return u.format2.intersects (glyphs);
-    default:return false;
-    }
-  }
-  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
-  {
-    switch (u.format)
+    unsigned subtables = get_subtable_count ();
+    if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
+
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-    case 1: return u.format1.intersects_coverage (glyphs, index);
-    case 2: return u.format2.intersects_coverage (glyphs, index);
-    default:return false;
+      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
+      if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
-  }
 
-  /* Might return false if array looks unsorted.
-   * Used for faster rejection of corrupt data. */
-  template <typename set_t>
-  bool collect_coverage (set_t *glyphs) const
-  {
-    switch (u.format)
+    if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
+      return_trace (false);
+
+    if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
     {
-    case 1: return u.format1.collect_coverage (glyphs);
-    case 2: return u.format2.collect_coverage (glyphs);
-    default:return false;
+      /* The spec says all subtables of an Extension lookup should
+       * have the same type, which shall not be the Extension type
+       * itself (but we already checked for that).
+       * This is specially important if one has a reverse type!
+       *
+       * We only do this if sanitizer edit_count is zero.  Otherwise,
+       * some of the subtables might have become insane after they
+       * were sanity-checked by the edits of subsequent subtables.
+       * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
+       */
+      unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
+      for (unsigned int i = 1; i < subtables; i++)
+	if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
+	  return_trace (false);
     }
+    return_trace (true);
   }
 
-  void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
+  private:
+  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
+  HBUINT16	lookupFlag;		/* Lookup qualifiers */
+  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
+					 * UseMarkFilteringSet of lookup flags is set. */
+  public:
+  DEFINE_SIZE_ARRAY (6, subTable);
+};
+
+template <typename Types>
+using LookupList = List16OfOffsetTo<Lookup, typename Types::HBUINT>;
+
+template <typename TLookup, typename OffsetType>
+struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
+{
+  bool subset (hb_subset_context_t        *c,
+	       hb_subset_layout_context_t *l) const
   {
-    switch (u.format)
-    {
-    case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs);
-    case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs);
-    default:return ;
-    }
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!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);
   }
 
-  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  bool sanitize (hb_sanitize_context_t *c) const
   {
-    static constexpr bool is_sorted_iterator = true;
-    iter_t (const Coverage &c_ = Null (Coverage))
-    {
-      memset (this, 0, sizeof (*this));
-      format = c_.u.format;
-      switch (format)
-      {
-      case 1: u.format1.init (c_.u.format1); return;
-      case 2: u.format2.init (c_.u.format2); return;
-      default:				     return;
-      }
-    }
-    bool __more__ () const
-    {
-      switch (format)
-      {
-      case 1: return u.format1.more ();
-      case 2: return u.format2.more ();
-      default:return false;
-      }
-    }
-    void __next__ ()
-    {
-      switch (format)
-      {
-      case 1: u.format1.next (); break;
-      case 2: u.format2.next (); break;
-      default:			 break;
-      }
-    }
-    typedef hb_codepoint_t __item_t__;
-    __item_t__ __item__ () const { return get_glyph (); }
-
-    hb_codepoint_t get_glyph () const
-    {
-      switch (format)
-      {
-      case 1: return u.format1.get_glyph ();
-      case 2: return u.format2.get_glyph ();
-      default:return 0;
-      }
-    }
-    bool operator != (const iter_t& o) const
-    {
-      if (unlikely (format != o.format)) return true;
-      switch (format)
-      {
-      case 1: return u.format1 != o.u.format1;
-      case 2: return u.format2 != o.u.format2;
-      default:return false;
-      }
-    }
-    iter_t __end__ () const
-    {
-      iter_t it = {};
-      it.format = format;
-      switch (format)
-      {
-      case 1: it.u.format1 = u.format1.__end__ (); break;
-      case 2: it.u.format2 = u.format2.__end__ (); break;
-      default: break;
-      }
-      return it;
-    }
+    TRACE_SANITIZE (this);
+    return_trace (List16OfOffset16To<TLookup>::sanitize (c, this));
+  }
+};
 
-    private:
-    unsigned int format;
-    union {
-    CoverageFormat2::iter_t	format2; /* Put this one first since it's larger; helps shut up compiler. */
-    CoverageFormat1::iter_t	format1;
-    } u;
-  };
-  iter_t iter () const { return iter_t (*this); }
 
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  CoverageFormat1	format1;
-  CoverageFormat2	format2;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
+/*
+ * Coverage Table
+ */
 
-template<typename Iterator>
-static inline void
-Coverage_serialize (hb_serialize_context_t *c,
-		    Iterator it)
-{ c->start_embed<Coverage> ()->serialize (c, it); }
 
 static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
 					  const hb_set_t &klasses,
@@ -1913,7 +1424,8 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
  * Class Definition Table
  */
 
-struct ClassDefFormat1
+template <typename Types>
+struct ClassDefFormat1_3
 {
   friend struct ClassDef;
 
@@ -1924,7 +1436,7 @@ struct ClassDefFormat1
   }
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
 		  Iterator it)
   {
@@ -2118,14 +1630,16 @@ struct ClassDefFormat1
 
   protected:
   HBUINT16	classFormat;	/* Format identifier--format = 1 */
-  HBGlyphID16	startGlyph;	/* First GlyphID of the classValueArray */
-  Array16Of<HBUINT16>
+  typename Types::HBGlyphID
+		 startGlyph;	/* First GlyphID of the classValueArray */
+  typename Types::template ArrayOf<HBUINT16>
 		classValue;	/* Array of Class Values--one per GlyphID */
   public:
-  DEFINE_SIZE_ARRAY (6, classValue);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, classValue);
 };
 
-struct ClassDefFormat2
+template <typename Types>
+struct ClassDefFormat2_4
 {
   friend struct ClassDef;
 
@@ -2136,7 +1650,7 @@ struct ClassDefFormat2
   }
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
 		  Iterator it)
   {
@@ -2154,12 +1668,12 @@ struct ClassDefFormat2
     hb_codepoint_t prev_gid = (*it).first;
     unsigned prev_klass = (*it).second;
 
-    RangeRecord range_rec;
+    RangeRecord<Types> range_rec;
     range_rec.first = prev_gid;
     range_rec.last = prev_gid;
     range_rec.value = prev_klass;
 
-    RangeRecord *record = c->copy (range_rec);
+    auto *record = c->copy (range_rec);
     if (unlikely (!record)) return_trace (false);
 
     for (const auto gid_klass_pair : + (++it))
@@ -2202,13 +1716,14 @@ struct ClassDefFormat2
     hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
     hb_set_t orig_klasses;
 
+    unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
     unsigned count = rangeRecord.len;
     for (unsigned i = 0; i < count; i++)
     {
       unsigned klass = rangeRecord[i].value;
       if (!klass) continue;
       hb_codepoint_t start = rangeRecord[i].first;
-      hb_codepoint_t end   = rangeRecord[i].last + 1;
+      hb_codepoint_t end   = hb_min (rangeRecord[i].last + 1, num_source_glyphs);
       for (hb_codepoint_t g = start; g < end; g++)
       {
         hb_codepoint_t new_gid = glyph_map[g];
@@ -2272,7 +1787,7 @@ struct ClassDefFormat2
     for (unsigned int i = 0; i < count; i++)
     {
       const auto& range = rangeRecord[i];
-      if (range.intersects (glyphs) && range.value)
+      if (range.intersects (*glyphs) && range.value)
 	return true;
     }
     return false;
@@ -2296,11 +1811,8 @@ struct ClassDefFormat2
 	return true;
       /* Fall through. */
     }
-    /* TODO Speed up, using set overlap first? */
-    /* TODO(iter) Rewrite as dagger. */
-    const RangeRecord *arr = rangeRecord.arrayZ;
-    for (unsigned int i = 0; i < count; i++)
-      if (arr[i].value == klass && arr[i].intersects (glyphs))
+    for (const auto &range : rangeRecord)
+      if (range.value == klass && range.intersects (*glyphs))
 	return true;
     return false;
   }
@@ -2374,18 +1886,18 @@ struct ClassDefFormat2
     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))
+    for (const auto& record : rangeRecord.iter ())
+      if (record.intersects (*glyphs))
         intersect_classes->add (record.value);
   }
 
   protected:
   HBUINT16	classFormat;	/* Format identifier--format = 2 */
-  SortedArray16Of<RangeRecord>
+  typename Types::template SortedArrayOf<RangeRecord<Types>>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
-  DEFINE_SIZE_ARRAY (4, rangeRecord);
+  DEFINE_SIZE_ARRAY (2 + Types::size, rangeRecord);
 };
 
 struct ClassDef
@@ -2404,12 +1916,16 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.get_class (glyph_id);
     case 2: return u.format2.get_class (glyph_id);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.get_class (glyph_id);
+    case 4: return u.format4.get_class (glyph_id);
+#endif
     default:return 0;
     }
   }
 
   template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
   {
     TRACE_SERIALIZE (this);
@@ -2418,10 +1934,11 @@ struct ClassDef
     auto it = + it_with_class_zero | hb_filter (hb_second);
 
     unsigned format = 2;
+    hb_codepoint_t glyph_max = 0;
     if (likely (it))
     {
       hb_codepoint_t glyph_min = (*it).first;
-      hb_codepoint_t glyph_max = glyph_min;
+      glyph_max = glyph_min;
 
       unsigned num_glyphs = 0;
       unsigned num_ranges = 1;
@@ -2446,12 +1963,22 @@ struct ClassDef
       if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
 	format = 1;
     }
+
+#ifndef HB_NO_BEYOND_64K
+    if (glyph_max > 0xFFFFu)
+      format += 2;
+#endif
+
     u.format = format;
 
     switch (u.format)
     {
     case 1: return_trace (u.format1.serialize (c, it));
     case 2: return_trace (u.format2.serialize (c, it));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.serialize (c, it));
+    case 4: return_trace (u.format4.serialize (c, it));
+#endif
     default:return_trace (false);
     }
   }
@@ -2466,6 +1993,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
     case 2: return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+    case 4: return_trace (u.format4.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+#endif
     default:return_trace (false);
     }
   }
@@ -2477,6 +2008,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return_trace (u.format1.sanitize (c));
     case 2: return_trace (u.format2.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+#endif
     default:return_trace (true);
     }
   }
@@ -2486,6 +2021,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.cost ();
     case 2: return u.format2.cost ();
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.cost ();
+    case 4: return u.format4.cost ();
+#endif
     default:return 0u;
     }
   }
@@ -2498,6 +2037,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.collect_coverage (glyphs);
     case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.collect_coverage (glyphs);
+    case 4: return u.format4.collect_coverage (glyphs);
+#endif
     default:return false;
     }
   }
@@ -2510,6 +2053,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.collect_class (glyphs, klass);
     case 2: return u.format2.collect_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.collect_class (glyphs, klass);
+    case 4: return u.format4.collect_class (glyphs, klass);
+#endif
     default:return false;
     }
   }
@@ -2519,6 +2066,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersects (glyphs);
     case 2: return u.format2.intersects (glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects (glyphs);
+    case 4: return u.format4.intersects (glyphs);
+#endif
     default:return false;
     }
   }
@@ -2527,6 +2078,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
     case 2: return u.format2.intersects_class (glyphs, klass);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersects_class (glyphs, klass);
+    case 4: return u.format4.intersects_class (glyphs, klass);
+#endif
     default:return false;
     }
   }
@@ -2536,6 +2091,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
     case 2: return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+    case 4: return u.format4.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+#endif
     default:return;
     }
   }
@@ -2545,6 +2104,10 @@ struct ClassDef
     switch (u.format) {
     case 1: return u.format1.intersected_classes (glyphs, intersect_classes);
     case 2: return u.format2.intersected_classes (glyphs, intersect_classes);
+#ifndef HB_NO_BEYOND_64K
+    case 3: return u.format3.intersected_classes (glyphs, intersect_classes);
+    case 4: return u.format4.intersected_classes (glyphs, intersect_classes);
+#endif
     default:return;
     }
   }
@@ -2552,9 +2115,13 @@ struct ClassDef
 
   protected:
   union {
-  HBUINT16		format;		/* Format identifier */
-  ClassDefFormat1	format1;
-  ClassDefFormat2	format2;
+  HBUINT16			format;		/* Format identifier */
+  ClassDefFormat1_3<SmallTypes>	format1;
+  ClassDefFormat2_4<SmallTypes>	format2;
+#ifndef HB_NO_BEYOND_64K
+  ClassDefFormat1_3<MediumTypes>format3;
+  ClassDefFormat2_4<MediumTypes>format4;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
@@ -2940,6 +2507,9 @@ struct VariationStore
 
   cache_t *create_cache () const
   {
+#ifdef HB_NO_VAR
+    return nullptr;
+#endif
     auto &r = this+regions;
     unsigned count = r.regionCount;
 
@@ -3000,6 +2570,10 @@ struct VariationStore
 		  const hb_array_t <hb_inc_bimap_t> &inner_maps)
   {
     TRACE_SERIALIZE (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
+
     if (unlikely (!c->extend_min (this))) return_trace (false);
 
     unsigned int set_count = 0;
@@ -3051,6 +2625,9 @@ struct VariationStore
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
+#ifdef HB_NO_VAR
+    return_trace (false);
+#endif
 
     VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
     if (unlikely (!varstore_prime)) return_trace (false);
@@ -3078,7 +2655,12 @@ struct VariationStore
   }
 
   unsigned int get_region_index_count (unsigned int major) const
-  { return (this+dataSets[major]).get_region_index_count (); }
+  {
+#ifdef HB_NO_VAR
+    return 0;
+#endif
+    return (this+dataSets[major]).get_region_index_count ();
+  }
 
   void get_region_scalars (unsigned int major,
 			   const int *coords, unsigned int coord_count,
@@ -3096,7 +2678,13 @@ struct VariationStore
 					       &scalars[0], num_scalars);
   }
 
-  unsigned int get_sub_table_count () const { return dataSets.len; }
+  unsigned int get_sub_table_count () const
+   {
+#ifdef HB_NO_VAR
+     return 0;
+#endif
+     return dataSets.len;
+   }
 
   protected:
   HBUINT16				format;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gdef-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gdef-table.hh
index 9d47bac2b9b866d76a521e51ac7f87032ca7d8a4..5bc26d91820e512ca807254014be4c07ac4c2d09 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gdef-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gdef-table.hh
@@ -510,6 +510,101 @@ struct MarkGlyphSets
  */
 
 
+template <typename Types>
+struct GDEFVersion1_2
+{
+  friend struct GDEF;
+
+  protected:
+  FixedVersion<>version;		/* Version of the GDEF table--currently
+					 * 0x00010003u */
+  typename Types::template OffsetTo<ClassDef>
+		glyphClassDef;		/* Offset to class definition table
+					 * for glyph type--from beginning of
+					 * GDEF header (may be Null) */
+  typename Types::template OffsetTo<AttachList>
+		attachList;		/* Offset to list of glyphs with
+					 * attachment points--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<LigCaretList>
+		ligCaretList;		/* Offset to list of positioning points
+					 * for ligature carets--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<ClassDef>
+		markAttachClassDef;	/* Offset to class definition table for
+					 * mark attachment type--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<MarkGlyphSets>
+		markGlyphSetsDef;	/* Offset to the table of mark set
+					 * definitions--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010002. */
+  Offset32To<VariationStore>
+		varStore;		/* Offset to the table of Item Variation
+					 * Store--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010003. */
+  public:
+  DEFINE_SIZE_MIN (4 + 4 * Types::size);
+
+  unsigned int get_size () const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  glyphClassDef.sanitize (c, this) &&
+		  attachList.sanitize (c, this) &&
+		  ligCaretList.sanitize (c, this) &&
+		  markAttachClassDef.sanitize (c, this) &&
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+
+    bool subset_markglyphsetsdef = false;
+    if (version.to_int () >= 0x00010002u)
+    {
+      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+    }
+
+    bool subset_varstore = false;
+    if (version.to_int () >= 0x00010003u)
+    {
+      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
+    }
+
+    if (subset_varstore)
+    {
+      out->version.minor = 3;
+    } else if (subset_markglyphsetsdef) {
+      out->version.minor = 2;
+    } else  {
+      out->version.minor = 0;
+    }
+
+    return_trace (subset_glyphclassdef || subset_attachlist ||
+		  subset_ligcaretlist || subset_markattachclassdef ||
+		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+		  (out->version.to_int () >= 0x00010003u && subset_varstore));
+  }
+};
+
 struct GDEF
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
@@ -522,42 +617,190 @@ struct GDEF
     ComponentGlyph	= 4
   };
 
-  bool has_data () const { return version.to_int (); }
-  bool has_glyph_classes () const { return glyphClassDef != 0; }
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset (c);
+#endif
+    default: return false;
+    }
+  }
+
+  bool has_glyph_classes () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.glyphClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.glyphClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_glyph_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.glyphClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.glyphClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.attachList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.attachList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const AttachList &get_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.attachList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.attachList;
+#endif
+    default: return Null(AttachList);
+    }
+  }
+  bool has_lig_carets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.ligCaretList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.ligCaretList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const LigCaretList &get_lig_caret_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.ligCaretList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.ligCaretList;
+#endif
+    default: return Null(LigCaretList);
+    }
+  }
+  bool has_mark_attachment_types () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.markAttachClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markAttachClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_mark_attach_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.markAttachClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markAttachClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markGlyphSetsDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const MarkGlyphSets &get_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markGlyphSetsDef;
+#endif
+    default: return Null(MarkGlyphSets);
+    }
+  }
+  bool has_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.varStore != 0;
+#endif
+    default: return false;
+    }
+  }
+  const VariationStore &get_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.varStore;
+#endif
+    default: return Null(VariationStore);
+    }
+  }
+
+
+  bool has_data () const { return u.version.to_int (); }
   unsigned int get_glyph_class (hb_codepoint_t glyph) const
-  { return (this+glyphClassDef).get_class (glyph); }
+  { return get_glyph_class_def ().get_class (glyph); }
   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
-  { (this+glyphClassDef).collect_class (glyphs, klass); }
+  { get_glyph_class_def ().collect_class (glyphs, klass); }
 
-  bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
-  { return (this+markAttachClassDef).get_class (glyph); }
+  { return get_mark_attach_class_def ().get_class (glyph); }
 
-  bool has_attach_points () const { return attachList != 0; }
   unsigned int get_attach_points (hb_codepoint_t glyph_id,
 				  unsigned int start_offset,
 				  unsigned int *point_count /* IN/OUT */,
 				  unsigned int *point_array /* OUT */) const
-  { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
+  { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
 
-  bool has_lig_carets () const { return ligCaretList != 0; }
   unsigned int get_lig_carets (hb_font_t *font,
 			       hb_direction_t direction,
 			       hb_codepoint_t glyph_id,
 			       unsigned int start_offset,
 			       unsigned int *caret_count /* IN/OUT */,
 			       hb_position_t *caret_array /* OUT */) const
-  { return (this+ligCaretList).get_lig_carets (font,
-					       direction, glyph_id, get_var_store(),
-					       start_offset, caret_count, caret_array); }
+  { return get_lig_caret_list ().get_lig_carets (font,
+						 direction, glyph_id, get_var_store(),
+						 start_offset, caret_count, caret_array); }
 
-  bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
   bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
-  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
-
-  bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
-  const VariationStore &get_var_store () const
-  { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
+  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
 
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
@@ -599,20 +842,13 @@ struct GDEF
     hb_blob_ptr_t<GDEF> table;
   };
 
-  unsigned int get_size () const
-  {
-    return min_size +
-	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
-	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
-  }
-
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  { (this+ligCaretList).collect_variation_indices (c); }
+  { get_lig_caret_list ().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 (!has_var_store ()) return;
     if (layout_variation_indices->is_empty ()) return;
 
     unsigned new_major = 0, new_minor = 0;
@@ -620,7 +856,7 @@ struct GDEF
     for (unsigned idx : layout_variation_indices->iter ())
     {
       uint16_t major = idx >> 16;
-      if (major >= (this+varStore).get_sub_table_count ()) break;
+      if (major >= get_var_store ().get_sub_table_count ()) break;
       if (major != last_major)
       {
 	new_minor = 0;
@@ -634,84 +870,16 @@ struct GDEF
     }
   }
 
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
-    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
-    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
-    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
-    bool subset_markglyphsetsdef = true;
-    if (version.to_int () >= 0x00010002u)
-    {
-      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
-      if (!subset_markglyphsetsdef &&
-	  version.to_int () == 0x00010002u)
-	out->version.minor = 0;
-    }
-
-    bool subset_varstore = true;
-    if (version.to_int () >= 0x00010003u)
-    {
-      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
-      if (!subset_varstore && version.to_int () == 0x00010003u)
-	out->version.minor = 2;
-    }
-
-    return_trace (subset_glyphclassdef || subset_attachlist ||
-		  subset_ligcaretlist || subset_markattachclassdef ||
-		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
-		  (out->version.to_int () >= 0x00010003u && subset_varstore));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (version.sanitize (c) &&
-		  likely (version.major == 1) &&
-		  glyphClassDef.sanitize (c, this) &&
-		  attachList.sanitize (c, this) &&
-		  ligCaretList.sanitize (c, this) &&
-		  markAttachClassDef.sanitize (c, this) &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
-		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
-  }
-
   protected:
-  FixedVersion<>version;		/* Version of the GDEF table--currently
-					 * 0x00010003u */
-  Offset16To<ClassDef>
-		glyphClassDef;		/* Offset to class definition table
-					 * for glyph type--from beginning of
-					 * GDEF header (may be Null) */
-  Offset16To<AttachList>
-		attachList;		/* Offset to list of glyphs with
-					 * attachment points--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<LigCaretList>
-		ligCaretList;		/* Offset to list of positioning points
-					 * for ligature carets--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<ClassDef>
-		markAttachClassDef;	/* Offset to class definition table for
-					 * mark attachment type--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<MarkGlyphSets>
-		markGlyphSetsDef;	/* Offset to the table of mark set
-					 * definitions--from beginning of GDEF
-					 * header (may be NULL).  Introduced
-					 * in version 0x00010002. */
-  Offset32To<VariationStore>
-		varStore;		/* Offset to the table of Item Variation
-					 * Store--from beginning of GDEF
-					 * header (may be NULL).  Introduced
-					 * in version 0x00010003. */
+  union {
+  FixedVersion<>		version;	/* Version identifier */
+  GDEFVersion1_2<SmallTypes>	version1;
+#ifndef HB_NO_BEYOND_64K
+  GDEFVersion1_2<MediumTypes>	version2;
+#endif
+  } u;
   public:
-  DEFINE_SIZE_MIN (12);
+  DEFINE_SIZE_MIN (4);
 };
 
 struct GDEF_accelerator_t : GDEF::accelerator_t {
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
index 59795cbba3ef4631a72c0af28be0b0d0cf826cb6..8fe987fc509cfeefbfe02ba07b0787fdfeea7782 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
@@ -29,12 +29,9 @@
 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
 #define HB_OT_LAYOUT_GPOS_TABLE_HH
 
-#include "OT/Layout/GPOS.hh"
+#include "OT/Layout/GPOS/GPOS.hh"
 
 namespace OT {
-
-using Layout::GPOS_impl::PosLookup;
-
 namespace Layout {
 namespace GPOS_impl {
 
@@ -75,4 +72,5 @@ inline bool PosLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply
 } /* namespace Layout */
 } /* namespace OT */
 
+
 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh
index 9e7f40c07bfa69936a42b63dbf9900b374ad9263..50301ff1d93d81d211ce18e0d2c5645282192c1d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh
@@ -32,12 +32,8 @@
 #include "OT/Layout/GSUB/GSUB.hh"
 
 namespace OT {
-
-using Layout::GSUB::SubstLookup;
-using Layout::GSUB::ExtensionSubst;
-
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 // TODO(garretrieger): Move into the new layout directory.
 /* Out-of-class implementation for methods recursing */
@@ -85,8 +81,9 @@ inline bool SubstLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_app
 }
 #endif
 
-} /* namespace GSUB */
+} /* namespace GSUB_impl */
 } /* namespace Layout */
 } /* namespace OT */
 
+
 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
index 31da4986520807c0ce2c4b58553a97959fc0cdc6..5acd228b836b69a7de7e96011775c43363245fa6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
@@ -150,7 +150,7 @@ struct hb_closure_context_t :
 
   bool pop_cur_done_glyphs ()
   {
-    if (active_glyphs_stack.length < 1)
+    if (!active_glyphs_stack)
       return false;
 
     active_glyphs_stack.pop ();
@@ -409,7 +409,7 @@ struct hb_ot_apply_context_t :
 	     match_func (nullptr),
 	     match_data (nullptr) {}
 
-    typedef bool (*match_func_t) (hb_glyph_info_t &info, const HBUINT16 &value, const void *data);
+    typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
 
     void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
@@ -428,14 +428,14 @@ struct hb_ot_apply_context_t :
     };
 
     may_match_t may_match (hb_glyph_info_t &info,
-			   const HBUINT16        *glyph_data) const
+			   hb_codepoint_t glyph_data) const
     {
       if (!(info.mask & mask) ||
 	  (syllable && syllable != info.syllable ()))
 	return MATCH_NO;
 
       if (match_func)
-	return match_func (info, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+	return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
       return MATCH_MAYBE;
     }
@@ -476,7 +476,10 @@ struct hb_ot_apply_context_t :
     void init (hb_ot_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      match_glyph_data = nullptr;
+      match_glyph_data16 = nullptr;
+#ifndef HB_NO_BEYOND_64K
+      match_glyph_data24 = nullptr;
+#endif
       matcher.set_match_func (nullptr, nullptr);
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
@@ -491,12 +494,24 @@ struct hb_ot_apply_context_t :
       matcher.set_lookup_props (lookup_props);
     }
     void set_match_func (matcher_t::match_func_t match_func_,
-			 const void *match_data_,
-			 const HBUINT16 glyph_data[])
+			 const void *match_data_)
     {
       matcher.set_match_func (match_func_, match_data_);
-      match_glyph_data = glyph_data;
     }
+    void set_glyph_data (const HBUINT16 glyph_data[])
+    {
+      match_glyph_data16 = glyph_data;
+#ifndef HB_NO_BEYOND_64K
+      match_glyph_data24 = nullptr;
+#endif
+    }
+#ifndef HB_NO_BEYOND_64K
+    void set_glyph_data (const HBUINT24 glyph_data[])
+    {
+      match_glyph_data16 = nullptr;
+      match_glyph_data24 = glyph_data;
+    }
+#endif
 
     void reset (unsigned int start_index_,
 		unsigned int num_items_)
@@ -510,7 +525,7 @@ struct hb_ot_apply_context_t :
     void reject ()
     {
       num_items++;
-      if (match_glyph_data) match_glyph_data--;
+      backup_glyph_data ();
     }
 
     matcher_t::may_skip_t
@@ -529,13 +544,13 @@ struct hb_ot_apply_context_t :
 	if (unlikely (skip == matcher_t::SKIP_YES))
 	  continue;
 
-	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+	matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
 	if (match == matcher_t::MATCH_YES ||
 	    (match == matcher_t::MATCH_MAYBE &&
 	     skip == matcher_t::SKIP_NO))
 	{
 	  num_items--;
-	  if (match_glyph_data) match_glyph_data++;
+	  advance_glyph_data ();
 	  return true;
 	}
 
@@ -562,13 +577,13 @@ struct hb_ot_apply_context_t :
 	if (unlikely (skip == matcher_t::SKIP_YES))
 	  continue;
 
-	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+	matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
 	if (match == matcher_t::MATCH_YES ||
 	    (match == matcher_t::MATCH_MAYBE &&
 	     skip == matcher_t::SKIP_NO))
 	{
 	  num_items--;
-	  if (match_glyph_data) match_glyph_data++;
+	  advance_glyph_data ();
 	  return true;
 	}
 
@@ -584,11 +599,43 @@ struct hb_ot_apply_context_t :
       return false;
     }
 
+    hb_codepoint_t
+    get_glyph_data ()
+    {
+      if (match_glyph_data16) return *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) return *match_glyph_data24;
+#endif
+      return 0;
+    }
+    void
+    advance_glyph_data ()
+    {
+      if (match_glyph_data16) match_glyph_data16++;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) match_glyph_data24++;
+#endif
+    }
+    void
+    backup_glyph_data ()
+    {
+      if (match_glyph_data16) match_glyph_data16--;
+#ifndef HB_NO_BEYOND_64K
+      else
+      if (match_glyph_data24) match_glyph_data24--;
+#endif
+    }
+
     unsigned int idx;
     protected:
     hb_ot_apply_context_t *c;
     matcher_t matcher;
-    const HBUINT16 *match_glyph_data;
+    const HBUINT16 *match_glyph_data16;
+#ifndef HB_NO_BEYOND_64K
+    const HBUINT24 *match_glyph_data24;
+#endif
 
     unsigned int num_items;
     unsigned int end;
@@ -941,10 +988,10 @@ struct hb_accelerate_subtables_context_t :
 };
 
 
-typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned 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_glyph_info_t &info, const HBUINT16 &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
+typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
 
 struct ContextClosureFuncs
 {
@@ -965,18 +1012,19 @@ struct ChainContextApplyFuncs
 };
 
 
-static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  Offset16To<Coverage> coverage;
+  coverage = value;
   return (data+coverage).intersects (glyphs);
 }
 
@@ -995,60 +1043,63 @@ static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const vo
 {
   Offset16To<Coverage> coverage;
   coverage = value;
-  (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
+  (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
 }
 
 
+template <typename HBUINT>
 static inline bool array_is_subset_of (const hb_set_t *glyphs,
 				       unsigned int count,
-				       const HBUINT16 values[],
+				       const HBUINT values[],
 				       intersects_func_t intersects_func,
 				       const void *intersects_data)
 {
-  for (const HBUINT16 &_ : + hb_iter (values, count))
+  for (const auto &_ : + hb_iter (values, count))
     if (!intersects_func (glyphs, _, intersects_data)) return false;
   return true;
 }
 
 
-static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   class_def.collect_class (glyphs, value);
 }
-static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  Offset16To<Coverage> coverage;
+  coverage = value;
   (data+coverage).collect_coverage (glyphs);
 }
+template <typename HBUINT>
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 				  hb_set_t *glyphs,
 				  unsigned int count,
-				  const HBUINT16 values[],
+				  const HBUINT values[],
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
   return
   + hb_iter (values, count)
-  | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
+  | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
   ;
 }
 
 
-static inline bool match_glyph (hb_glyph_info_t &info, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
 {
   return info.codepoint == value;
 }
-static inline bool match_class (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
+static inline bool match_class (hb_glyph_info_t &info, unsigned value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (info.codepoint) == value;
 }
-static inline bool match_class_cached (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
+static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
 {
   unsigned klass = info.syllable();
   if (klass < 255)
@@ -1059,15 +1110,17 @@ static inline bool match_class_cached (hb_glyph_info_t &info, const HBUINT16 &va
     info.syllable() = klass;
   return klass == value;
 }
-static inline bool match_coverage (hb_glyph_info_t &info, const HBUINT16 &value, const void *data)
+static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
 {
-  const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
+  Offset16To<Coverage> coverage;
+  coverage = value;
   return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
 }
 
+template <typename HBUINT>
 static inline bool would_match_input (hb_would_apply_context_t *c,
 				      unsigned int count, /* Including the first glyph (not matched) */
-				      const HBUINT16 input[], /* Array of input values--start with second glyph */
+				      const HBUINT input[], /* Array of input values--start with second glyph */
 				      match_func_t match_func,
 				      const void *match_data)
 {
@@ -1084,9 +1137,10 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
 
   return true;
 }
+template <typename HBUINT>
 static inline bool match_input (hb_ot_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
-				const HBUINT16 input[], /* Array of input values--start with second glyph */
+				const HBUINT input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_position,
@@ -1101,7 +1155,8 @@ static inline bool match_input (hb_ot_apply_context_t *c,
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx, count - 1);
-  skippy_iter.set_match_func (match_func, match_data, input);
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (input);
 
   /*
    * This is perhaps the trickiest part of OpenType...  Remarks:
@@ -1322,9 +1377,10 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
   return_trace (true);
 }
 
+template <typename HBUINT>
 static inline bool match_backtrack (hb_ot_apply_context_t *c,
 				    unsigned int count,
-				    const HBUINT16 backtrack[],
+				    const HBUINT backtrack[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int *match_start)
@@ -1333,7 +1389,8 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len (), count);
-  skippy_iter.set_match_func (match_func, match_data, backtrack);
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (backtrack);
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -1349,9 +1406,10 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
   return_trace (true);
 }
 
+template <typename HBUINT>
 static inline bool match_lookahead (hb_ot_apply_context_t *c,
 				    unsigned int count,
-				    const HBUINT16 lookahead[],
+				    const HBUINT lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int start_index,
@@ -1361,7 +1419,8 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c,
 
   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (start_index - 1, count);
-  skippy_iter.set_match_func (match_func, match_data, lookahead);
+  skippy_iter.set_match_func (match_func, match_data);
+  skippy_iter.set_glyph_data (lookahead);
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -1425,8 +1484,9 @@ static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
 
 enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
 
+template <typename HBUINT>
 static void context_closure_recurse_lookups (hb_closure_context_t *c,
-					     unsigned inputCount, const HBUINT16 input[],
+					     unsigned inputCount, const HBUINT input[],
 					     unsigned lookupCount,
 					     const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
 					     unsigned value,
@@ -1645,9 +1705,10 @@ struct ContextApplyLookupContext
   const void *match_data;
 };
 
+template <typename HBUINT>
 static inline bool context_intersects (const hb_set_t *glyphs,
 				       unsigned int inputCount, /* Including the first glyph (not matched) */
-				       const HBUINT16 input[], /* Array of input values--start with second glyph */
+				       const HBUINT input[], /* Array of input values--start with second glyph */
 				       ContextClosureLookupContext &lookup_context)
 {
   return array_is_subset_of (glyphs,
@@ -1655,9 +1716,10 @@ static inline bool context_intersects (const hb_set_t *glyphs,
 			     lookup_context.funcs.intersects, lookup_context.intersects_data);
 }
 
+template <typename HBUINT>
 static inline void context_closure_lookup (hb_closure_context_t *c,
 					   unsigned int inputCount, /* Including the first glyph (not matched) */
-					   const HBUINT16 input[], /* Array of input values--start with second glyph */
+					   const HBUINT input[], /* Array of input values--start with second glyph */
 					   unsigned int lookupCount,
 					   const LookupRecord lookupRecord[],
 					   unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
@@ -1675,9 +1737,10 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
 				     lookup_context.funcs.intersected_glyphs);
 }
 
+template <typename HBUINT>
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						  unsigned int inputCount, /* Including the first glyph (not matched) */
-						  const HBUINT16 input[], /* Array of input values--start with second glyph */
+						  const HBUINT input[], /* Array of input values--start with second glyph */
 						  unsigned int lookupCount,
 						  const LookupRecord lookupRecord[],
 						  ContextCollectGlyphsLookupContext &lookup_context)
@@ -1689,9 +1752,10 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c
 		   lookupCount, lookupRecord);
 }
 
+template <typename HBUINT>
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const HBUINT16 input[], /* Array of input values--start with second glyph */
+					       const HBUINT input[], /* Array of input values--start with second glyph */
 					       unsigned int lookupCount HB_UNUSED,
 					       const LookupRecord lookupRecord[] HB_UNUSED,
 					       ContextApplyLookupContext &lookup_context)
@@ -1700,9 +1764,11 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data);
 }
+
+template <typename HBUINT>
 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
-					 const HBUINT16 input[], /* Array of input values--start with second glyph */
+					 const HBUINT input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
@@ -1728,6 +1794,7 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
   }
 }
 
+template <typename Types>
 struct Rule
 {
   bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
@@ -1741,8 +1808,8 @@ struct Rule
   {
     if (unlikely (c->lookup_limit_exceeded ())) return;
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
     context_closure_lookup (c,
 			    inputCount, inputZ.arrayZ,
 			    lookupCount, lookupRecord.arrayZ,
@@ -1755,16 +1822,16 @@ struct Rule
     if (unlikely (c->lookup_limit_exceeded ())) return;
     if (!intersects (c->glyphs, lookup_context)) return;
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 		       ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     context_collect_glyphs_lookup (c,
 				   inputCount, inputZ.arrayZ,
 				   lookupCount, lookupRecord.arrayZ,
@@ -1774,8 +1841,8 @@ struct Rule
   bool would_apply (hb_would_apply_context_t *c,
 		    ContextApplyLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     return context_would_apply_lookup (c,
 				       inputCount, inputZ.arrayZ,
 				       lookupCount, lookupRecord.arrayZ,
@@ -1786,8 +1853,8 @@ struct Rule
 	      ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
   }
 
@@ -1800,7 +1867,7 @@ struct Rule
     if (unlikely (!c->extend_min (out))) return_trace (false);
 
     out->inputCount = inputCount;
-    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    const auto input = inputZ.as_array (inputCount - 1);
     for (const auto org : input)
     {
       HBUINT16 d;
@@ -1808,8 +1875,8 @@ struct Rule
       c->copy (d);
     }
 
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
-						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+					   (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
 
     unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
     return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
@@ -1821,7 +1888,7 @@ struct Rule
   {
     TRACE_SUBSET (this);
     if (unlikely (!inputCount)) return_trace (false);
-    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    const auto input = inputZ.as_array (inputCount - 1);
 
     const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
     if (!hb_all (input, mapping)) return_trace (false);
@@ -1844,7 +1911,7 @@ struct Rule
 					 * glyph sequence--includes the first
 					 * glyph */
   HBUINT16	lookupCount;		/* Number of LookupRecords */
-  UnsizedArrayOf<HBUINT16>
+  UnsizedArrayOf<typename Types::HBUINT>
 		inputZ;			/* Array of match inputs--start with
 					 * second glyph */
 /*UnsizedArrayOf<LookupRecord>
@@ -1854,8 +1921,11 @@ struct Rule
   DEFINE_SIZE_ARRAY (4, inputZ);
 };
 
+template <typename Types>
 struct RuleSet
 {
+  using Rule = OT::Rule<Types>;
+
   bool intersects (const hb_set_t *glyphs,
 		   ContextClosureLookupContext &lookup_context) const
   {
@@ -1968,8 +2038,11 @@ struct RuleSet
 };
 
 
-struct ContextFormat1
+template <typename Types>
+struct ContextFormat1_4
 {
+  using RuleSet = OT::RuleSet<Types>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ContextClosureLookupContext lookup_context = {
@@ -1993,9 +2066,8 @@ struct ContextFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
-                                                 cur_active_glyphs);
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph, intersected_glyph},
@@ -2106,19 +2178,22 @@ struct ContextFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  Array16OfOffset16To<RuleSet>
+  Array16Of<typename Types::template OffsetTo<RuleSet>>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ruleSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
 };
 
 
-struct ContextFormat2
+template <typename Types>
+struct ContextFormat2_5
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverage).intersects (glyphs))
@@ -2133,7 +2208,7 @@ struct ContextFormat2
     };
 
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -2159,8 +2234,8 @@ struct ContextFormat2
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
                                                  cur_active_glyphs);
 
     const ClassDef &class_def = this+classDef;
@@ -2175,7 +2250,7 @@ struct ContextFormat2
     | hb_filter ([&] (unsigned _)
     { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
 		 hb_first)
-    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
                 {
                   const RuleSet& rule_set = this+_.second;
                   rule_set.closure (c, _.first, lookup_context);
@@ -2305,7 +2380,7 @@ struct ContextFormat2
 
     const hb_set_t* glyphset = c->plan->glyphset_gsub ();
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -2351,22 +2426,24 @@ struct ContextFormat2
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
 		classDef;		/* Offset to glyph ClassDef table--from
 					 * beginning of table */
-  Array16OfOffset16To<RuleSet>
+  Array16Of<typename Types::template OffsetTo<RuleSet>>
 		ruleSet;		/* Array of RuleSet tables
 					 * ordered by class */
   public:
-  DEFINE_SIZE_ARRAY (8, ruleSet);
+  DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
 };
 
 
 struct ContextFormat3
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverageZ[0]).intersects (glyphs))
@@ -2390,8 +2467,8 @@ struct ContextFormat3
     if (!(this+coverageZ[0]).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
                                                  cur_active_glyphs);
 
 
@@ -2483,7 +2560,7 @@ struct ContextFormat3
       if (!o->serialize_subset (c, offset, this)) return_trace (false);
     }
 
-    const UnsizedArrayOf<LookupRecord>& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
+    const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
     const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
 
 
@@ -2530,16 +2607,24 @@ struct Context
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  HBUINT16		format;		/* Format identifier */
-  ContextFormat1	format1;
-  ContextFormat2	format2;
-  ContextFormat3	format3;
+  HBUINT16			format;		/* Format identifier */
+  ContextFormat1_4<SmallTypes>	format1;
+  ContextFormat2_5<SmallTypes>	format2;
+  ContextFormat3		format3;
+#ifndef HB_NO_BEYOND_64K
+  ContextFormat1_4<MediumTypes>	format4;
+  ContextFormat2_5<MediumTypes>	format5;
+#endif
   } u;
 };
 
@@ -2565,13 +2650,14 @@ struct ChainContextApplyLookupContext
   const void *match_data[3];
 };
 
+template <typename HBUINT>
 static inline bool chain_context_intersects (const hb_set_t *glyphs,
 					     unsigned int backtrackCount,
-					     const HBUINT16 backtrack[],
+					     const HBUINT backtrack[],
 					     unsigned int inputCount, /* Including the first glyph (not matched) */
-					     const HBUINT16 input[], /* Array of input values--start with second glyph */
+					     const HBUINT input[], /* Array of input values--start with second glyph */
 					     unsigned int lookaheadCount,
-					     const HBUINT16 lookahead[],
+					     const HBUINT lookahead[],
 					     ChainContextClosureLookupContext &lookup_context)
 {
   return array_is_subset_of (glyphs,
@@ -2585,13 +2671,14 @@ static inline bool chain_context_intersects (const hb_set_t *glyphs,
 			     lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
 }
 
+template <typename HBUINT>
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
-						 const HBUINT16 backtrack[],
+						 const HBUINT backtrack[],
 						 unsigned int inputCount, /* Including the first glyph (not matched) */
-						 const HBUINT16 input[], /* Array of input values--start with second glyph */
+						 const HBUINT input[], /* Array of input values--start with second glyph */
 						 unsigned int lookaheadCount,
-						 const HBUINT16 lookahead[],
+						 const HBUINT lookahead[],
 						 unsigned int lookupCount,
 						 const LookupRecord lookupRecord[],
 						 unsigned value,
@@ -2611,13 +2698,14 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 		     lookup_context.funcs.intersected_glyphs);
 }
 
+template <typename HBUINT>
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 							unsigned int backtrackCount,
-							const HBUINT16 backtrack[],
+							const HBUINT backtrack[],
 							unsigned int inputCount, /* Including the first glyph (not matched) */
-							const HBUINT16 input[], /* Array of input values--start with second glyph */
+							const HBUINT input[], /* Array of input values--start with second glyph */
 							unsigned int lookaheadCount,
-							const HBUINT16 lookahead[],
+							const HBUINT lookahead[],
 							unsigned int lookupCount,
 							const LookupRecord lookupRecord[],
 							ChainContextCollectGlyphsLookupContext &lookup_context)
@@ -2635,13 +2723,14 @@ static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_contex
 		   lookupCount, lookupRecord);
 }
 
+template <typename HBUINT>
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
-						     const HBUINT16 backtrack[] HB_UNUSED,
+						     const HBUINT backtrack[] HB_UNUSED,
 						     unsigned int inputCount, /* Including the first glyph (not matched) */
-						     const HBUINT16 input[], /* Array of input values--start with second glyph */
+						     const HBUINT input[], /* Array of input values--start with second glyph */
 						     unsigned int lookaheadCount,
-						     const HBUINT16 lookahead[] HB_UNUSED,
+						     const HBUINT lookahead[] HB_UNUSED,
 						     unsigned int lookupCount HB_UNUSED,
 						     const LookupRecord lookupRecord[] HB_UNUSED,
 						     ChainContextApplyLookupContext &lookup_context)
@@ -2652,13 +2741,14 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
 			    lookup_context.funcs.match[1], lookup_context.match_data[1]);
 }
 
+template <typename HBUINT>
 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
 					       unsigned int backtrackCount,
-					       const HBUINT16 backtrack[],
+					       const HBUINT backtrack[],
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const HBUINT16 input[], /* Array of input values--start with second glyph */
+					       const HBUINT input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
-					       const HBUINT16 lookahead[],
+					       const HBUINT lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
@@ -2697,12 +2787,13 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
   return true;
 }
 
+template <typename Types>
 struct ChainRule
 {
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     return chain_context_intersects (glyphs,
 				     backtrack.len, backtrack.arrayZ,
 				     input.lenP1, input.arrayZ,
@@ -2715,9 +2806,9 @@ struct ChainRule
   {
     if (unlikely (c->lookup_limit_exceeded ())) return;
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.arrayZ,
 				  input.lenP1, input.arrayZ,
@@ -2733,18 +2824,18 @@ struct ChainRule
     if (unlikely (c->lookup_limit_exceeded ())) return;
     if (!intersects (c->glyphs, lookup_context)) return;
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     recurse_lookups (c, lookup.len, lookup.arrayZ);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 		       ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.arrayZ,
 					 input.lenP1, input.arrayZ,
@@ -2756,9 +2847,9 @@ struct ChainRule
   bool would_apply (hb_would_apply_context_t *c,
 		    ChainContextApplyLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return chain_context_would_apply_lookup (c,
 					     backtrack.len, backtrack.arrayZ,
 					     input.lenP1, input.arrayZ,
@@ -2769,9 +2860,9 @@ struct ChainRule
   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.arrayZ,
 					      input.lenP1, input.arrayZ,
@@ -2804,22 +2895,22 @@ struct ChainRule
     serialize_array (c, backtrack.len, + backtrack.iter ()
 				       | hb_map (mapping));
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (input_map) mapping = input_map;
     serialize_array (c, input.lenP1, + input.iter ()
 				     | hb_map (mapping));
 
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (lookahead_map) mapping = lookahead_map;
     serialize_array (c, lookahead.len, + lookahead.iter ()
 				       | hb_map (mapping));
 
-    const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
 
-    HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+    HBUINT16* lookupCount = c->embed (&(lookup.len));
     if (!lookupCount) return_trace (false);
 
-    unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (), lookup_map);
+    unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
     return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
@@ -2831,8 +2922,8 @@ struct ChainRule
   {
     TRACE_SUBSET (this);
 
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
 
     if (!backtrack_map)
     {
@@ -2861,23 +2952,23 @@ struct ChainRule
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (!lookahead.sanitize (c)) return_trace (false);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  Array16Of<HBUINT16>
+  Array16Of<typename Types::HBUINT>
 		backtrack;		/* Array of backtracking values
 					 * (to be matched before the input
 					 * sequence) */
-  HeadlessArrayOf<HBUINT16>
+  HeadlessArrayOf<typename Types::HBUINT>
 		inputX;			/* Array of input values (start with
 					 * second glyph) */
-  Array16Of<HBUINT16>
+  Array16Of<typename Types::HBUINT>
 		lookaheadX;		/* Array of lookahead values's (to be
 					 * matched after the input sequence) */
   Array16Of<LookupRecord>
@@ -2887,8 +2978,11 @@ struct ChainRule
   DEFINE_SIZE_MIN (8);
 };
 
+template <typename Types>
 struct ChainRuleSet
 {
+  using ChainRule = OT::ChainRule<Types>;
+
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
     return
@@ -3001,8 +3095,11 @@ struct ChainRuleSet
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
-struct ChainContextFormat1
+template <typename Types>
+struct ChainContextFormat1_4
 {
+  using ChainRuleSet = OT::ChainRuleSet<Types>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     struct ChainContextClosureLookupContext lookup_context = {
@@ -3026,8 +3123,8 @@ struct ChainContextFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
                                                  cur_active_glyphs);
 
     struct ChainContextClosureLookupContext lookup_context = {
@@ -3138,18 +3235,21 @@ struct ChainContextFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  Array16OfOffset16To<ChainRuleSet>
+  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ruleSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
 };
 
-struct ChainContextFormat2
+template <typename Types>
+struct ChainContextFormat2_5
 {
+  using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
     if (!(this+coverage).intersects (glyphs))
@@ -3168,7 +3268,7 @@ struct ChainContextFormat2
     };
 
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -3193,8 +3293,8 @@ struct ChainContextFormat2
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
                                                  cur_active_glyphs);
 
 
@@ -3214,7 +3314,7 @@ struct ChainContextFormat2
     | hb_filter ([&] (unsigned _)
     { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
 		 hb_first)
-    | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
+    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
                 {
                   const ChainRuleSet& chainrule_set = this+_.second;
                   chainrule_set.closure (c, _.first, lookup_context);
@@ -3330,7 +3430,7 @@ struct ChainContextFormat2
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    /* For ChainContextFormat2 we cache the LookaheadClassDef instead of InputClassDef.
+    /* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef.
      * The reason is that most heavy fonts want to identify a glyph in context and apply
      * a lookup to it. In this scenario, the length of the input sequence is one, whereas
      * the lookahead / backtrack are typically longer.  The one glyph in input sequence is
@@ -3378,7 +3478,7 @@ struct ChainContextFormat2
 
     const hb_set_t* glyphset = c->plan->glyphset_gsub ();
     hb_set_t retained_coverage_glyphs;
-    (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
+    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
 
     hb_set_t coverage_glyph_classes;
     (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
@@ -3433,38 +3533,40 @@ struct ChainContextFormat2
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
 		backtrackClassDef;	/* Offset to glyph ClassDef table
 					 * containing backtrack sequence
 					 * data--from beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
 		inputClassDef;		/* Offset to glyph ClassDef
 					 * table containing input sequence
 					 * data--from beginning of table */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
 		lookaheadClassDef;	/* Offset to glyph ClassDef table
 					 * containing lookahead sequence
 					 * data--from beginning of table */
-  Array16OfOffset16To<ChainRuleSet>
+  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by class */
   public:
-  DEFINE_SIZE_ARRAY (12, ruleSet);
+  DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
 };
 
 struct ChainContextFormat3
 {
+  using RuleSet = OT::RuleSet<SmallTypes>;
+
   bool intersects (const hb_set_t *glyphs) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     if (!(this+input[0]).intersects (glyphs))
       return false;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage, intersected_coverage_glyphs},
       ContextFormat::CoverageBasedContext,
@@ -3482,18 +3584,18 @@ struct ChainContextFormat3
 
   void closure (hb_closure_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
-    hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
-    get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
+    hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
                                                  cur_active_glyphs);
 
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage, intersected_coverage_glyphs},
       ContextFormat::CoverageBasedContext,
@@ -3514,9 +3616,9 @@ struct ChainContextFormat3
     if (!intersects (c->glyphs))
       return;
 
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     recurse_lookups (c, lookup.len, lookup.arrayZ);
   }
 
@@ -3524,12 +3626,13 @@ struct ChainContextFormat3
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     (this+input[0]).collect_coverage (c->input);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
+
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
@@ -3544,9 +3647,9 @@ struct ChainContextFormat3
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {{match_coverage, match_coverage, match_coverage}},
       {this, this, this}
@@ -3560,20 +3663,20 @@ struct ChainContextFormat3
 
   const Coverage &get_coverage () const
   {
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     return this+input[0];
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {{match_coverage, match_coverage, match_coverage}},
       {this, this, this}
@@ -3615,21 +3718,21 @@ struct ChainContextFormat3
     if (!serialize_coverage_offsets (c, backtrack.iter (), this))
       return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (!serialize_coverage_offsets (c, input.iter (), this))
       return_trace (false);
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (!serialize_coverage_offsets (c, lookahead.iter (), this))
       return_trace (false);
 
-    const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
 
-    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookupRecord.len);
+    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
     if (!lookupCount) return_trace (false);
 
-    unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (), lookup_map);
+    unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
     return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
@@ -3637,12 +3740,12 @@ struct ChainContextFormat3
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return_trace (false);
-    const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &input = StructAfter<decltype (inputX)> (backtrack);
     if (!input.sanitize (c, this)) return_trace (false);
     if (!input.len) return_trace (false); /* To be consistent with Context. */
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
-    const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
+    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
@@ -3678,16 +3781,24 @@ struct ChainContext
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+#ifndef HB_NO_BEYOND_64K
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  HBUINT16		format;	/* Format identifier */
-  ChainContextFormat1	format1;
-  ChainContextFormat2	format2;
-  ChainContextFormat3	format3;
+  HBUINT16				format;	/* Format identifier */
+  ChainContextFormat1_4<SmallTypes>	format1;
+  ChainContextFormat2_5<SmallTypes>	format2;
+  ChainContextFormat3			format3;
+#ifndef HB_NO_BEYOND_64K
+  ChainContextFormat1_4<MediumTypes>	format4;
+  ChainContextFormat2_5<MediumTypes>	format5;
+#endif
   } u;
 };
 
@@ -3871,39 +3982,209 @@ struct hb_ot_layout_lookup_accelerator_t
 #endif
 };
 
+template <typename Types>
+struct GSUBGPOSVersion1_2
+{
+  friend struct GSUBGPOS;
+
+  protected:
+  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
+				 * to 0x00010000u */
+  typename Types:: template OffsetTo<ScriptList>
+		scriptList;	/* ScriptList table */
+  typename Types::template OffsetTo<FeatureList>
+		featureList;	/* FeatureList table */
+  typename Types::template OffsetTo<LookupList<Types>>
+		lookupList;	/* LookupList table */
+  Offset32To<FeatureVariations>
+		featureVars;	/* Offset to Feature Variations
+				   table--from beginning of table
+				 * (may be NULL).  Introduced
+				 * in version 0x00010001. */
+  public:
+  DEFINE_SIZE_MIN (4 + 3 * Types::size);
+
+  unsigned int get_size () const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+  }
+
+  template <typename TLookup>
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
+    if (unlikely (!(scriptList.sanitize (c, this) &&
+		    featureList.sanitize (c, this) &&
+		    reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
+      return_trace (false);
+
+#ifndef HB_NO_VAR
+    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
+      return_trace (false);
+#endif
+
+    return_trace (true);
+  }
+
+  template <typename TLookup>
+  bool subset (hb_subset_layout_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
+    reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
+	.serialize_subset (c->subset_context,
+			   reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
+			   this,
+			   c);
+
+    reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
+	.serialize_subset (c->subset_context,
+			   reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
+			   this,
+			   c);
+
+    out->scriptList.serialize_subset (c->subset_context,
+				      scriptList,
+				      this,
+				      c);
+
+#ifndef HB_NO_VAR
+    if (version.to_int () >= 0x00010001u)
+    {
+      bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
+      if (!ret && version.major == 1)
+      {
+	out->version.major = 1;
+	out->version.minor = 0;
+      }
+    }
+#endif
+
+    return_trace (true);
+  }
+};
+
 struct GSUBGPOS
 {
-  bool has_data () const { return version.to_int (); }
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  template <typename TLookup>
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize<TLookup> (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize<TLookup> (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  template <typename TLookup>
+  bool subset (hb_subset_layout_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset<TLookup> (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset<TLookup> (c);
+#endif
+    default: return false;
+    }
+  }
+
+  const ScriptList &get_script_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.scriptList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.scriptList;
+#endif
+    default: return Null (ScriptList);
+    }
+  }
+  const FeatureList &get_feature_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.featureList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.featureList;
+#endif
+    default: return Null (FeatureList);
+    }
+  }
+  unsigned int get_lookup_count () const
+  {
+    switch (u.version.major) {
+    case 1: return (this+u.version1.lookupList).len;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return (this+u.version2.lookupList).len;
+#endif
+    default: return 0;
+    }
+  }
+  const Lookup& get_lookup (unsigned int i) const
+  {
+    switch (u.version.major) {
+    case 1: return (this+u.version1.lookupList)[i];
+#ifndef HB_NO_BEYOND_64K
+    case 2: return (this+u.version2.lookupList)[i];
+#endif
+    default: return Null (Lookup);
+    }
+  }
+  const FeatureVariations &get_feature_variations () const
+  {
+    switch (u.version.major) {
+    case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.featureVars;
+#endif
+    default: return Null (FeatureVariations);
+    }
+  }
+
+  bool has_data () const { return u.version.to_int (); }
   unsigned int get_script_count () const
-  { return (this+scriptList).len; }
+  { return get_script_list ().len; }
   const Tag& get_script_tag (unsigned int i) const
-  { return (this+scriptList).get_tag (i); }
+  { return get_script_list ().get_tag (i); }
   unsigned int get_script_tags (unsigned int start_offset,
 				unsigned int *script_count /* IN/OUT */,
 				hb_tag_t     *script_tags /* OUT */) const
-  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
+  { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
   const Script& get_script (unsigned int i) const
-  { return (this+scriptList)[i]; }
+  { return get_script_list ()[i]; }
   bool find_script_index (hb_tag_t tag, unsigned int *index) const
-  { return (this+scriptList).find_index (tag, index); }
+  { return get_script_list ().find_index (tag, index); }
 
   unsigned int get_feature_count () const
-  { return (this+featureList).len; }
+  { return get_feature_list ().len; }
   hb_tag_t get_feature_tag (unsigned int i) const
-  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
+  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
   unsigned int get_feature_tags (unsigned int start_offset,
 				 unsigned int *feature_count /* IN/OUT */,
 				 hb_tag_t     *feature_tags /* OUT */) const
-  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
+  { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
   const Feature& get_feature (unsigned int i) const
-  { return (this+featureList)[i]; }
+  { return get_feature_list ()[i]; }
   bool find_feature_index (hb_tag_t tag, unsigned int *index) const
-  { return (this+featureList).find_index (tag, index); }
-
-  unsigned int get_lookup_count () const
-  { return (this+lookupList).len; }
-  const Lookup& get_lookup (unsigned int i) const
-  { return (this+lookupList)[i]; }
+  { return get_feature_list ().find_index (tag, index); }
 
   bool find_variations_index (const int *coords, unsigned int num_coords,
 			      unsigned int *index) const
@@ -3912,18 +4193,17 @@ struct GSUBGPOS
     *index = FeatureVariations::NOT_FOUND_INDEX;
     return false;
 #endif
-    return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
-	    .find_index (coords, num_coords, index);
+    return get_feature_variations ().find_index (coords, num_coords, index);
   }
   const Feature& get_feature_variation (unsigned int feature_index,
 					unsigned int variations_index) const
   {
 #ifndef HB_NO_VAR
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
-	version.to_int () >= 0x00010001u)
+	u.version.to_int () >= 0x00010001u)
     {
-      const Feature *feature = (this+featureVars).find_substitute (variations_index,
-								   feature_index);
+      const Feature *feature = get_feature_variations ().find_substitute (variations_index,
+									  feature_index);
       if (feature)
 	return *feature;
     }
@@ -3935,8 +4215,7 @@ struct GSUBGPOS
 					  hb_set_t       *lookup_indexes /* OUT */) const
   {
 #ifndef HB_NO_VAR
-    if (version.to_int () >= 0x00010001u)
-      (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+    get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes);
 #endif
   }
 
@@ -3971,108 +4250,6 @@ struct GSUBGPOS
     }
   }
 
-  template <typename TLookup>
-  bool subset (hb_subset_layout_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->subset_context->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    typedef LookupOffsetList<TLookup> TLookupList;
-    reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
-	.serialize_subset (c->subset_context,
-			   reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
-			   this,
-			   c);
-
-    reinterpret_cast<Offset16To<RecordListOfFeature> &> (out->featureList)
-	.serialize_subset (c->subset_context,
-			   reinterpret_cast<const Offset16To<RecordListOfFeature> &> (featureList),
-			   this,
-			   c);
-
-    out->scriptList.serialize_subset (c->subset_context,
-				      scriptList,
-				      this,
-				      c);
-
-#ifndef HB_NO_VAR
-    if (version.to_int () >= 0x00010001u)
-    {
-      bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
-      if (!ret)
-      {
-	out->version.major = 1;
-	out->version.minor = 0;
-      }
-    }
-#endif
-
-    return_trace (true);
-  }
-
-  void find_duplicate_features (const hb_map_t *lookup_indices,
-                                const hb_set_t *feature_indices,
-                                hb_map_t *duplicate_feature_map /* OUT */) const
-  {
-    if (feature_indices->is_empty ()) return;
-    hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
-    //find out duplicate features after subset
-    for (unsigned i : feature_indices->iter ())
-    {
-      hb_tag_t t = get_feature_tag (i);
-      if (t == HB_MAP_VALUE_INVALID) continue;
-      if (!unique_features.has (t))
-      {
-        if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
-          return;
-        if (unique_features.has (t))
-          unique_features.get (t)->add (i);
-        duplicate_feature_map->set (i, i);
-        continue;
-      }
-
-      bool found = false;
-
-      hb_set_t* same_tag_features = unique_features.get (t);
-      for (unsigned other_f_index : same_tag_features->iter ())
-      {
-        const 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);
-      }
-    }
-  }
-
   void prune_features (const hb_map_t *lookup_indices, /* IN */
 		       hb_set_t       *feature_indices /* IN/OUT */) const
   {
@@ -4081,8 +4258,7 @@ struct GSUBGPOS
     // if the FeatureVariation's table and the alternate version(s) intersect the
     // set of lookup indices.
     hb_set_t alternate_feature_indices;
-    if (version.to_int () >= 0x00010001u)
-      (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
+    get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices);
     if (unlikely (alternate_feature_indices.in_error()))
     {
       feature_indices->err ();
@@ -4115,32 +4291,6 @@ struct GSUBGPOS
     }
   }
 
-  unsigned int get_size () const
-  {
-    return min_size +
-	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
-  }
-
-  template <typename TLookup>
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    typedef List16OfOffset16To<TLookup> TLookupList;
-    if (unlikely (!(version.sanitize (c) &&
-		    likely (version.major == 1) &&
-		    scriptList.sanitize (c, this) &&
-		    featureList.sanitize (c, this) &&
-		    reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
-      return_trace (false);
-
-#ifndef HB_NO_VAR
-    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
-      return_trace (false);
-#endif
-
-    return_trace (true);
-  }
-
   template <typename T>
   struct accelerator_t
   {
@@ -4180,21 +4330,15 @@ struct GSUBGPOS
   };
 
   protected:
-  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
-				 * to 0x00010000u */
-  Offset16To<ScriptList>
-		scriptList;	/* ScriptList table */
-  Offset16To<FeatureList>
-		featureList;	/* FeatureList table */
-  Offset16To<LookupList>
-		lookupList;	/* LookupList table */
-  Offset32To<FeatureVariations>
-		featureVars;	/* Offset to Feature Variations
-				   table--from beginning of table
-				 * (may be NULL).  Introduced
-				 * in version 0x00010001. */
+  union {
+  FixedVersion<>			version;	/* Version identifier */
+  GSUBGPOSVersion1_2<SmallTypes>	version1;
+#ifndef HB_NO_BEYOND_64K
+  GSUBGPOSVersion1_2<MediumTypes>	version2;
+#endif
+  } u;
   public:
-  DEFINE_SIZE_MIN (10);
+  DEFINE_SIZE_MIN (4);
 };
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
index 142c843dad8a7432ed832a2037cb9514a1778815..f9c0daa486c3f64955b35f753de5fdf6f3dd7e5f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
@@ -54,7 +54,7 @@
 #include "hb-aat-layout-morx-table.hh"
 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
-using OT::Layout::GSUB::GSUB;
+using OT::Layout::GSUB;
 using OT::Layout::GPOS;
 
 /**
@@ -79,7 +79,7 @@ using OT::Layout::GPOS;
  * 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
@@ -95,7 +95,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
  * Tests whether a face includes any state-machine kerning in the 'kern' table.
  * Does NOT examine the GPOS table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 bool
@@ -115,7 +115,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
  *
  * Does NOT examine the GPOS table.
  *
- * Return value: %true is data found, %false otherwise
+ * Return value: `true` is data found, `false` otherwise
  *
  **/
 bool
@@ -272,7 +272,7 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
  *
  * Tests whether a face has any glyph classes defined in its GDEF table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -461,7 +461,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t    *face,
  * Fetches the index if a given script tag in the specified face's GSUB table
  * or GPOS table.
  *
- * Return value: %true if the script is found, %false otherwise
+ * Return value: `true` if the script is found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -535,7 +535,7 @@ hb_ot_layout_table_choose_script (hb_face_t      *face,
  * #HB_OT_LAYOUT_NO_SCRIPT_INDEX.
  *
  * Return value:
- * %true if one of the requested scripts is selected, %false if a fallback
+ * `true` if one of the requested scripts is selected, `false` if a fallback
  * script is selected or if no scripts are selected.
  *
  * Since: 2.0.0
@@ -628,7 +628,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
  * Fetches the index for a given feature tag in the specified face's GSUB table
  * or GPOS table.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
  **/
 bool
 hb_ot_layout_table_find_feature (hb_face_t    *face,
@@ -695,7 +695,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t    *face,
  * Fetches the index of a given language tag in the specified face's GSUB table
  * or GPOS table, underneath the specified script tag.
  *
- * Return value: %true if the language tag is found, %false otherwise
+ * Return value: `true` if the language tag is found, `false` otherwise
  *
  * Since: 0.6.0
  * Deprecated: 2.0.0
@@ -730,10 +730,10 @@ hb_ot_layout_script_find_language (hb_face_t    *face,
  * in the specified face's GSUB or GPOS table, underneath the specified script
  * index.
  *
- * If none of the given language tags is found, %false is returned and
+ * 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
+ * Return value: `true` if one of the given language tags is found, `false` otherwise
  *
  * Since: 2.0.0
  **/
@@ -776,7 +776,7 @@ hb_ot_layout_script_select_language (hb_face_t      *face,
  * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
  * underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -807,7 +807,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
  * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
  * underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
  *
  * Since: 0.9.30
  **/
@@ -917,7 +917,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
  * Fetches the index of a given feature tag in the specified face's GSUB table
  * or GPOS table, underneath the specified script and language.
  *
- * Return value: %true if the feature is found, %false otherwise
+ * Return value: `true` if the feature is found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -1314,7 +1314,7 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
  * Fetches a list of feature variations in the specified face's GSUB table
  * or GPOS table, at the specified variation coordinates.
  *
- * Return value: %true if feature variations were found, %false otherwise.
+ * Return value: `true` if feature variations were found, `false` otherwise.
  *
  **/
 hb_bool_t
@@ -1377,7 +1377,7 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
  *
  * Tests whether the specified face includes any GSUB substitutions.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 hb_bool_t
@@ -1399,7 +1399,7 @@ hb_ot_layout_has_substitution (hb_face_t *face)
  * Tests whether a specified lookup in the specified face would
  * trigger a substitution on the given glyph sequence.
  *
- * Return value: %true if a substitution would be triggered, %false otherwise
+ * Return value: `true` if a substitution would be triggered, `false` otherwise
  *
  * Since: 0.9.7
  **/
@@ -1561,7 +1561,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
  *
  * Tests whether the specified face includes any GPOS positioning.
  *
- * Return value: %true if the face has GPOS data, %false otherwise
+ * Return value: `true` if the face has GPOS data, `false` otherwise
  *
  **/
 hb_bool_t
@@ -1634,7 +1634,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
  * For more information on this distinction, see the [`size` feature documentation](
  * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.10
  **/
@@ -1698,7 +1698,7 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
  * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
  * "Character Variant" ('cvXX') features.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.0.0
  **/
@@ -2051,7 +2051,7 @@ hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)
  *
  * Fetches a baseline value from the face.
  *
- * Return value: %true if found baseline value in the font.
+ * Return value: `true` if found baseline value in the font.
  *
  * Since: 2.6.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
index 6395f06670674fb8b59b940df4a8eff06304ecfd..de06610cb5af057a973a68426db1fe75c2ede11c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
@@ -110,7 +110,7 @@ namespace OT {
   struct hb_ot_apply_context_t;
   struct hb_ot_layout_lookup_accelerator_t;
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
   struct SubstLookup;
 }
 }
@@ -118,7 +118,7 @@ namespace GSUB {
 
 HB_INTERNAL void
 hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
-				const OT::Layout::GSUB::SubstLookup &lookup,
+				const OT::Layout::GSUB_impl::SubstLookup &lookup,
 				const OT::hb_ot_layout_lookup_accelerator_t &accel);
 
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc
index f085c78ff8f000ac81cd0abc2195348b7bc5f74e..39215b335fbfbd7bd38fad123b178bdf57da74a1 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc
@@ -43,7 +43,7 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_o
 
 
 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
-					  const hb_segment_properties_t *props_)
+					  const hb_segment_properties_t &props_)
 {
   memset (this, 0, sizeof (*this));
 
@@ -52,7 +52,7 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
     stages[table_index].init ();
 
   face = face_;
-  props = *props_;
+  props = props_;
 
   /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
    * features not available in either table and not waste precious bits for them. */
@@ -109,6 +109,21 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag,
   info->stage[1] = current_stage[1];
 }
 
+bool hb_ot_map_builder_t::has_feature (hb_tag_t tag)
+{
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
+    if (hb_ot_layout_language_find_feature (face,
+					    table_tags[table_index],
+					    script_index[table_index],
+					    language_index[table_index],
+					    tag,
+					    nullptr))
+      return true;
+  }
+  return false;
+}
+
 void
 hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
 				  unsigned int  table_index,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.hh
index f1cbf752fcb0ad700686d39e21ad65744d6110fe..a7b5eec30d7d64c2ccc8f94d6893187bb3fdb415 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.hh
@@ -139,19 +139,15 @@ struct hb_ot_map_t
     return map ? map->stage[table_index] : UINT_MAX;
   }
 
-  void get_stage_lookups (unsigned int table_index, unsigned int stage,
-			  const struct lookup_map_t **plookups, unsigned int *lookup_count) const
+  hb_array_t<const hb_ot_map_t::lookup_map_t>
+  get_stage_lookups (unsigned int table_index, unsigned int stage) const
   {
     if (unlikely (stage > stages[table_index].length))
-    {
-      *plookups = nullptr;
-      *lookup_count = 0;
-      return;
-    }
+      return hb_array<const hb_ot_map_t::lookup_map_t> (nullptr, 0);
+
     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
     unsigned int end   = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
-    *plookups = end == start ? nullptr : &lookups[table_index][start];
-    *lookup_count = end - start;
+    return lookups[table_index].as_array ().sub_array (start, end - start);
   }
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
@@ -167,7 +163,7 @@ struct hb_ot_map_t
 
   private:
 
-  hb_mask_t global_mask;
+  hb_mask_t global_mask = 0;
 
   hb_sorted_vector_t<feature_map_t> features;
   hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
@@ -204,7 +200,7 @@ struct hb_ot_map_builder_t
   public:
 
   HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
-				   const hb_segment_properties_t *props_);
+				   const hb_segment_properties_t &props_);
 
   HB_INTERNAL ~hb_ot_map_builder_t ();
 
@@ -212,6 +208,8 @@ struct hb_ot_map_builder_t
 				hb_ot_map_feature_flags_t flags=F_NONE,
 				unsigned int value=1);
 
+  HB_INTERNAL bool has_feature (hb_tag_t tag);
+
   void add_feature (const hb_ot_map_feature_t &feat)
   { add_feature (feat.tag, feat.flags); }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math.cc
index f44ac358493acdb20482f544edd4b9b60e82d742..c515867bdf141509b583e7db7f388559894a4ce6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/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 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
  *
  * Tests whether the given glyph index is an extended shape in the face.
  *
- * Return value: %true if the glyph is an extended shape, %false otherwise
+ * Return value: `true` if the glyph is an extended shape, `false` otherwise
  *
  * Since: 1.3.3
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc
index f9c4b96fff65699daa145c0bdbb561e964fa883e..5b12482b979eaf7910b03fa70b9671677b74914f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc
@@ -71,12 +71,12 @@ _hb_ot_metrics_get_position_common (hb_font_t           *font,
 #endif
 #define GET_METRIC_X(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
-      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+    ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
 #define GET_METRIC_Y(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
-      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+    ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
 
   case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
     return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
@@ -154,10 +154,10 @@ hb_ot_metrics_get_position (hb_font_t           *font,
 #endif
 #define GET_METRIC_X(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true))
+    ((void) (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR))), true))
 #define GET_METRIC_Y(TABLE, ATTR) \
   (face->table.TABLE->has_data () && \
-    (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true))
+    ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true))
   case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:  return GET_METRIC_Y (OS2, usWinAscent);
   case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name-table.hh
index 01107aad67bb62645865034b3faa047ec8b76099..1f2131ffcccd691233a7f46327813b5337747803 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name-table.hh
@@ -175,15 +175,11 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
 
   signed c = strcmp (astr, bstr);
 
-  if (!exact && c)
-  {
-    unsigned la = strlen (astr);
-    unsigned lb = strlen (bstr);
-    // 'a' is the user request, and 'b' is string in the font.
-    // If eg. user asks for "en-us" and font has "en", approve.
-    if (la > lb && astr[lb] == '-' && !strncmp (astr, bstr, lb))
-      return 0;
-  }
+  // 'a' is the user request, and 'b' is string in the font.
+  // If eg. user asks for "en-us" and font has "en", approve.
+  if (!exact && c &&
+      hb_language_matches (b->language, a->language))
+    return 0;
 
   return c;
 }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
index a4844e94bccaf13da443bd72a91aad52ccec6cd1..a4c0c4aa17ec18c2039b77ba5ad2bbb76fca922e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table.hh
@@ -263,10 +263,10 @@ struct post
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-			  (version.to_int () == 0x00010000 ||
-			   (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
-			   version.to_int () == 0x00030000)));
+    return_trace (c->check_struct (this) &&
+		  (version.to_int () == 0x00010000 ||
+		   (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
+		   version.to_int () == 0x00030000));
   }
 
   public:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
index 0806abb7dd39fe579dc4083e74972972038c2e89..2ada84b8a3c3601f5a843176da1940f395617d08 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
@@ -53,11 +53,11 @@ _hb_codepoint_is_regional_indicator (hb_codepoint_t u)
 
 #ifndef HB_NO_AAT_SHAPE
 static inline bool
-_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props)
+_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t &props)
 {
   /* https://github.com/harfbuzz/harfbuzz/issues/2124 */
   return hb_aat_layout_has_substitution (face) &&
-	 (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face));
+	 (HB_DIRECTION_IS_HORIZONTAL (props.direction) || !hb_ot_layout_has_substitution (face));
 }
 #endif
 
@@ -77,9 +77,9 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      unsigned int                    num_user_features);
 
 hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *face,
-					      const hb_segment_properties_t *props) :
+					      const hb_segment_properties_t &props) :
 						face (face),
-						props (*props),
+						props (props),
 						map (face, props),
 						aat_map (face, props)
 #ifndef HB_NO_AAT_SHAPE
@@ -225,7 +225,7 @@ hb_ot_shape_plan_t::init0 (hb_face_t                     *face,
 #endif
 
   hb_ot_shape_planner_t planner (face,
-				 &key->props);
+				 key->props);
 
   hb_ot_shape_collect_features (&planner,
 				key->user_features,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
index 17fa58b3377a5772ab40f2f0d1aa3cbeab9c32cd..cd6f15cbe2477b8850302c84d49ba0a9bdc9a688 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.hh
@@ -60,6 +60,8 @@ struct hb_shape_plan_key_t;
 
 struct hb_ot_shape_plan_t
 {
+  ~hb_ot_shape_plan_t () { fini (); }
+
   hb_segment_properties_t props;
   const struct hb_ot_shaper_t *shaper;
   hb_ot_map_t map;
@@ -161,7 +163,7 @@ struct hb_ot_shape_planner_t
   const struct hb_ot_shaper_t *shaper;
 
   HB_INTERNAL hb_ot_shape_planner_t (hb_face_t                     *face,
-				     const hb_segment_properties_t *props);
+				     const hb_segment_properties_t &props);
 
   HB_INTERNAL void compile (hb_ot_shape_plan_t           &plan,
 			    const hb_ot_shape_plan_key_t &key);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
index e869d78509a4a84fc76ce9c10553a6a1d3cfe93a..b331a048b653047e8a6c3faa0fb583909298a9ed 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-arabic.cc
@@ -201,24 +201,21 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
    * work.  However, testing shows that rlig and calt are applied
    * together for Mongolian in Uniscribe.  As such, we only add a
    * pause for Arabic, not other scripts.
-   *
-   * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
-   * work correctly.  See https://github.com/harfbuzz/harfbuzz/issues/505
    */
 
 
   map->enable_feature (HB_TAG('s','t','c','h'));
   map->add_gsub_pause (record_stch);
 
-  map->enable_feature (HB_TAG('c','c','m','p'));
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('l','o','c','l'), F_MANUAL_ZWJ);
 
   map->add_gsub_pause (nullptr);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   {
     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
-    map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE);
+    map->add_feature (arabic_features[i], F_MANUAL_ZWJ | (has_fallback ? F_HAS_FALLBACK : F_NONE));
     map->add_gsub_pause (nullptr);
   }
    map->add_gsub_pause (deallocate_buffer_var);
@@ -232,10 +229,16 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
   if (plan->props.script == HB_SCRIPT_ARABIC)
     map->add_gsub_pause (arabic_fallback_shape);
 
-  /* No pause after rclt.  See 98460779bae19e4d64d29461ff154b3527bf8420. */
-  map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
-  map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
-  map->add_gsub_pause (nullptr);
+   map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
+   /* https://github.com/harfbuzz/harfbuzz/issues/1573 */
+   if (!map->has_feature (HB_TAG('r','c','l','t')))
+   {
+     map->add_gsub_pause (nullptr);
+     map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
+   }
+
+   map->enable_feature (HB_TAG('l','i','g','a'), F_MANUAL_ZWJ);
+   map->enable_feature (HB_TAG('c','l','i','g'), F_MANUAL_ZWJ);
 
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
@@ -245,8 +248,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
    * Note that IranNastaliq uses this feature extensively
    * to fixup broken glyph sequences.  Oh well...
    * Test case: U+0643,U+0640,U+0631. */
-  //map->enable_feature (HB_TAG('c','s','w','h'));
-  map->enable_feature (HB_TAG('m','s','e','t'));
+  //map->enable_feature (HB_TAG('c','s','w','h'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('m','s','e','t'), F_MANUAL_ZWJ);
 }
 
 #include "hb-ot-shaper-arabic-fallback.hh"
@@ -735,12 +738,12 @@ const hb_ot_shaper_t _hb_ot_shaper_arabic =
   data_destroy_arabic,
   nullptr, /* preprocess_text */
   postprocess_glyphs_arabic,
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_arabic,
-  HB_TAG_NONE, /* gpos_tag */
   reorder_marks_arabic,
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-default.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-default.cc
index 25716aa81f525c4be61231e5ab91c3a7b5672547..2f6f499eecea185aaa04184365b74c552538bf7d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-default.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-default.cc
@@ -39,12 +39,12 @@ const hb_ot_shaper_t _hb_ot_shaper_default =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
@@ -59,12 +59,12 @@ const hb_ot_shaper_t _hb_ot_shaper_dumber =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
index aa507c75caac57c1204e62ca32b9c82409356033..c90476bc468b1b5f287c4236cef67a8373f4e4a1 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hangul.cc
@@ -422,12 +422,12 @@ const hb_ot_shaper_t _hb_ot_shaper_hangul =
   data_destroy_hangul,
   preprocess_text_hangul,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_hangul,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hebrew.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hebrew.cc
index f3b6cde17969a8fa99b1ebb6875dacf1db877200..e18edd6b3f226c5b94036375dbcadfb3b3105a52 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hebrew.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-hebrew.cc
@@ -89,7 +89,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
 	      found = true;
 	  }
 	  break;
-      case 0x05B7u: /* patah */
+      case 0x05B7u: /* PATAH */
 	  if (a == 0x05F2u) { /* YIDDISH YOD YOD */
 	      *ab = 0xFB1Fu;
 	      found = true;
@@ -162,6 +162,32 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
   return found;
 }
 
+static void
+reorder_marks_hebrew (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		      hb_buffer_t              *buffer,
+		      unsigned int              start,
+		      unsigned int              end)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  for (unsigned i = start + 2; i < end; i++)
+  {
+    unsigned c0 = info_cc (info[i - 2]);
+    unsigned c1 = info_cc (info[i - 1]);
+    unsigned c2 = info_cc (info[i - 0]);
+
+    if ((c0 == HB_MODIFIED_COMBINING_CLASS_CCC17 || c0 == HB_MODIFIED_COMBINING_CLASS_CCC18) /* patach or qamats */ &&
+	(c1 == HB_MODIFIED_COMBINING_CLASS_CCC10 || c1 == HB_MODIFIED_COMBINING_CLASS_CCC14) /* sheva or hiriq */ &&
+	(c2 == HB_MODIFIED_COMBINING_CLASS_CCC22 || c2 == HB_UNICODE_COMBINING_CLASS_BELOW) /* meteg or below */)
+    {
+      buffer->merge_clusters (i - 1, i + 1);
+      hb_swap (info[i - 1], info[i]);
+      break;
+    }
+  }
+
+
+}
 
 const hb_ot_shaper_t _hb_ot_shaper_hebrew =
 {
@@ -171,12 +197,12 @@ const hb_ot_shaper_t _hb_ot_shaper_hebrew =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   compose_hebrew,
   nullptr, /* setup_masks */
+  reorder_marks_hebrew,
   HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */
-  nullptr, /* reorder_marks */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-machine.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-machine.hh
index d52b13f6161d48fb7864c74211b8f5fc0b3dadaa..d3a7cce3ded38731f8a42141d3e5e845281f021c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-machine.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
 };
 
 
-#line 57 "hb-ot-shaper-indic-machine.hh"
+#line 54 "hb-ot-shaper-indic-machine.hh"
 #define indic_syllable_machine_ex_A 9u
 #define indic_syllable_machine_ex_C 1u
 #define indic_syllable_machine_ex_CM 16u
@@ -75,7 +75,7 @@ enum indic_syllable_type_t {
 #define indic_syllable_machine_ex_ZWNJ 5u
 
 
-#line 79 "hb-ot-shaper-indic-machine.hh"
+#line 74 "hb-ot-shaper-indic-machine.hh"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
 	8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u, 
 	5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u, 
@@ -422,7 +422,7 @@ find_syllables_indic (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 426 "hb-ot-shaper-indic-machine.hh"
+#line 415 "hb-ot-shaper-indic-machine.hh"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
@@ -438,7 +438,7 @@ find_syllables_indic (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
   
-#line 442 "hb-ot-shaper-indic-machine.hh"
+#line 427 "hb-ot-shaper-indic-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -452,7 +452,7 @@ _resume:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 456 "hb-ot-shaper-indic-machine.hh"
+#line 439 "hb-ot-shaper-indic-machine.hh"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -555,7 +555,7 @@ _eof_trans:
 #line 113 "hb-ot-shaper-indic-machine.rl"
 	{act = 6;}
 	break;
-#line 559 "hb-ot-shaper-indic-machine.hh"
+#line 521 "hb-ot-shaper-indic-machine.hh"
 	}
 
 _again:
@@ -564,7 +564,7 @@ _again:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 568 "hb-ot-shaper-indic-machine.hh"
+#line 528 "hb-ot-shaper-indic-machine.hh"
 	}
 
 	if ( ++p != pe )
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
index 48a3c744630efe8e955939b985e808b247181966..6eb400ab16ccb297db761a475176c8994371f076 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic.cc
@@ -92,24 +92,22 @@ struct hb_indic_would_substitute_feature_t
   void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
   {
     zero_context = zero_context_;
-    map->get_stage_lookups (0/*GSUB*/,
-			    map->get_feature_stage (0/*GSUB*/, feature_tag),
-			    &lookups, &count);
+    lookups = map->get_stage_lookups (0/*GSUB*/,
+				      map->get_feature_stage (0/*GSUB*/, feature_tag));
   }
 
   bool would_substitute (const hb_codepoint_t *glyphs,
 			 unsigned int          glyphs_count,
 			 hb_face_t            *face) const
   {
-    for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+    for (const auto &lookup : lookups)
+      if (hb_ot_layout_lookup_would_substitute (face, lookup.index, glyphs, glyphs_count, zero_context))
 	return true;
     return false;
   }
 
   private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
+  hb_array_t<const hb_ot_map_t::lookup_map_t> lookups;
   bool zero_context;
 };
 
@@ -1528,12 +1526,12 @@ const hb_ot_shaper_t _hb_ot_shaper_indic =
   data_destroy_indic,
   preprocess_text_indic,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
   setup_masks_indic,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer-machine.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer-machine.hh
index e18bd75ef1ffcbcaf26dc470357249d949963703..2c40663bdd5e47b4e4fcfe2e946de22e66a5c975 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer-machine.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
 };
 
 
-#line 52 "hb-ot-shaper-khmer-machine.hh"
+#line 49 "hb-ot-shaper-khmer-machine.hh"
 #define khmer_syllable_machine_ex_C 1u
 #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
 #define khmer_syllable_machine_ex_H 4u
@@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
 #define khmer_syllable_machine_ex_ZWNJ 5u
 
 
-#line 70 "hb-ot-shaper-khmer-machine.hh"
+#line 65 "hb-ot-shaper-khmer-machine.hh"
 static const unsigned char _khmer_syllable_machine_trans_keys[] = {
 	5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 
 	5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 
@@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 298 "hb-ot-shaper-khmer-machine.hh"
+#line 287 "hb-ot-shaper-khmer-machine.hh"
 	{
 	cs = khmer_syllable_machine_start;
 	ts = 0;
@@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
   
-#line 314 "hb-ot-shaper-khmer-machine.hh"
+#line 299 "hb-ot-shaper-khmer-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -324,7 +324,7 @@ _resume:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 328 "hb-ot-shaper-khmer-machine.hh"
+#line 311 "hb-ot-shaper-khmer-machine.hh"
 	}
 
 	_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -394,7 +394,7 @@ _eof_trans:
 #line 98 "hb-ot-shaper-khmer-machine.rl"
 	{act = 3;}
 	break;
-#line 398 "hb-ot-shaper-khmer-machine.hh"
+#line 368 "hb-ot-shaper-khmer-machine.hh"
 	}
 
 _again:
@@ -403,7 +403,7 @@ _again:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 407 "hb-ot-shaper-khmer-machine.hh"
+#line 375 "hb-ot-shaper-khmer-machine.hh"
 	}
 
 	if ( ++p != pe )
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer.cc
index e04d633195876584793983fd2a2a4135f574d1b4..d9795589fa65070c899f445aa7567d21bd042369 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-khmer.cc
@@ -368,12 +368,12 @@ const hb_ot_shaper_t _hb_ot_shaper_khmer =
   data_destroy_khmer,
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_khmer,
   compose_khmer,
   setup_masks_khmer,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar-machine.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar-machine.hh
index b109708937b8eefa5aca7d53c52413a8d02f0f3d..464cf796d438c4063353bbd86282db035563221f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar-machine.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar-machine.hh
@@ -50,7 +50,7 @@ enum myanmar_syllable_type_t {
 };
 
 
-#line 54 "hb-ot-shaper-myanmar-machine.hh"
+#line 51 "hb-ot-shaper-myanmar-machine.hh"
 #define myanmar_syllable_machine_ex_A 9u
 #define myanmar_syllable_machine_ex_As 32u
 #define myanmar_syllable_machine_ex_C 1u
@@ -77,7 +77,7 @@ enum myanmar_syllable_type_t {
 #define myanmar_syllable_machine_ex_ZWNJ 5u
 
 
-#line 81 "hb-ot-shaper-myanmar-machine.hh"
+#line 76 "hb-ot-shaper-myanmar-machine.hh"
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
 	1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, 
 	5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u, 
@@ -443,7 +443,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 447 "hb-ot-shaper-myanmar-machine.hh"
+#line 436 "hb-ot-shaper-myanmar-machine.hh"
 	{
 	cs = myanmar_syllable_machine_start;
 	ts = 0;
@@ -459,7 +459,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
   
-#line 463 "hb-ot-shaper-myanmar-machine.hh"
+#line 448 "hb-ot-shaper-myanmar-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -473,7 +473,7 @@ _resume:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 477 "hb-ot-shaper-myanmar-machine.hh"
+#line 460 "hb-ot-shaper-myanmar-machine.hh"
 	}
 
 	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -519,7 +519,7 @@ _eof_trans:
 #line 113 "hb-ot-shaper-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
 	break;
-#line 523 "hb-ot-shaper-myanmar-machine.hh"
+#line 498 "hb-ot-shaper-myanmar-machine.hh"
 	}
 
 _again:
@@ -528,7 +528,7 @@ _again:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 532 "hb-ot-shaper-myanmar-machine.hh"
+#line 505 "hb-ot-shaper-myanmar-machine.hh"
 	}
 
 	if ( ++p != pe )
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar.cc
index 1ccafbca7e79651dcf8fa0fb80356b931c259ac7..78bd8de524e91c8a5c5879f0069cb0d3842d64a8 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-myanmar.cc
@@ -320,12 +320,12 @@ const hb_ot_shaper_t _hb_ot_shaper_myanmar =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   nullptr, /* decompose */
   nullptr, /* compose */
   setup_masks_myanmar,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
@@ -342,12 +342,12 @@ const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
   nullptr, /* data_destroy */
   nullptr, /* preprocess_text */
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
index 1280e7ed17ba858a4dd505197e28701a9ef48ccb..15349b1e64b527794126f9f7cf0020966ca44e6a 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-thai.cc
@@ -379,12 +379,12 @@ const hb_ot_shaper_t _hb_ot_shaper_thai =
   nullptr, /* data_destroy */
   preprocess_text_thai,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   nullptr, /* decompose */
   nullptr, /* compose */
   nullptr, /* setup_masks */
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-machine.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-machine.hh
index 65e65ff39d00a6389b3c90fe367405eb8fe5de51..5b3ec05616ef32a7b76edff28534a96c9be063b6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-machine.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ enum use_syllable_type_t {
 };
 
 
-#line 57 "hb-ot-shaper-use-machine.hh"
+#line 54 "hb-ot-shaper-use-machine.hh"
 #define use_syllable_machine_ex_B 1u
 #define use_syllable_machine_ex_CGJ 6u
 #define use_syllable_machine_ex_CMAbv 31u
@@ -97,7 +97,7 @@ enum use_syllable_type_t {
 #define use_syllable_machine_ex_ZWNJ 14u
 
 
-#line 101 "hb-ot-shaper-use-machine.hh"
+#line 96 "hb-ot-shaper-use-machine.hh"
 static const unsigned char _use_syllable_machine_trans_keys[] = {
 	0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 
 	45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, 
@@ -780,7 +780,7 @@ find_syllables_use (hb_buffer_t *buffer)
   unsigned int act HB_UNUSED;
   int cs;
   
-#line 784 "hb-ot-shaper-use-machine.hh"
+#line 773 "hb-ot-shaper-use-machine.hh"
 	{
 	cs = use_syllable_machine_start;
 	ts = 0;
@@ -793,7 +793,7 @@ find_syllables_use (hb_buffer_t *buffer)
 
   unsigned int syllable_serial = 1;
   
-#line 797 "hb-ot-shaper-use-machine.hh"
+#line 782 "hb-ot-shaper-use-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -807,7 +807,7 @@ _resume:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 811 "hb-ot-shaper-use-machine.hh"
+#line 794 "hb-ot-shaper-use-machine.hh"
 	}
 
 	_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -897,7 +897,7 @@ _eof_trans:
 #line 171 "hb-ot-shaper-use-machine.rl"
 	{act = 2;}
 	break;
-#line 901 "hb-ot-shaper-use-machine.hh"
+#line 866 "hb-ot-shaper-use-machine.hh"
 	}
 
 _again:
@@ -906,7 +906,7 @@ _again:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 910 "hb-ot-shaper-use-machine.hh"
+#line 873 "hb-ot-shaper-use-machine.hh"
 	}
 
 	if ( ++p != pe )
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-table.hh
index 5aa025fb4c6cc72e1df172ef55ff8e73b6d7ec55..4f09fa805e4e5db077da07c7ae8db73b8b22b9dc 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use-table.hh
@@ -89,1440 +89,264 @@
 #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,    WJ,     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,    WJ,    WJ, 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,    WJ,    WJ,     O,    WJ,
-
-#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,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     B,
-  /* 0990 */     B,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 09A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 09B0 */     B,    WJ,     B,    WJ,    WJ,    WJ,     B,     B,     B,     B,    WJ,    WJ, CMBlw,     B,  VPst,  VPre,
-  /* 09C0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,    WJ,    WJ,  VPre,  VPre,    WJ,    WJ,  VPre,  VPre,     H,     O,    WJ,
-  /* 09D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst,    WJ,    WJ,    WJ,    WJ,     B,     B,    WJ,     B,
-  /* 09E0 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     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,    WJ,
-
-  /* Gurmukhi */
-
-  /* 0A00 */    WJ, VMAbv, VMAbv, VMPst,    WJ,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,     B,
-  /* 0A10 */     B,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 0A30 */     B,    WJ,     B,     B,    WJ,     B,     B,    WJ,     B,     B,    WJ,    WJ, CMBlw,    WJ,  VPst,  VPre,
-  /* 0A40 */  VPst,  VBlw,  VBlw,    WJ,    WJ,    WJ,    WJ,  VAbv,  VAbv,    WJ,    WJ,  VAbv,  VAbv,     H,    WJ,    WJ,
-  /* 0A50 */    WJ, VMBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,    WJ,     B,    WJ,
-  /* 0A60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0A70 */ VMAbv, CMAbv,    GB,    GB,     O,  MBlw,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Gujarati */
-
-  /* 0A80 */    WJ, VMAbv, VMAbv, VMPst,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,
-  /* 0A90 */     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0AA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 0AB0 */     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,    WJ,    WJ, CMBlw,     B,  VPst,  VPre,
-  /* 0AC0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,    WJ,  VAbv,  VAbv,  VAbv,    WJ,  VPst,  VPst,     H,    WJ,    WJ,
-  /* 0AD0 */     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 0AE0 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0AF0 */     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv,
-
-  /* Oriya */
-
-  /* 0B00 */    WJ, VMAbv, VMPst, VMPst,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     B,
-  /* 0B10 */     B,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 0B30 */     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,    WJ,    WJ, CMBlw,     B,  VPst,  VAbv,
-  /* 0B40 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,    WJ,    WJ,  VPre,  VPre,    WJ,    WJ,  VPre,  VPre,     H,    WJ,    WJ,
-  /* 0B50 */    WJ,    WJ,    WJ,    WJ,    WJ,  VAbv,  VAbv,  VAbv,    WJ,    WJ,    WJ,    WJ,     B,     B,    WJ,     B,
-  /* 0B60 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0B70 */     O,     B,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Tamil */
-
-  /* 0B80 */    WJ,    WJ, VMAbv,     O,    WJ,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,     B,     B,
-  /* 0B90 */     B,    WJ,     B,     B,     B,     B,    WJ,    WJ,    WJ,     B,     B,    WJ,     B,    WJ,     B,     B,
-  /* 0BA0 */    WJ,    WJ,    WJ,     B,     B,    WJ,    WJ,    WJ,     B,     B,     B,    WJ,    WJ,    WJ,     B,     B,
-  /* 0BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,  VPst,  VPst,
-  /* 0BC0 */  VAbv,  VPst,  VPst,    WJ,    WJ,    WJ,  VPre,  VPre,  VPre,    WJ,  VPre,  VPre,  VPre,     H,    WJ,    WJ,
-  /* 0BD0 */     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 0BE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0BF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Telugu */
-
-  /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,
-  /* 0C10 */     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 0C30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ, CMBlw,     B,  VAbv,  VAbv,
-  /* 0C40 */  VAbv,  VPst,  VPst,  VPst,  VPst,    WJ,  VAbv,  VAbv,  VAbv,    WJ,  VAbv,  VAbv,  VAbv,     H,    WJ,    WJ,
-  /* 0C50 */    WJ,    WJ,    WJ,    WJ,    WJ,  VAbv,  VBlw,    WJ,     B,     B,     B,    WJ,    WJ,     O,    WJ,    WJ,
-  /* 0C60 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0C70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-
-  /* Kannada */
-
-  /* 0C80 */     B, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,
-  /* 0C90 */     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 0CB0 */     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,    WJ,    WJ, CMBlw,     B,  VPst,  VAbv,
-  /* 0CC0 */  VAbv,  VPst,  VPst,  VPst,  VPst,    WJ,  VAbv,  VAbv,  VAbv,    WJ,  VAbv,  VAbv,  VAbv,     H,    WJ,    WJ,
-  /* 0CD0 */    WJ,    WJ,    WJ,    WJ,    WJ,  VPst,  VPst,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     B,    WJ,
-  /* 0CE0 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0CF0 */    WJ,    CS,    CS,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Malayalam */
-
-  /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,
-  /* 0D10 */     B,    WJ,     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,    WJ,  VPre,  VPre,  VPre,    WJ,  VPre,  VPre,  VPre,     H,     R,     O,
-  /* 0D50 */    WJ,    WJ,    WJ,    WJ,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,
-  /* 0D60 */     B,     B,  VBlw,  VBlw,    WJ,    WJ,     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 */    WJ, VMAbv, VMPst, VMPst,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0D90 */     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,     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,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,    WJ,    WJ,
-  /* 0DC0 */     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,   HVM,    WJ,    WJ,    WJ,    WJ,  VPst,
-  /* 0DD0 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,    WJ,  VBlw,    WJ,  VPst,  VPre,  VPre,  VPre,  VPre,  VPre,  VPre,  VPst,
-  /* 0DE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0DF0 */    WJ,    WJ,  VPst,  VPst,     O,    WJ,    WJ,    WJ,
-
-#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,    WJ,     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,    WJ,    WJ,    WJ,
-  /* 0F70 */    WJ, 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,    WJ,   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,    WJ,     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,    IS,  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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Buhid */
-
-  /* 1740 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1750 */     B,     B,  VAbv,  VBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Tagbanwa */
-
-  /* 1760 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,
-  /* 1770 */     B,    WJ,  VAbv,  VBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    IS, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,    WJ,    WJ,
-  /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 17F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Mongolian */
-
-  /* 1800 */     B,     O,     O,     O,     O,     O,     O,     B,     O,     O,     B,   CGJ,   CGJ,   CGJ,    WJ,   CGJ,
-  /* 1810 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#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,    WJ,
-  /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,    WJ,    WJ,    WJ,    WJ,
-  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw, VMAbv, FMBlw,    WJ,    WJ,    WJ,    WJ,
-  /* 1940 */     O,    WJ,    WJ,    WJ,     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,    WJ,    WJ,
-  /* 1970 */     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,     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,    WJ,    WJ,     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,    WJ,
-  /* 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,    WJ,    WJ, VMBlw,
-  /* 1A80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 1A90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#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,    WJ,    WJ,    WJ,
-  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 1B60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
-  /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,
-
-  /* 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,    IS,   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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     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,    WJ,    WJ,    WJ,     O,     O,     O,     O,     O,
-  /* 1C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,     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,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#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,    WJ,  ZWNJ,   CGJ,    WJ,    WJ,
-  /* 2010 */    GB,    GB,    GB,    GB,    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2020 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,     O,
-  /* 2030 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2040 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2050 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2060 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Superscripts and Subscripts */
-
-  /* 2070 */     O,     O,    WJ,    WJ, 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 3184
-
-
-  /* Combining Diacritical Marks for Symbols */
-
-  /* 20F0 */ VMAbv,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x25c8u 3192
-
-
-  /* Geometric Shapes */
-                                                                         O,     O,     O,     O,     B,     O,     O,     O,
-
-#define use_offset_0x2d30u 3200
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,
-  /* 2D70 */     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     H,
-
-#define use_offset_0xa800u 3280
-
-
-  /* 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,    WJ,    WJ,    WJ,
-  /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     O,
-  /* A8D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     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,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,     O,
-  /* A9D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,     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,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* AA40 */     B,     B,     B,  FAbv,     B,     B,     B,     B,     B,     B,     B,     B,  FAbv,  FPst,    WJ,    WJ,
-  /* AA50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* AAD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     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,    IS,    WJ,
-
-#define use_offset_0xabc0u 4040
-
-
-  /* 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,    WJ,    WJ,
-  /* ABF0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0xfe00u 4104
-
-
-  /* Variation Selectors */
-
-  /* FE00 */   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,   CGJ,
-
-#define use_offset_0xfef8u 4120
-
-
-  /* Arabic Presentation Forms-B */
-                                                                         O,     O,     O,     O,     O,    WJ,    WJ,    WJ,
-
-#define use_offset_0xfff0u 4128
-
-
-  /* Specials */
-
-  /* FFF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     O,     O,     O,     O,    WJ,    WJ,
-
-#define use_offset_0x10570u 4144
-
-
-  /* Vithkuqi */
-
-  /* 10570 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,
-  /* 10580 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,
-  /* 10590 */     B,     B,     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 105A0 */     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 105B0 */     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,    WJ,    WJ,    WJ,
-
-#define use_offset_0x10a00u 4224
-
-
-  /* Kharoshthi */
-
-  /* 10A00 */     B,  VBlw,  VBlw,  VBlw,    WJ,  VAbv,  VBlw,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst, VMBlw, VMBlw, VMAbv,
-  /* 10A10 */     B,     B,     B,     B,    WJ,     B,     B,     B,    WJ,     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,    WJ,    WJ, CMBlw, CMBlw, CMBlw,    WJ,    WJ,    WJ,    WJ,    IS,
-  /* 10A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x10ac0u 4304
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,     B,
-
-#define use_offset_0x10b80u 4352
-
-
-  /* Psalter Pahlavi */
-
-  /* 10B80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10B90 */     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     O,     O,     O,    WJ,    WJ,    WJ,
-  /* 10BA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     O,
-
-#define use_offset_0x10d00u 4400
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 10D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x10e80u 4464
-
-
-  /* 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,    WJ,  VAbv,  VAbv,     O,    WJ,    WJ,
-  /* 10EB0 */     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x10f30u 4520
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 10F60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 10F90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 10FA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,
-  /* 10FD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,
-  /* 11050 */    WJ,    WJ,     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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    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,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x11100u 4928
-
-
-  /* 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,    IS, CMAbv,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,     O, 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 */    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 111F0 */     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Khojki */
-
-  /* 11200 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11210 */     B,     B,    WJ,     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,    WJ,
-
-#define use_offset_0x11280u 5248
-
-
-  /* Multani */
-
-  /* 11280 */     B,     B,     B,     B,     B,     B,     B,    WJ,     B,    WJ,     B,     B,     B,     B,    WJ,     B,
-  /* 11290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,
-  /* 112A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 112F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Grantha */
-
-  /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     B,
-  /* 11310 */     B,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
-  /* 11330 */     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,    WJ, CMBlw, CMBlw,     B,  VPst,  VPst,
-  /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,    WJ,    WJ,  VPre,  VPre,    WJ,    WJ,  VPre,  VPre,     H,    WJ,    WJ,
-  /* 11350 */     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     B,     B,
-  /* 11360 */     B,     B,  VPst,  VPst,    WJ,    WJ, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    WJ,    WJ,    WJ,
-  /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    WJ,    WJ,    WJ,
-
-#define use_offset_0x11400u 5496
-
-
-  /* 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,    WJ,     O, FMAbv,     B,
-  /* 11460 */    CS,    CS,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11470 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 114D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x11580u 5720
-
-
-  /* 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,    WJ,    WJ,  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,    WJ,    WJ,
-  /* 115E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 115F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11650 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11660 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,
-  /* 11670 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 116D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 116E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 116F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,  MBlw,  MPre,  MAbv,
-  /* 11720 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VBlw,  VAbv,  VAbv,  VAbv,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,
-
-#define use_offset_0x11800u 6176
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x11900u 6240
-
-
-  /* Dives Akuru */
-
-  /* 11900 */     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     B,    WJ,    WJ,     B,     B,     B,     B,
-  /* 11910 */     B,     B,     B,     B,    WJ,     B,     B,    WJ,     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,    WJ,  VPre,  VPre,    WJ,    WJ, VMAbv, VMAbv,  VPst,    IS,     R,
-  /* 11940 */  MPst,     R,  MPst, CMBlw,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x119a0u 6336
-
-
-  /* Nandinagari */
-
-  /* 119A0 */     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     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,    WJ,    WJ,  VAbv,  VAbv,  VPst,  VPst, VMPst, VMPst,
-  /* 119E0 */     H,     B,     O,     O,  VPre,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 119F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    IS,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    IS,     O,     O,     O,     B,     O,     O,
-
-#define use_offset_0x11c00u 6592
-
-
-  /* Bhaiksuki */
-
-  /* 11C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     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,    WJ,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMAbv, VMPst,     H,
-  /* 11C40 */     B,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,    WJ,
-
-  /* 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 */    WJ,    WJ,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
-  /* 11CA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,    WJ,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
-  /* 11CB0 */  VBlw,  VPre,  VBlw,  VAbv,  VPst, VMAbv, VMAbv,    WJ,
-
-#define use_offset_0x11d00u 6776
-
-
-  /* Masaram Gondi */
-
-  /* 11D00 */     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,    WJ,     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,    WJ,    WJ,    WJ,  VAbv,    WJ,  VAbv,  VAbv,    WJ,  VAbv,
-  /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,    IS,     R,  MBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* Gunjala Gondi */
-
-  /* 11D60 */     B,     B,     B,     B,     B,     B,    WJ,     B,     B,    WJ,     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,    WJ,
-  /* 11D90 */  VAbv,  VAbv,    WJ,  VPst,  VPst, VMAbv, VMPst,    IS,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 11DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x11ee0u 6952
-
-
-  /* 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 6976
-
-
-  /* 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,    WJ,
-
-  /* Egyptian Hieroglyph Format Controls */
-
-  /* 13430 */     H,     H,     H,     H,     H,     H,     H,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-#define use_offset_0x16ac0u 8064
-
-
-  /* Tangsa */
-
-  /* 16AC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 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,    WJ,    WJ,
-  /* 16AF0 */     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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 8184
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ, 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,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ, VMBlw,
-  /* 16F90 */ VMBlw, VMBlw, VMBlw,     O,     O,     O,     O,     O,
-
-#define use_offset_0x16fe0u 8336
-
-
-  /* Ideographic Symbols and Punctuation */
-
-  /* 16FE0 */     O,     O,     O,     O,     B,    WJ,    WJ,    WJ,
-
-#define use_offset_0x18b00u 8344
-
-
-  /* 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,    WJ,    WJ,
-
-#define use_offset_0x1bc00u 8816
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 1BC70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,
-  /* 1BC80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* 1BC90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     O, CMBlw, CMBlw,     O,
-
-#define use_offset_0x1d170u 8976
-
-
-  /* Musical Symbols */
-
-  /* 1D170 */     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     O,     O,     O,     O,
-
-#define use_offset_0x1e100u 8992
-
-
-  /* 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,    WJ,    WJ,    WJ,
-  /* 1E130 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,
-  /* 1E140 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,     B,     B,
-
-#define use_offset_0x1e290u 9072
-
-
-  /* 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,    WJ,
-  /* 1E2B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,    WJ,     O,
-
-#define use_offset_0x1e900u 9184
-
-
-  /* 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,    WJ,    WJ,    WJ,    WJ,
-  /* 1E950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,     O,     O,
-
-#define use_offset_0xe0000u 9280
-
-
-  /* Tags */
-
-  /* E0000 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0010 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0020 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0030 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0040 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0050 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0060 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0070 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* No_Block */
-
-  /* E0080 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0090 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E00F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-  /* 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,
-
-  /* No_Block */
-
-  /* E01F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0200 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0210 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0220 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0230 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0240 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0250 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0260 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0270 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0280 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0290 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E02F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0300 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0310 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0320 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0330 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0340 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0350 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0360 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0370 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0380 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0390 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E03F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0400 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0410 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0420 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0430 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0440 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0450 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0460 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0470 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0480 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0490 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E04F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0500 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0510 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0520 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0530 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0540 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0550 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0560 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0570 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0580 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0590 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E05F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0600 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0610 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0620 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0630 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0640 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0650 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0660 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0670 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0680 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0690 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E06F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0700 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0710 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0720 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0730 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0740 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0750 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0760 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0770 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0780 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0790 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E07F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0800 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0810 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0820 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0830 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0840 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0850 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0860 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0870 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0880 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0890 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E08F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0900 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0910 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0920 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0930 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0940 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0950 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0960 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0970 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0980 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0990 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09A0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09B0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09C0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09D0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09E0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E09F0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0A90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0AF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0B90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0BF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0C90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0CF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0D90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0DF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0E90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0EA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0EB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0EC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0ED0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0EE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0EF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F00 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F10 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F20 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F30 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F40 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F50 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F60 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F70 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F80 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0F90 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FA0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FB0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FC0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FD0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FE0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-  /* E0FF0 */    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
-
-}; /* Table items: 13376; occupancy: 84% */
-
-static inline uint8_t
-hb_use_get_category (hb_glyph_info_t info)
+static const uint8_t
+hb_use_u8[1842] =
 {
-  hb_codepoint_t u = info.codepoint;
-  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, 0x2087u)) return use_table[u - 0x2008u + use_offset_0x2008u];
-      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];
-      if (hb_in_range<hb_codepoint_t> (u, 0xFEF8u, 0xFEFFu)) return use_table[u - 0xFEF8u + use_offset_0xfef8u];
-      if (hb_in_range<hb_codepoint_t> (u, 0xFFF0u, 0xFFFFu)) return use_table[u - 0xFFF0u + use_offset_0xfff0u];
-      break;
-
-    case 0x10u:
-      if (hb_in_range<hb_codepoint_t> (u, 0xFFF0u, 0xFFFFu)) return use_table[u - 0xFFF0u + use_offset_0xfff0u];
-      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 0x1Du:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1D170u, 0x1D17Fu)) return use_table[u - 0x1D170u + use_offset_0x1d170u];
-      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, 0xE0000u, 0xE0FFFu)) return use_table[u - 0xE0000u + use_offset_0xe0000u];
-      break;
-
-    case 0xE1u:
-      if (hb_in_range<hb_codepoint_t> (u, 0xE0000u, 0xE0FFFu)) return use_table[u - 0xE0000u + use_offset_0xe0000u];
-      break;
-
-    default:
-      break;
-  }
-  if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED)
-    return WJ;
-  return O;
+      0,    1,    2,    3,    3,    3,    3,    3,    3,    3,    4,    3,    3,    3,    3,    5,
+      6,    7,    3,    8,    3,    3,    9,    3,   10,    3,    3,   11,    3,   12,   13,    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,    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,    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,    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,    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,
+      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,    3,    3,    3,
+      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+     14,    0,    0,    1,    1,    2,    1,    1,    3,    4,    5,    6,    7,    8,    9,   10,
+      1,   11,   12,    1,    1,    1,    1,    1,    1,   13,   14,   15,   16,   17,   18,   19,
+      1,    1,   20,    1,    1,    1,    1,   21,    1,    1,    1,    1,    1,    1,    1,   22,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   23,   24,   25,   26,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+     27,   28,    1,    1,    1,    1,    1,   29,    1,    1,    1,    1,   30,   31,    1,   32,
+     33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,    1,   46,   47,
+     48,    1,   49,   49,   49,   49,   50,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   51,   52,    1,    1,
+      1,   53,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   49,   54,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   55,    1,
+      1,    1,    1,   56,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,    1,   57,   58,    1,    1,    1,    1,    1,    1,   59,    1,    1,    1,    1,
+      1,    1,   60,   61,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+     60,   60,    O,    O,    O,    O,    O,   GB,    O,    O,    B,    B,    B,    B,    B,    B,
+      O,    O,   GB,    O,    O,    O,    O,   WJ,    O,    O,    O,    O,FMPst,FMPst,    O,    O,
+      O,   GB,    O,    O,    O,  CGJ,    B,    O,    O,    O,    O,    O,    B,    B,    B,    B,
+      B,VMAbv,VMAbv,VMAbv,VMAbv,VMAbv,    O,    O,    B,    O,    O,VMAbv,    O,    O,    B,CMBlw,
+  CMBlw,CMBlw,VMAbv,VMAbv,VMAbv,VMPst,    B,    B, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw,
+   VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst,    H, VPre, VPst,    O,VMAbv,
+  VMBlw,    O,    O, VAbv, VBlw, VBlw,    B,    B, VBlw, VBlw,   GB,VMAbv,VMPst,VMPst,    O,    B,
+      B,    B,    B,    O,    O,    B,    B,    O,    B,    B,    B,    O,    B,    O, VBlw,    O,
+      O, VPre, VPre,    O,    O, VPre, VPre,    H,    O,    O,    O,    O,    O, VPst,    B,    B,
+      O,    B,    B,    O,FMAbv,    O,    O,VMAbv,VMAbv,VMPst,    B,    B,    B,    O,    O,    O,
+      O,    B,    O,    B,    B,    O,CMBlw,    O, VPst, VPre, VPst, VBlw, VBlw,    O,    O,    O,
+      O, VAbv, VAbv,    O,    O, VAbv, VAbv,    H,    O,    O,    O,VMBlw,    O,    O,VMAbv,CMAbv,
+     GB,   GB,    O, MBlw,    O,    O, VBlw, VAbv,    O, VAbv, VAbv, VAbv,    O, VPst, VPst,    H,
+      O,    O,    O,    B,VMAbv,VMAbv,VMAbv,CMAbv,CMAbv,CMAbv,    O,VMAbv,VMPst,VMPst,CMBlw,    B,
+   VPst, VAbv,    O, VAbv, VAbv, VAbv,    O,    B,    O,    O,    O,    O,VMAbv,    O,    O,    O,
+   VPst, VPst, VAbv, VPst, VPst,    O,    O,    O, VPre, VPre, VPre,    O, VPre, VPre,VMAbv,VMPst,
+  VMPst,VMPst,VMAbv,    B,    B,    B,CMBlw,    B, VAbv, VAbv, VPst,    O, VAbv, VAbv, VAbv,    O,
+   VAbv, VAbv,    O, VAbv, VBlw,    O,    B,VMAbv,VMPst,VMPst,    O, VPst, VPst,    O,    O,   CS,
+     CS,    O,VMAbv,VMAbv,VMPst,VMPst,    B,    B,    B, VAbv, VAbv,    B, VPst, VPst, VPst, VPst,
+   VPst, VBlw, VBlw,    O, VPre, VPre, VPre,    H,    R,    O,    O,    O,  HVM,    O, VPst, VPst,
+   VAbv, VAbv, VBlw,    O, VBlw,    O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, VBlw, VBlw,
+      O,    O,    O, FBlw,    O, FBlw,    O,CMAbv,    O,    O,    O,    O, VPst, VPre,    O,CMBlw,
+   VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,VMAbv,    O, VBlw, VAbv,
+  VMAbv,VMAbv, VBlw,    O,VMAbv,VMAbv,    B,  SUB,  SUB,  SUB,  SUB,  SUB,  SUB,  SUB,    O,  SUB,
+    SUB,  SUB,  SUB,    O,    O,    O,    O,    O, FBlw,    O,    B,    B,    B, VPst, VPst, VAbv,
+   VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv, VAbv,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw,
+   MBlw,    B,    B,    B,    O,   GB,    O,    O,   GB,    O,    B,    B, VPst, VPst, VBlw, VBlw,
+      B,    B,    B,    B, MBlw, MBlw, MBlw,    B, VPst,VMPst,VMPst,    B,    B, VPst, VPst,VMPst,
+  VMPst,VMPst,VMPst,VMPst,    B,    B,    B, VAbv, VAbv, VAbv, VAbv,    B,    B,    B,    B,    B,
+   MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMPst,VMPst,VMPst,VMPst,VMBlw,    B,VMPst,    B,    B,
+  VMPst,VMPst, VPst, VAbv,    O,    O,    B,    B, VAbv, VBlw, VBlw, VPst,    O,    O, VPst,    O,
+      O,    O,    B,    O, VAbv, VBlw,  CGJ,  CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw,
+   VPre, VPre, VPre, VPre, VPre, VPre, VPre, VPre,VMAbv,VMPst, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,
+  FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    O,    O,    O,    O,    B,  CGJ,  CGJ,  CGJ,
+     WJ,  CGJ,   GB,   GB,   GB,   GB,   GB,CMAbv,CMAbv,    B,    B,CMBlw,    B,    O,   GB,    B,
+      B,    B, VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv,  SUB,  SUB,  SUB, FPst, FPst,
+  VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw,VMAbv,FMBlw,VMPst,VMPst,    O,    O, VAbv, VPre,
+   VPst, VAbv,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,  SUB,  SUB,  SUB,    O,   Sk, VPst,
+   VAbv, VPst, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, VPre, VPre, VPre, VAbv,VMAbv,VMAbv,
+   VAbv,VMAbv,VMAbv,    O,    O,VMBlw,VMAbv,VMAbv,VMAbv, FAbv,VMPst,    B,    B,    B,CMAbv, VPst,
+   VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, VPre, VPre, VAbv, VAbv,    H,    B,
+      B,    B,    O,    O,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,VMAbv, FAbv,
+  VMPst,    B, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst,   IS,  SUB,  SUB,    B,    B,    B,    B,
+  CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv, FAbv, FAbv,CMBlw,CMBlw,  SUB,  SUB,
+   VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv,VMPre,VMPre,
+  FMAbv,CMBlw,VMAbv,VMAbv,VMAbv,    O,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMAbv,VMAbv,VMAbv,VMPst,
+  VMBlw,VMBlw,VMBlw,    O,    O,    O,VMAbv,   CS,   CS,VMPst,VMAbv,VMAbv,   GB,    O,    O,    O,
+      O,FMAbv,    O,    O,    O,   WJ, ZWNJ,  CGJ,   WJ,   WJ,    O,    O,   WJ,   WJ,   WJ,   WJ,
+     WJ,    O,   WJ,   WJ,   WJ,   WJ,FMPst,    O,    O,    O,VMAbv,    O,    O,    O,    O,    O,
+      O,    H,    B,    B, VAbv,    B,    B,    B,    H,    B, VPst, VBlw, VAbv, VPst, VBlw,    O,
+      O,    O, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst,    H,VMAbv,    O,    O,VMAbv,VMAbv,
+      B,    B,    O,    O,    B, VAbv,    B,    B, VAbv, VAbv, VAbv, VAbv, VAbv,VMBlw,VMBlw,VMBlw,
+      O,    O,    B,    B,    B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv, FAbv, FAbv,
+   FPst, VPst,VMAbv,VMAbv, FAbv,VMPst,    B,    B,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O,
+      O,    O,    B, VAbv,    O,    B,    B,VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre, VPre, VAbv,
+   VBlw, MPst, MPre, MAbv, MBlw,    O,    B,    B,    B, FAbv, FAbv, FPst,    O,    O,   GB,   GB,
+     GB,    O,    O,    O,    B,VMPst,VMAbv,VMPst,    B,    B, VAbv,    B, VAbv, VAbv, VBlw,    B,
+      B, VAbv,    B,    B, VAbv,VMAbv,    B,VMAbv,    B,    O,    B,    B,    B, VPre, VBlw, VAbv,
+   VPre, VPst,    O,VMPst,   IS,    O, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst,    O,VMPst, VBlw,
+      O,    O,  CGJ,  CGJ,  CGJ,  CGJ,   WJ,    O,    O,    O,    B, VBlw, VBlw, VBlw, VPst,VMBlw,
+  VMBlw,VMAbv,CMBlw,CMBlw,CMBlw,    O,    O,    O,    O,   IS,    B,CMBlw,CMBlw,    O,VMAbv,VMAbv,
+  VMAbv,CMAbv,    B,    B,    O, VAbv, VAbv,    O,    O,    O,    B,    B,VMBlw,VMBlw,VMBlw,    B,
+      B,    B,    B,    B,CMBlw,CMBlw,CMBlw,CMBlw,    O,    O,VMPst,VMAbv,VMPst,   CS,   CS,    B,
+      B,    B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,    H,    O,    O,    O,
+      N,    N,    N,    N,    N,    N,    N,    N,    B,    B, VAbv,    B,    B, VAbv, VAbv,    B,
+      O,    O,    O,    O,    O,   HN,VMAbv,VMAbv,VMPst,    B, VPst, VPre, VPst, VBlw, VBlw, VAbv,
+   VAbv, VPst, VPst,    H,CMBlw,    O,    O,    O, VBlw,    O,VMAbv,VMAbv,VMAbv,    B, VPre, VBlw,
+   VAbv, VAbv, VBlw, VAbv, VAbv,   IS,CMAbv,    O,    B,    B,    B, VPst, VPst,    B,    B,    B,
+      B,CMBlw, VPre, VPst, VBlw, VBlw,    H,    B,    R,    R,    O,FMBlw,CMBlw, VAbv, VBlw,    O,
+   VPre,VMAbv,VMAbv,    H,CMAbv,CMAbv, VAbv,CMBlw, VBlw,    O,    B,    B,    O,CMBlw,CMBlw,    B,
+   VPst, VPst, VPst,    O,    O, VPre,    O,    O,VMAbv,VMAbv,    B, VPst, VPre, VPst, VPst, VPst,
+      H,VMAbv,VMAbv,VMPst,CMBlw,    B,    O,    O,FMAbv,    B,   CS,   CS,    O,    O, VBlw, VPre,
+   VAbv, VPre, VPre, VPst, VPre,VMAbv,VMAbv,VMAbv,    H,CMBlw,VMAbv,VMAbv,VMPst,    H,CMBlw,    O,
+      O,    O, VPst,VMAbv,VMPst,    H,VMPst, VAbv, VPre, VPst, VAbv, VAbv,    H,CMBlw,    O, MBlw,
+   MPre, MAbv, VBlw, VBlw, VPre, VAbv, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,VMAbv,VMPst,    H,
+  CMBlw,    O, VPst, VPre,    O, VPre, VPre,    O,    O,VMAbv,VMAbv, VPst,   IS,    R, MPst,    R,
+   MPst,CMBlw,    O,    O, VAbv, VAbv, VPst, VPst,VMPst,VMPst,    H,    B,    O,    O, VPre,    O,
+      O,    O,    B, VAbv, VBlw, VBlw, VAbv, VAbv, VBlw,    B,    B,    B,    B,FMBlw, VBlw,VMAbv,
+  VMAbv,VMAbv,VMAbv,VMPst,    R, MBlw, MBlw, MBlw, MBlw,   GB,    O,   GB,    O,   IS, VAbv, VAbv,
+   VAbv, VPst,    R,    R,    R,    R,    R,    R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
+  VMAbv,VMPst,CMAbv,   IS,    O,    O, VBlw, VBlw, VBlw,    O,    O,    O,  SUB,  SUB, VBlw, VPre,
+   VBlw, VAbv, VPst,VMAbv,VMAbv,    O, VAbv, VAbv, VBlw,    O,    O,    O, VAbv,    O, VAbv, VAbv,
+      O, VAbv,VMAbv,VMAbv,CMBlw, VAbv, VBlw,   IS,    R, MBlw, VPst, VPst, VPst,    O, VPst,VMAbv,
+  VMPst,   IS,    B,    B,   GB, VAbv, VBlw, VPre, VPst,    O,    H,    H,    H,    H,    H,    H,
+      H,    B,    O,    O,    O,CMBlw,    O, VBlw, VBlw, VBlw,    O,    O,    O,VMBlw,VMBlw,VMBlw,
+  VMBlw,    O,    O,CMBlw,CMBlw,    O,    B,    B,VMAbv,    O,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,
+  CMAbv,    B,
+};
+static const uint16_t
+hb_use_u16[2056] =
+{
+    0,  0,  1,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  5,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  7,  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, 10, 11,
+    0,  0,  0,  0,  9, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   13,  9,  9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 17, 25,
+   26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35,  0, 17, 36,
+   37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46, 30,  0,
+   47, 48, 21, 49, 50, 51, 17,  0, 52, 48, 21, 53, 50, 54, 17, 55,
+   56, 48,  9, 57, 58, 59, 17,  0, 60, 61,  9, 62, 63, 64, 30, 65,
+   66, 67,  9, 68, 69,  9, 70, 71, 72, 73, 74, 75, 76,  0,  0,  0,
+    9,  9, 77, 78, 79, 80, 81, 82, 83, 84,  0,  0,  0,  0,  0,  0,
+    9, 85,  9, 86,  9, 87, 88, 89,  9,  9,  9, 90, 91, 92,  2,  0,
+   93,  0,  9,  9,  9,  9,  9, 94, 95,  9, 96,  0,  0,  0,  0,  0,
+   97, 98, 99,100, 30,  9,101,102,  9,  9,103,  9,104,105,  0,  0,
+    9,106,  9,  9,  9,107,108,109,  2,  2,  0,  0,  0,  0,  0,  0,
+  110,  9,  9,111,112,  2,113,114,115,  9,116,  9,  9,  9,117,118,
+    9,  9,119,120,121,  0,  0,  0,  0,  0,  0,  0,  0,122,123,124,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,125,
+  126,127,128,  0,  0,  0,129,130,131,  0,  0,  0,  0,  0,  0,132,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,133,  0,  0,  0,
+    0,  0,  0,  9,  9,  9,134,135,  0,  0,  0,  0,  0,  0,  0,  0,
+  136,  9,137,  0,  9,  9,  9,138,139,  9,  9,140,141,  2,142,143,
+    9,  9,144,  9,145,146,  0,  0,147,  9,  9,148,149,  2,150, 98,
+    9,  9,151,152,153,  2,  9,154,  9,  9,  9,155,156,  0,157,158,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,159,  2,
+  160,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,161,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,
+    0,  0,  0,  0,  0,  0,  0,163,163,164, 33,165,  0,  0,  0,  0,
+  166,167,  9,168, 94,  0,  0,  0,  0,  0,  0,  0, 69,  9,169,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  9,170,171,  0,  0,  0,  0,  0,
+    9,  9,172,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  9,  9,173,170,  0,  0,  0,  0,
+    0,  0,  0,  9,174,175,  0,  9,176,  0,  0,177,178,  0,  0,  0,
+  179,  9,  9,180,181,182,183,184,185,  9,  9,186,187,  0,  0,  0,
+  188,  9,189,190,191,  9,  9,192,185,  9,  9,193,194,105,195,102,
+    9, 33,196,197,  0,  0,  0,  0,198,199, 94,  9,  9,200,201,  2,
+  202, 20, 21,203,204,205,206,207,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  9,  9,208,209,210,211,  0,195,  9,  9,212,213,  2,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  9,  9,214,215,216,217,  0,  0,
+    9,  9,  9,218,219,  2,  0,  0,  9,  9,220,221,  2,  0,  0,  0,
+    9,222,223,103,224,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  9,225,226,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  227,228,  9,229,230,  2,  0,  0,  0,  0,231,  9,  9,232,233,  0,
+  234,  9,  9,235,236,237,  9,  9,238,239,  0,  0,  0,  0,  0,  0,
+   21,  9,214,240,  7,  9, 70, 18,  9,241, 73,242,  0,  0,  0,  0,
+  243,  9,  9,244,245,  2,246,  9,247,248,  2,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,249,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9, 98,250,  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,  0,  0,  0,
+    9,  9,  9,251,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  9,  9,  9,252,253,254,254,255,256,  0,  0,  0,  0,257,  0,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,258,  0,  0,
+    9,  9,  9,  9,  9,  9,105, 70, 94,259,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,260,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  9, 70,261,262,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  9,263,  0,  9,  9,264,  2,
+    9,  9,  9,  9,265,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
+  160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
+    0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  3,  0,  4,  0,  0,  5,
+    6,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,
+    0,  0, 10,  2,  2,  2,  2,  2,  2,  2, 11, 12, 12,  0, 13, 14,
+    2,  2, 15,  0, 16,  2,  2,  2,  2,  2, 17, 18, 19, 20, 21, 22,
+   23, 24,  2,  2, 25, 10,  2,  2, 10,  2,  2,  2, 26, 27,  2, 28,
+   28,  2,  2,  2,  2,  2, 29,  2, 30, 10,  3, 18, 19, 31, 32, 33,
+    0, 34,  0, 35,  3,  0,  0, 36, 37, 27, 38, 39, 29, 40,  3, 41,
+   42, 43, 44, 45, 46,  0, 27, 30,  0, 10,  2,  2, 47, 48,  0,  0,
+   37, 27,  2, 35, 35,  2,  2,  2, 29, 27,  3, 18, 19, 49, 50, 51,
+    0,  0, 52, 53, 54, 27,  2, 28, 29, 27,  3, 55,  0, 56,  0, 35,
+   57,  0,  0,  0, 58, 27, 38, 10, 29,  3, 40, 29, 39,  9, 38, 10,
+    2,  2,  3, 59, 60, 61, 62, 33,  0, 34,  0,  0, 63, 64,  2, 29,
+   29,  2,  2,  2,  2,  2,  3, 65, 21, 66, 67, 45,  0, 68, 38,  0,
+   69, 27,  2, 29,  2, 27,  3, 55,  0, 70,  0, 13, 71,  0,  0,  0,
+   72,  2,  2, 29,  2,  2, 73, 74, 75, 76, 62, 77,  0, 34,  0, 39,
+   54, 27,  2,  2,  2, 38, 10,  2, 35,  2,  2, 57,  2, 38, 78, 34,
+   79, 80, 81, 82, 59,  0,  0,  0,  3, 38,  0,  0,  0,  0, 83,  0,
+    2, 84, 85, 86,  2,  2, 27,  2,  2,  2,  2,  9, 87, 88, 89, 90,
+   91, 92,  2, 93, 94, 94, 95, 94, 94, 94, 94, 94, 94, 94, 94, 96,
+    0, 97,  0,  0,  2,  2, 98, 99,100,101,102,103,  2,  2,104,105,
+    2,106,107,108,109,110,111,112,113,114,  2,  2,115,116,117,118,
+    2,  2,119,120,121,122,  0, 39,121,123,  0,  0,121,  0,  0,  0,
+    2,  2,  2, 29,124,  0,  0,  0,  2,125,126,127,128,129,130,131,
+  132,  0,  0,133,  9, 39,134,135,  2,  2,  9,  0,136,137,  2,  2,
+    2,  2,138,  0,139,  2,  2,  2,  2,  2,  2, 38,140,141,142,  0,
+  143,144,145,  0,  2,  2,  2,  3,  2,  9,  0,  0,  2,  2,  2,  0,
+    2,  2,146,  0,  2,  2, 38,  0,  2, 73,147,  0,  2,148,149,150,
+  151,141,152,153,154, 12,155,156,157,158,  2,  2,  2,159,160,161,
+  162,163,  2,  9,  0,  0,164,165,166,  0,  0,  0,167,  2,  2,  2,
+   93,168,169,170,  2,171,172,173,174,  0,  0,  0,  2,175,176,177,
+  178,179,  0,  0,  2,  2,  3, 27,180,181,182,181,183,181,184, 46,
+    0,185,186,  0,  0,  0,187,  0,  0,  0,188,189,136,  4,  0,  0,
+    0,  0,190,191,192,192,192,192,  0,193,  0,  0,  6,193,  0,  0,
+  194,  0,  0,  0,  0,  0,  0,  9,  2,  2,  0, 39,  0,  0,  0,195,
+  196,197, 11,  2, 98,198,  0,199,  2,  0,  0,  0,112,  2,  2,  2,
+    2,200,201,201,201,202,  0,  0, 12, 12, 12, 12,203,  0,  0,204,
+    2,205,206,207,  2,208,209,210,211,  0,  0,  0,212,  2,  2,  2,
+  213, 79,127,214,215,  0,  0,  0,  2,216,  2,  2,  2,  2,217,218,
+  219,220,  0,  0,221,  2,  2,222, 27,223,224,225,226,227,114,228,
+  229,  0,  0,  0,  2,  2,230,231,  0,232,  0,  0, 98,233,234,235,
+  236,236,236,236,  0,  0,  0,188,192,192,237,  0,  2,  2, 38,  2,
+   38, 35,  2,  2, 35,  2, 35,  9,238, 68,  0,239,  2, 27, 27,  2,
+    2,  3,240,241,  2,242, 39,  2,  3,  0,  0,  0,  0,  0, 27, 38,
+    2,243,  0,  0,  2,  2,244,245,  2,246,181,181,247,  9,  0,  0,
+  248,249,  0,  0, 29, 38,  2,  2, 27,  9, 27,  0,250,251,  2,  2,
+    2,  2,252,160,253,254,  0,  0,255,256,256,256,256,257,  2,  2,
+  258,259,  0,260,261,  2,  2,  2,262,263,264,  0,265,  0,  0,  0,
+  266,  2,  2,  2,  2,208,253,267,268,269,  2,  2,  0,270,  0,  0,
+  271,  0,  0,  0, 98,272,160,252,273,  0,274,275, 27,  2,  2,  2,
+    2,  2,  2, 75,252,276,  0, 58,  2, 38, 29, 35,  2,  2,  2, 35,
+    2,  2,  2, 11,262, 20,277,  0, 12, 27,  2, 28, 29, 27,278,279,
+   21,280, 32, 33,  0, 34,  0, 10,106,281, 12,194, 12,194,  0,  0,
+    2,282,160,253,283,284,  0,  0,  2,  2,  3,285,286,  0,  0,  0,
+  262,160,287,288,289,  9,  0,  0,  2,  2,  2, 98,272, 83,128,290,
+  291,  0,  0,  0,  0,  0,  2, 83, 75,160,263,292,245,  0,  0,  0,
+    2,  2, 11,293,253,294,  9,  0,  2,  2, 38,295, 79,296, 20,  0,
+    2, 38,  0,  0,  2,  2,  2,262,297,298,299,  0,  2, 38, 57,  2,
+    2, 40,  2,  2,201,300,301,302,303,  0,  0,  0,  2,  2, 10,  2,
+  282,160,304,305,306,307,  0,  0,308,252,309,  2,310,311,312,313,
+    0,314,  0,  0,308,315, 19,  2,  2,316,317,318,318,319,320, 57,
+   89,321,252,290,322, 94, 94, 94,323,324,  0,  0,  2, 38, 35,  2,
+  113,325,326,327,328,329,  0,  0,  2, 35, 29,  2,  2,  2,106,330,
+   50,331,  0,  0,332,333,  0,  0,334,335,  9,  0, 12,180,  0,  0,
+    2,  2, 38,336,337,160,160,160,160,160,160,160,160,160,  0,338,
+  339,  0,  0,  0,  0,  9,  0,  0,  2,  3,  0,  0,  2,  2,  3,340,
+  188,192,191,  0, 12,266,  2,  3,  2,  2,  3, 10,  2,  2,  2,341,
+    2,  2,  2, 12,  2,342,343,  0,
+};
+
+static inline uint_fast8_t
+hb_use_get_category (unsigned u)
+{
+  return u<921600u?hb_use_u8[466+(((hb_use_u16[992+(((hb_use_u16[((hb_use_u8[226+(((hb_use_u8[u>>2>>2>>4>>4])<<4)+((u>>2>>2>>4)&15u))])<<4)+((u>>2>>2)&15u)])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:O;
 }
 
 #undef B
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use.cc
index 60394ed4d8a34601046960d889ff66676d6ddfe9..c40ec52f9c4dcf49cd1b2322895e89ab6f0f82ce 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-use.cc
@@ -206,7 +206,7 @@ setup_masks_use (const hb_ot_shape_plan_t *plan,
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    info[i].use_category() = hb_use_get_category (info[i]);
+    info[i].use_category() = hb_use_get_category (info[i].codepoint);
 }
 
 static void
@@ -490,12 +490,12 @@ const hb_ot_shaper_t _hb_ot_shaper_use =
   data_destroy_use,
   preprocess_text_use,
   nullptr, /* postprocess_glyphs */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   nullptr, /* decompose */
   compose_use,
   setup_masks_use,
-  HB_TAG_NONE, /* gpos_tag */
   nullptr, /* reorder_marks */
+  HB_TAG_NONE, /* gpos_tag */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper.hh
index b823bf003c5c7e0ce25424df3197ad0121e8c24e..e160987f83edecdbfd34032513b35689643f81d2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper.hh
@@ -117,8 +117,6 @@ struct hb_ot_shaper_t
 			      hb_font_t                *font);
 
 
-  hb_ot_shape_normalization_mode_t normalization_preference;
-
   /* decompose()
    * Called during shape()'s normalization.
    * May be NULL.
@@ -147,12 +145,6 @@ struct hb_ot_shaper_t
 		       hb_buffer_t              *buffer,
 		       hb_font_t                *font);
 
-  /* gpos_tag()
-   * If not HB_TAG_NONE, then must match found GPOS script tag for
-   * GPOS to be applied.  Otherwise, fallback positioning will be used.
-   */
-  hb_tag_t gpos_tag;
-
   /* reorder_marks()
    * Called during shape().
    * Shapers can use to modify ordering of combining marks.
@@ -163,6 +155,14 @@ struct hb_ot_shaper_t
 			 unsigned int              start,
 			 unsigned int              end);
 
+  /* gpos_tag()
+   * If not HB_TAG_NONE, then must match found GPOS script tag for
+   * GPOS to be applied.  Otherwise, fallback positioning will be used.
+   */
+  hb_tag_t gpos_tag;
+
+  hb_ot_shape_normalization_mode_t normalization_preference;
+
   hb_ot_shape_zero_width_marks_type_t zero_width_marks;
 
   bool fallback_position;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-stat-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-stat-table.hh
index 41d1734b39397b18649aef5af4117f510cedbf26..d83bf1421947ba9ae8ddc75e30e1236a7141e7bf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-stat-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-stat-table.hh
@@ -57,6 +57,31 @@ enum
   // Reserved = 0xFFFC				/* Reserved for future use — set to zero. */
 };
 
+struct StatAxisRecord
+{
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  hb_ot_name_id_t get_name_id () const { return nameID; }
+
+  hb_tag_t get_axis_tag () const { return tag; }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  protected:
+  Tag		tag;		/* A tag identifying the axis of design variation. */
+  NameID	nameID;		/* The name ID for entries in the 'name' table that
+				 * provide a display string for this axis. */
+  HBUINT16	ordering;	/* A value that applications can use to determine
+				 * primary sorting of face names, or for ordering
+				 * of descriptors when composing family or face names. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
 struct AxisValueFormat1
 {
   unsigned int get_axis_index () const { return axisIndex; }
@@ -64,10 +89,41 @@ struct AxisValueFormat1
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>*  user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -92,10 +148,41 @@ struct AxisValueFormat2
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>*  user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -124,10 +211,41 @@ struct AxisValueFormat3
 
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -155,7 +273,7 @@ struct AxisValueRecord
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -172,12 +290,47 @@ struct AxisValueFormat4
   const AxisValueRecord &get_axis_record (unsigned int axis_index) const
   { return axisValues.as_array (axisCount)[axis_index]; }
 
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
+
+    for (const auto& rec : axis_value_records)
+    {
+      unsigned axis_idx = rec.get_axis_index ();
+      float axis_value = rec.get_value ();
+      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
+
+      if (user_axes_location->has (axis_tag) &&
+          fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f)
+        return false;
+    }
+
+    return true;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float> *user_axes_location = c->plan->user_axes_location;
+    if (!keep_axis_value (axis_records, user_axes_location))
+      return_trace (false);
+
+    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
+    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
+    if (unlikely (!out)) return_trace (false);
+    memcpy (out, this, total_size);
+    return_trace (true);
+  }
+
   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (likely (c->check_struct (this) &&
+                          axisValues.sanitize (c, axisCount)));
   }
 
   protected:
@@ -234,6 +387,33 @@ struct AxisValue
     }
   }
 
+  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)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
+    case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
+    case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
+    case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
+    default:return false;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -263,27 +443,35 @@ struct AxisValue
   DEFINE_SIZE_UNION (2, format);
 };
 
-struct StatAxisRecord
+struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
 {
-  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+  bool subset (hb_subset_context_t *c,
+               unsigned axisValueCount,
+               unsigned& count,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out)) return_trace (false);
 
-  hb_ot_name_id_t get_name_id () const { return nameID; }
+    auto axisValueOffsets = as_array (axisValueCount);
+    count = 0;
+    for (const auto& offset : axisValueOffsets)
+    {
+      if (!offset) continue;
+      auto o_snap = c->serializer->snapshot ();
+      auto *o = c->serializer->embed (offset);
+      if (!o) return_trace (false);
+      if (!o->serialize_subset (c, offset, this, axis_records))
+      {
+        c->serializer->revert (o_snap);
+        continue;
+      }
+      count++;
+    }
 
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (count);
   }
-
-  protected:
-  Tag		tag;		/* A tag identifying the axis of design variation. */
-  NameID	nameID;		/* The name ID for entries in the 'name' table that
-				 * provide a display string for this axis. */
-  HBUINT16	ordering;	/* A value that applications can use to determine
-				 * primary sorting of face names, or for ordering
-				 * of descriptors when composing family or face names. */
-  public:
-  DEFINE_SIZE_STATIC (8);
 };
 
 struct STAT
@@ -329,7 +517,8 @@ struct STAT
     return axis_value.get_value_name_id ();
   }
 
-  void collect_name_ids (hb_set_t *nameids_to_retain) const
+  void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+                         hb_set_t *nameids_to_retain /* OUT */) const
   {
     if (!has_data ()) return;
 
@@ -338,13 +527,38 @@ struct STAT
     | hb_sink (nameids_to_retain)
     ;
 
+    auto designAxes = get_design_axes ();
+
     + get_axis_value_offsets ()
     | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+    | hb_filter ([&] (const AxisValue& _)
+                 { return _.keep_axis_value (designAxes, user_axes_location); })
     | hb_map (&AxisValue::get_value_name_id)
     | hb_sink (nameids_to_retain)
     ;
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    STAT *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto designAxes = get_design_axes ();
+    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
+      if (unlikely (!c->serializer->embed (designAxes[i])))
+          return_trace (false);
+
+    if (designAxisCount)
+      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
+                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    unsigned count = 0;
+    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
+                                                    axisValueCount, count, designAxes);
+    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -381,7 +595,7 @@ struct STAT
 				 * set to zero; if designAxisCount is greater
 				 * than zero, must be greater than zero. */
   HBUINT16	axisValueCount;	/* The number of axis value tables. */
-  NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
+  NNOffset32To<AxisValueOffsetArray>
 		offsetToAxisValueOffsets;
 				/* Offset in bytes from the beginning of
 				 * the STAT table to the start of the design
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
index ce5cdce98bd2e7ca872faefa8ae7b4f7fceac297..ceb3bf6df5016c00fb7cd6420e324520c5c20cae 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag.cc
@@ -214,6 +214,8 @@ lang_matches (const char *lang_str,
 	      const char *spec,
 	      unsigned    spec_len)
 {
+  /* Same as hb_language_matches(); duplicated. */
+
   if (likely ((unsigned) (limit - lang_str) < spec_len))
     return false;
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-avar-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-avar-table.hh
index 65f26c1d22dd76d54575b65e241f29f551f45d79..5946aef635d5bc46f3b7775195e17841763627ec 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-avar-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-avar-table.hh
@@ -28,6 +28,8 @@
 #define HB_OT_VAR_AVAR_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-var-common.hh"
+
 
 /*
  * avar -- Axis Variations
@@ -40,6 +42,28 @@
 namespace OT {
 
 
+/* "Spec": https://github.com/be-fonts/boring-expansion-spec/issues/14 */
+struct avarV2Tail
+{
+  friend struct avar;
+
+  bool sanitize (hb_sanitize_context_t *c,
+		 const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (varIdxMap.sanitize (c, base) &&
+		  varStore.sanitize (c, base));
+  }
+
+  protected:
+  Offset32To<DeltaSetIndexMap>	varIdxMap;	/* Offset from the beginning of 'avar' table. */
+  Offset32To<VariationStore>	varStore;	/* Offset from the beginning of 'avar' table. */
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+
 struct AxisValueMap
 {
   bool sanitize (hb_sanitize_context_t *c) const
@@ -106,12 +130,24 @@ struct avar
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
 
+  bool has_data () const { return version.to_int (); }
+
+  const SegmentMaps* get_segment_maps () const
+  { return &firstAxisSegmentMaps; }
+
+  unsigned get_axis_count () const
+  { return axisCount; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!(version.sanitize (c) &&
-		    version.major == 1 &&
-		    c->check_struct (this))))
+    if (!(version.sanitize (c) &&
+	  (version.major == 1
+#ifndef HB_NO_VARIATIONS2
+	   || version.major == 2
+#endif
+	   ) &&
+	  c->check_struct (this)))
       return_trace (false);
 
     const SegmentMaps *map = &firstAxisSegmentMaps;
@@ -123,6 +159,15 @@ struct avar
       map = &StructAfter<SegmentMaps> (*map);
     }
 
+#ifndef HB_NO_VARIATIONS2
+    if (version.major < 2)
+      return_trace (true);
+
+    const auto &v2 = * (const avarV2Tail *) map;
+    if (unlikely (!v2.sanitize (c, this)))
+      return_trace (false);
+#endif
+
     return_trace (true);
   }
 
@@ -136,6 +181,37 @@ struct avar
       coords[i] = map->map (coords[i]);
       map = &StructAfter<SegmentMaps> (*map);
     }
+
+#ifndef HB_NO_VARIATIONS2
+    if (version.major < 2)
+      return;
+
+    for (; count < axisCount; count++)
+      map = &StructAfter<SegmentMaps> (*map);
+
+    const auto &v2 = * (const avarV2Tail *) map;
+
+    const auto &varidx_map = this+v2.varIdxMap;
+    const auto &var_store = this+v2.varStore;
+    auto *var_store_cache = var_store.create_cache ();
+
+    hb_vector_t<int> out;
+    out.alloc (coords_length);
+    for (unsigned i = 0; i < coords_length; i++)
+    {
+      int v = coords[i];
+      uint32_t varidx = varidx_map.map (i);
+      float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache);
+      v += roundf (delta);
+      v = hb_clamp (v, -(1<<14), +(1<<14));
+      out.push (v);
+    }
+
+    OT::VariationStore::destroy_cache (var_store_cache);
+
+    for (unsigned i = 0; i < coords_length; i++)
+      coords[i] = out[i];
+#endif
   }
 
   void unmap_coords (int *coords, unsigned int coords_length) const
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-common.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-common.hh
index 0eafb949d54cc78a7efac0ab78b05f388d5a0033..1d29e3e4f96e648851be93c1c2dced02dc4c4750 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-common.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-common.hh
@@ -31,12 +31,13 @@
 
 namespace OT {
 
-struct DeltaSetIndexMapFormat0
+template <typename MapCountT>
+struct DeltaSetIndexMapFormat01
 {
   friend struct DeltaSetIndexMap;
 
   private:
-  DeltaSetIndexMapFormat0* copy (hb_serialize_context_t *c) const
+  DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
@@ -128,56 +129,12 @@ struct DeltaSetIndexMapFormat0
   HBUINT8       format;         /* Format identifier--format = 0 */
   HBUINT8       entryFormat;    /* A packed field that describes the compressed
                                  * representation of delta-set indices. */
-  HBUINT16      mapCount;       /* The number of mapping entries. */
+  MapCountT     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);
+  DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
 };
 
 struct DeltaSetIndexMap
@@ -186,8 +143,11 @@ struct DeltaSetIndexMap
   bool serialize (hb_serialize_context_t *c, const T &plan)
   {
     TRACE_SERIALIZE (this);
+    unsigned length = plan.get_output_map ().length;
+    u.format = length <= 0xFFFF ? 0 : 1;
     switch (u.format) {
     case 0: return_trace (u.format0.serialize (c, plan));
+    case 1: return_trace (u.format1.serialize (c, plan));
     default:return_trace (false);
     }
   }
@@ -196,6 +156,7 @@ struct DeltaSetIndexMap
   {
     switch (u.format) {
     case 0: return (u.format0.map (v));
+    case 1: return (u.format1.map (v));
     default:return v;
     }
   }
@@ -250,9 +211,9 @@ struct DeltaSetIndexMap
 
   protected:
   union {
-  HBUINT8                       format;         /* Format identifier */
-  DeltaSetIndexMapFormat0       format0;
-  DeltaSetIndexMapFormat1       format1;
+  HBUINT8                            format;         /* Format identifier */
+  DeltaSetIndexMapFormat01<HBUINT16> format0;
+  DeltaSetIndexMapFormat01<HBUINT32> format1;
   } u;
   public:
   DEFINE_SIZE_UNION (1, format);
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-fvar-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-fvar-table.hh
index c5c476bc0e06a36a3a960dbaf3b48f0a7db77364..b9b49f2287e327108dcbffdc69677bb405585e19 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-fvar-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-fvar-table.hh
@@ -96,6 +96,8 @@ struct AxisRecord
     info->reserved = 0;
   }
 
+  hb_tag_t get_axis_tag () const { return axisTag; }
+
   int normalize_axis_value (float v) const
   {
     float min_value, default_value, max_value;
@@ -133,7 +135,6 @@ struct AxisRecord
     return_trace (c->check_struct (this));
   }
 
-  protected:
   void get_coordinates (float &min, float &default_, float &max) const
   {
     default_ = defaultValue / 65536.f;
@@ -142,6 +143,11 @@ struct AxisRecord
     max = hb_max (default_, maxValue / 65536.f);
   }
 
+  float get_default () const
+  {
+    return defaultValue / 65536.f;
+  }
+
   public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
   protected:
@@ -270,24 +276,49 @@ struct fvar
     return axisCount;
   }
 
-  void collect_name_ids (hb_set_t *nameids) const
+  void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+			 hb_set_t *nameids  /* IN/OUT */) const
   {
     if (!has_data ()) return;
+    hb_map_t pinned_axes;
 
-    + get_axes ()
-    | hb_map (&AxisRecord::get_name_id)
-    | hb_sink (nameids)
-    ;
-
-    + hb_range ((unsigned) instanceCount)
-    | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); })
-    | hb_sink (nameids)
-    ;
+    auto axis_records = get_axes ();
+    for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+    {
+      hb_tag_t axis_tag = axis_records[i].get_axis_tag ();
+      if (user_axes_location->has (axis_tag))
+      {
+        pinned_axes.set (i, axis_tag);
+        continue;
+      }
+
+      nameids->add (axis_records[i].get_name_id ());
+    }
 
-    + hb_range ((unsigned) instanceCount)
-    | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); })
-    | hb_sink (nameids)
-    ;
+    for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+    {
+      const InstanceRecord *instance = get_instance (i);
+
+      if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
+                  | hb_filter (pinned_axes, hb_second)
+                  | hb_map ([&] (const hb_pair_t<const HBFixed&, unsigned>& _)
+                            {
+                              hb_tag_t axis_tag = pinned_axes.get (_.second);
+                              float location = user_axes_location->get (axis_tag);
+                              if (fabs ((double)location - (double)_.first.to_float ()) > 0.001) return true;
+                              return false;
+                            })
+                  ))
+        continue;
+
+      nameids->add (instance->subfamilyNameID);
+
+      if (instanceSize >= axisCount * 4 + 6)
+      {
+        unsigned post_script_name_id = StructAfter<NameID> (instance->get_coordinates (axisCount));
+        if (post_script_name_id != HB_OT_NAME_ID_INVALID) nameids->add (post_script_name_id);
+      }
+    }
   }
 
   public:
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-hvar-table.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-hvar-table.hh
index 56efcdbee9e5dfcfac45fc7ac9762ade384b6078..53355c50779105333a38f07f33c96a99c52b7ddb 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-hvar-table.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-hvar-table.hh
@@ -319,27 +319,26 @@ struct HVARVVAR
 						hvar_plan.index_map_plans.as_array ()));
   }
 
-  float get_advance_var (hb_codepoint_t  glyph,
-			 hb_font_t      *font,
-			 VariationStore::cache_t *store_cache = nullptr) const
+  float get_advance_delta_unscaled (hb_codepoint_t  glyph,
+				    const int *coords, unsigned int coord_count,
+				    VariationStore::cache_t *store_cache = nullptr) const
   {
     uint32_t varidx = (this+advMap).map (glyph);
     return (this+varStore).get_delta (varidx,
-				      font->coords,
-				      font->num_coords,
+				      coords, coord_count,
 				      store_cache);
   }
 
-  float get_side_bearing_var (hb_codepoint_t glyph,
-			      const int *coords, unsigned int coord_count) const
+  bool get_lsb_delta_unscaled (hb_codepoint_t glyph,
+			       const int *coords, unsigned int coord_count,
+			       float *lsb) const
   {
-    if (!has_side_bearing_deltas ()) return 0.f;
+    if (!lsbMap) return false;
     uint32_t varidx = (this+lsbMap).map (glyph);
-    return (this+varStore).get_delta (varidx, coords, coord_count);
+    *lsb = (this+varStore).get_delta (varidx, coords, coord_count);
+    return true;
   }
 
-  bool has_side_bearing_deltas () const { return lsbMap && rsbMap; }
-
   public:
   FixedVersion<>version;	/* Version of the metrics variation table
 				 * initially set to 0x00010000u */
@@ -392,6 +391,16 @@ struct VVAR : HVARVVAR {
 
   bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
 
+  bool get_vorg_delta_unscaled (hb_codepoint_t glyph,
+				const int *coords, unsigned int coord_count,
+				float *delta) const
+  {
+    if (!vorgMap) return false;
+    uint32_t varidx = (this+vorgMap).map (glyph);
+    *delta = (this+varStore).get_delta (varidx, coords, coord_count);
+    return true;
+  }
+
   protected:
   Offset32To<DeltaSetIndexMap>
 		vorgMap;	/* Offset to vertical-origin var-idx mapping. */
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var.cc
index 0376e26b4aa03c9298fffe3fd75e553585457509..f000f272636e59576b89abc257e47f34487d5b8b 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var.cc
@@ -56,7 +56,7 @@
  *
  * Tests whether a face includes any OpenType variation data in the `fvar` table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.4.2
  **/
@@ -162,7 +162,7 @@ hb_ot_var_get_axis_infos (hb_face_t             *face,
  * Fetches the variation-axis information corresponding to the specified axis tag
  * in the specified face.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.2.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh
index 683a441ec36f4bdf03f88993ee81c4e83a67681c..173fe4a2fb87929a462efe323fc69f1fd6886233 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh
@@ -172,7 +172,7 @@ hb_resolve_overflows (const T& packed,
       && will_overflow)
   {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
-    if (sorted_graph.assign_32bit_spaces ())
+    if (sorted_graph.assign_spaces ())
       sorted_graph.sort_shortest_distance ();
   }
 
@@ -181,7 +181,7 @@ hb_resolve_overflows (const T& packed,
   // TODO(garretrieger): select a good limit for max rounds.
   while (!sorted_graph.in_error ()
          && graph::will_overflow (sorted_graph, &overflows)
-         && round++ < max_rounds) {
+         && round < max_rounds) {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round);
     print_overflows (sorted_graph, overflows);
 
@@ -189,6 +189,9 @@ hb_resolve_overflows (const T& packed,
 
     if (!_try_isolating_subgraphs (overflows, sorted_graph))
     {
+      // Don't count space isolation towards round limit. Only increment
+      // round counter if space isolation made no changes.
+      round++;
       if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
       {
         DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc
index 2d458294f8adcdf6ef333c3f2889b15ea5ec1de8..5bf9d7c8cd20fa7e9b15a04f9d1dbcde673e192f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc
@@ -56,8 +56,6 @@ hb_set_create ()
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
-  set->init_shallow ();
-
   return set;
 }
 
@@ -107,8 +105,6 @@ hb_set_destroy (hb_set_t *set)
 {
   if (!hb_object_destroy (set)) return;
 
-  set->fini_shallow ();
-
   hb_free (set);
 }
 
@@ -122,7 +118,7 @@ hb_set_destroy (hb_set_t *set)
  *
  * Attaches a user-data key/data pair to the specified set.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -162,7 +158,7 @@ hb_set_get_user_data (hb_set_t           *set,
  *
  * Tests whether memory allocation for a set was successful.
  *
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -212,7 +208,7 @@ hb_set_clear (hb_set_t *set)
  *
  * Tests whether a set is empty (contains no elements).
  *
- * Return value: %true if @set is empty
+ * Return value: `true` if @set is empty
  *
  * Since: 0.9.7
  **/
@@ -229,7 +225,7 @@ hb_set_is_empty (const hb_set_t *set)
  *
  * Tests whether @codepoint belongs to @set.
  *
- * Return value: %true if @codepoint is in @set, %false otherwise
+ * Return value: `true` if @codepoint is in @set, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -348,7 +344,7 @@ hb_set_del_range (hb_set_t       *set,
  * Tests whether @set and @other are equal (contain the same
  * elements).
  *
- * Return value: %true if the two sets are equal, %false otherwise.
+ * Return value: `true` if the two sets are equal, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -383,7 +379,7 @@ hb_set_hash (const hb_set_t *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
  **/
@@ -553,7 +549,7 @@ hb_set_get_max (const hb_set_t *set)
  *
  * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a next value, %false otherwise
+ * Return value: `true` if there was a next value, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -574,7 +570,7 @@ hb_set_next (const hb_set_t *set,
  *
  * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a previous value, %false otherwise
+ * Return value: `true` if there was a previous value, `false` otherwise
  *
  * Since: 1.8.0
  **/
@@ -597,7 +593,7 @@ hb_set_previous (const hb_set_t *set,
  *
  * Set @last to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a next range, %false otherwise
+ * Return value: `true` if there was a next range, `false` otherwise
  *
  * Since: 0.9.7
  **/
@@ -621,7 +617,7 @@ hb_set_next_range (const hb_set_t *set,
  *
  * Set @first to #HB_SET_VALUE_INVALID to get started.
  *
- * Return value: %true if there was a previous range, %false otherwise
+ * Return value: `true` if there was a previous range, `false` otherwise
  *
  * Since: 1.8.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
index 7eb5e19a2a634c0d3291f53ea0f5e4e8ef00b2d2..5d5576cb9ecafc973895108393060fcab3a18996 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
@@ -59,17 +59,15 @@ struct hb_sparseset_t
     hb_copy (o, *this);
   }
 
-  void init_shallow () { s.init (); }
   void init ()
   {
     hb_object_init (this);
-    init_shallow ();
+    s.init ();
   }
-  void fini_shallow () { s.fini (); }
   void fini ()
   {
     hb_object_fini (this);
-    fini_shallow ();
+    s.fini ();
   }
 
   explicit operator bool () const { return !is_empty (); }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc
index 0af07825fc956bc7f596e771dfe9d553003ba4ae..8dbb661cd2229c16dba640a0288a654781f81fd8 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc
@@ -117,7 +117,7 @@ hb_shape_plan_key_t::init (bool                           copy,
   }
   else
   {
-    const hb_shaper_entry_t *shapers = _hb_shapers_get ();
+    const HB_UNUSED hb_shaper_entry_t *shapers = _hb_shapers_get ();
     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
       if (false)
 	;
@@ -318,10 +318,6 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 {
   if (!hb_object_destroy (shape_plan)) return;
 
-#ifndef HB_NO_OT_SHAPE
-  shape_plan->ot.fini ();
-#endif
-  shape_plan->key.fini ();
   hb_free (shape_plan);
 }
 
@@ -335,7 +331,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
  *
  * Attaches a user-data key/data pair to the given shaping plan. 
  *
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -440,7 +436,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t    *shape_plan,
  * Executes the given shaping plan on the specified buffer, using
  * the given @font and @features.
  *
- * Return value: %true if success, %false otherwise.
+ * Return value: `true` if success, `false` otherwise.
  *
  * Since: 0.9.7
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.hh
index 8cb4ddb927c45f5388307ce51cd4e09eeec9aa4a..6fc73939b37ffee3bb5421a38fbdd23498b2fd5e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.hh
@@ -55,7 +55,7 @@ struct hb_shape_plan_key_t
 			 unsigned int                   num_coords,
 			 const char * const            *shaper_list);
 
-  HB_INTERNAL void fini () { hb_free ((void *) user_features); }
+  HB_INTERNAL void fini () { hb_free ((void *) user_features); user_features = nullptr; }
 
   HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
 
@@ -64,6 +64,7 @@ struct hb_shape_plan_key_t
 
 struct hb_shape_plan_t
 {
+  ~hb_shape_plan_t () { key.fini (); }
   hb_object_header_t header;
   hb_face_t *face_unsafe; /* We don't carry a reference to face. */
   hb_shape_plan_key_t key;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
index 14ec92828fcd446ddca695bc5df92c65ffb07cd1..547d0afc470702349db189dd85ffa29277c70ade 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-shape.cc
@@ -106,12 +106,12 @@ hb_shape_list_shapers ()
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
  * @features: (array length=num_features) (nullable): an array of user
- *    specified #hb_feature_t or %NULL
+ *    specified #hb_feature_t or `NULL`
  * @num_features: the length of @features array
- * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated
- *    array of shapers to use or %NULL
+ * @shaper_list: (array zero-terminated=1) (nullable): a `NULL`-terminated
+ *    array of shapers to use or `NULL`
  *
- * See hb_shape() for details. If @shaper_list is not %NULL, the specified
+ * See hb_shape() for details. If @shaper_list is not `NULL`, the specified
  * shapers will be used in the given order, otherwise the default shapers list
  * will be used.
  *
@@ -173,11 +173,11 @@ hb_shape_full (hb_font_t          *font,
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
  * @features: (array length=num_features) (nullable): an array of user
- *    specified #hb_feature_t or %NULL
+ *    specified #hb_feature_t or `NULL`
  * @num_features: the length of @features array
  *
  * Shapes @buffer using @font turning its Unicode characters content to
- * positioned glyphs. If @features is not %NULL, it will be used to control the
+ * positioned glyphs. If @features is not `NULL`, it will be used to control the
  * features applied during shaping. If two @features have the same tag but
  * overlapping ranges the value of the feature with the higher index takes
  * precedence.
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-shaper.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-shaper.cc
index da4253ed649468c9af691dd0bc5bf9d457a48674..a900ac69917ee34866c8823c6686ff232b977a5d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-shaper.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-shaper.cc
@@ -64,7 +64,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<hb_shaper_entry_t,
       if (!end)
 	end = p + strlen (p);
 
-      for (unsigned int j = i; j < ARRAY_LENGTH (_hb_all_shapers); j++)
+      for (unsigned int j = i; j < ARRAY_LENGTH_CONST (_hb_all_shapers); j++)
 	if (end - p == (int) strlen (shapers[j].name) &&
 	    0 == strncmp (shapers[j].name, p, end - p))
 	{
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
index 5c5ecce880949edc114c12390da4b668e9dcd725..af95615c162c7b9a60436c67f8d05318768cde94 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
@@ -46,11 +46,10 @@ uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof
 DEFINE_NULL_NAMESPACE_BYTES (OT, Index) =  {0xFF,0xFF};
 DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) =  {0xFF,0xFF,0xFF,0xFF};
 DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
-DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00};
+DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x01};
 DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00};
 DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF};
-/* Hand-coded because Lookup is a template.  Sad. */
-const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
+DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
 
 
 /* hb_map_t */
@@ -59,7 +58,7 @@ const hb_codepoint_t minus_1 = -1;
 
 /* hb_face_t */
 
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
 static inline unsigned
 load_num_glyphs_from_loca (const hb_face_t *face)
 {
@@ -89,7 +88,7 @@ hb_face_t::load_num_glyphs () const
 {
   unsigned ret = 0;
 
-#ifndef HB_NO_BORING_EXPANSION
+#ifndef HB_NO_BEYOND_64K
   ret = hb_max (ret, load_num_glyphs_from_loca (this));
 #endif
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc
index 028ddf9035e034afc73310aaae0fd821b5e13a4e..7d1949627525f22b7fea810e9bc88342bd1cabb4 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc
@@ -32,7 +32,7 @@
  *
  * Creates a new subset input object.
  *
- * Return value: (transfer full): New subset input, or %NULL if failed. Destroy
+ * Return value: (transfer full): New subset input, or `NULL` if failed. Destroy
  * with hb_subset_input_destroy().
  *
  * Since: 1.8.0
@@ -48,7 +48,9 @@ hb_subset_input_create_or_fail (void)
   for (auto& set : input->sets_iter ())
     set = hb_set_create ();
 
-  if (input->in_error ())
+  input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
+  
+  if (!input->axes_location || input->in_error ())
   {
     hb_subset_input_destroy (input);
     return nullptr;
@@ -96,7 +98,6 @@ hb_subset_input_create_or_fail (void)
     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));
@@ -203,6 +204,8 @@ hb_subset_input_create_or_fail (void)
 
   input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
 
+  input->sets.layout_scripts->invert (); // Default to all scripts.
+
   if (input->in_error ())
   {
     hb_subset_input_destroy (input);
@@ -244,6 +247,8 @@ hb_subset_input_destroy (hb_subset_input_t *input)
   for (hb_set_t* set : input->sets_iter ())
     hb_set_destroy (set);
 
+  hb_hashmap_destroy (input->axes_location);
+
   hb_free (input);
 }
 
@@ -342,7 +347,7 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
  *
  * Attaches a user-data key/data pair to the given subset input object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 2.9.0
  **/
@@ -374,3 +379,56 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
 {
   return hb_object_get_user_data (input, key);
 }
+
+#ifdef HB_EXPERIMENTAL_API
+#ifndef HB_NO_VAR
+/**
+ * hb_subset_input_pin_axis_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ *
+ * Pin an axis to its default location in the given subset input object.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: REPLACEME
+ **/
+hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
+                                     hb_face_t          *face,
+                                     hb_tag_t            axis_tag)
+{
+  hb_ot_var_axis_info_t axis_info;
+  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+    return false;
+
+  return input->axes_location->set (axis_tag, axis_info.default_value);
+}
+
+/**
+ * hb_subset_input_pin_axis_location: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis to be pinned
+ * @axis_value: Location on the axis to be pinned at
+ *
+ * Pin an axis to a fixed location in the given subset input object.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: REPLACEME
+ **/
+hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
+                                   hb_face_t          *face,
+                                   hb_tag_t            axis_tag,
+                                   float               axis_value)
+{
+  hb_ot_var_axis_info_t axis_info;
+  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+    return false;
+
+  float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
+  return input->axes_location->set (axis_tag, val);
+}
+#endif
+#endif
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh
index 07c0e2267604065d2c61693a19083bd8fb7d2935..2335f0634f03949fda58270eebd57c0999247b88 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh
@@ -50,6 +50,7 @@ struct hb_subset_input_t
     hb_set_t *name_ids;
     hb_set_t *name_languages;
     hb_set_t *layout_features;
+    hb_set_t *layout_scripts;
   };
 
   union {
@@ -58,6 +59,7 @@ struct hb_subset_input_t
   };
 
   unsigned flags;
+  hb_hashmap_t<hb_tag_t, float> *axes_location;
 
   inline unsigned num_sets () const
   {
@@ -76,7 +78,8 @@ struct hb_subset_input_t
       if (unlikely (set_ptrs[i]->in_error ()))
         return true;
     }
-    return false;
+
+    return axes_location->in_error ();
   }
 };
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
index 4e3bb1d47747629549996df75bfcea5bef881bbe..7ff66333a8a612b1f75efdf65fe2a2a3d2843c2e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
@@ -37,10 +37,11 @@
 #include "hb-ot-color-colr-table.hh"
 #include "hb-ot-color-colrv1-closure.hh"
 #include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-var-avar-table.hh"
 #include "hb-ot-stat-table.hh"
 #include "hb-ot-math-table.hh"
 
-using OT::Layout::GSUB::GSUB;
+using OT::Layout::GSUB;
 using OT::Layout::GPOS;
 
 typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
@@ -91,100 +92,171 @@ _remap_indexes (const hb_set_t *indexes,
 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 */);
 
 
+/*
+ * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
+ * Returns true if anything was removed (not including duplicates).
+ */
+static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
+                             const hb_set_t* filter)
+{
+  hb_vector_t<hb_tag_t> out;
+  out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator.
+
+  bool removed = false;
+  hb_set_t visited;
+
+  for (hb_tag_t tag : *tags)
+  {
+    if (!tag) continue;
+    if (visited.has (tag)) continue;
+
+    if (!filter->has (tag))
+    {
+      removed = true;
+      continue;
+    }
+
+    visited.add (tag);
+    out.push (tag);
+  }
+
+  // The collect function needs a null element to signal end of the array.
+  out.push (HB_TAG_NONE);
+
+  hb_swap (out, *tags);
+  return removed;
+}
+
 template <typename T>
-static void _collect_layout_indices (hb_face_t		  *face,
+static void _collect_layout_indices (hb_subset_plan_t     *plan,
                                      const T&              table,
-                                     const hb_set_t	  *layout_features_to_retain,
                                      layout_collect_func_t layout_collect_func,
                                      hb_set_t		  *indices /* OUT */)
 {
+  unsigned num_features = table.get_feature_count ();
   hb_vector_t<hb_tag_t> features;
-  if (!features.alloc (table.get_feature_count () + 1))
+  if (!plan->check_success (features.resize (num_features))) return;
+  table.get_feature_tags (0, &num_features, features.arrayZ);
+  bool retain_all_features = !_filter_tag_list (&features, plan->layout_features);
+
+  unsigned num_scripts = table.get_script_count ();
+  hb_vector_t<hb_tag_t> scripts;
+  if (!plan->check_success (scripts.resize (num_scripts))) return;
+  table.get_script_tags (0, &num_scripts, scripts.arrayZ);
+  bool retain_all_scripts = !_filter_tag_list (&scripts, plan->layout_scripts);
+
+  if (!plan->check_success (!features.in_error ()) || !features
+      || !plan->check_success (!scripts.in_error ()) || !scripts)
     return;
 
-  hb_set_t visited_features;
-  bool retain_all_features = true;
-  for (unsigned i = 0; i < table.get_feature_count (); i++)
+  layout_collect_func (plan->source,
+                       T::tableTag,
+                       retain_all_scripts ? nullptr : scripts.arrayZ,
+		       nullptr,
+		       retain_all_features ? nullptr : features.arrayZ,
+		       indices);
+}
+
+
+static inline void
+_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
+				   const hb_map_t *lookup_indices,
+				   const hb_set_t *feature_indices,
+				   hb_map_t *duplicate_feature_map /* OUT */)
+{
+  if (feature_indices->is_empty ()) return;
+  hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
+  //find out duplicate features after subset
+  for (unsigned i : feature_indices->iter ())
   {
-    hb_tag_t tag = table.get_feature_tag (i);
-    if (!tag) continue;
-    if (!layout_features_to_retain->has (tag))
+    hb_tag_t t = g.get_feature_tag (i);
+    if (t == HB_MAP_VALUE_INVALID) continue;
+    if (!unique_features.has (t))
     {
-      retain_all_features = false;
+      if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
+	return;
+      if (unique_features.has (t))
+	unique_features.get (t)->add (i);
+      duplicate_feature_map->set (i, i);
       continue;
     }
 
-    if (visited_features.has (tag))
-      continue;
+    bool found = false;
 
-    features.push (tag);
-    visited_features.add (tag);
-  }
+    hb_set_t* same_tag_features = unique_features.get (t);
+    for (unsigned other_f_index : same_tag_features->iter ())
+    {
+      const OT::Feature& f = g.get_feature (i);
+      const OT::Feature& other_f = g.get_feature (other_f_index);
 
-  if (!features)
-    return;
+      auto f_iter =
+      + hb_iter (f.lookupIndex)
+      | hb_filter (lookup_indices)
+      ;
 
-  // The collect function needs a null element to signal end of the array.
-  features.push (0);
+      auto other_f_iter =
+      + hb_iter (other_f.lookupIndex)
+      | hb_filter (lookup_indices)
+      ;
 
-  if (retain_all_features)
-  {
-    // Looking for all features, trigger the faster collection method.
-    layout_collect_func (face,
-                         T::tableTag,
-                         nullptr,
-                         nullptr,
-                         nullptr,
-                         indices);
-    return;
-  }
+      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; }
+      }
 
-  layout_collect_func (face,
-                       T::tableTag,
-		       nullptr,
-		       nullptr,
-		       features.arrayZ,
-		       indices);
+      if (is_equal == false || f_iter || other_f_iter) continue;
+
+      found = true;
+      duplicate_feature_map->set (i, other_f_index);
+      break;
+    }
+
+    if (found == false)
+    {
+      same_tag_features->add (i);
+      duplicate_feature_map->set (i, i);
+    }
+  }
 }
 
 template <typename T>
 static inline void
-_closure_glyphs_lookups_features (hb_face_t	     *face,
+_closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
 				  hb_set_t	     *gids_to_retain,
-				  const hb_set_t     *layout_features_to_retain,
 				  hb_map_t	     *lookups,
 				  hb_map_t	     *features,
 				  script_langsys_map *langsys_map)
 {
-  hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
+  hb_blob_ptr_t<T> table = plan->source_table<T> ();
   hb_tag_t table_tag = table->tableTag;
   hb_set_t lookup_indices;
-  _collect_layout_indices<T> (face,
+  _collect_layout_indices<T> (plan,
                               *table,
-                              layout_features_to_retain,
                               hb_ot_layout_collect_lookups,
                               &lookup_indices);
 
   if (table_tag == HB_OT_TAG_GSUB)
-    hb_ot_layout_lookups_substitute_closure (face,
-					    &lookup_indices,
+    hb_ot_layout_lookups_substitute_closure (plan->source,
+                                             &lookup_indices,
 					     gids_to_retain);
-  table->closure_lookups (face,
+  table->closure_lookups (plan->source,
 			  gids_to_retain,
-			 &lookup_indices);
+                          &lookup_indices);
   _remap_indexes (&lookup_indices, lookups);
 
   // Collect and prune features
   hb_set_t feature_indices;
-  _collect_layout_indices<T> (face,
+  _collect_layout_indices<T> (plan,
                               *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);
+  _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map);
 
   feature_indices.clear ();
   table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
@@ -197,14 +269,14 @@ _closure_glyphs_lookups_features (hb_face_t	     *face,
 
 #ifndef HB_NO_VAR
 static inline void
-  _collect_layout_variation_indices (hb_face_t *face,
-				     const hb_set_t *glyphset,
-				     const hb_map_t *gpos_lookups,
-				     hb_set_t  *layout_variation_indices,
-				     hb_map_t  *layout_variation_idx_map)
+_collect_layout_variation_indices (hb_subset_plan_t* plan,
+				   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<GPOS> gpos = hb_sanitize_context_t ().reference_table<GPOS> (face);
+  hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
+  hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
 
   if (!gdef->has_data ())
   {
@@ -215,7 +287,7 @@ static inline void
   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))
+  if (hb_ot_layout_has_positioning (plan->source))
     gpos->collect_variation_indices (&c);
 
   gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
@@ -242,22 +314,16 @@ static void _colr_closure (hb_face_t *face,
   OT::COLR::accelerator_t colr (face);
   if (!colr.is_valid ()) return;
 
-  unsigned iteration_count = 0;
   hb_set_t palette_indices, layer_indices;
-  unsigned glyphs_num;
-  {
-    glyphs_num = glyphs_colred->get_population ();
-    // Collect all glyphs referenced by COLRv0
-    hb_set_t glyphset_colrv0;
-    for (hb_codepoint_t gid : glyphs_colred->iter ())
-      colr.closure_glyphs (gid, &glyphset_colrv0);
+  // Collect all glyphs referenced by COLRv0
+  hb_set_t glyphset_colrv0;
+  for (hb_codepoint_t gid : *glyphs_colred)
+    colr.closure_glyphs (gid, &glyphset_colrv0);
 
-    glyphs_colred->union_ (glyphset_colrv0);
+  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 ());
+  //closure for COLRv1
+  colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
 
   colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
   _remap_indexes (&layer_indices, layers_map);
@@ -265,10 +331,10 @@ static void _colr_closure (hb_face_t *face,
 }
 
 static inline void
-_math_closure (hb_face_t           *face,
-               hb_set_t            *glyphset)
+_math_closure (hb_subset_plan_t *plan,
+               hb_set_t         *glyphset)
 {
-  hb_blob_ptr_t<OT::MATH> math = hb_sanitize_context_t ().reference_table<OT::MATH> (face);
+  hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> ();
   if (math->has_data ())
     math->closure_glyphs (glyphset);
   math.destroy ();
@@ -368,7 +434,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
   for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
     operation_count =
       _glyf_add_gid_and_children (glyf,
-				  item.glyphIndex,
+				  item.get_gid (),
 				  gids_to_retain,
 				  operation_count,
 				  depth);
@@ -395,18 +461,16 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
   if (close_over_gsub)
     // closure all glyphs/lookups/features needed for GSUB substitutions.
     _closure_glyphs_lookups_features<GSUB> (
-        plan->source,
+        plan,
         plan->_glyphset_gsub,
-        plan->layout_features,
         plan->gsub_lookups,
         plan->gsub_features,
         plan->gsub_langsys);
 
   if (close_over_gpos)
     _closure_glyphs_lookups_features<GPOS> (
-        plan->source,
+        plan,
         plan->_glyphset_gsub,
-        plan->layout_features,
         plan->gpos_lookups,
         plan->gpos_features,
         plan->gpos_langsys);
@@ -414,7 +478,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
   _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);
+  _math_closure (plan, plan->_glyphset_mathed);
   _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
 
   hb_set_t cur_glyphset = *plan->_glyphset_mathed;
@@ -442,7 +506,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
 
 #ifndef HB_NO_VAR
   if (close_over_gdef)
-    _collect_layout_variation_indices (plan->source,
+    _collect_layout_variation_indices (plan,
 				       plan->_glyphset_gsub,
 				       plan->gpos_lookups,
 				       plan->layout_variation_indices,
@@ -506,16 +570,62 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
 
 static void
 _nameid_closure (hb_face_t *face,
-		 hb_set_t  *nameids)
+		 hb_set_t  *nameids,
+		 bool all_axes_pinned,
+		 hb_hashmap_t<hb_tag_t, float> *user_axes_location)
 {
 #ifndef HB_NO_STYLE
-  face->table.STAT->collect_name_ids (nameids);
+  face->table.STAT->collect_name_ids (user_axes_location, nameids);
 #endif
 #ifndef HB_NO_VAR
-  face->table.fvar->collect_name_ids (nameids);
+  if (!all_axes_pinned)
+    face->table.fvar->collect_name_ids (user_axes_location, nameids);
 #endif
 }
 
+#ifndef HB_NO_VAR
+static void
+_normalize_axes_location (hb_face_t *face,
+			  const hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+			  hb_hashmap_t<hb_tag_t, int> *normalized_axes_location, /* OUT */
+			  bool &all_axes_pinned)
+{
+  if (user_axes_location->is_empty ())
+    return;
+
+  hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
+
+  bool has_avar = face->table.avar->has_data ();
+  const OT::SegmentMaps *seg_maps = nullptr;
+  if (has_avar)
+    seg_maps = face->table.avar->get_segment_maps ();
+
+  bool axis_not_pinned = false;
+  unsigned axis_count = 0;
+  for (const auto& axis : axes)
+  {
+    hb_tag_t axis_tag = axis.get_axis_tag ();
+    if (!user_axes_location->has (axis_tag))
+    {
+      axis_not_pinned = true;
+    }
+    else
+    {
+      int normalized_v = axis.normalize_axis_value (user_axes_location->get (axis_tag));
+      if (has_avar && axis_count < face->table.avar->get_axis_count ())
+      {
+        normalized_v = seg_maps->map (normalized_v);
+      }
+      normalized_axes_location->set (axis_tag, normalized_v);
+    }
+    if (has_avar)
+      seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
+    
+    axis_count++;
+  }
+  all_axes_pinned = !axis_not_pinned;
+}
+#endif
 /**
  * hb_subset_plan_create_or_fail:
  * @face: font face to create the plan for.
@@ -546,9 +656,9 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
   plan->unicode_to_new_gid_list.init ();
 
   plan->name_ids = hb_set_copy (input->sets.name_ids);
-  _nameid_closure (face, plan->name_ids);
   plan->name_languages = hb_set_copy (input->sets.name_languages);
   plan->layout_features = hb_set_copy (input->sets.layout_features);
+  plan->layout_scripts = hb_set_copy (input->sets.layout_scripts);
   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);
@@ -566,10 +676,8 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
   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->check_success (plan->gsub_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
+  plan->check_success (plan->gpos_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
 
   plan->gsub_features = hb_map_create ();
   plan->gpos_features = hb_map_create ();
@@ -578,6 +686,13 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
   plan->layout_variation_indices = hb_set_create ();
   plan->layout_variation_idx_map = hb_map_create ();
 
+  plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ());
+  plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ());
+  plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
+  if (plan->user_axes_location && input->axes_location)
+      *plan->user_axes_location = *input->axes_location;
+  plan->all_axes_pinned = false;
+
   if (unlikely (plan->in_error ())) {
     hb_subset_plan_destroy (plan);
     return nullptr;
@@ -610,6 +725,14 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
         plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second);
   }
 
+#ifndef HB_NO_VAR
+  _normalize_axes_location (face,
+                            input->axes_location,
+                            plan->axes_location,
+                            plan->all_axes_pinned);
+#endif
+
+  _nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location);
   if (unlikely (plan->in_error ())) {
     hb_subset_plan_destroy (plan);
     return nullptr;
@@ -632,10 +755,10 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
   if (!hb_object_destroy (plan)) return;
 
   hb_set_destroy (plan->unicodes);
-  plan->unicode_to_new_gid_list.fini ();
   hb_set_destroy (plan->name_ids);
   hb_set_destroy (plan->name_languages);
   hb_set_destroy (plan->layout_features);
+  hb_set_destroy (plan->layout_scripts);
   hb_set_destroy (plan->glyphs_requested);
   hb_set_destroy (plan->drop_tables);
   hb_set_destroy (plan->no_subset_tables);
@@ -658,18 +781,15 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
   hb_set_destroy (plan->layout_variation_indices);
   hb_map_destroy (plan->layout_variation_idx_map);
 
-  if (plan->gsub_langsys)
-  {
-    hb_object_destroy (plan->gsub_langsys);
-    plan->gsub_langsys->fini_shallow ();
-    hb_free (plan->gsub_langsys);
-  }
+  hb_hashmap_destroy (plan->gsub_langsys);
+  hb_hashmap_destroy (plan->gpos_langsys);
+  hb_hashmap_destroy (plan->axes_location);
+  hb_hashmap_destroy (plan->sanitized_table_cache);
 
-  if (plan->gpos_langsys)
+  if (plan->user_axes_location)
   {
-    hb_object_destroy (plan->gpos_langsys);
-    plan->gpos_langsys->fini_shallow ();
-    hb_free (plan->gpos_langsys);
+    hb_object_destroy (plan->user_axes_location);
+    hb_free (plan->user_axes_location);
   }
 
   hb_free (plan);
@@ -755,7 +875,7 @@ hb_subset_plan_reference (hb_subset_plan_t *plan)
  *
  * Attaches a user-data key/data pair to the given subset plan object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 4.0.0
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh
index 2aaf19c61de686a1676bb5a8620b836a3c5bd337..8912ae70d50d221ed3ed34e2a056d800cc528027 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh
@@ -55,6 +55,9 @@ struct hb_subset_plan_t
   //layout features which will be preserved
   hb_set_t *layout_features;
 
+  // layout scripts which will be preserved.
+  hb_set_t *layout_scripts;
+
   //glyph ids requested to retain
   hb_set_t *glyphs_requested;
 
@@ -103,8 +106,34 @@ struct hb_subset_plan_t
   //Old -> New layout item variation store delta set index mapping
   hb_map_t *layout_variation_idx_map;
 
+  hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
+  //normalized axes location map
+  hb_hashmap_t<hb_tag_t, int> *axes_location;
+  //user specified axes location map
+  hb_hashmap_t<hb_tag_t, float> *user_axes_location;
+  bool all_axes_pinned;
+
  public:
 
+  template<typename T>
+  hb_blob_ptr_t<T> source_table()
+  {
+    if (sanitized_table_cache
+        && !sanitized_table_cache->in_error ()
+        && sanitized_table_cache->has (T::tableTag)) {
+      return hb_blob_reference (sanitized_table_cache->get (T::tableTag).get ());
+    }
+
+    hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
+    hb_blob_t* ret = hb_blob_reference (table_blob.get ());
+
+    if (likely (sanitized_table_cache))
+      sanitized_table_cache->set (T::tableTag,
+                                  std::move (table_blob));
+
+    return ret;
+  }
+
   bool in_error () const { return !successful; }
 
   bool check_success(bool success)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.cc
index 2447d296b8bfa3628f257feae2fb013c93163c96..03e3feb1f65421665de5fd6e249f5198d833624f 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.cc
@@ -43,7 +43,7 @@ hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_ob
   packed.push (nullptr);
   for (unsigned i = 0 ; i < num_hb_objs ; i++)
     packed.push (&(hb_objects[i]));
+
   return hb_resolve_overflows (packed, HB_OT_TAG_GSUB);
 }
 #endif
-
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.h
index f9a238369820d339aaeab45940cefe0ba48cb22a..e28f879362a506e37903375d300dabbd70ae77b6 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-repacker.h
@@ -31,13 +31,13 @@
 HB_BEGIN_DECLS
 
 #ifdef HB_EXPERIMENTAL_API
-/**
+/*
  * struct hb_link_t
  * width:    offsetSize in bytes
  * position: position of the offset field in bytes
  * from beginning of subtable
  * objidx:   index of subtable
- **/
+ */
 struct hb_link_t
 {
   unsigned width;
@@ -47,7 +47,7 @@ struct hb_link_t
 
 typedef struct hb_link_t hb_link_t;
 
-/**
+/*
  * struct hb_object_t
  * head:    start of object data
  * tail:    end of object data
@@ -56,7 +56,7 @@ typedef struct hb_link_t hb_link_t;
  * num_virtual_links: num of objects that must be packed
  * after current object in the final serialized order
  * virtual_links:     array of virtual link info
- **/
+ */
 struct hb_object_t
 {
   char *head;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
index 10c572c2f7108e0968c9618430026d0a53e035a0..f62e7e895bc8c51b1347b6260d972bbaa74dbe64 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
@@ -53,9 +53,10 @@
 #include "hb-ot-var-gvar-table.hh"
 #include "hb-ot-var-hvar-table.hh"
 #include "hb-ot-math-table.hh"
+#include "hb-ot-stat-table.hh"
 #include "hb-repacker.hh"
 
-using OT::Layout::GSUB::GSUB;
+using OT::Layout::GSUB;
 using OT::Layout::GPOS;
 
 /**
@@ -242,10 +243,15 @@ _try_subset (const TableType *table,
 
   unsigned buf_size = buf->allocated;
   buf_size = buf_size * 2 + 16;
+
+
+
+
   DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
              HB_UNTAG (c->table_tag), buf_size);
 
-  if (unlikely (!buf->alloc (buf_size)))
+  if (unlikely (buf_size > c->source_blob->length * 16 ||
+		!buf->alloc (buf_size)))
   {
     DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
                HB_UNTAG (c->table_tag), buf_size);
@@ -260,15 +266,15 @@ template<typename TableType>
 static bool
 _subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
 {
-  hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
-  const TableType *table = source_blob->as<TableType> ();
+  hb_blob_ptr_t<TableType> source_blob = plan->source_table<TableType> ();
+  const TableType *table = source_blob.get ();
 
   hb_tag_t tag = TableType::tableTag;
-  if (!source_blob->data)
+  if (!source_blob.get_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);
+    source_blob.destroy ();
     return false;
   }
 
@@ -278,23 +284,23 @@ _subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
 			 TableType::tableTag == HB_OT_TAG_GPOS ||
 			 TableType::tableTag == HB_OT_TAG_name;
 
-  unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length, same_size_table);
+  unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob.get_length (), same_size_table);
   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);
+    source_blob.destroy ();
     return false;
   }
 
   bool needed = false;
   hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
   {
-    hb_subset_context_t c (source_blob, plan, &serializer, tag);
+    hb_subset_context_t c (source_blob.get_blob (), plan, &serializer, tag);
     needed = _try_subset (table, &buf, &c);
   }
-  hb_blob_destroy (source_blob);
+  source_blob.destroy ();
 
   if (serializer.in_error () && !serializer.only_offset_overflow ())
   {
@@ -356,6 +362,8 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
   switch (tag)
   {
   case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
+    return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
+
   case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */
   case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */
   case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
@@ -375,6 +383,14 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
     return true;
 #endif
 
+  case HB_TAG ('a','v','a','r'):
+  case HB_TAG ('f','v','a','r'):
+  case HB_TAG ('g','v','a','r'):
+  case HB_OT_TAG_HVAR:
+  case HB_OT_TAG_VVAR:
+  case HB_TAG ('M','V','A','R'):
+    return plan->all_axes_pinned;
+
   default:
     return false;
   }
@@ -438,6 +454,11 @@ _subset_table (hb_subset_plan_t *plan,
   case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
   case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
 #endif
+  case HB_OT_TAG_STAT:
+    /*TODO(qxliu): change the condition as we support more complex
+     * instancing operation*/
+    if (plan->all_axes_pinned) return _subset<const OT::STAT> (plan, buf);
+    else return _passthrough (plan, tag);
 
   default:
     if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h
index a2799d91e8a80045ccf1cdb79ad9647265b6e55e..08e52dbd2d16a1475f2c1d1cc2c189fe1135e6cf 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h
@@ -100,6 +100,8 @@ typedef enum { /*< flags >*/
  * @HB_SUBSET_SETS_NAME_LANG_ID: the set of name lang ids that will be retained.
  * @HB_SUBSET_SETS_LAYOUT_FEATURE_TAG: the set of layout feature tags that will be retained
  * in the subset.
+ * @HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG: the set of layout script tags that will be retained
+ * in the subset. Defaults to all tags. Since: 5.0.0
  *
  * List of sets that can be configured on the subset input.
  *
@@ -113,6 +115,7 @@ typedef enum {
   HB_SUBSET_SETS_NAME_ID,
   HB_SUBSET_SETS_NAME_LANG_ID,
   HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+  HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
 } hb_subset_sets_t;
 
 HB_EXTERN hb_subset_input_t *
@@ -151,6 +154,21 @@ HB_EXTERN void
 hb_subset_input_set_flags (hb_subset_input_t *input,
 			   unsigned value);
 
+#ifdef HB_EXPERIMENTAL_API
+#ifndef HB_NO_VAR
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
+				     hb_face_t          *face,
+				     hb_tag_t            axis_tag);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
+				   hb_face_t          *face,
+				   hb_tag_t            axis_tag,
+				   float               axis_value);
+#endif
+#endif
+
 HB_EXTERN hb_face_t *
 hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.cc b/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.cc
index 05f74b923776f76b0821310851cef5e69e5bbc93..9899e01a41dbd65b70ad6f8d0ca9022fb31e9a23 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.cc
@@ -281,7 +281,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
  *
  * Attaches a user-data key/data pair to the specified Unicode-functions structure. 
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -340,7 +340,7 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
  * Tests whether the specified Unicode-functions structure
  * is immutable.
  *
- * Return value: %true if @ufuncs is immutable, %false otherwise
+ * Return value: `true` if @ufuncs is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -421,7 +421,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
  * Calls the composition function of the specified
  * Unicode-functions structure @ufuncs.
  *
- * Return value: %true if @a and @b composed, %false otherwise
+ * Return value: `true` if @a and @b composed, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -446,7 +446,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
  * Calls the decomposition function of the specified
  * Unicode-functions structure @ufuncs.
  *
- * Return value: %true if @ab was decomposed, %false otherwise
+ * Return value: `true` if @ab was decomposed, `false` otherwise
  *
  * Since: 0.9.2
  **/
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.h b/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.h
index c04ee15a09b1d7143b65aeb84ed03f9674014980..a500384575e5c19bc44b0c345583b2a5f1997239 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.h
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-unicode.h
@@ -429,7 +429,7 @@ typedef hb_script_t			(*hb_unicode_script_func_t)		(hb_unicode_funcs_t *ufuncs,
  * The method must return an #hb_bool_t indicating the success
  * of the composition.
  * 
- * Return value: %true is @a,@b composed, %false otherwise
+ * Return value: `true` is @a,@b composed, `false` otherwise
  *
  **/
 typedef hb_bool_t			(*hb_unicode_compose_func_t)		(hb_unicode_funcs_t *ufuncs,
@@ -453,7 +453,7 @@ typedef hb_bool_t			(*hb_unicode_compose_func_t)		(hb_unicode_funcs_t *ufuncs,
  * output parameters (if successful). The method must return an
  * #hb_bool_t indicating the success of the composition.
  * 
- * Return value: %true if @ab decomposed, %false otherwise
+ * Return value: `true` if @ab decomposed, `false` otherwise
  *
  **/
 typedef hb_bool_t			(*hb_unicode_decompose_func_t)		(hb_unicode_funcs_t *ufuncs,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh b/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
index 7b08e3b4d2796452cb6a36e95347e19072fbe157..a6d9f6b3fb59d23cb5757937c8d1d0f196dd2f59 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
+++ b/source/libs/harfbuzz/harfbuzz-src/src/hb-vector.hh
@@ -43,7 +43,6 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty
   using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type;
 
   hb_vector_t () = default;
-  hb_vector_t (std::nullptr_t) : hb_vector_t () {}
   hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t ()
   {
     alloc (lst.size ());
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/main.cc b/source/libs/harfbuzz/harfbuzz-src/src/main.cc
index 7a7614f7b690c370098ca7063f6d37e7b3ec84bd..99e1528da10f302afb84fb17ea25c3c3c195c3ed 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/main.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/main.cc
@@ -492,12 +492,12 @@ print_layout_info_using_private_api (hb_blob_t *blob)
 		  gdef.has_glyph_classes () ? "" : "no ");
 	printf ("    Has %smark attachment types\n",
 		  gdef.has_mark_attachment_types () ? "" : "no ");
-	printf ("    Has %sattach points\n",
-		  gdef.has_attach_points () ? "" : "no ");
+	printf ("    Has %sattach list\n",
+		  gdef.has_attach_list () ? "" : "no ");
 	printf ("    Has %slig carets\n",
 		  gdef.has_lig_carets () ? "" : "no ");
-	printf ("    Has %smark sets\n",
-		  gdef.has_mark_sets () ? "" : "no ");
+	printf ("    Has %smark glyph sets\n",
+		  gdef.has_mark_glyph_sets () ? "" : "no ");
 	break;
 	}
       }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/meson.build b/source/libs/harfbuzz/harfbuzz-src/src/meson.build
index b4fc6d408074335e2a91284ba8b21dd5be16ad39..e336037a2e55bdd7099ec6982ab5e3cbfac7634e 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/meson.build
+++ b/source/libs/harfbuzz/harfbuzz-src/src/meson.build
@@ -101,57 +101,65 @@ hb_base_sources = files(
   'OT/glyf/SimpleGlyph.hh',
   'OT/glyf/CompositeGlyph.hh',
   'OT/glyf/SubsetGlyph.hh',
-  'OT/Layout/GSUB/Common.hh',
-  'OT/Layout/GSUB/Sequence.hh',
-  'OT/Layout/GSUB/SingleSubstFormat1.hh',
-  'OT/Layout/GSUB/SingleSubstFormat2.hh',
-  'OT/Layout/GSUB/SingleSubst.hh',
-  'OT/Layout/GSUB/MultipleSubstFormat1.hh',
-  'OT/Layout/GSUB/MultipleSubst.hh',
-  'OT/Layout/GSUB/AlternateSubstFormat1.hh',
-  'OT/Layout/GSUB/AlternateSubst.hh',
-  'OT/Layout/GSUB/AlternateSet.hh',
-  'OT/Layout/GSUB/LigatureSubstFormat1.hh',
-  'OT/Layout/GSUB/LigatureSubst.hh',
-  'OT/Layout/GSUB/LigatureSet.hh',
-  'OT/Layout/GSUB/Ligature.hh',
-  'OT/Layout/GSUB/ReverseChainSingleSubst.hh',
-  'OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh',
-  'OT/Layout/GSUB/ContextSubst.hh',
-  'OT/Layout/GSUB/ChainContextSubst.hh',
-  'OT/Layout/GSUB/ExtensionSubst.hh',
-  'OT/Layout/GSUB/SubstLookupSubTable.hh',
-  'OT/Layout/GSUB/SubstLookup.hh',
-  'OT/Layout/GSUB/GSUB.hh',
-  'OT/Layout/GPOS.hh',
-  'OT/Layout/GPOS/CursivePosFormat1.hh',
-  'OT/Layout/GPOS/MarkLigPos.hh',
-  'OT/Layout/GPOS/PairPos.hh',
-  'OT/Layout/GPOS/Anchor.hh',
+  'OT/Layout/types.hh',
+  'OT/Layout/Common/Coverage.hh',
+  'OT/Layout/Common/CoverageFormat1.hh',
+  'OT/Layout/Common/CoverageFormat2.hh',
+  'OT/Layout/Common/RangeRecord.hh',
   'OT/Layout/GPOS/AnchorFormat1.hh',
-  'OT/Layout/GPOS/MarkLigPosFormat1.hh',
-  'OT/Layout/GPOS/PairPosFormat1.hh',
-  'OT/Layout/GPOS/ExtensionPos.hh',
+  'OT/Layout/GPOS/AnchorFormat2.hh',
+  'OT/Layout/GPOS/AnchorFormat3.hh',
+  'OT/Layout/GPOS/Anchor.hh',
+  'OT/Layout/GPOS/AnchorMatrix.hh',
   'OT/Layout/GPOS/ChainContextPos.hh',
   'OT/Layout/GPOS/Common.hh',
-  'OT/Layout/GPOS/ValueFormat.hh',
-  'OT/Layout/GPOS/AnchorMatrix.hh',
+  'OT/Layout/GPOS/ContextPos.hh',
+  'OT/Layout/GPOS/CursivePosFormat1.hh',
+  'OT/Layout/GPOS/CursivePos.hh',
+  'OT/Layout/GPOS/ExtensionPos.hh',
+  'OT/Layout/GPOS/GPOS.hh',
+  'OT/Layout/GPOS/LigatureArray.hh',
+  'OT/Layout/GPOS/MarkArray.hh',
   'OT/Layout/GPOS/MarkBasePosFormat1.hh',
-  'OT/Layout/GPOS/AnchorFormat3.hh',
-  'OT/Layout/GPOS/PosLookup.hh',
-  'OT/Layout/GPOS/MarkMarkPos.hh',
-  'OT/Layout/GPOS/PairPosFormat2.hh',
   'OT/Layout/GPOS/MarkBasePos.hh',
+  'OT/Layout/GPOS/MarkLigPosFormat1.hh',
+  'OT/Layout/GPOS/MarkLigPos.hh',
   'OT/Layout/GPOS/MarkMarkPosFormat1.hh',
-  'OT/Layout/GPOS/SinglePos.hh',
-  'OT/Layout/GPOS/MarkArray.hh',
-  'OT/Layout/GPOS/CursivePos.hh',
-  'OT/Layout/GPOS/PosLookupSubTable.hh',
+  'OT/Layout/GPOS/MarkMarkPos.hh',
   'OT/Layout/GPOS/MarkRecord.hh',
-  'OT/Layout/GPOS/AnchorFormat2.hh',
-  'OT/Layout/GPOS/ContextPos.hh',
-  'OT/Layout/GPOS/SinglePosFormat2.hh',
+  'OT/Layout/GPOS/PairPosFormat1.hh',
+  'OT/Layout/GPOS/PairPosFormat2.hh',
+  'OT/Layout/GPOS/PairPos.hh',
+  'OT/Layout/GPOS/PairSet.hh',
+  'OT/Layout/GPOS/PairValueRecord.hh',
+  'OT/Layout/GPOS/PosLookup.hh',
+  'OT/Layout/GPOS/PosLookupSubTable.hh',
   'OT/Layout/GPOS/SinglePosFormat1.hh',
+  'OT/Layout/GPOS/SinglePosFormat2.hh',
+  'OT/Layout/GPOS/SinglePos.hh',
+  'OT/Layout/GPOS/ValueFormat.hh',
+  'OT/Layout/GSUB/AlternateSet.hh',
+  'OT/Layout/GSUB/AlternateSubstFormat1.hh',
+  'OT/Layout/GSUB/AlternateSubst.hh',
+  'OT/Layout/GSUB/ChainContextSubst.hh',
+  'OT/Layout/GSUB/Common.hh',
+  'OT/Layout/GSUB/ContextSubst.hh',
+  'OT/Layout/GSUB/ExtensionSubst.hh',
+  'OT/Layout/GSUB/GSUB.hh',
+  'OT/Layout/GSUB/Ligature.hh',
+  'OT/Layout/GSUB/LigatureSet.hh',
+  'OT/Layout/GSUB/LigatureSubstFormat1.hh',
+  'OT/Layout/GSUB/LigatureSubst.hh',
+  'OT/Layout/GSUB/MultipleSubstFormat1.hh',
+  'OT/Layout/GSUB/MultipleSubst.hh',
+  'OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh',
+  'OT/Layout/GSUB/ReverseChainSingleSubst.hh',
+  'OT/Layout/GSUB/Sequence.hh',
+  'OT/Layout/GSUB/SingleSubstFormat1.hh',
+  'OT/Layout/GSUB/SingleSubstFormat2.hh',
+  'OT/Layout/GSUB/SingleSubst.hh',
+  'OT/Layout/GSUB/SubstLookup.hh',
+  'OT/Layout/GSUB/SubstLookupSubTable.hh',
   'hb-ot-layout-gsubgpos.hh',
   'hb-ot-layout-jstf-table.hh',
   'hb-ot-layout.cc',
@@ -429,7 +437,6 @@ endif
 if conf.get('HAVE_DIRECTWRITE', 0) == 1
   hb_sources += hb_directwrite_sources
   hb_headers += hb_directwrite_headers
-  harfbuzz_deps += directwrite_dep
   # hb-directwrite needs a C++ linker
   libharfbuzz_link_language = 'cpp'
 endif
@@ -520,6 +527,14 @@ libharfbuzz_subset = library('harfbuzz-subset', hb_subset_sources,
   link_language: 'c',
 )
 
+custom_target('harfbuzz-subset.cc',
+  build_by_default: true,
+  output: 'harfbuzz-subset.cc',
+  input: hb_base_sources + hb_subset_sources,
+  command: [find_program('gen-harfbuzzcc.py'),
+            '@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
+)
+
 libharfbuzz_subset_dep = declare_dependency(
   link_with: libharfbuzz_subset,
   include_directories: incsrc,
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
index 8d5a694275701a691669e39d3b5ae69b2521e6ae..bbebcbe7a04d7e7e75f5155a51d600ed6ae252f2 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-buffer-serialize.cc
@@ -75,15 +75,15 @@ main (int argc, char **argv)
     while (hb_buffer_deserialize_glyphs (buf,
 					 p, -1, &p,
 					 font,
-					 HB_BUFFER_SERIALIZE_FORMAT_JSON))
+					 HB_BUFFER_SERIALIZE_FORMAT_TEXT))
       ;
     if (*p && *p != '\n')
       ret = false;
 
     hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
 				out, sizeof (out), nullptr,
-				font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
-				HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+				font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+				HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS);
     puts (out);
   }
 
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc
index dc85b7214794d7983ef5c3be98c776fd1ed55701..c37d1e74d5802d1cbddd250c7556131ff98b2539 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc
@@ -31,7 +31,6 @@
 #include "hb-set.hh"
 #include "hb-ot-layout-common.hh"
 
-
 template <typename T>
 struct array_iter_t : hb_iter_with_fallback_t<array_iter_t<T>, T&>
 {
@@ -226,7 +225,7 @@ main (int argc, char **argv)
   test_iterable<hb_sorted_array_t<const int>> ();
   test_iterable<hb_vector_t<float>> ();
   test_iterable<hb_set_t> ();
-  test_iterable<OT::Coverage> ();
+  test_iterable<OT::Array16Of<OT::HBUINT16>> ();
 
   test_iterator (hb_zip (st, v));
   test_iterator_non_default_constructable (hb_enumerate (st));
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-map.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-map.cc
index 4cb248bd40e8d8e9f5e39f296c3099b8cb145839..473e8f4f6470a60d8c7d7080b533092e39d0606c 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-map.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-map.cc
@@ -195,6 +195,11 @@ main (int argc, char **argv)
     m.get (hb::shared_ptr<hb_set_t> ());
     m.get (hb::shared_ptr<hb_set_t> (hb_set_get_empty ()));
     m.iter ();
+    m.keys ();
+    m.values ();
+    m.iter_ref ();
+    m.keys_ref ();
+    m.values_ref ();
   }
   /* Test hb::unique_ptr. */
   hb_hash (hb::unique_ptr<hb_set_t> ());
@@ -204,6 +209,18 @@ main (int argc, char **argv)
     m.get (hb::unique_ptr<hb_set_t> ());
     m.get (hb::unique_ptr<hb_set_t> (hb_set_get_empty ()));
     m.iter_ref ();
+    m.keys_ref ();
+    m.values_ref ();
+  }
+  /* Test more complex unique_ptr's. */
+  {
+    hb_hashmap_t<int, hb::unique_ptr<hb_hashmap_t<int, int>>> m;
+
+    m.get (0);
+    const hb::unique_ptr<hb_hashmap_t<int, int>> *v1;
+    m.has (0, &v1);
+    hb::unique_ptr<hb_hashmap_t<int, int>> *v2;
+    m.has (0, &v2);
   }
 
   return 0;
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-ot-glyphname.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-ot-glyphname.cc
index 50d023166f91ea64ca375774b86fc8dadba892b7..ec6e149a56951edfd385bbfc1ba677d3d3597443 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-ot-glyphname.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-ot-glyphname.cc
@@ -85,5 +85,5 @@ main (int argc, char **argv)
   hb_font_destroy (font);
   hb_face_destroy (face);
 
-  return result;
+  return !result;
 }
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc
index 69863b562f250b706bf46d46c3e4533a3a736a25..4bc731d8e1f28be538bc67004c8c780629a2f35d 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc
@@ -57,6 +57,14 @@ static void add_offset (unsigned id,
   c->add_link (*offset, id);
 }
 
+static void add_24_offset (unsigned id,
+                           hb_serialize_context_t* c)
+{
+  OT::Offset24* offset = c->start_embed<OT::Offset24> ();
+  c->extend_min (offset);
+  c->add_link (*offset, id);
+}
+
 static void add_wide_offset (unsigned id,
                              hb_serialize_context_t* c)
 {
@@ -812,6 +820,51 @@ populate_serializer_virtual_link (hb_serialize_context_t* c)
   c->end_serialize();
 }
 
+static void
+populate_serializer_with_24_and_32_bit_offsets (hb_serialize_context_t* c)
+{
+  std::string large_string(60000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_f = add_object ("f", 1, c);
+  unsigned obj_g = add_object ("g", 1, c);
+  unsigned obj_j = add_object ("j", 1, c);
+  unsigned obj_k = add_object ("k", 1, c);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_f, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_g, c);
+  unsigned obj_d = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_j, c);
+  unsigned obj_h = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 40000, c);
+  add_offset (obj_k, c);
+  unsigned obj_i = c->pop_pack (false);
+
+  start_object ("e", 1, c);
+  add_wide_offset (obj_h, c);
+  add_wide_offset (obj_i, c);
+  unsigned obj_e = c->pop_pack (false);
+
+  start_object ("b", 1, c);
+  add_24_offset (obj_c, c);
+  add_24_offset (obj_d, c);
+  add_24_offset (obj_e, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_24_offset (obj_b, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
 static void test_sort_shortest ()
 {
   size_t buffer_size = 100;
@@ -1129,6 +1182,36 @@ static void test_resolve_overflows_via_isolation_spaces ()
   hb_blob_destroy (out);
 }
 
+static void test_resolve_mixed_overflows_via_isolation_spaces ()
+{
+  size_t buffer_size = 200000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_24_and_32_bit_offsets (&c);
+  graph_t graph (c.object_graph ());
+
+  assert (c.offset_overflow ());
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
+
+  unsigned expected_length =
+      // Objects
+      7 +
+      4 * 40000;
+
+  expected_length +=
+      // Links
+      2 * 4 +  // 32
+      4 * 3 +  // 24
+      4 * 2;   // 16
+
+  assert (result.length == expected_length);
+
+  free (buffer);
+  hb_blob_destroy (out);
+}
+
 static void test_resolve_overflows_via_splitting_spaces ()
 {
   size_t buffer_size = 160000;
@@ -1270,6 +1353,7 @@ main (int argc, char **argv)
   test_resolve_overflows_via_isolating_16bit_space_2 ();
   test_resolve_overflows_via_splitting_spaces ();
   test_resolve_overflows_via_splitting_spaces_2 ();
+  test_resolve_mixed_overflows_via_isolation_spaces ();
   test_duplicate_leaf ();
   test_duplicate_interior ();
   test_virtual_link ();
diff --git a/source/libs/harfbuzz/harfbuzz-src/src/test-serialize.cc b/source/libs/harfbuzz/harfbuzz-src/src/test-serialize.cc
index 44a2e0fe1d626f2772f2f5ea98d88e88cc0c2e0f..4c90abb1145b779e93132eec1eaf068d9b82d1cc 100644
--- a/source/libs/harfbuzz/harfbuzz-src/src/test-serialize.cc
+++ b/source/libs/harfbuzz/harfbuzz-src/src/test-serialize.cc
@@ -27,6 +27,7 @@
 #include "hb-serialize.hh"
 #include "hb-ot-layout-common.hh"
 
+using OT::Layout::Common::Coverage;
 
 int
 main (int argc, char **argv)
@@ -37,7 +38,7 @@ main (int argc, char **argv)
 
   hb_sorted_vector_t<hb_codepoint_t> v{1, 2, 5};
 
-  auto c = s.start_serialize<OT::Coverage> ();
+  auto c = s.start_serialize<Coverage> ();
 
   c->serialize (&s, hb_iter (v));
 
diff --git a/source/libs/harfbuzz/version.ac b/source/libs/harfbuzz/version.ac
index 57cb3c7fdf8bd4a98f33c663b83b43de1af2a203..add04eb0cd665c98001048855c99ea5fdab5bf00 100644
--- a/source/libs/harfbuzz/version.ac
+++ b/source/libs/harfbuzz/version.ac
@@ -8,4 +8,4 @@ dnl
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current harfbuzz version
-m4_define([harfbuzz_version], [4.4.1])
+m4_define([harfbuzz_version], [5.0.1])
diff --git a/source/texk/web2c/luatexdir/luatex_svnversion.h b/source/texk/web2c/luatexdir/luatex_svnversion.h
index a37a3c3f428c4001443a1174a2d1078721bb8800..a7074e3525d6a55379e104c67907bc4f3519bd0b 100644
--- a/source/texk/web2c/luatexdir/luatex_svnversion.h
+++ b/source/texk/web2c/luatexdir/luatex_svnversion.h
@@ -1,4 +1,4 @@
 #ifndef luatex_svn_revision_h
 #define luatex_svn_revision_h
-#define luatex_svn_revision 7529
+#define luatex_svn_revision 7530
 #endif
diff --git a/source/texk/web2c/uptexdir/uptex_version.h b/source/texk/web2c/uptexdir/uptex_version.h
index 0b751989f7d1b24e0106be2a1820ec8bc35be27e..6b38ed922c4c1a899bd2a2ad5ea36f965bfd6f9c 100644
--- a/source/texk/web2c/uptexdir/uptex_version.h
+++ b/source/texk/web2c/uptexdir/uptex_version.h
@@ -1 +1 @@
-#define UPTEX_VERSION "u1.28"
+#define UPTEX_VERSION "u1.29"