texlive[63761] Build/source/libs: harfbuzz 4.4.1

commits+kakuto at tug.org commits+kakuto at tug.org
Wed Jun 29 22:49:56 CEST 2022


Revision: 63761
          http://tug.org/svn/texlive?view=revision&revision=63761
Author:   kakuto
Date:     2022-06-29 22:49:55 +0200 (Wed, 29 Jun 2022)
Log Message:
-----------
harfbuzz 4.4.1

Modified Paths:
--------------
    trunk/Build/source/libs/README
    trunk/Build/source/libs/harfbuzz/ChangeLog
    trunk/Build/source/libs/harfbuzz/Makefile.am
    trunk/Build/source/libs/harfbuzz/Makefile.in
    trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog
    trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes
    trunk/Build/source/libs/harfbuzz/configure
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/Makefile.am
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/mingw-configure.sh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SimpleGlyph.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-indic-table.py
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-table.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build
    trunk/Build/source/libs/harfbuzz/version.ac

Added Paths:
-----------
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Anchor.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat2.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat3.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorMatrix.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ChainContextPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Common.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ContextPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ExtensionPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkArray.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkRecord.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookup.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookupSubTable.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat2.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ValueFormat.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh

Modified: trunk/Build/source/libs/README
===================================================================
--- trunk/Build/source/libs/README	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/README	2022-06-29 20:49:55 UTC (rev 63761)
@@ -25,8 +25,8 @@
   http://sourceforge.net/projects/silgraphite/files/graphite2/
   (requires C++11)
 
-harfbuzz 4.4.0 - checked 28jun22
-  https://github.com/harfbuzz/harfbuzz/releases/download/4.4.0/
+harfbuzz 4.4.1 - checked 30jun22
+  https://github.com/harfbuzz/harfbuzz/releases/download/4.4.1/
 
 icu 70.1 - checked 16jan22
   https://github.com/unicode-org/icu/releases/

Modified: trunk/Build/source/libs/harfbuzz/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/ChangeLog	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/ChangeLog	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,3 +1,8 @@
+2022-06-30  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Import harfbuzz-4.4.1.
+	* version.ac, Makefile.am: Adjusted.
+
 2022-06-28  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Import harfbuzz-4.4.0.

Modified: trunk/Build/source/libs/harfbuzz/Makefile.am
===================================================================
--- trunk/Build/source/libs/harfbuzz/Makefile.am	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/Makefile.am	2022-06-29 20:49:55 UTC (rev 63761)
@@ -261,6 +261,35 @@
 	@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/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/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/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/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/SinglePosFormat1.hh \
 	@HARFBUZZ_TREE@/src/graph/graph.hh \
 	@HARFBUZZ_TREE@/src/graph/serialize.hh
 

Modified: trunk/Build/source/libs/harfbuzz/Makefile.in
===================================================================
--- trunk/Build/source/libs/harfbuzz/Makefile.in	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/Makefile.in	2022-06-29 20:49:55 UTC (rev 63761)
@@ -930,6 +930,35 @@
 	@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/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/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/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/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/SinglePosFormat1.hh \
 	@HARFBUZZ_TREE@/src/graph/graph.hh \
 	@HARFBUZZ_TREE@/src/graph/serialize.hh \
 	@HARFBUZZ_TREE@/src/hb-graphite2.cc

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,3 +1,8 @@
+2022-06-30  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Imported harfbuzz-4.4.1 source tree from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/4.4.1/
+
 2022-06-28  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Imported harfbuzz-4.4.0 source tree from:

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,5 +1,5 @@
-Changes applied to the harfbuzz-4.4.0/ tree as obtained from:
-	https://github.com/harfbuzz/harfbuzz/releases/download/4.4.0/
+Changes applied to the harfbuzz-4.4.1/ tree as obtained from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/4.4.1/
 
 Removed:
 	COPYING

Modified: trunk/Build/source/libs/harfbuzz/configure
===================================================================
--- trunk/Build/source/libs/harfbuzz/configure	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/configure	2022-06-29 20:49:55 UTC (rev 63761)
@@ -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.0.
+# Generated by GNU Autoconf 2.71 for harfbuzz (TeX Live) 4.4.1.
 #
 # Report bugs to <tex-k at tug.org>.
 #
@@ -611,8 +611,8 @@
 # Identity of this package.
 PACKAGE_NAME='harfbuzz (TeX Live)'
 PACKAGE_TARNAME='harfbuzz--tex-live-'
-PACKAGE_VERSION='4.4.0'
-PACKAGE_STRING='harfbuzz (TeX Live) 4.4.0'
+PACKAGE_VERSION='4.4.1'
+PACKAGE_STRING='harfbuzz (TeX Live) 4.4.1'
 PACKAGE_BUGREPORT='tex-k at tug.org'
 PACKAGE_URL=''
 
@@ -1346,7 +1346,7 @@
   # 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.0 to adapt to many kinds of systems.
+\`configure' configures harfbuzz (TeX Live) 4.4.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1418,7 +1418,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 4.4.0:";;
+     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 4.4.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1523,7 +1523,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-harfbuzz (TeX Live) configure 4.4.0
+harfbuzz (TeX Live) configure 4.4.1
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2064,7 +2064,7 @@
 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.0, which was
+It was created by harfbuzz (TeX Live) $as_me 4.4.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4823,7 +4823,7 @@
 
 # Define the identity of the package.
  PACKAGE='harfbuzz--tex-live-'
- VERSION='4.4.0'
+ VERSION='4.4.1'
 
 
 # Some tools Automake needs.
@@ -5035,8 +5035,8 @@
 
 HB_VERSION_MAJOR=4
 HB_VERSION_MINOR=4
-HB_VERSION_MICRO=0
-HB_VERSION=4.4.0
+HB_VERSION_MICRO=1
+HB_VERSION=4.4.1
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -8817,7 +8817,7 @@
 # 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.0, which was
+This file was extended by harfbuzz (TeX Live) $as_me 4.4.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8885,7 +8885,7 @@
 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.0
+harfbuzz (TeX Live) config.status 4.4.1
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,3 +1,504 @@
+commit 096aaa62a6e0d07c02a4894fc036efc927e5aaf9
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Jun 29 07:30:05 2022 +0200
+
+    4.4.1
+
+ NEWS             | 7 +++++++
+ configure.ac     | 2 +-
+ meson.build      | 2 +-
+ src/hb-version.h | 4 ++--
+ 4 files changed, 11 insertions(+), 4 deletions(-)
+
+commit 4d1d7aec8d7430ea062241b46be5fa78660df2f4
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Jun 29 07:29:39 2022 +0200
+
+    [docs] Add missing 4.4.0 index
+
+ docs/harfbuzz-docs.xml | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 050f169078e272abb56c35fe3ec00a1c6238e518
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 18:52:27 2022 -0600
+
+    [GPOS/kerx] Call into impl namespace from kerx
+
+ src/hb-aat-layout-kerx-table.hh | 8 ++++----
+ src/hb-ot-layout-gpos-table.hh  | 3 ---
+ 2 files changed, 4 insertions(+), 7 deletions(-)
+
+commit 910a137f4ef61b4986fb9071253e25b4f9c56c06
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Jun 29 00:05:35 2022 +0000
+
+    [reorg] Fix propagate_attachment_offsets definition.
+
+ src/OT/Layout/GPOS.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3fbf2dece7f2a0b5820e01846da76114babe5a2f
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Jun 28 23:55:32 2022 +0000
+
+    [reorg] Move OT::Layout::GPOS_impl::GPOS to OT::Layout::GPOS.
+
+ src/Makefile.sources             | 29 +++++++++++++++++++++++++++
+ src/OT/Layout/{GPOS => }/GPOS.hh | 42 ++++++++++++++++++----------------------
+ src/OT/Layout/GPOS/PosLookup.hh  |  2 +-
+ src/hb-ot-layout-gpos-table.hh   |  2 +-
+ src/hb-ot-layout.cc              |  2 +-
+ src/hb-subset-plan.cc            |  2 +-
+ src/hb-subset.cc                 |  2 +-
+ src/meson.build                  | 29 +++++++++++++++++++++++++++
+ 8 files changed, 82 insertions(+), 28 deletions(-)
+
+commit 88ef3c5a9abc22927365e9c60d7aa0e3e8a339b9
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Jun 28 23:26:49 2022 +0000
+
+    [reorg] Change OT::Layout::GPOS to OT::Layout::GPOS_impl.
+
+ src/OT/Layout/GPOS/Anchor.hh             |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat1.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat2.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorFormat3.hh      |  2 +-
+ src/OT/Layout/GPOS/AnchorMatrix.hh       |  2 +-
+ src/OT/Layout/GPOS/ChainContextPos.hh    |  2 +-
+ src/OT/Layout/GPOS/Common.hh             |  2 +-
+ src/OT/Layout/GPOS/ContextPos.hh         |  2 +-
+ src/OT/Layout/GPOS/CursivePos.hh         |  2 +-
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |  4 ++--
+ src/OT/Layout/GPOS/ExtensionPos.hh       |  2 +-
+ src/OT/Layout/GPOS/GPOS.hh               |  6 +++---
+ src/OT/Layout/GPOS/MarkArray.hh          |  2 +-
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  2 +-
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  2 +-
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  2 +-
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh |  2 +-
+ src/OT/Layout/GPOS/MarkRecord.hh         |  2 +-
+ src/OT/Layout/GPOS/PairPos.hh            |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat1.hh     |  2 +-
+ src/OT/Layout/GPOS/PairPosFormat2.hh     |  2 +-
+ src/OT/Layout/GPOS/PosLookup.hh          |  2 +-
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |  2 +-
+ src/OT/Layout/GPOS/SinglePos.hh          |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat1.hh   |  2 +-
+ src/OT/Layout/GPOS/SinglePosFormat2.hh   |  2 +-
+ src/OT/Layout/GPOS/ValueFormat.hh        |  2 +-
+ src/hb-ot-layout-gpos-table.hh           | 20 ++++++++++----------
+ src/hb-ot-layout.cc                      |  2 +-
+ src/hb-subset-plan.cc                    |  2 +-
+ src/hb-subset.cc                         |  2 +-
+ 33 files changed, 45 insertions(+), 45 deletions(-)
+
+commit 49ddf069e02bea6786f47780cbd2e5917e9364a5
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Jun 28 23:15:07 2022 +0000
+
+    [reorg] Move GPOS reverse_cursive_minor_offset implementation into new directory layout.
+
+ src/OT/Layout/GPOS/CursivePosFormat1.hh | 25 ++++++++++++++-
+ src/hb-ot-layout-gpos-table.hh          | 56 ++++++---------------------------
+ 2 files changed, 33 insertions(+), 48 deletions(-)
+
+commit 74f45f7c2ac4bb1d465926ebf2c3fba5a4572767
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Jun 24 23:14:30 2022 +0000
+
+    [reorg] Move remaining GPOS lookup types to new directory.
+
+ src/OT/Layout/GPOS/ChainContextPos.hh    |  14 ++
+ src/OT/Layout/GPOS/ContextPos.hh         |  14 ++
+ src/OT/Layout/GPOS/ExtensionPos.hh       |  17 ++
+ src/OT/Layout/GPOS/GPOS.hh               | 101 +++++++-
+ src/OT/Layout/GPOS/MarkBasePos.hh        |   1 +
+ src/OT/Layout/GPOS/MarkLigPos.hh         |   1 +
+ src/OT/Layout/GPOS/MarkMarkPos.hh        |  36 +++
+ src/OT/Layout/GPOS/MarkMarkPosFormat1.hh | 227 ++++++++++++++++++
+ src/OT/Layout/GPOS/PosLookup.hh          |   1 -
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |   6 +-
+ src/OT/Layout/GPOS/ValueFormat.hh        |   2 +
+ src/hb-ot-layout-gpos-table.hh           | 382 +------------------------------
+ src/hb-ot-layout.cc                      |  15 +-
+ src/hb-subset-plan.cc                    |   6 +-
+ src/hb-subset.cc                         |   3 +-
+ 15 files changed, 442 insertions(+), 384 deletions(-)
+
+commit 197d9a5c994eb41c8c89b7b958b26b1eacfeeb00
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Jun 24 22:36:14 2022 +0000
+
+    [reorg] Move more GPOS lookups to new directory.
+
+ src/OT/Layout/GPOS/Anchor.hh             |  84 +++
+ src/OT/Layout/GPOS/AnchorFormat1.hh      |  46 ++
+ src/OT/Layout/GPOS/AnchorFormat2.hh      |  58 ++
+ src/OT/Layout/GPOS/AnchorFormat3.hh      |  70 +++
+ src/OT/Layout/GPOS/AnchorMatrix.hh       |  77 +++
+ src/OT/Layout/GPOS/Common.hh             |  14 +
+ src/OT/Layout/GPOS/CursivePosFormat1.hh  |   2 +
+ src/OT/Layout/GPOS/MarkArray.hh          | 113 ++++
+ src/OT/Layout/GPOS/MarkBasePos.hh        |  34 ++
+ src/OT/Layout/GPOS/MarkBasePosFormat1.hh | 217 ++++++++
+ src/OT/Layout/GPOS/MarkLigPos.hh         |  34 ++
+ src/OT/Layout/GPOS/MarkLigPosFormat1.hh  | 244 +++++++++
+ src/OT/Layout/GPOS/MarkRecord.hh         |  52 ++
+ src/OT/Layout/GPOS/PosLookupSubTable.hh  |   2 +
+ src/hb-ot-layout-gpos-table.hh           | 875 +------------------------------
+ 15 files changed, 1049 insertions(+), 873 deletions(-)
+
+commit c7307ca06ab3126f7783093a27388745af1d646b
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Jun 24 22:01:02 2022 +0000
+
+    [reorg] Begin moving GPOS into the new directory layout.
+
+ src/OT/Layout/GPOS/Common.hh            |   18 +
+ src/OT/Layout/GPOS/CursivePos.hh        |   35 +
+ src/OT/Layout/GPOS/CursivePosFormat1.hh |  256 ++++
+ src/OT/Layout/GPOS/GPOS.hh              |   69 ++
+ src/OT/Layout/GPOS/PairPos.hh           |   38 +
+ src/OT/Layout/GPOS/PairPosFormat1.hh    |  420 +++++++
+ src/OT/Layout/GPOS/PairPosFormat2.hh    |  314 +++++
+ src/OT/Layout/GPOS/PosLookup.hh         |   80 ++
+ src/OT/Layout/GPOS/PosLookupSubTable.hh |   73 ++
+ src/OT/Layout/GPOS/SinglePos.hh         |   98 ++
+ src/OT/Layout/GPOS/SinglePosFormat1.hh  |  124 ++
+ src/OT/Layout/GPOS/SinglePosFormat2.hh  |  140 +++
+ src/OT/Layout/GPOS/ValueFormat.hh       |  327 +++++
+ src/hb-ot-layout-gpos-table.hh          | 1975 ++-----------------------------
+ 14 files changed, 2075 insertions(+), 1892 deletions(-)
+
+commit 7b0d8d9d18fe4d0371b62bdc87b9d6e52e05f6e2
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Jun 29 00:34:09 2022 +0200
+
+    [meson] Remove ttf-parser wrap
+    
+    We don’t have a ttf-parser dependency anymore.
+
+ Makefile.am                 | 1 -
+ subprojects/ttf-parser.wrap | 5 -----
+ 2 files changed, 6 deletions(-)
+
+commit 9909d11f6f7b3eeddc00a981e24f26559d9ef3b7
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 15:59:40 2022 -0600
+
+    [indic generator] Fix regression
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3690
+
+ src/gen-indic-table.py                                   |   2 +-
+ src/hb-ot-shaper-indic-table.cc                          |  12 ++++++------
+ .../fonts/e716f6bd00a108d186b7e9f47b4515565f784f36.ttf   | Bin 0 -> 6260 bytes
+ test/shape/data/in-house/tests/indic-special-cases.tests |   1 +
+ 4 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 4499ae0225172ab7590619219b21fe0a0c14d66e
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 15:43:57 2022 -0600
+
+    [coretext] Fix positioning of out-of-order glyphs
+    
+    Unfortunately this now generates negative advances. To be fixed...
+
+ src/hb-coretext.cc | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 58d2e9309952c139a4fa05ed44c22bb712fd6cd4
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 15:38:58 2022 -0600
+
+    [coretext] Fix up clusters only if needed
+
+ src/hb-coretext.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit eaba5e74a9285647739dfc563471321d4d0ec9e0
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 13:47:49 2022 -0600
+
+    [directwrite] Simplify
+
+ src/hb-directwrite.cc | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+commit 33e3bf2d79c9b5598ba373ab093ec8b71404794b
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 13:46:04 2022 -0600
+
+    [font] Drop caches on variation changes
+
+ src/hb-font.cc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit c90130e6252b2914d9fdf9007a62fc924ef3d963
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 13:30:44 2022 -0600
+
+    [coretext] Remove old hack now that font layer takes care...
+    
+    of invalidating font data when font settings change.
+
+ src/hb-coretext.cc | 37 +++----------------------------------
+ 1 file changed, 3 insertions(+), 34 deletions(-)
+
+commit c1c78ade71fabe826f695704acda836c7bc21bf4
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Jun 28 13:19:12 2022 -0600
+
+    [font] When font changes, drop font shaper data
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3683#issuecomment-1168016509
+
+ src/hb-font.hh      | 2 ++
+ src/hb-machinery.hh | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 34c6c0193c57110219eecd58cc67daffcd84d071
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 20:26:19 2022 -0600
+
+    [glyf] Fix byterange check again
+
+ src/OT/glyf/SimpleGlyph.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 20572f914ce7c386e9ffb9cc2833b1f43d0025b2
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 20:22:09 2022 -0600
+
+    [glyf] Move read_flags into a function
+
+ src/OT/glyf/SimpleGlyph.hh | 41 ++++++++++++++++++++++++-----------------
+ 1 file changed, 24 insertions(+), 17 deletions(-)
+
+commit 7b0fc0be539ae02af71a7fa076a96c779c116b68
+Author: David Corbett <corbett.dav at northeastern.edu>
+Date:   Mon Jun 27 21:18:36 2022 -0400
+
+    [test] Test the reordering of U+0E33 and U+0EB3
+
+ test/shape/README.md                               |   2 +-
+ test/shape/data/in-house/Makefile.sources          |   1 +
+ .../63a539a90a371ccf028dc2dcced9b63b07163be7.ttf   | Bin 0 -> 1656 bytes
+ test/shape/data/in-house/meson.build               |   1 +
+ test/shape/data/in-house/tests/sara-am.tests       |  52 +++++++++++++++++++++
+ 5 files changed, 55 insertions(+), 1 deletion(-)
+
+commit 3c34b9ec30f4d07414a8053ae39be555001c64cc
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 19:45:58 2022 -0600
+
+    [mingw2] Turn optimization flag on
+
+ mingw-configure.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 31e985d7d1089e50c80c7186ebf1e475cc6c238d
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 16:32:02 2022 -0600
+
+    [buffer] Likely that not messaging
+
+ src/hb-buffer.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 4be074e2cb6d94fb9dfb833e713e30c0e6c6cc72
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 16:12:42 2022 -0600
+
+    [gvar] Whitespace
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a96647841afb02579caf7eb926dfeb7979cbfbe7
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:41:02 2022 -0600
+
+    [gvar] Optimize apply_deltas_to_points
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit e9af9062c0e1be1f479a43ad878cda622c781a56
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:38:42 2022 -0600
+
+    [gvar] Optimize unpack_deltas
+
+ src/hb-ot-var-gvar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 573e77280b4f78c9a880c4abfa1f86d70354bc79
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:35:28 2022 -0600
+
+    [gvar] Optimize unpack_deltas
+
+ src/hb-ot-var-gvar-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 698f51464c4a8f2e7e49c2e99fb0c8b4bfce9493
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:30:19 2022 -0600
+
+    [gvar] Share vector allocation across delta-sets
+
+ src/hb-ot-var-gvar-table.hh | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+commit 39e280c256894662d4591b4de7517b7e1147c66f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:25:50 2022 -0600
+
+    [gvar] Handle a couple of error conditions
+
+ src/hb-ot-var-gvar-table.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 5be6e5dd577b8680ee5ffdedeec93638dffb5547
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:22:16 2022 -0600
+
+    [gvar] Rewrite linear interpolation
+
+ src/hb-ot-var-gvar-table.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 57519b532da6fb1ef2442eb1eda26192f9617552
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:18:56 2022 -0600
+
+    [gvar] Use pointer-to-member instead of function
+
+ src/hb-ot-var-gvar-table.hh | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+commit ab15fe082ab79b608d9ff346c92dcc000404343d
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:13:10 2022 -0600
+
+    [gvar] Handle a couple of error conditions
+
+ src/hb-ot-var-gvar-table.hh | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+commit b7e9e8785c75b1a9b97a6eb648e5887093a3257a
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 15:08:51 2022 -0600
+
+    [gvar] Optimize deltas and points loading
+
+ src/hb-ot-var-gvar-table.hh | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+commit 6e72c2e3faf84634ac98d31be2344c2d604bed14
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 14:02:15 2022 -0600
+
+    [glyf] Add an assertion
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 5da341ce92352860fb43296cdeb7ed4141ff2864
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:29:22 2022 -0600
+
+    [map] Another try at hiding minus1
+    
+    To fix https://github.com/harfbuzz/harfbuzz/issues/3684
+
+ src/hb-map.hh    | 8 +++++++-
+ src/hb-static.cc | 3 +++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+commit c72d3104ed0fe1fa91eb1ff02b0761578161edb0
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:31:05 2022 -0600
+
+    [map] Return const reference in operator[]
+
+ src/hb-map.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 69d53f3e7fde164a1fe7bb5f812045e5275893a7
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:17:10 2022 -0600
+
+    [map] Make default_value() inline
+    
+    See if it make fix https://github.com/harfbuzz/harfbuzz/issues/3684
+
+ src/hb-map.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 3a0e27e794bd7a0a49ed5be41c044d9be910ea07
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:07:39 2022 -0600
+
+    [glyf] Move comment
+
+ src/OT/glyf/Glyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d0836dee7a6b81a4d037b3e1dc841416cc14bf87
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:05:58 2022 -0600
+
+    [glyf] Minor typo change
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5cca25e5d0d976020eead5113da82aae11c0d2ae
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:03:06 2022 -0600
+
+    [glyf] Accumulate points as int
+    
+    Everything is int at this stage.
+    Doesn't seem to matter for performance though.
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d6f60b3c190e3fd050f8c4a0613939d417f53a69
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 13:00:08 2022 -0600
+
+    [glyf] Minor optimization
+
+ src/OT/glyf/SimpleGlyph.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b30a3dcba3e69f93e551fb1736785dcec5a0ca70
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 12:56:21 2022 -0600
+
+    [glyf] Another bounds check
+    
+    Very unlikely that is needed but technically possible.
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 2e9dbdcbbe17a1c55e39f1d4acef023e5a26842f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Jun 27 12:55:13 2022 -0600
+
+    [glyf] Protect against an unlikely overflow
+
+ src/OT/glyf/SimpleGlyph.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
 commit 8537d681728e141550b4470b591fa059f6ca2670
 Author: Khaled Hosny <khaled at aliftype.com>
 Date:   Mon Jun 27 20:51:16 2022 +0200

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/Makefile.am
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/Makefile.am	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/Makefile.am	2022-06-29 20:49:55 UTC (rev 63761)
@@ -25,7 +25,6 @@
 	subprojects/google-benchmark.wrap \
 	subprojects/ragel.wrap \
 	subprojects/packagefiles/ragel/meson.build \
-	subprojects/ttf-parser.wrap \
 	mingw-configure.sh \
 	$(NULL)
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,3 +1,10 @@
+Overview of changes leading to 4.4.1
+Wednesday, June 29, 2022
+====================================
+- Fix test failure with some compilers.
+- Fix Telugu and Kannada kerning regression.
+
+
 Overview of changes leading to 4.4.0
 Monday, June 27, 2022
 ====================================

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [4.4.0],
+        [4.4.1],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1,6 +1,6 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.55.0',
-  version: '4.4.0',
+  version: '4.4.1',
   default_options: [
     'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway
     'cpp_std=c++11',

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/mingw-configure.sh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/mingw-configure.sh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/mingw-configure.sh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -17,7 +17,7 @@
 	CPP= \
 	LD= \
 	CFLAGS="-static-libgcc" \
-	CXXFLAGS="-static-libgcc -static-libstdc++" \
+	CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \
 	CPPFLAGS="-I$HOME/.local/$target/include" \
 	LDFLAGS=-L$HOME/.local/$target/lib \
 	PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources	2022-06-29 20:49:55 UTC (rev 63761)
@@ -119,6 +119,35 @@
 	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/GPOS/AnchorFormat1.hh \
+	OT/Layout/GPOS/MarkLigPosFormat1.hh \
+	OT/Layout/GPOS/PairPosFormat1.hh \
+	OT/Layout/GPOS/ExtensionPos.hh \
+	OT/Layout/GPOS/ChainContextPos.hh \
+	OT/Layout/GPOS/Common.hh \
+	OT/Layout/GPOS/ValueFormat.hh \
+	OT/Layout/GPOS/AnchorMatrix.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/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/MarkRecord.hh \
+	OT/Layout/GPOS/AnchorFormat2.hh \
+	OT/Layout/GPOS/ContextPos.hh \
+	OT/Layout/GPOS/SinglePosFormat2.hh \
+	OT/Layout/GPOS/SinglePosFormat1.hh \
 	hb-ot-layout-gsubgpos.hh \
 	hb-ot-layout-jstf-table.hh \
 	hb-ot-layout.cc \

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Anchor.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Anchor.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Anchor.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,84 @@
+#ifndef OT_LAYOUT_GPOS_ANCHOR_HH
+#define OT_LAYOUT_GPOS_ANCHOR_HH
+
+#include "AnchorFormat1.hh"
+#include "AnchorFormat2.hh"
+#include "AnchorFormat3.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct Anchor
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  AnchorFormat1         format1;
+  AnchorFormat2         format2;
+  AnchorFormat3         format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+                   float *x, float *y) const
+  {
+    *x = *y = 0;
+    switch (u.format) {
+    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
+    default:                                          return;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    switch (u.format) {
+    case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+    case 2:
+      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      {
+        // AnchorFormat 2 just containins extra hinting information, so
+        // if hints are being dropped convert to format 1.
+        return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+      }
+      return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
+    case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
+                                                                            c->plan->layout_variation_idx_map))));
+    default:return_trace (false);
+    }
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    switch (u.format) {
+    case 1: case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (c);
+      return;
+    default: return;
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHOR_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,46 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  public:
+  DEFINE_SIZE_STATIC (6);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+                   float *x, float *y) const
+  {
+    hb_font_t *font = c->font;
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+  }
+
+  AnchorFormat1* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
+    if (!out) return_trace (out);
+    out->format = 1;
+    return_trace (out);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT1_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat2.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat2.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat2.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,58 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat2
+{
+
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  HBUINT16      anchorPoint;            /* Index to glyph contour point */
+  public:
+  DEFINE_SIZE_STATIC (8);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
+                   float *x, float *y) const
+  {
+    hb_font_t *font = c->font;
+
+#ifdef HB_NO_HINTING
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+    return;
+#endif
+
+    unsigned int x_ppem = font->x_ppem;
+    unsigned int y_ppem = font->y_ppem;
+    hb_position_t cx = 0, cy = 0;
+    bool ret;
+
+    ret = (x_ppem || y_ppem) &&
+          font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+    *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
+    *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
+  }
+
+  AnchorFormat2* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat2> (this));
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT2_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat3.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat3.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorFormat3.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,70 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+#define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorFormat3
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 3 */
+  FWORD         xCoordinate;            /* Horizontal value--in design units */
+  FWORD         yCoordinate;            /* Vertical value--in design units */
+  Offset16To<Device>
+                xDeviceTable;           /* Offset to Device table for X
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  Offset16To<Device>
+                yDeviceTable;           /* Offset to Device table for Y
+                                         * coordinate-- from beginning of
+                                         * Anchor table (may be NULL) */
+  public:
+  DEFINE_SIZE_STATIC (10);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+  }
+
+  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
+                   float *x, float *y) const
+  {
+    hb_font_t *font = c->font;
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+
+    if (font->x_ppem || font->num_coords)
+      *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
+    if (font->y_ppem || font->num_coords)
+      *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
+  }
+
+  AnchorFormat3* copy (hb_serialize_context_t *c,
+                       const hb_map_t *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    if (!layout_variation_idx_map) return_trace (nullptr);
+
+    auto *out = c->embed<AnchorFormat3> (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+    return_trace (out);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
+    (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorMatrix.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorMatrix.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/AnchorMatrix.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,77 @@
+#ifndef OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+#define OT_LAYOUT_GPOS_ANCHORMATRIX_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct AnchorMatrix
+{
+  HBUINT16      rows;                   /* Number of rows */
+  UnsizedArrayOf<Offset16To<Anchor>>
+                matrixZ;                /* Matrix of offsets to Anchor tables--
+                                         * from beginning of AnchorMatrix table */
+  public:
+  DEFINE_SIZE_ARRAY (2, matrixZ);
+
+  bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+  {
+    TRACE_SANITIZE (this);
+    if (!c->check_struct (this)) return_trace (false);
+    if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
+    unsigned int count = rows * cols;
+    if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+    for (unsigned int i = 0; i < count; i++)
+      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
+  }
+
+  const Anchor& get_anchor (unsigned int row, unsigned int col,
+                            unsigned int cols, bool *found) const
+  {
+    *found = false;
+    if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
+    *found = !matrixZ[row * cols + col].is_null ();
+    return this+matrixZ[row * cols + col];
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  Iterator index_iter) const
+  {
+    for (unsigned i : index_iter)
+      (this+matrixZ[i]).collect_variation_indices (c);
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               unsigned             num_rows,
+               Iterator             index_iter) const
+  {
+    TRACE_SUBSET (this);
+
+    auto *out = c->serializer->start_embed (this);
+
+    if (!index_iter) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
+
+    out->rows = num_rows;
+    for (const unsigned i : index_iter)
+    {
+      auto *offset = c->serializer->embed (matrixZ[i]);
+      if (!offset) return_trace (false);
+      offset->serialize_subset (c, matrixZ[i], this);
+    }
+
+    return_trace (true);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_ANCHORMATRIX_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ChainContextPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ChainContextPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ChainContextPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ChainContextPos : ChainContext {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Common.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Common.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/Common.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,32 @@
+#ifndef OT_LAYOUT_GPOS_COMMON_HH
+#define OT_LAYOUT_GPOS_COMMON_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+enum attach_type_t {
+  ATTACH_TYPE_NONE      = 0X00,
+
+  /* Each attachment should be either a mark or a cursive; can't be both. */
+  ATTACH_TYPE_MARK      = 0X01,
+  ATTACH_TYPE_CURSIVE   = 0X02,
+};
+
+/* buffer **position** var allocations */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+template<typename Iterator, typename SrcLookup>
+static void SinglePos_serialize (hb_serialize_context_t *c,
+                                 const SrcLookup *src,
+                                 Iterator it,
+                                 const hb_map_t *layout_variation_idx_map);
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_COMMON_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ContextPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ContextPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ContextPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,14 @@
+#ifndef OT_LAYOUT_GPOS_CONTEXTPOS_HH
+#define OT_LAYOUT_GPOS_CONTEXTPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ContextPos : Context {};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CONTEXTPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOS_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOS_HH
+
+#include "CursivePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct CursivePos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  CursivePosFormat1     format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CURSIVEPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/CursivePosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,281 @@
+#ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
+
+#include "Anchor.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct EntryExitRecord
+{
+  friend struct CursivePosFormat1;
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+entryAnchor).collect_variation_indices (c);
+    (src_base+exitAnchor).collect_variation_indices (c);
+  }
+
+  EntryExitRecord* subset (hb_subset_context_t *c,
+                           const void *src_base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+    return_trace (out);
+  }
+
+  protected:
+  Offset16To<Anchor>
+                entryAnchor;            /* Offset to EntryAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  Offset16To<Anchor>
+                exitAnchor;             /* Offset to ExitAnchor table--from
+                                         * beginning of CursivePos
+                                         * subtable--may be NULL */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) {
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
+    return;
+
+  pos[i].attach_chain() = 0;
+
+  unsigned int j = (int) i + chain;
+
+  /* Stop if we see new parent in the chain. */
+  if (j == new_parent)
+    return;
+
+  reverse_cursive_minor_offset (pos, j, direction, new_parent);
+
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    pos[j].y_offset = -pos[i].y_offset;
+  else
+    pos[j].x_offset = -pos[i].x_offset;
+
+  pos[j].attach_chain() = -chain;
+  pos[j].attach_type() = type;
+}
+
+
+struct CursivePosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  Array16Of<EntryExitRecord>
+                entryExitRecord;        /* Array of EntryExit records--in
+                                         * Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (6, entryExitRecord);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
+    if (!this_record.entryAnchor) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    unsigned unsafe_from;
+    if (!skippy_iter.prev (&unsafe_from))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
+    if (!prev_record.exitAnchor)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int i = skippy_iter.idx;
+    unsigned int j = buffer->idx;
+
+    buffer->unsafe_to_break (i, j);
+    float entry_x, entry_y, exit_x, exit_y;
+    (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
+
+    hb_glyph_position_t *pos = buffer->pos;
+
+    hb_position_t d;
+    /* Main-direction adjustment */
+    switch (c->direction) {
+      case HB_DIRECTION_LTR:
+        pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
+
+        d = roundf (entry_x) + pos[j].x_offset;
+        pos[j].x_advance -= d;
+        pos[j].x_offset  -= d;
+        break;
+      case HB_DIRECTION_RTL:
+        d = roundf (exit_x) + pos[i].x_offset;
+        pos[i].x_advance -= d;
+        pos[i].x_offset  -= d;
+
+        pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
+        break;
+      case HB_DIRECTION_TTB:
+        pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
+
+        d = roundf (entry_y) + pos[j].y_offset;
+        pos[j].y_advance -= d;
+        pos[j].y_offset  -= d;
+        break;
+      case HB_DIRECTION_BTT:
+        d = roundf (exit_y) + pos[i].y_offset;
+        pos[i].y_advance -= d;
+        pos[i].y_offset  -= d;
+
+        pos[j].y_advance  = roundf (entry_y);
+        break;
+      case HB_DIRECTION_INVALID:
+      default:
+        break;
+    }
+
+    /* Cross-direction adjustment */
+
+    /* We attach child to parent (think graph theory and rooted trees whereas
+     * the root stays on baseline and each node aligns itself against its
+     * parent.
+     *
+     * Optimize things for the case of RightToLeft, as that's most common in
+     * Arabic. */
+    unsigned int child  = i;
+    unsigned int parent = j;
+    hb_position_t x_offset = entry_x - exit_x;
+    hb_position_t y_offset = entry_y - exit_y;
+    if  (!(c->lookup_props & LookupFlag::RightToLeft))
+    {
+      unsigned int k = child;
+      child = parent;
+      parent = k;
+      x_offset = -x_offset;
+      y_offset = -y_offset;
+    }
+
+    /* If child was already connected to someone else, walk through its old
+     * chain and reverse the link direction, such that the whole tree of its
+     * previous connection now attaches to new parent.  Watch out for case
+     * where new parent is on the path from old chain...
+     */
+    reverse_cursive_minor_offset (pos, child, c->direction, parent);
+
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+    pos[child].attach_chain() = (int) parent - (int) child;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+      pos[child].y_offset = y_offset;
+    else
+      pos[child].x_offset = x_offset;
+
+    /* If parent was attached to child, separate them.
+     * https://github.com/harfbuzz/harfbuzz/issues/2469
+     */
+    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+      pos[parent].attach_chain() = 0;
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_subset_context_t *c,
+                  Iterator it,
+                  const void *src_base)
+  {
+    if (unlikely (!c->serializer->extend_min ((*this)))) return;
+    this->format = 1;
+    this->entryExitRecord.len = it.len ();
+
+    for (const EntryExitRecord& entry_record : + it
+                                               | hb_map (hb_second))
+      entry_record.subset (c, src_base);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c->serializer, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto it =
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
+                              { return hb_pair (glyph_map[p.first], p.second);})
+    ;
+
+    bool ret = bool (it);
+    out->serialize (c, it, this);
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ExtensionPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ExtensionPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ExtensionPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,17 @@
+#ifndef OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+#define OT_LAYOUT_GPOS_EXTENSIONPOS_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct ExtensionPos : Extension<ExtensionPos>
+{
+  typedef struct PosLookupSubTable SubTable;
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_EXTENSIONPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkArray.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkArray.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkArray.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,113 @@
+#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
+#define OT_LAYOUT_GPOS_MARKARRAY_HH
+
+#include "AnchorMatrix.hh"
+#include "MarkRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Coverage order */
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
+  }
+
+  bool apply (hb_ot_apply_context_t *c,
+              unsigned int mark_index, unsigned int glyph_index,
+              const AnchorMatrix &anchors, unsigned int class_count,
+              unsigned int glyph_pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
+    unsigned int mark_class = record.klass;
+
+    const Anchor& mark_anchor = this + record.markAnchor;
+    bool found;
+    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+    /* If this subtable doesn't have an anchor for this base and this class,
+     * return false such that the subsequent subtables have a chance at it. */
+    if (unlikely (!found)) return_trace (false);
+
+    float mark_x, mark_y, base_x, base_y;
+
+    buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
+    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+
+    hb_glyph_position_t &o = buffer->cur_pos();
+    o.x_offset = roundf (base_x - mark_x);
+    o.y_offset = roundf (base_y - mark_y);
+    o.attach_type() = ATTACH_TYPE_MARK;
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               Iterator             coverage,
+               const hb_map_t      *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+    auto* out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    auto mark_iter =
+    + hb_zip (coverage, this->iter ())
+    | hb_filter (glyphset, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    unsigned new_length = 0;
+    for (const auto& mark_record : mark_iter) {
+      if (unlikely (!mark_record.subset (c, this, klass_mapping)))
+        return_trace (false);
+      new_length++;
+    }
+
+    if (unlikely (!c->serializer->check_assign (out->len, new_length,
+                                                HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
+      return_trace (false);
+
+    return_trace (true);
+  }
+};
+
+static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
+                                                 const MarkArray &mark_array,
+                                                 const hb_set_t  &glyphset,
+                                                 hb_map_t*        klass_mapping /* INOUT */)
+{
+  hb_set_t orig_classes;
+
+  + hb_zip (mark_coverage, mark_array)
+  | hb_filter (glyphset, hb_first)
+  | hb_map (hb_second)
+  | hb_map (&MarkRecord::get_class)
+  | hb_sink (orig_classes)
+  ;
+
+  unsigned idx = 0;
+  for (auto klass : orig_classes.iter ())
+  {
+    if (klass_mapping->has (klass)) continue;
+    klass_mapping->set (klass, idx);
+    idx++;
+  }
+}
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOS_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOS_HH
+
+#include "MarkBasePosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkBasePos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  MarkBasePosFormat1    format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,217 @@
+#ifndef OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
+
+#include "MarkArray.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix BaseArray;         /* base-major--
+                                         * in order of BaseCoverage Index--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+struct MarkBasePosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                markCoverage;           /* Offset to MarkCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  Offset16To<Coverage>
+                baseCoverage;           /* Offset to BaseCoverage table--from
+                                         * beginning of MarkBasePos subtable */
+  HBUINT16      classCount;             /* Number of classes defined for marks */
+  Offset16To<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkBasePos subtable */
+  Offset16To<BaseArray>
+                baseArray;              /* Offset to BaseArray table--from
+                                         * beginning of MarkBasePos subtable */
+
+  public:
+  DEFINE_SIZE_STATIC (12);
+
+    bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  baseCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  baseArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+baseCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : base_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+markCoverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph */
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+    do {
+      unsigned unsafe_from;
+      if (!skippy_iter.prev (&unsafe_from))
+      {
+        buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+        return_trace (false);
+      }
+
+      /* We only want to attach to the first of a MultipleSubst sequence.
+       * https://github.com/harfbuzz/harfbuzz/issues/740
+       * Reject others...
+       * ...but stop if we find a mark in the MultipleSubst sequence:
+       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
+      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
+          0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
+          (skippy_iter.idx == 0 ||
+           _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
+           _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
+           _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
+           _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
+           _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
+           ))
+        break;
+      skippy_iter.reject ();
+    } while (true);
+
+    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
+    if (base_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    out->markArray.serialize_subset (c, markArray, this,
+                                     (this+markCoverage).iter (),
+                                     &klass_mapping);
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + base_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : + base_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+
+    out->baseArray.serialize_subset (c, baseArray, this,
+                                     base_iter.len (),
+                                     base_indexes.iter ());
+
+    return_trace (true);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,35 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOS_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOS_HH
+
+#include "MarkLigPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkLigPos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  MarkLigPosFormat1     format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,244 @@
+#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_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
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                markCoverage;           /* Offset to Mark Coverage table--from
+                                         * beginning of MarkLigPos subtable */
+  Offset16To<Coverage>
+                ligatureCoverage;       /* Offset to Ligature Coverage
+                                         * table--from beginning of MarkLigPos
+                                         * subtable */
+  HBUINT16      classCount;             /* Number of defined mark classes */
+  Offset16To<MarkArray>
+                markArray;              /* Offset to MarkArray table--from
+                                         * beginning of MarkLigPos subtable */
+  Offset16To<LigatureArray>
+                ligatureArray;          /* Offset to LigatureArray table--from
+                                         * beginning of MarkLigPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (12);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  markCoverage.sanitize (c, this) &&
+                  ligatureCoverage.sanitize (c, this) &&
+                  markArray.sanitize (c, this) &&
+                  ligatureArray.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+ligatureCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned ligcount = (this+ligatureArray).len;
+    auto lig_iter =
+    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    for (const unsigned i : lig_iter)
+    {
+      hb_sorted_vector_t<unsigned> lig_indexes;
+      unsigned row_count = lig_array[i].rows;
+      for (unsigned row : + hb_range (row_count))
+      {
+        + hb_range ((unsigned) classCount)
+        | hb_filter (klass_mapping)
+        | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+        | hb_sink (lig_indexes)
+        ;
+      }
+
+      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
+    }
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+markCoverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+    /* Now we search backwards for a non-mark glyph */
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+    unsigned unsafe_from;
+    if (!skippy_iter.prev (&unsafe_from))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+    unsigned int j = skippy_iter.idx;
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
+    if (lig_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    const LigatureAttach& lig_attach = lig_array[lig_index];
+
+    /* Find component to attach to */
+    unsigned int comp_count = lig_attach.rows;
+    if (unlikely (!comp_count))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    /* We must now check whether the ligature ID of the current mark glyph
+     * is identical to the ligature ID of the found ligature.  If yes, we
+     * can directly use the component index.  If not, we attach the mark
+     * glyph to the last component of the ligature. */
+    unsigned int comp_index;
+    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    if (lig_id && lig_id == mark_id && mark_comp > 0)
+      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+    else
+      comp_index = comp_count - 1;
+
+    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    auto new_mark_coverage =
+    + mark_iter
+    | hb_map_retains_sorting (hb_first)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
+      return_trace (false);
+
+    out->markArray.serialize_subset (c, markArray, this,
+                                     (this+markCoverage).iter (),
+                                     &klass_mapping);
+
+    auto new_ligature_coverage =
+    + hb_iter (this + ligatureCoverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
+      return_trace (false);
+
+    out->ligatureArray.serialize_subset (c, ligatureArray, this,
+                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
+
+    return_trace (true);
+  }
+
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,36 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOS_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOS_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkMarkPos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  MarkMarkPosFormat1    format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,227 @@
+#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
+
+#include "MarkMarkPosFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef AnchorMatrix Mark2Array;        /* mark2-major--
+                                         * in order of Mark2Coverage Index--,
+                                         * mark1-minor--
+                                         * ordered by class--zero-based. */
+
+struct MarkMarkPosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                mark1Coverage;          /* Offset to Combining Mark1 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  Offset16To<Coverage>
+                mark2Coverage;          /* Offset to Combining Mark2 Coverage
+                                         * table--from beginning of MarkMarkPos
+                                         * subtable */
+  HBUINT16      classCount;             /* Number of defined mark classes */
+  Offset16To<MarkArray>
+                mark1Array;             /* Offset to Mark1Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  Offset16To<Mark2Array>
+                mark2Array;             /* Offset to Mark2Array table--from
+                                         * beginning of MarkMarkPos subtable */
+  public:
+  DEFINE_SIZE_STATIC (12);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  mark1Coverage.sanitize (c, this) &&
+                  mark2Coverage.sanitize (c, this) &&
+                  mark1Array.sanitize (c, this) &&
+                  mark2Array.sanitize (c, this, (unsigned int) classCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+mark1Coverage).intersects (glyphs) &&
+           (this+mark2Coverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
+
+    unsigned mark2_count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : mark2_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+mark1Coverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+
+    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+    unsigned unsafe_from;
+    if (!skippy_iter.prev (&unsafe_from))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    unsigned int j = skippy_iter.idx;
+
+    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
+
+    if (likely (id1 == id2))
+    {
+      if (id1 == 0) /* Marks belonging to the same base. */
+        goto good;
+      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
+        goto good;
+    }
+    else
+    {
+      /* If ligature ids don't match, it may be the case that one of the marks
+       * itself is a ligature.  In which case match. */
+      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
+        goto good;
+    }
+
+    /* Didn't match. */
+    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+    return_trace (false);
+
+    good:
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
+    if (mark2_index == NOT_COVERED)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      return_trace (false);
+    }
+
+    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark1_iter =
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark1_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    out->mark1Array.serialize_subset (c, mark1Array, this,
+                                      (this+mark1Coverage).iter (),
+                                      &klass_mapping);
+
+    unsigned mark2count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2count))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + mark2_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : + mark2_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+
+    out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
+
+    return_trace (true);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkRecord.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkRecord.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/MarkRecord.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,52 @@
+#ifndef OT_LAYOUT_GPOS_MARKRECORD_HH
+#define OT_LAYOUT_GPOS_MARKRECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct MarkRecord
+{
+  friend struct MarkArray;
+
+  protected:
+  HBUINT16      klass;                  /* Class defined for this mark */
+  Offset16To<Anchor>
+                markAnchor;             /* Offset to Anchor table--from
+                                         * beginning of MarkArray table */
+  public:
+  DEFINE_SIZE_STATIC (4);
+
+  unsigned get_class () const { return (unsigned) klass; }
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+  }
+
+  MarkRecord *subset (hb_subset_context_t    *c,
+                      const void             *src_base,
+                      const hb_map_t         *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->klass = klass_mapping->get (klass);
+    out->markAnchor.serialize_subset (c, markAnchor, src_base);
+    return_trace (out);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+markAnchor).collect_variation_indices (c);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_MARKRECORD_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,38 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOS_HH
+#define OT_LAYOUT_GPOS_PAIRPOS_HH
+
+#include "PairPosFormat1.hh"
+#include "PairPosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairPos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  PairPosFormat1        format1;
+  PairPosFormat2        format2;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOS_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,420 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_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
+{
+  friend struct PairPosFormat1;
+
+  bool intersects (const hb_set_t *glyphs,
+                   const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs->has (record->secondGlyph))
+        return true;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+    return false;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c,
+                       const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    c->input->add_array (&record->secondGlyph, len, record_size);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats) const
+  {
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (c->glyph_set->has (record->secondGlyph))
+      { record->collect_variation_indices (c, valueFormats, this); }
+
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+  }
+
+  bool apply (hb_ot_apply_context_t *c,
+              const ValueFormat *valueFormats,
+              unsigned int pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+                                                &firstPairValueRecord,
+                                                len,
+                                                record_size);
+    if (record)
+    {
+      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+      if (applied_first || applied_second)
+        buffer->unsafe_to_break (buffer->idx, pos + 1);
+      if (len2)
+        pos++;
+      buffer->idx = pos;
+      return_trace (true);
+    }
+    buffer->unsafe_to_concat (buffer->idx, pos + 1);
+    return_trace (false);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const ValueFormat valueFormats[2],
+               const ValueFormat newFormats[2]) const
+  {
+    TRACE_SUBSET (this);
+    auto snap = c->serializer->snapshot ();
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->len = 0;
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+    PairValueRecord::context_t context =
+    {
+      this,
+      valueFormats,
+      newFormats,
+      len1,
+      &glyph_map,
+      c->plan->layout_variation_idx_map
+    };
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len, num = 0;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (glyphset.has (record->secondGlyph)
+         && record->subset (c, &context)) num++;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+
+    out->len = num;
+    if (!num) c->serializer->revert (snap);
+    return_trace (num);
+  }
+
+  struct sanitize_closure_t
+  {
+    const ValueFormat *valueFormats;
+    unsigned int len1; /* valueFormats[0].get_len() */
+    unsigned int stride; /* 1 + len1 + len2 */
+  };
+
+  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && c->check_range (&firstPairValueRecord,
+                          len,
+                          HBUINT16::static_size,
+                          closure->stride))) return_trace (false);
+
+    unsigned int count = len;
+    const PairValueRecord *record = &firstPairValueRecord;
+    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+  }
+
+  protected:
+  HBUINT16              len;    /* Number of PairValueRecords */
+  PairValueRecord       firstPairValueRecord;
+                                /* Array of PairValueRecords--ordered
+                                 * by GlyphID of the second glyph */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct PairPosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat[2];         /* [0] Defines the types of data in
+                                         * ValueRecord1--for the first glyph
+                                         * in the pair--may be zero (0) */
+                                        /* [1] Defines the types of data in
+                                         * ValueRecord2--for the second glyph
+                                         * in the pair--may be zero (0) */
+  Array16OfOffset16To<PairSet>
+                pairSet;                /* Array of PairSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (10, pairSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!c->check_struct (this)) return_trace (false);
+
+    unsigned int len1 = valueFormat[0].get_len ();
+    unsigned int len2 = valueFormat[1].get_len ();
+    PairSet::sanitize_closure_t closure =
+    {
+      valueFormat,
+      len1,
+      1 + len1 + len2
+    };
+
+    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+  }
+
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
+              { return (this+_).intersects (glyphs, valueFormat); })
+    | hb_any
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
+
+    auto it =
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    if (!it) return;
+    + it
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, valueFormat);
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    unsigned unsafe_to;
+    if (!skippy_iter.next (&unsafe_to))
+    {
+      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
+      return_trace (false);
+    }
+
+    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat[0] = valueFormat[0];
+    out->valueFormat[1] = valueFormat[1];
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+    {
+      hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
+      out->valueFormat[0] = newFormats.first;
+      out->valueFormat[1] = newFormats.second;
+    }
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
+                 {
+                   auto snap = c->serializer->snapshot ();
+                   auto *o = out->pairSet.serialize_append (c->serializer);
+                   if (unlikely (!o)) return false;
+                   bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
+                   if (!ret)
+                   {
+                     out->pairSet.pop ();
+                     c->serializer->revert (snap);
+                   }
+                   return ret;
+                 },
+                 hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+
+    return_trace (bool (new_coverage));
+  }
+
+
+  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+  {
+    unsigned len1 = valueFormat[0].get_len ();
+    unsigned len2 = valueFormat[1].get_len ();
+    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+    unsigned format1 = 0;
+    unsigned format2 = 0;
+    for (const Offset16To<PairSet>& _ :
+             + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
+    {
+      const PairSet& set = (this + _);
+      const PairValueRecord *record = &set.firstPairValueRecord;
+
+      for (unsigned i = 0; i < set.len; i++)
+      {
+        if (record->intersects (glyphset))
+        {
+          format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
+          format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+        }
+        record = &StructAtOffset<const PairValueRecord> (record, record_size);
+      }
+    }
+
+    return hb_pair (format1, format2);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PairPosFormat2.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,314 @@
+#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
+
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PairPosFormat2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat1;           /* ValueRecord definition--for the
+                                         * first glyph of the pair--may be zero
+                                         * (0) */
+  ValueFormat   valueFormat2;           /* ValueRecord definition--for the
+                                         * second glyph of the pair--may be
+                                         * zero (0) */
+  Offset16To<ClassDef>
+                classDef1;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the first glyph of the pair */
+  Offset16To<ClassDef>
+                classDef2;              /* Offset to ClassDef table--from
+                                         * beginning of PairPos subtable--for
+                                         * the second glyph of the pair */
+  HBUINT16      class1Count;            /* Number of classes in ClassDef1
+                                         * table--includes Class0 */
+  HBUINT16      class2Count;            /* Number of classes in ClassDef2
+                                         * table--includes Class0 */
+  ValueRecord   values;                 /* Matrix of value pairs:
+                                         * class1-major, class2-minor,
+                                         * Each entry has value1 and value2 */
+  public:
+  DEFINE_SIZE_ARRAY (16, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && coverage.sanitize (c, this)
+       && classDef1.sanitize (c, this)
+       && classDef2.sanitize (c, this))) return_trace (false);
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int stride = len1 + len2;
+    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
+    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+    return_trace (c->check_range ((const void *) values,
+                                  count,
+                                  record_size) &&
+                  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+                  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+coverage).intersects (glyphs) &&
+           (this+classDef2).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!intersects (c->glyph_set)) return;
+    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
+
+    hb_set_t klass1_glyphs, klass2_glyphs;
+    if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
+    if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
+
+    hb_set_t class1_set, class2_set;
+    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
+    {
+      if (!klass1_glyphs.has (cp)) class1_set.add (0);
+      else
+      {
+        unsigned klass1 = (this+classDef1).get (cp);
+        class1_set.add (klass1);
+      }
+    }
+
+    class2_set.add (0);
+    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
+    {
+      unsigned klass2 = (this+classDef2).get (cp);
+      class2_set.add (klass2);
+    }
+
+    if (class1_set.is_empty ()
+        || class2_set.is_empty ()
+        || (class2_set.get_population() == 1 && class2_set.has(0)))
+      return;
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
+    for (const unsigned class1_idx : class1_set.iter ())
+    {
+      for (const unsigned class2_idx : class2_set.iter ())
+      {
+        unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        if (valueFormat1.has_device ())
+          valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
+
+        if (valueFormat2.has_device ())
+          valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
+      }
+    }
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    unsigned unsafe_to;
+    if (!skippy_iter.next (&unsafe_to))
+    {
+      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
+      return_trace (false);
+    }
+
+    unsigned int len1 = valueFormat1.get_len ();
+    unsigned int len2 = valueFormat2.get_len ();
+    unsigned int record_len = len1 + len2;
+
+    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+    if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
+    {
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+      return_trace (false);
+    }
+
+    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
+
+    bool applied_first = false, applied_second = false;
+
+
+    /* Isolate simple kerning and apply it half to each side.
+     * Results in better cursor positinoing / underline drawing.
+     *
+     * Disabled, because causes issues... :-(
+     * https://github.com/harfbuzz/harfbuzz/issues/3408
+     * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
+     */
+#ifndef HB_SPLIT_KERN
+    if (0)
+#endif
+    {
+      if (!len2)
+      {
+        const hb_direction_t dir = buffer->props.direction;
+        const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir);
+        const bool backward = HB_DIRECTION_IS_BACKWARD (dir);
+        unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance;
+        if (backward)
+          mask |= mask >> 2; /* Add eg. xPlacement in RTL. */
+        /* Add Devices. */
+        mask |= mask << 4;
+
+        if (valueFormat1 & ~mask)
+          goto bail;
+
+        /* Is simple kern. Apply value on an empty position slot,
+         * then split it between sides. */
+
+        hb_glyph_position_t pos{};
+        if (valueFormat1.apply_value (c, this, v, pos))
+        {
+          hb_position_t *src  = &pos.x_advance;
+          hb_position_t *dst1 = &buffer->cur_pos().x_advance;
+          hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance;
+          unsigned i = horizontal ? 0 : 1;
+
+          hb_position_t kern  = src[i];
+          hb_position_t kern1 = kern >> 1;
+          hb_position_t kern2 = kern - kern1;
+
+          if (!backward)
+          {
+            dst1[i] += kern1;
+            dst2[i] += kern2;
+            dst2[i + 2] += kern2;
+          }
+          else
+          {
+            dst1[i] += kern1;
+            dst1[i + 2] += src[i + 2] - kern2;
+            dst2[i] += kern2;
+          }
+
+          applied_first = applied_second = kern != 0;
+          goto success;
+        }
+        goto boring;
+      }
+    }
+    bail:
+
+
+    applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+    applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+
+    success:
+    if (applied_first || applied_second)
+      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
+    else
+    boring:
+      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+
+
+    buffer->idx = skippy_iter.idx;
+    if (len2)
+      buffer->idx++;
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass1_map;
+    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
+    out->class1Count = klass1_map.get_population ();
+
+    hb_map_t klass2_map;
+    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
+    out->class2Count = klass2_map.get_population ();
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+
+    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      newFormats = compute_effective_value_formats (klass1_map, klass2_map);
+
+    out->valueFormat1 = newFormats.first;
+    out->valueFormat2 = newFormats.second;
+
+    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+    {
+      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+      {
+        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
+        valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
+      }
+    }
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    out->coverage.serialize_serialize (c->serializer, it);
+    return_trace (out->class1Count && out->class2Count && bool (it));
+  }
+
+
+  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
+                                                                 const hb_map_t& klass2_map) const
+  {
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+
+    unsigned format1 = 0;
+    unsigned format2 = 0;
+
+    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+    {
+      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+      {
+        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
+        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+      }
+    }
+
+    return hb_pair (format1, format2);
+  }
+};
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookup.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookup.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookup.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUP_HH
+#define OT_LAYOUT_GPOS_POSLOOKUP_HH
+
+#include "PosLookupSubTable.hh"
+#include "../../../hb-ot-layout-common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookup : Lookup
+{
+  using SubTable = PosLookupSubTable;
+
+  const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
+
+  bool is_reverse () const
+  {
+    return false;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
+  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { return dispatch (c); }
+
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+  {
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
+  template <typename set_t>
+  void collect_coverage (set_t *glyphs) const
+  {
+    hb_collect_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  template <typename context_t>
+  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
+
+  bool subset (hb_subset_context_t *c) const
+  { return Lookup::subset<SubTable> (c); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return Lookup::sanitize<SubTable> (c); }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GPOS_POSLOOKUP_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookupSubTable.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookupSubTable.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/PosLookupSubTable.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,79 @@
+#ifndef OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
+
+#include "SinglePos.hh"
+#include "PairPos.hh"
+#include "CursivePos.hh"
+#include "MarkBasePos.hh"
+#include "MarkLigPos.hh"
+#include "MarkMarkPos.hh"
+#include "ContextPos.hh"
+#include "ChainContextPos.hh"
+#include "ExtensionPos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct PosLookupSubTable
+{
+  friend struct ::OT::Lookup;
+  friend struct PosLookup;
+
+  enum Type {
+    Single              = 1,
+    Pair                = 2,
+    Cursive             = 3,
+    MarkBase            = 4,
+    MarkLig             = 5,
+    MarkMark            = 6,
+    Context             = 7,
+    ChainContext        = 8,
+    Extension           = 9
+  };
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
+    case Pair:                  return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
+    case Cursive:               return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkBase:              return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkLig:               return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
+    case MarkMark:              return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+
+  protected:
+  union {
+  SinglePos             single;
+  PairPos               pair;
+  CursivePos            cursive;
+  MarkBasePos           markBase;
+  MarkLigPos            markLig;
+  MarkMarkPos           markMark;
+  ContextPos            context;
+  ChainContextPos       chainContext;
+  ExtensionPos          extension;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePos.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,98 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOS_HH
+#define OT_LAYOUT_GPOS_SINGLEPOS_HH
+
+#include "SinglePosFormat1.hh"
+#include "SinglePosFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePos
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  SinglePosFormat1      format1;
+  SinglePosFormat2      format2;
+  } u;
+
+  public:
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  unsigned get_format (Iterator glyph_val_iter_pairs)
+  {
+    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+    for (const auto iter : glyph_val_iter_pairs)
+      for (const auto _ : hb_zip (iter.second, first_val_iter))
+        if (_.first != _.second)
+          return 2;
+
+    return 1;
+  }
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup* src,
+                  Iterator glyph_val_iter_pairs,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    if (unlikely (!c->extend_min (u.format))) return;
+    unsigned format = 2;
+    ValueFormat new_format = src->get_value_format ();
+
+    if (glyph_val_iter_pairs)
+    {
+      format = get_format (glyph_val_iter_pairs);
+      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
+    }
+
+    u.format = format;
+    switch (u.format) {
+    case 1: u.format1.serialize (c,
+                                 src,
+                                 glyph_val_iter_pairs,
+                                 new_format,
+                                 layout_variation_idx_map);
+      return;
+    case 2: u.format2.serialize (c,
+                                 src,
+                                 glyph_val_iter_pairs,
+                                 new_format,
+                                 layout_variation_idx_map);
+      return;
+    default:return;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+
+template<typename Iterator, typename SrcLookup>
+static void
+SinglePos_serialize (hb_serialize_context_t *c,
+                     const SrcLookup *src,
+                     Iterator it,
+                     const hb_map_t *layout_variation_idx_map)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat1.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,124 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
+
+#include "Common.hh"
+#include "ValueFormat.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  ValueRecord   values;                 /* Defines positioning
+                                         * value(s)--applied to all glyphs in
+                                         * the Coverage table */
+  public:
+  DEFINE_SIZE_ARRAY (6, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  valueFormat.sanitize_value (c, this, values));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (c->glyph_set)
+    ;
+
+    if (!it) return;
+    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  ValueFormat get_value_format () const { return valueFormat; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    valueFormat.apply_value (c, this, values, buffer->cur_pos());
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup *src,
+                  Iterator it,
+                  ValueFormat newFormat,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    if (unlikely (!c->extend_min (this))) return;
+    if (unlikely (!c->check_assign (valueFormat,
+                                    newFormat,
+                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+
+    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
+    {
+      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_map);
+      // Only serialize the first entry in the iterator, the rest are assumed to
+      // be the same.
+      break;
+    }
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat2.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat2.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/SinglePosFormat2.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,140 @@
+#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+struct SinglePosFormat2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of subtable */
+  ValueFormat   valueFormat;            /* Defines the types of data in the
+                                         * ValueRecord */
+  HBUINT16      valueCount;             /* Number of ValueRecords */
+  ValueRecord   values;                 /* Array of ValueRecords--positioning
+                                         * values applied to glyphs */
+  public:
+  DEFINE_SIZE_ARRAY (8, values);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  valueFormat.sanitize_values (c, this, values, valueCount));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (c->glyph_set, hb_first)
+    ;
+
+    if (!it) return;
+
+    unsigned sub_length = valueFormat.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
+
+    for (unsigned i : + it
+                      | hb_map (hb_second))
+      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
+
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  ValueFormat get_value_format () const { return valueFormat; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (likely (index >= valueCount)) return_trace (false);
+
+    valueFormat.apply_value (c, this,
+                             &values[index * valueFormat.get_len ()],
+                             buffer->cur_pos());
+
+    buffer->idx++;
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+      typename SrcLookup,
+      hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const SrcLookup *src,
+                  Iterator it,
+                  ValueFormat newFormat,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    auto out = c->extend_min (this);
+    if (unlikely (!out)) return;
+    if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+    if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
+
+    + it
+    | hb_map (hb_second)
+    | hb_apply ([&] (hb_array_t<const Value> _)
+    { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize_serialize (c, glyphs);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned sub_length = valueFormat.get_len ();
+    auto values_array = values.as_array (valueCount * sub_length);
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+                              {
+                                return hb_pair (glyph_map[_.first],
+                                                values_array.sub_array (_.second * sub_length,
+                                                                        sub_length));
+                              })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
+    return_trace (ret);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ValueFormat.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ValueFormat.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS/ValueFormat.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,329 @@
+#ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
+#define OT_LAYOUT_GPOS_VALUEFORMAT_HH
+
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+typedef HBUINT16 Value;
+
+typedef UnsizedArrayOf<Value> ValueRecord;
+
+struct ValueFormat : HBUINT16
+{
+  enum Flags {
+    xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
+    yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
+    xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
+    yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
+    xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
+    yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
+    xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
+    yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
+    ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
+    reserved    = 0xF000u,      /* For future use */
+
+    devices     = 0x00F0u       /* Mask for having any Device table */
+  };
+
+/* All fields are options.  Only those available advance the value pointer. */
+#if 0
+  HBINT16               xPlacement;     /* Horizontal adjustment for
+                                         * placement--in design units */
+  HBINT16               yPlacement;     /* Vertical adjustment for
+                                         * placement--in design units */
+  HBINT16               xAdvance;       /* Horizontal adjustment for
+                                         * advance--in design units (only used
+                                         * for horizontal writing) */
+  HBINT16               yAdvance;       /* Vertical adjustment for advance--in
+                                         * design units (only used for vertical
+                                         * writing) */
+  Offset16To<Device>    xPlaDevice;     /* Offset to Device table for
+                                         * horizontal placement--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset16To<Device>    yPlaDevice;     /* Offset to Device table for vertical
+                                         * placement--measured from beginning
+                                         * of PosTable (may be NULL) */
+  Offset16To<Device>    xAdvDevice;     /* Offset to Device table for
+                                         * horizontal advance--measured from
+                                         * beginning of PosTable (may be NULL) */
+  Offset16To<Device>    yAdvDevice;     /* Offset to Device table for vertical
+                                         * advance--measured from beginning of
+                                         * PosTable (may be NULL) */
+#endif
+
+  IntType& operator = (uint16_t i) { v = i; return *this; }
+
+  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
+  unsigned int get_size () const { return get_len () * Value::static_size; }
+
+  bool apply_value (hb_ot_apply_context_t *c,
+                    const void            *base,
+                    const Value           *values,
+                    hb_glyph_position_t   &glyph_pos) const
+  {
+    bool ret = false;
+    unsigned int format = *this;
+    if (!format) return ret;
+
+    hb_font_t *font = c->font;
+    bool horizontal =
+#ifndef HB_NO_VERTICAL
+      HB_DIRECTION_IS_HORIZONTAL (c->direction)
+#else
+      true
+#endif
+      ;
+
+    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
+    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
+    if (format & xAdvance) {
+      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
+      values++;
+    }
+    /* y_advance values grow downward but font-space grows upward, hence negation */
+    if (format & yAdvance) {
+      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
+      values++;
+    }
+
+    if (!has_device ()) return ret;
+
+    bool use_x_device = font->x_ppem || font->num_coords;
+    bool use_y_device = font->y_ppem || font->num_coords;
+
+    if (!use_x_device && !use_y_device) return ret;
+
+    const VariationStore &store = c->var_store;
+    auto *cache = c->var_store_cache;
+
+    /* pixel -> fractional pixel */
+    if (format & xPlaDevice) {
+      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+      values++;
+    }
+    if (format & yPlaDevice) {
+      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+      values++;
+    }
+    if (format & xAdvDevice) {
+      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+      values++;
+    }
+    if (format & yAdvDevice) {
+      /* y_advance values grow downward but font-space grows upward, hence negation */
+      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+      values++;
+    }
+    return ret;
+  }
+
+  unsigned int get_effective_format (const Value *values) const
+  {
+    unsigned int format = *this;
+    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
+      if (format & flag) should_drop (*values++, (Flags) flag, &format);
+    }
+
+    return format;
+  }
+
+  template<typename Iterator,
+      hb_requires (hb_is_iterator (Iterator))>
+  unsigned int get_effective_format (Iterator it) const {
+    unsigned int new_format = 0;
+
+    for (const hb_array_t<const Value>& values : it)
+      new_format = new_format | get_effective_format (&values);
+
+    return new_format;
+  }
+
+  void copy_values (hb_serialize_context_t *c,
+                    unsigned int new_format,
+                    const void *base,
+                    const Value *values,
+                    const hb_map_t *layout_variation_idx_map) const
+  {
+    unsigned int format = *this;
+    if (!format) return;
+
+    if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
+    if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
+    if (format & xAdvance)   copy_value (c, new_format, xAdvance, *values++);
+    if (format & yAdvance)   copy_value (c, new_format, yAdvance, *values++);
+
+    if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+  }
+
+  void copy_value (hb_serialize_context_t *c,
+                   unsigned int new_format,
+                   Flags flag,
+                   Value value) const
+  {
+    // Filter by new format.
+    if (!(new_format & flag)) return;
+    c->copy (value);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *base,
+                                  const hb_array_t<const Value>& values) const
+  {
+    unsigned format = *this;
+    unsigned i = 0;
+    if (format & xPlacement) i++;
+    if (format & yPlacement) i++;
+    if (format & xAdvance) i++;
+    if (format & yAdvance) i++;
+    if (format & xPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::yPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::xAdvDevice)
+    {
+
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::yAdvDevice)
+    {
+
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+  }
+
+  private:
+  bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    unsigned int format = *this;
+
+    if (format & xPlacement) values++;
+    if (format & yPlacement) values++;
+    if (format & xAdvance)   values++;
+    if (format & yAdvance)   values++;
+
+    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+
+    return true;
+  }
+
+  static inline Offset16To<Device>& get_device (Value* value)
+  {
+    return *static_cast<Offset16To<Device> *> (value);
+  }
+  static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
+  {
+    if (worked) *worked |= bool (*value);
+    return *static_cast<const Offset16To<Device> *> (value);
+  }
+
+  bool copy_device (hb_serialize_context_t *c, const void *base,
+                    const Value *src_value, const hb_map_t *layout_variation_idx_map) const
+  {
+    Value       *dst_value = c->copy (*src_value);
+
+    if (!dst_value) return false;
+    if (*dst_value == 0) return true;
+
+    *dst_value = 0;
+    c->push ();
+    if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
+    {
+      c->add_link (*dst_value, c->pop_pack ());
+      return true;
+    }
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+  {
+    if (worked) *worked |= bool (*value);
+    return *reinterpret_cast<const HBINT16 *> (value);
+  }
+
+  public:
+
+  bool has_device () const
+  {
+    unsigned int format = *this;
+    return (format & devices) != 0;
+  }
+
+  bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+  }
+
+  bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+  {
+    TRACE_SANITIZE (this);
+    unsigned int len = get_len ();
+
+    if (!c->check_range (values, count, get_size ())) return_trace (false);
+
+    if (!has_device ()) return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++) {
+      if (!sanitize_value_devices (c, base, values))
+        return_trace (false);
+      values += len;
+    }
+
+    return_trace (true);
+  }
+
+  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
+  bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!has_device ()) return_trace (true);
+
+    for (unsigned int i = 0; i < count; i++) {
+      if (!sanitize_value_devices (c, base, values))
+        return_trace (false);
+      values += stride;
+    }
+
+    return_trace (true);
+  }
+
+ private:
+
+  void should_drop (Value value, Flags flag, unsigned int* format) const
+  {
+    if (value) return;
+    *format = *format & ~flag;
+  }
+
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/Layout/GPOS.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -0,0 +1,165 @@
+#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 */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/Glyph.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -84,6 +84,7 @@
     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
     contour_point_vector_t stack_points;
     bool inplace = type == SIMPLE && all_points.length == 0;
+    /* Load into all_points if it's empty, as an optimization. */
     contour_point_vector_t &points = inplace ? all_points : stack_points;
 
     switch (type) {
@@ -95,7 +96,6 @@
       break;
     }
     case SIMPLE:
-      /* Load into all_points if it's empty, as an optimization. */
       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
 	return false;
       break;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SimpleGlyph.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SimpleGlyph.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/OT/glyf/SimpleGlyph.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -117,6 +117,28 @@
     first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
   }
 
+  static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
+			  contour_point_vector_t &points_ /* IN/OUT */,
+			  const HBUINT8 *end)
+  {
+    unsigned count = points_.length;
+    for (unsigned int i = 0; i < count;)
+    {
+      if (unlikely (p + 1 > end)) return false;
+      uint8_t flag = *p++;
+      points_.arrayZ[i++].flag = flag;
+      if (flag & FLAG_REPEAT)
+      {
+	if (unlikely (p + 1 > end)) return false;
+	unsigned int repeat_count = *p++;
+	unsigned stop = hb_min (i + repeat_count, count);
+	for (; i < stop;)
+	  points_.arrayZ[i++].flag = flag;
+      }
+    }
+    return true;
+  }
+
   static bool read_points (const HBUINT8 *&p /* IN/OUT */,
 			   contour_point_vector_t &points_ /* IN/OUT */,
 			   const HBUINT8 *end,
@@ -124,12 +146,12 @@
 			   const simple_glyph_flag_t short_flag,
 			   const simple_glyph_flag_t same_flag)
   {
-    float v = 0;
+    int v = 0;
 
     unsigned count = points_.length;
     for (unsigned i = 0; i < count; i++)
     {
-      uint8_t flag = points_[i].flag;
+      unsigned flag = points_[i].flag;
       if (flag & short_flag)
       {
 	if (unlikely (p + 1 > end)) return false;
@@ -157,7 +179,9 @@
   {
     const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
     int num_contours = header.numberOfContours;
-    if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours - 1]))) return false;
+    assert (num_contours);
+    /* One extra item at the end, for the instruction-count below. */
+    if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
     unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
 
     points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy
@@ -171,26 +195,13 @@
     const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
 						 endPtsOfContours[num_contours]);
 
+    if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */
     const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length);
+    if (unlikely (p >= end)) return false;
 
-    /* Read flags */
-    for (unsigned int i = 0; i < num_points;)
-    {
-      if (unlikely (p + 1 > end)) return false;
-      uint8_t flag = *p++;
-      points_[i++].flag = flag;
-      if (flag & FLAG_REPEAT)
-      {
-	if (unlikely (p + 1 > end)) return false;
-	unsigned int repeat_count = *p++;
-	unsigned stop = hb_min (i + repeat_count, num_points);
-	for (; i < stop;)
-	  points_.arrayZ[i++].flag = flag;
-      }
-    }
-
     /* Read x & y coordinates */
-    return read_points (p, points_, end, &contour_point_t::x,
+    return read_flags (p, points_, end)
+        && read_points (p, points_, end, &contour_point_t::x,
 			FLAG_X_SHORT, FLAG_X_SAME)
 	&& read_points (p, points_, end, &contour_point_t::y,
 			FLAG_Y_SHORT, FLAG_Y_SAME);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-indic-table.py
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-indic-table.py	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-indic-table.py	2022-06-29 20:49:55 UTC (rev 63761)
@@ -458,7 +458,7 @@
     if block.startswith('Khmer') or block.startswith('Myanmar'):
       cat = position_to_category(pos)
     else:
-      pos = indic_matra_position(u, pos, block)
+      pos = indic_matra_position(k, pos, block)
   elif cat in smvd_categories:
     pos = 'SMVD';
   indic_data[k] = (cat, pos, block)

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -287,7 +287,7 @@
 	       * in the 'kern' table example. */
 	      if (v == -0x8000)
 	      {
-		o.attach_type() = ATTACH_TYPE_NONE;
+		o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
 		o.attach_chain() = 0;
 		o.y_offset = 0;
 	      }
@@ -310,7 +310,7 @@
 	      /* CoreText doesn't do crossStream kerning in vertical.  We do. */
 	      if (v == -0x8000)
 	      {
-		o.attach_type() = ATTACH_TYPE_NONE;
+		o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
 		o.attach_chain() = 0;
 		o.x_offset = 0;
 	      }
@@ -567,7 +567,7 @@
 	  }
 	  break;
 	}
-	o.attach_type() = ATTACH_TYPE_MARK;
+	o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
 	o.attach_chain() = (int) mark - (int) buffer->idx;
 	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
@@ -901,7 +901,7 @@
 	unsigned int count = c->buffer->len;
 	for (unsigned int i = 0; i < count; i++)
 	{
-	  pos[i].attach_type() = ATTACH_TYPE_CURSIVE;
+	  pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
 	  pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
 	  /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
 	   * since there needs to be a non-zero attachment for post-positioning to

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -552,7 +552,7 @@
 #ifdef HB_NO_BUFFER_MESSAGE
    return true;
 #else
-    if (!messaging ())
+    if (likely (!messaging ()))
       return true;
 
     message_depth++;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -379,37 +379,6 @@
   CFRelease ((CTFontRef) data);
 }
 
-static const hb_coretext_font_data_t *
-hb_coretext_font_data_sync (hb_font_t *font)
-{
-retry:
-  const hb_coretext_font_data_t *data = font->data.coretext;
-  if (unlikely (!data)) return nullptr;
-
-  if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5)
-  {
-    /* XXX-MT-bug
-     * Note that evaluating condition above can be dangerous if another thread
-     * got here first and destructed data.  That's, as always, bad use pattern.
-     * If you modify the font (change font size), other threads must not be
-     * using it at the same time.  However, since this check is delayed to
-     * when one actually tries to shape something, this is a XXX race condition
-     * (and the only one we have that I know of) right now.  Ie. you modify the
-     * font size in one thread, then (supposedly safely) try to use it from two
-     * or more threads and BOOM!  I'm not sure how to fix this.  We want RCU.
-     */
-
-    /* Drop and recreate. */
-    /* If someone dropped it in the mean time, throw it away and don't touch it.
-     * Otherwise, destruct it. */
-    if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr)))
-      _hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data));
-    else
-      goto retry;
-  }
-  return font->data.coretext;
-}
-
 /**
  * hb_coretext_font_create:
  * @ct_font: The CTFontRef to work upon
@@ -455,8 +424,8 @@
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
-  const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font);
-  return data ? (CTFontRef) data : nullptr;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+  return ct_font ? (CTFontRef) ct_font : nullptr;
 }
 
 
@@ -516,7 +485,7 @@
 {
   hb_face_t *face = font->face;
   CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
-  CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font);
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -1106,7 +1075,8 @@
 	      advance = positions[j + 1].x - positions[j].x;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].x - positions[0].x);
-	    info->mask = round (advance * x_mult);
+	    /* int cast necessary to pass through negative values. */
+	    info->mask = (int) round (advance * x_mult);
 	    info->var1.i32 = x_offset;
 	    info->var2.i32 = round (positions[j].y * y_mult);
 	    info++;
@@ -1122,7 +1092,8 @@
 	      advance = positions[j + 1].y - positions[j].y;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].y - positions[0].y);
-	    info->mask = round (advance * y_mult);
+	    /* int cast necessary to pass through negative values. */
+	    info->mask = (int) round (advance * y_mult);
 	    info->var1.i32 = round (positions[j].x * x_mult);
 	    info->var2.i32 = y_offset;
 	    info++;
@@ -1173,7 +1144,8 @@
      * This does *not* mean we'll form the same clusters as Uniscribe
      * or the native OT backend, only that the cluster indices will be
      * monotonic in the output buffer. */
-    if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
+    if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
+	buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
     {
       hb_glyph_info_t *info = buffer->info;
       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
@@ -1197,6 +1169,10 @@
     }
   }
 
+  /* TODO: Sometimes the above positioning code generates negative
+   * advance values. Fix them up. Example, with NotoNastaliqUrdu
+   * font and sequence ابهد. */
+
   buffer->clear_glyph_flags ();
   buffer->unsafe_to_break ();
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -241,17 +241,12 @@
 hb_directwrite_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
-  hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
-  if (unlikely (!data))
-    return nullptr;
-
-  return data;
+  return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
 {
-  delete data;
 }
 
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -1737,6 +1737,8 @@
   font->coords = coords;
   font->design_coords = design_coords;
   font->num_coords = coords_length;
+
+  font->mults_changed (); // Easiest to call this to drop cached data
 }
 
 /**
@@ -1766,7 +1768,6 @@
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
   font->slant = parent->slant;
-  font->mults_changed ();
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
@@ -1789,6 +1790,8 @@
     }
   }
 
+  font->mults_changed ();
+
   return font;
 }
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-font.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -639,6 +639,8 @@
     bool y_neg = y_scale < 0;
     y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
     slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
+
+    data.fini ();
   }
 
   hb_position_t em_mult (int16_t v, int64_t mult)

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-machinery.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -176,7 +176,7 @@
 
   void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
   void init ()  { instance.set_relaxed (nullptr); }
-  void fini ()  { do_destroy (instance.get ()); }
+  void fini ()  { do_destroy (instance.get ()); init (); }
 
   void free_instance ()
   {

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -34,6 +34,8 @@
  * hb_hashmap_t
  */
 
+extern HB_INTERNAL const hb_codepoint_t minus_1;
+
 template <typename K, typename V,
 	  bool minus_one = false>
 struct hb_hashmap_t
@@ -77,10 +79,14 @@
 
     template <bool v = minus_one,
 	      hb_enable_if (v == false)>
-    static const V& default_value () { return Null(V); };
+    static inline const V& default_value () { return Null(V); };
     template <bool v = minus_one,
 	      hb_enable_if (v == true)>
-    static const V& default_value () { static const V minus_1 = -1; return minus_1; };
+    static inline const V& default_value ()
+    {
+      static_assert (hb_is_same (V, hb_codepoint_t), "");
+      return minus_1;
+    };
 
     void clear ()
     {
@@ -211,7 +217,7 @@
   void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
 
   /* Has interface. */
-  typedef V value_t;
+  typedef const V& value_t;
   value_t operator [] (K k) const { return get (k); }
   bool has (K key, const V **vp = nullptr) const
   {

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -29,3092 +29,14 @@
 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
 #define HB_OT_LAYOUT_GPOS_TABLE_HH
 
-#include "hb-ot-layout-gsubgpos.hh"
+#include "OT/Layout/GPOS.hh"
 
-
 namespace OT {
 
-struct MarkArray;
-static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
-						 const MarkArray &mark_array,
-						 const hb_set_t  &glyphset,
-						 hb_map_t*        klass_mapping /* INOUT */);
+using Layout::GPOS_impl::PosLookup;
 
-/* buffer **position** var allocations */
-#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
-#define attach_type() var.u8[2] /* attachment type */
-/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
-
-enum attach_type_t {
-  ATTACH_TYPE_NONE	= 0X00,
-
-  /* Each attachment should be either a mark or a cursive; can't be both. */
-  ATTACH_TYPE_MARK	= 0X01,
-  ATTACH_TYPE_CURSIVE	= 0X02,
-};
-
-
-/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
-
-typedef HBUINT16 Value;
-
-typedef UnsizedArrayOf<Value> ValueRecord;
-
-struct ValueFormat : HBUINT16
-{
-  enum Flags {
-    xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
-    yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
-    xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
-    yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
-    xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
-    yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
-    xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
-    yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
-    ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
-    reserved	= 0xF000u,	/* For future use */
-
-    devices	= 0x00F0u	/* Mask for having any Device table */
-  };
-
-/* All fields are options.  Only those available advance the value pointer. */
-#if 0
-  HBINT16		xPlacement;	/* Horizontal adjustment for
-					 * placement--in design units */
-  HBINT16		yPlacement;	/* Vertical adjustment for
-					 * placement--in design units */
-  HBINT16		xAdvance;	/* Horizontal adjustment for
-					 * advance--in design units (only used
-					 * for horizontal writing) */
-  HBINT16		yAdvance;	/* Vertical adjustment for advance--in
-					 * design units (only used for vertical
-					 * writing) */
-  Offset16To<Device>	xPlaDevice;	/* Offset to Device table for
-					 * horizontal placement--measured from
-					 * beginning of PosTable (may be NULL) */
-  Offset16To<Device>	yPlaDevice;	/* Offset to Device table for vertical
-					 * placement--measured from beginning
-					 * of PosTable (may be NULL) */
-  Offset16To<Device>	xAdvDevice;	/* Offset to Device table for
-					 * horizontal advance--measured from
-					 * beginning of PosTable (may be NULL) */
-  Offset16To<Device>	yAdvDevice;	/* Offset to Device table for vertical
-					 * advance--measured from beginning of
-					 * PosTable (may be NULL) */
-#endif
-
-  IntType& operator = (uint16_t i) { v = i; return *this; }
-
-  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
-  unsigned int get_size () const { return get_len () * Value::static_size; }
-
-  bool apply_value (hb_ot_apply_context_t *c,
-		    const void            *base,
-		    const Value           *values,
-		    hb_glyph_position_t   &glyph_pos) const
-  {
-    bool ret = false;
-    unsigned int format = *this;
-    if (!format) return ret;
-
-    hb_font_t *font = c->font;
-    bool horizontal =
-#ifndef HB_NO_VERTICAL
-      HB_DIRECTION_IS_HORIZONTAL (c->direction)
-#else
-      true
-#endif
-      ;
-
-    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
-    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
-    if (format & xAdvance) {
-      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
-      values++;
-    }
-    /* y_advance values grow downward but font-space grows upward, hence negation */
-    if (format & yAdvance) {
-      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
-      values++;
-    }
-
-    if (!has_device ()) return ret;
-
-    bool use_x_device = font->x_ppem || font->num_coords;
-    bool use_y_device = font->y_ppem || font->num_coords;
-
-    if (!use_x_device && !use_y_device) return ret;
-
-    const VariationStore &store = c->var_store;
-    auto *cache = c->var_store_cache;
-
-    /* pixel -> fractional pixel */
-    if (format & xPlaDevice) {
-      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
-      values++;
-    }
-    if (format & yPlaDevice) {
-      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
-      values++;
-    }
-    if (format & xAdvDevice) {
-      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
-      values++;
-    }
-    if (format & yAdvDevice) {
-      /* y_advance values grow downward but font-space grows upward, hence negation */
-      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
-      values++;
-    }
-    return ret;
-  }
-
-  unsigned int get_effective_format (const Value *values) const
-  {
-    unsigned int format = *this;
-    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
-      if (format & flag) should_drop (*values++, (Flags) flag, &format);
-    }
-
-    return format;
-  }
-
-  template<typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  unsigned int get_effective_format (Iterator it) const {
-    unsigned int new_format = 0;
-
-    for (const hb_array_t<const Value>& values : it)
-      new_format = new_format | get_effective_format (&values);
-
-    return new_format;
-  }
-
-  void copy_values (hb_serialize_context_t *c,
-                    unsigned int new_format,
-                    const void *base,
-                    const Value *values,
-                    const hb_map_t *layout_variation_idx_map) const
-  {
-    unsigned int format = *this;
-    if (!format) return;
-
-    if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
-    if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
-    if (format & xAdvance)   copy_value (c, new_format, xAdvance, *values++);
-    if (format & yAdvance)   copy_value (c, new_format, yAdvance, *values++);
-
-    if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
-    if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
-  }
-
-  void copy_value (hb_serialize_context_t *c,
-                   unsigned int new_format,
-                   Flags flag,
-                   Value value) const
-  {
-    // Filter by new format.
-    if (!(new_format & flag)) return;
-    c->copy (value);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  const void *base,
-				  const hb_array_t<const Value>& values) const
-  {
-    unsigned format = *this;
-    unsigned i = 0;
-    if (format & xPlacement) i++;
-    if (format & yPlacement) i++;
-    if (format & xAdvance) i++;
-    if (format & yAdvance) i++;
-    if (format & xPlaDevice)
-    {
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::yPlaDevice)
-    {
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::xAdvDevice)
-    {
-
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-
-    if (format & ValueFormat::yAdvDevice)
-    {
-
-      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
-      i++;
-    }
-  }
-
-  private:
-  bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
-  {
-    unsigned int format = *this;
-
-    if (format & xPlacement) values++;
-    if (format & yPlacement) values++;
-    if (format & xAdvance)   values++;
-    if (format & yAdvance)   values++;
-
-    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
-    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
-
-    return true;
-  }
-
-  static inline Offset16To<Device>& get_device (Value* value)
-  {
-    return *static_cast<Offset16To<Device> *> (value);
-  }
-  static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
-  {
-    if (worked) *worked |= bool (*value);
-    return *static_cast<const Offset16To<Device> *> (value);
-  }
-
-  bool copy_device (hb_serialize_context_t *c, const void *base,
-		    const Value *src_value, const hb_map_t *layout_variation_idx_map) const
-  {
-    Value	*dst_value = c->copy (*src_value);
-
-    if (!dst_value) return false;
-    if (*dst_value == 0) return true;
-
-    *dst_value = 0;
-    c->push ();
-    if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
-    {
-      c->add_link (*dst_value, c->pop_pack ());
-      return true;
-    }
-    else
-    {
-      c->pop_discard ();
-      return false;
-    }
-  }
-
-  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
-  {
-    if (worked) *worked |= bool (*value);
-    return *reinterpret_cast<const HBINT16 *> (value);
-  }
-
-  public:
-
-  bool has_device () const
-  {
-    unsigned int format = *this;
-    return (format & devices) != 0;
-  }
-
-  bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
-  }
-
-  bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
-  {
-    TRACE_SANITIZE (this);
-    unsigned int len = get_len ();
-
-    if (!c->check_range (values, count, get_size ())) return_trace (false);
-
-    if (!has_device ()) return_trace (true);
-
-    for (unsigned int i = 0; i < count; i++) {
-      if (!sanitize_value_devices (c, base, values))
-	return_trace (false);
-      values += len;
-    }
-
-    return_trace (true);
-  }
-
-  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
-  bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (!has_device ()) return_trace (true);
-
-    for (unsigned int i = 0; i < count; i++) {
-      if (!sanitize_value_devices (c, base, values))
-	return_trace (false);
-      values += stride;
-    }
-
-    return_trace (true);
-  }
-
- private:
-
-  void should_drop (Value value, Flags flag, unsigned int* format) const
-  {
-    if (value) return;
-    *format = *format & ~flag;
-  }
-
-};
-
-template<typename Iterator, typename SrcLookup>
-static void SinglePos_serialize (hb_serialize_context_t *c,
-				 const SrcLookup *src,
-				 Iterator it,
-				 const hb_map_t *layout_variation_idx_map);
-
-
-struct AnchorFormat1
-{
-  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
-		   float *x, float *y) const
-  {
-    hb_font_t *font = c->font;
-    *x = font->em_fscale_x (xCoordinate);
-    *y = font->em_fscale_y (yCoordinate);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  AnchorFormat1* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
-    if (!out) return_trace (out);
-    out->format = 1;
-    return_trace (out);
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  FWORD		xCoordinate;		/* Horizontal value--in design units */
-  FWORD		yCoordinate;		/* Vertical value--in design units */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-struct AnchorFormat2
-{
-  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
-		   float *x, float *y) const
-  {
-    hb_font_t *font = c->font;
-
-#ifdef HB_NO_HINTING
-    *x = font->em_fscale_x (xCoordinate);
-    *y = font->em_fscale_y (yCoordinate);
-    return;
-#endif
-
-    unsigned int x_ppem = font->x_ppem;
-    unsigned int y_ppem = font->y_ppem;
-    hb_position_t cx = 0, cy = 0;
-    bool ret;
-
-    ret = (x_ppem || y_ppem) &&
-	  font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
-    *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
-    *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  AnchorFormat2* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (c->embed<AnchorFormat2> (this));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 2 */
-  FWORD		xCoordinate;		/* Horizontal value--in design units */
-  FWORD		yCoordinate;		/* Vertical value--in design units */
-  HBUINT16	anchorPoint;		/* Index to glyph contour point */
-  public:
-  DEFINE_SIZE_STATIC (8);
-};
-
-struct AnchorFormat3
-{
-  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
-		   float *x, float *y) const
-  {
-    hb_font_t *font = c->font;
-    *x = font->em_fscale_x (xCoordinate);
-    *y = font->em_fscale_y (yCoordinate);
-
-    if (font->x_ppem || font->num_coords)
-      *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
-    if (font->y_ppem || font->num_coords)
-      *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
-  }
-
-  AnchorFormat3* copy (hb_serialize_context_t *c,
-		       const hb_map_t *layout_variation_idx_map) const
-  {
-    TRACE_SERIALIZE (this);
-    if (!layout_variation_idx_map) return_trace (nullptr);
-
-    auto *out = c->embed<AnchorFormat3> (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
-    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
-    return_trace (out);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
-    (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 3 */
-  FWORD		xCoordinate;		/* Horizontal value--in design units */
-  FWORD		yCoordinate;		/* Vertical value--in design units */
-  Offset16To<Device>
-		xDeviceTable;		/* Offset to Device table for X
-					 * coordinate-- from beginning of
-					 * Anchor table (may be NULL) */
-  Offset16To<Device>
-		yDeviceTable;		/* Offset to Device table for Y
-					 * coordinate-- from beginning of
-					 * Anchor table (may be NULL) */
-  public:
-  DEFINE_SIZE_STATIC (10);
-};
-
-struct Anchor
-{
-  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
-		   float *x, float *y) const
-  {
-    *x = *y = 0;
-    switch (u.format) {
-    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
-    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
-    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
-    default:					      return;
-    }
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
-    switch (u.format) {
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 3: return_trace (u.format3.sanitize (c));
-    default:return_trace (true);
-    }
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    switch (u.format) {
-    case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
-    case 2:
-      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-      {
-        // AnchorFormat 2 just containins extra hinting information, so
-        // if hints are being dropped convert to format 1.
-        return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
-      }
-      return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
-    case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
-                                                                            c->plan->layout_variation_idx_map))));
-    default:return_trace (false);
-    }
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: case 2:
-      return;
-    case 3:
-      u.format3.collect_variation_indices (c);
-      return;
-    default: return;
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  AnchorFormat1		format1;
-  AnchorFormat2		format2;
-  AnchorFormat3		format3;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (2, format);
-};
-
-
-struct AnchorMatrix
-{
-  const Anchor& get_anchor (unsigned int row, unsigned int col,
-			    unsigned int cols, bool *found) const
-  {
-    *found = false;
-    if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
-    *found = !matrixZ[row * cols + col].is_null ();
-    return this+matrixZ[row * cols + col];
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_iterator (Iterator))>
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  Iterator index_iter) const
-  {
-    for (unsigned i : index_iter)
-      (this+matrixZ[i]).collect_variation_indices (c);
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               unsigned             num_rows,
-               Iterator             index_iter) const
-  {
-    TRACE_SUBSET (this);
-
-    auto *out = c->serializer->start_embed (this);
-
-    if (!index_iter) return_trace (false);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    out->rows = num_rows;
-    for (const unsigned i : index_iter)
-    {
-      auto *offset = c->serializer->embed (matrixZ[i]);
-      if (!offset) return_trace (false);
-      offset->serialize_subset (c, matrixZ[i], this);
-    }
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
-  {
-    TRACE_SANITIZE (this);
-    if (!c->check_struct (this)) return_trace (false);
-    if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
-    unsigned int count = rows * cols;
-    if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
-    for (unsigned int i = 0; i < count; i++)
-      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
-    return_trace (true);
-  }
-
-  HBUINT16	rows;			/* Number of rows */
-  UnsizedArrayOf<Offset16To<Anchor>>
-		matrixZ;		/* Matrix of offsets to Anchor tables--
-					 * from beginning of AnchorMatrix table */
-  public:
-  DEFINE_SIZE_ARRAY (2, matrixZ);
-};
-
-
-struct MarkRecord
-{
-  friend struct MarkArray;
-
-  unsigned get_class () const { return (unsigned) klass; }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
-  }
-
-  MarkRecord *subset (hb_subset_context_t    *c,
-                      const void             *src_base,
-                      const hb_map_t         *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->klass = klass_mapping->get (klass);
-    out->markAnchor.serialize_subset (c, markAnchor, src_base);
-    return_trace (out);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  const void *src_base) const
-  {
-    (src_base+markAnchor).collect_variation_indices (c);
-  }
-
-  protected:
-  HBUINT16	klass;			/* Class defined for this mark */
-  Offset16To<Anchor>
-		markAnchor;		/* Offset to Anchor table--from
-					 * beginning of MarkArray table */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-struct MarkArray : Array16Of<MarkRecord>	/* Array of MarkRecords--in Coverage order */
-{
-  bool apply (hb_ot_apply_context_t *c,
-	      unsigned int mark_index, unsigned int glyph_index,
-	      const AnchorMatrix &anchors, unsigned int class_count,
-	      unsigned int glyph_pos) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
-    unsigned int mark_class = record.klass;
-
-    const Anchor& mark_anchor = this + record.markAnchor;
-    bool found;
-    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
-    /* If this subtable doesn't have an anchor for this base and this class,
-     * return false such that the subsequent subtables have a chance at it. */
-    if (unlikely (!found)) return_trace (false);
-
-    float mark_x, mark_y, base_x, base_y;
-
-    buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
-    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
-    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
-
-    hb_glyph_position_t &o = buffer->cur_pos();
-    o.x_offset = roundf (base_x - mark_x);
-    o.y_offset = roundf (base_y - mark_y);
-    o.attach_type() = ATTACH_TYPE_MARK;
-    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-      hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator		    coverage,
-               const hb_map_t      *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto* out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    auto mark_iter =
-    + hb_zip (coverage, this->iter ())
-    | hb_filter (glyphset, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    unsigned new_length = 0;
-    for (const auto& mark_record : mark_iter) {
-      if (unlikely (!mark_record.subset (c, this, klass_mapping)))
-        return_trace (false);
-      new_length++;
-    }
-
-    if (unlikely (!c->serializer->check_assign (out->len, new_length,
-                                                HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
-      return_trace (false);
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
-  }
-};
-
-
-/* Lookups */
-
-struct SinglePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!valueFormat.has_device ()) return;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (c->glyph_set)
-    ;
-
-    if (!it) return;
-    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  ValueFormat get_value_format () const { return valueFormat; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    valueFormat.apply_value (c, this, values, buffer->cur_pos());
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-		  const SrcLookup *src,
-		  Iterator it,
-		  ValueFormat newFormat,
-		  const hb_map_t *layout_variation_idx_map)
-  {
-    if (unlikely (!c->extend_min (this))) return;
-    if (unlikely (!c->check_assign (valueFormat,
-                                    newFormat,
-                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
-
-    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
-    {
-      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_map);
-      // Only serialize the first entry in the iterator, the rest are assumed to
-      // be the same.
-      break;
-    }
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
-    ;
-
-    bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  coverage.sanitize (c, this) &&
-		  valueFormat.sanitize_value (c, this, values));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of subtable */
-  ValueFormat	valueFormat;		/* Defines the types of data in the
-					 * ValueRecord */
-  ValueRecord	values;			/* Defines positioning
-					 * value(s)--applied to all glyphs in
-					 * the Coverage table */
-  public:
-  DEFINE_SIZE_ARRAY (6, values);
-};
-
-struct SinglePosFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!valueFormat.has_device ()) return;
-
-    auto it =
-    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
-    | hb_filter (c->glyph_set, hb_first)
-    ;
-
-    if (!it) return;
-
-    unsigned sub_length = valueFormat.get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
-
-    for (unsigned i : + it
-		      | hb_map (hb_second))
-      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
-
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  ValueFormat get_value_format () const { return valueFormat; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    if (likely (index >= valueCount)) return_trace (false);
-
-    valueFormat.apply_value (c, this,
-			     &values[index * valueFormat.get_len ()],
-			     buffer->cur_pos());
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-		  const SrcLookup *src,
-		  Iterator it,
-		  ValueFormat newFormat,
-		  const hb_map_t *layout_variation_idx_map)
-  {
-    auto out = c->extend_min (this);
-    if (unlikely (!out)) return;
-    if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
-    if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
-
-    + it
-    | hb_map (hb_second)
-    | hb_apply ([&] (hb_array_t<const Value> _)
-    { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
-    ;
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned sub_length = valueFormat.get_len ();
-    auto values_array = values.as_array (valueCount * sub_length);
-
-    auto it =
-    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
-    | hb_filter (glyphset, hb_first)
-    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
-			      {
-				return hb_pair (glyph_map[_.first],
-						values_array.sub_array (_.second * sub_length,
-									sub_length));
-			      })
-    ;
-
-    bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  coverage.sanitize (c, this) &&
-		  valueFormat.sanitize_values (c, this, values, valueCount));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 2 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of subtable */
-  ValueFormat	valueFormat;		/* Defines the types of data in the
-					 * ValueRecord */
-  HBUINT16	valueCount;		/* Number of ValueRecords */
-  ValueRecord	values;			/* Array of ValueRecords--positioning
-					 * values applied to glyphs */
-  public:
-  DEFINE_SIZE_ARRAY (8, values);
-};
-
-struct SinglePos
-{
-  template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
-  unsigned get_format (Iterator glyph_val_iter_pairs)
-  {
-    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
-
-    for (const auto iter : glyph_val_iter_pairs)
-      for (const auto _ : hb_zip (iter.second, first_val_iter))
-	if (_.first != _.second)
-	  return 2;
-
-    return 1;
-  }
-
-
-  template<typename Iterator,
-      typename SrcLookup,
-      hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_serialize_context_t *c,
-		  const SrcLookup* src,
-		  Iterator glyph_val_iter_pairs,
-		  const hb_map_t *layout_variation_idx_map)
-  {
-    if (unlikely (!c->extend_min (u.format))) return;
-    unsigned format = 2;
-    ValueFormat new_format = src->get_value_format ();
-
-    if (glyph_val_iter_pairs)
-    {
-      format = get_format (glyph_val_iter_pairs);
-      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
-    }
-
-    u.format = format;
-    switch (u.format) {
-    case 1: u.format1.serialize (c,
-                                 src,
-                                 glyph_val_iter_pairs,
-                                 new_format,
-                                 layout_variation_idx_map);
-      return;
-    case 2: u.format2.serialize (c,
-                                 src,
-                                 glyph_val_iter_pairs,
-                                 new_format,
-                                 layout_variation_idx_map);
-      return;
-    default:return;
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  SinglePosFormat1	format1;
-  SinglePosFormat2	format2;
-  } u;
-};
-
-template<typename Iterator, typename SrcLookup>
-static void
-SinglePos_serialize (hb_serialize_context_t *c,
-		     const SrcLookup *src,
-		     Iterator it,
-		     const hb_map_t *layout_variation_idx_map)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
-
-
-struct PairValueRecord
-{
-  friend struct PairSet;
-
-  int cmp (hb_codepoint_t k) const
-  { return secondGlyph.cmp (k); }
-
-  struct context_t
-  {
-    const void 		*base;
-    const ValueFormat	*valueFormats;
-    const ValueFormat	*newFormats;
-    unsigned		len1; /* valueFormats[0].get_len() */
-    const hb_map_t 	*glyph_map;
-    const hb_map_t      *layout_variation_idx_map;
-  };
-
-  bool subset (hb_subset_context_t *c,
-               context_t *closure) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *s = c->serializer;
-    auto *out = s->start_embed (*this);
-    if (unlikely (!s->extend_min (out))) return_trace (false);
-
-    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
-
-    closure->valueFormats[0].copy_values (s,
-                                          closure->newFormats[0],
-                                          closure->base, &values[0],
-                                          closure->layout_variation_idx_map);
-    closure->valueFormats[1].copy_values (s,
-                                          closure->newFormats[1],
-                                          closure->base,
-                                          &values[closure->len1],
-                                          closure->layout_variation_idx_map);
-
-    return_trace (true);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  const ValueFormat *valueFormats,
-				  const void *base) const
-  {
-    unsigned record1_len = valueFormats[0].get_len ();
-    unsigned record2_len = valueFormats[1].get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
-
-    if (valueFormats[0].has_device ())
-      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
-
-    if (valueFormats[1].has_device ())
-      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
-  }
-
-  bool intersects (const hb_set_t& glyphset) const
-  {
-    return glyphset.has(secondGlyph);
-  }
-
-  const Value* get_values_1 () const
-  {
-    return &values[0];
-  }
-
-  const Value* get_values_2 (ValueFormat format1) const
-  {
-    return &values[format1.get_len ()];
-  }
-
-  protected:
-  HBGlyphID16	secondGlyph;		/* GlyphID of second glyph in the
-					 * pair--first glyph is listed in the
-					 * Coverage table */
-  ValueRecord	values;			/* Positioning data for the first glyph
-					 * followed by for second glyph */
-  public:
-  DEFINE_SIZE_ARRAY (2, values);
-};
-
-struct PairSet
-{
-  friend struct PairPosFormat1;
-
-  bool intersects (const hb_set_t *glyphs,
-		   const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (glyphs->has (record->secondGlyph))
-	return true;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-    return false;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c,
-		       const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    c->input->add_array (&record->secondGlyph, len, record_size);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  const ValueFormat *valueFormats) const
-  {
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (c->glyph_set->has (record->secondGlyph))
-      { record->collect_variation_indices (c, valueFormats, this); }
-
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-  }
-
-  bool apply (hb_ot_apply_context_t *c,
-	      const ValueFormat *valueFormats,
-	      unsigned int pos) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
-						&firstPairValueRecord,
-						len,
-						record_size);
-    if (record)
-    {
-      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
-      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
-      if (applied_first || applied_second)
-	buffer->unsafe_to_break (buffer->idx, pos + 1);
-      if (len2)
-	pos++;
-      buffer->idx = pos;
-      return_trace (true);
-    }
-    buffer->unsafe_to_concat (buffer->idx, pos + 1);
-    return_trace (false);
-  }
-
-  bool subset (hb_subset_context_t *c,
-	       const ValueFormat valueFormats[2],
-               const ValueFormat newFormats[2]) const
-  {
-    TRACE_SUBSET (this);
-    auto snap = c->serializer->snapshot ();
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->len = 0;
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    PairValueRecord::context_t context =
-    {
-      this,
-      valueFormats,
-      newFormats,
-      len1,
-      &glyph_map,
-      c->plan->layout_variation_idx_map
-    };
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len, num = 0;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (glyphset.has (record->secondGlyph)
-	 && record->subset (c, &context)) num++;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-
-    out->len = num;
-    if (!num) c->serializer->revert (snap);
-    return_trace (num);
-  }
-
-  struct sanitize_closure_t
-  {
-    const ValueFormat *valueFormats;
-    unsigned int len1; /* valueFormats[0].get_len() */
-    unsigned int stride; /* 1 + len1 + len2 */
-  };
-
-  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && c->check_range (&firstPairValueRecord,
-			  len,
-			  HBUINT16::static_size,
-			  closure->stride))) return_trace (false);
-
-    unsigned int count = len;
-    const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
-		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
-  }
-
-  protected:
-  HBUINT16		len;	/* Number of PairValueRecords */
-  PairValueRecord	firstPairValueRecord;
-				/* Array of PairValueRecords--ordered
-				 * by GlyphID of the second glyph */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct PairPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (*glyphs, hb_first)
-    | hb_map (hb_second)
-    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
-	      { return (this+_).intersects (glyphs, valueFormat); })
-    | hb_any
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
-
-    auto it =
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    if (!it) return;
-    + it
-    | hb_map (hb_add (this))
-    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned int count = pairSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+pairSet[i]).collect_glyphs (c, valueFormat);
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
-    {
-      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
-      return_trace (false);
-    }
-
-    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-    out->valueFormat[0] = valueFormat[0];
-    out->valueFormat[1] = valueFormat[1];
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-    {
-      hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
-      out->valueFormat[0] = newFormats.first;
-      out->valueFormat[1] = newFormats.second;
-    }
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-
-    + hb_zip (this+coverage, pairSet)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
-		 {
-                   auto snap = c->serializer->snapshot ();
-		   auto *o = out->pairSet.serialize_append (c->serializer);
-		   if (unlikely (!o)) return false;
-		   bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
-		   if (!ret)
-		   {
-		     out->pairSet.pop ();
-		     c->serializer->revert (snap);
-		   }
-		   return ret;
-		 },
-		 hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-
-    return_trace (bool (new_coverage));
-  }
-
-
-  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
-  {
-    unsigned len1 = valueFormat[0].get_len ();
-    unsigned len2 = valueFormat[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    unsigned format1 = 0;
-    unsigned format2 = 0;
-    for (const Offset16To<PairSet>& _ :
-             + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
-    {
-      const PairSet& set = (this + _);
-      const PairValueRecord *record = &set.firstPairValueRecord;
-
-      for (unsigned i = 0; i < set.len; i++)
-      {
-        if (record->intersects (glyphset))
-        {
-          format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
-          format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
-        }
-        record = &StructAtOffset<const PairValueRecord> (record, record_size);
-      }
-    }
-
-    return hb_pair (format1, format2);
-  }
-
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (!c->check_struct (this)) return_trace (false);
-
-    unsigned int len1 = valueFormat[0].get_len ();
-    unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure =
-    {
-      valueFormat,
-      len1,
-      1 + len1 + len2
-    };
-
-    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of subtable */
-  ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
-					 * ValueRecord1--for the first glyph
-					 * in the pair--may be zero (0) */
-					/* [1] Defines the types of data in
-					 * ValueRecord2--for the second glyph
-					 * in the pair--may be zero (0) */
-  Array16OfOffset16To<PairSet>
-		pairSet;		/* Array of PairSet tables
-					 * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (10, pairSet);
-};
-
-struct PairPosFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+coverage).intersects (glyphs) &&
-	   (this+classDef2).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    if (!intersects (c->glyph_set)) return;
-    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
-
-    hb_set_t klass1_glyphs, klass2_glyphs;
-    if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
-    if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
-
-    hb_set_t class1_set, class2_set;
-    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
-    {
-      if (!klass1_glyphs.has (cp)) class1_set.add (0);
-      else
-      {
-        unsigned klass1 = (this+classDef1).get (cp);
-        class1_set.add (klass1);
-      }
-    }
-
-    class2_set.add (0);
-    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
-    {
-      unsigned klass2 = (this+classDef2).get (cp);
-      class2_set.add (klass2);
-    }
-
-    if (class1_set.is_empty ()
-        || class2_set.is_empty ()
-        || (class2_set.get_population() == 1 && class2_set.has(0)))
-      return;
-
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
-    for (const unsigned class1_idx : class1_set.iter ())
-    {
-      for (const unsigned class2_idx : class2_set.iter ())
-      {
-	unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-	if (valueFormat1.has_device ())
-	  valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
-
-	if (valueFormat2.has_device ())
-	  valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
-      }
-    }
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    unsigned unsafe_to;
-    if (!skippy_iter.next (&unsafe_to))
-    {
-      buffer->unsafe_to_concat (buffer->idx, unsafe_to);
-      return_trace (false);
-    }
-
-    unsigned int len1 = valueFormat1.get_len ();
-    unsigned int len2 = valueFormat2.get_len ();
-    unsigned int record_len = len1 + len2;
-
-    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
-    if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
-    {
-      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
-      return_trace (false);
-    }
-
-    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
-
-    bool applied_first = false, applied_second = false;
-
-
-    /* Isolate simple kerning and apply it half to each side.
-     * Results in better cursor positinoing / underline drawing.
-     *
-     * Disabled, because causes issues... :-(
-     * https://github.com/harfbuzz/harfbuzz/issues/3408
-     * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
-     */
-#ifndef HB_SPLIT_KERN
-    if (0)
-#endif
-    {
-      if (!len2)
-      {
-	const hb_direction_t dir = buffer->props.direction;
-	const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir);
-	const bool backward = HB_DIRECTION_IS_BACKWARD (dir);
-	unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance;
-	if (backward)
-	  mask |= mask >> 2; /* Add eg. xPlacement in RTL. */
-	/* Add Devices. */
-	mask |= mask << 4;
-
-	if (valueFormat1 & ~mask)
-	  goto bail;
-
-	/* Is simple kern. Apply value on an empty position slot,
-	 * then split it between sides. */
-
-	hb_glyph_position_t pos{};
-	if (valueFormat1.apply_value (c, this, v, pos))
-	{
-	  hb_position_t *src  = &pos.x_advance;
-	  hb_position_t *dst1 = &buffer->cur_pos().x_advance;
-	  hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance;
-	  unsigned i = horizontal ? 0 : 1;
-
-	  hb_position_t kern  = src[i];
-	  hb_position_t kern1 = kern >> 1;
-	  hb_position_t kern2 = kern - kern1;
-
-	  if (!backward)
-	  {
-	    dst1[i] += kern1;
-	    dst2[i] += kern2;
-	    dst2[i + 2] += kern2;
-	  }
-	  else
-	  {
-	    dst1[i] += kern1;
-	    dst1[i + 2] += src[i + 2] - kern2;
-	    dst2[i] += kern2;
-	  }
-
-	  applied_first = applied_second = kern != 0;
-	  goto success;
-	}
-	goto boring;
-      }
-    }
-    bail:
-
-
-    applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
-    applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
-
-    success:
-    if (applied_first || applied_second)
-      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
-    else
-    boring:
-      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
-
-
-    buffer->idx = skippy_iter.idx;
-    if (len2)
-      buffer->idx++;
-
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass1_map;
-    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
-    out->class1Count = klass1_map.get_population ();
-
-    hb_map_t klass2_map;
-    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
-    out->class2Count = klass2_map.get_population ();
-
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-
-    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
-    if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-      newFormats = compute_effective_value_formats (klass1_map, klass2_map);
-
-    out->valueFormat1 = newFormats.first;
-    out->valueFormat2 = newFormats.second;
-
-    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
-    {
-      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
-      {
-        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-        valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
-        valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
-      }
-    }
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    out->coverage.serialize_serialize (c->serializer, it);
-    return_trace (out->class1Count && out->class2Count && bool (it));
-  }
-
-
-  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
-                                                                 const hb_map_t& klass2_map) const
-  {
-    unsigned len1 = valueFormat1.get_len ();
-    unsigned len2 = valueFormat2.get_len ();
-
-    unsigned format1 = 0;
-    unsigned format2 = 0;
-
-    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
-    {
-      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
-      {
-        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
-        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
-      }
-    }
-
-    return hb_pair (format1, format2);
-  }
-
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && coverage.sanitize (c, this)
-       && classDef1.sanitize (c, this)
-       && classDef2.sanitize (c, this))) return_trace (false);
-
-    unsigned int len1 = valueFormat1.get_len ();
-    unsigned int len2 = valueFormat2.get_len ();
-    unsigned int stride = len1 + len2;
-    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
-    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
-    return_trace (c->check_range ((const void *) values,
-				  count,
-				  record_size) &&
-		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
-		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 2 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of subtable */
-  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
-					 * first glyph of the pair--may be zero
-					 * (0) */
-  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
-					 * second glyph of the pair--may be
-					 * zero (0) */
-  Offset16To<ClassDef>
-		classDef1;		/* Offset to ClassDef table--from
-					 * beginning of PairPos subtable--for
-					 * the first glyph of the pair */
-  Offset16To<ClassDef>
-		classDef2;		/* Offset to ClassDef table--from
-					 * beginning of PairPos subtable--for
-					 * the second glyph of the pair */
-  HBUINT16	class1Count;		/* Number of classes in ClassDef1
-					 * table--includes Class0 */
-  HBUINT16	class2Count;		/* Number of classes in ClassDef2
-					 * table--includes Class0 */
-  ValueRecord	values;			/* Matrix of value pairs:
-					 * class1-major, class2-minor,
-					 * Each entry has value1 and value2 */
-  public:
-  DEFINE_SIZE_ARRAY (16, values);
-};
-
-struct PairPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  PairPosFormat1	format1;
-  PairPosFormat2	format2;
-  } u;
-};
-
-
-struct EntryExitRecord
-{
-  friend struct CursivePosFormat1;
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-				  const void *src_base) const
-  {
-    (src_base+entryAnchor).collect_variation_indices (c);
-    (src_base+exitAnchor).collect_variation_indices (c);
-  }
-
-  EntryExitRecord* subset (hb_subset_context_t *c,
-                           const void *src_base) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->serializer->embed (this);
-    if (unlikely (!out)) return_trace (nullptr);
-
-    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
-    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
-    return_trace (out);
-  }
-
-  protected:
-  Offset16To<Anchor>
-		entryAnchor;		/* Offset to EntryAnchor table--from
-					 * beginning of CursivePos
-					 * subtable--may be NULL */
-  Offset16To<Anchor>
-		exitAnchor;		/* Offset to ExitAnchor table--from
-					 * beginning of CursivePos
-					 * subtable--may be NULL */
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
-
-struct CursivePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+coverage, entryExitRecord)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
-    if (!this_record.entryAnchor) return_trace (false);
-
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
-    if (!prev_record.exitAnchor)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    unsigned int i = skippy_iter.idx;
-    unsigned int j = buffer->idx;
-
-    buffer->unsafe_to_break (i, j);
-    float entry_x, entry_y, exit_x, exit_y;
-    (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
-    (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
-
-    hb_glyph_position_t *pos = buffer->pos;
-
-    hb_position_t d;
-    /* Main-direction adjustment */
-    switch (c->direction) {
-      case HB_DIRECTION_LTR:
-	pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
-
-	d = roundf (entry_x) + pos[j].x_offset;
-	pos[j].x_advance -= d;
-	pos[j].x_offset  -= d;
-	break;
-      case HB_DIRECTION_RTL:
-	d = roundf (exit_x) + pos[i].x_offset;
-	pos[i].x_advance -= d;
-	pos[i].x_offset  -= d;
-
-	pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
-	break;
-      case HB_DIRECTION_TTB:
-	pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
-
-	d = roundf (entry_y) + pos[j].y_offset;
-	pos[j].y_advance -= d;
-	pos[j].y_offset  -= d;
-	break;
-      case HB_DIRECTION_BTT:
-	d = roundf (exit_y) + pos[i].y_offset;
-	pos[i].y_advance -= d;
-	pos[i].y_offset  -= d;
-
-	pos[j].y_advance  = roundf (entry_y);
-	break;
-      case HB_DIRECTION_INVALID:
-      default:
-	break;
-    }
-
-    /* Cross-direction adjustment */
-
-    /* We attach child to parent (think graph theory and rooted trees whereas
-     * the root stays on baseline and each node aligns itself against its
-     * parent.
-     *
-     * Optimize things for the case of RightToLeft, as that's most common in
-     * Arabic. */
-    unsigned int child  = i;
-    unsigned int parent = j;
-    hb_position_t x_offset = entry_x - exit_x;
-    hb_position_t y_offset = entry_y - exit_y;
-    if  (!(c->lookup_props & LookupFlag::RightToLeft))
-    {
-      unsigned int k = child;
-      child = parent;
-      parent = k;
-      x_offset = -x_offset;
-      y_offset = -y_offset;
-    }
-
-    /* If child was already connected to someone else, walk through its old
-     * chain and reverse the link direction, such that the whole tree of its
-     * previous connection now attaches to new parent.  Watch out for case
-     * where new parent is on the path from old chain...
-     */
-    reverse_cursive_minor_offset (pos, child, c->direction, parent);
-
-    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
-    pos[child].attach_chain() = (int) parent - (int) child;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
-    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
-      pos[child].y_offset = y_offset;
-    else
-      pos[child].x_offset = x_offset;
-
-    /* If parent was attached to child, separate them.
-     * https://github.com/harfbuzz/harfbuzz/issues/2469
-     */
-    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
-      pos[parent].attach_chain() = 0;
-
-    buffer->idx++;
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_iterator (Iterator))>
-  void serialize (hb_subset_context_t *c,
-		  Iterator it,
-		  const void *src_base)
-  {
-    if (unlikely (!c->serializer->extend_min ((*this)))) return;
-    this->format = 1;
-    this->entryExitRecord.len = it.len ();
-
-    for (const EntryExitRecord& entry_record : + it
-					       | hb_map (hb_second))
-      entry_record.subset (c, src_base);
-
-    auto glyphs =
-    + it
-    | hb_map_retains_sorting (hb_first)
-    ;
-
-    coverage.serialize_serialize (c->serializer, glyphs);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    auto it =
-    + hb_zip (this+coverage, entryExitRecord)
-    | hb_filter (glyphset, hb_first)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
-			      { return hb_pair (glyph_map[p.first], p.second);})
-    ;
-
-    bool ret = bool (it);
-    out->serialize (c, it, this);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of subtable */
-  Array16Of<EntryExitRecord>
-		entryExitRecord;	/* Array of EntryExit records--in
-					 * Coverage Index order */
-  public:
-  DEFINE_SIZE_ARRAY (6, entryExitRecord);
-};
-
-struct CursivePos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  CursivePosFormat1	format1;
-  } u;
-};
-
-
-typedef AnchorMatrix BaseArray;		/* base-major--
-					 * in order of BaseCoverage Index--,
-					 * mark-minor--
-					 * ordered by class--zero-based. */
-
-static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
-						 const MarkArray &mark_array,
-						 const hb_set_t  &glyphset,
-						 hb_map_t*        klass_mapping /* INOUT */)
-{
-  hb_set_t orig_classes;
-
-  + hb_zip (mark_coverage, mark_array)
-  | hb_filter (glyphset, hb_first)
-  | hb_map (hb_second)
-  | hb_map (&MarkRecord::get_class)
-  | hb_sink (orig_classes)
-  ;
-
-  unsigned idx = 0;
-  for (auto klass : orig_classes.iter ())
-  {
-    if (klass_mapping->has (klass)) continue;
-    klass_mapping->set (klass, idx);
-    idx++;
-  }
-}
-
-struct MarkBasePosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+markCoverage).intersects (glyphs) &&
-	   (this+baseCoverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
-    unsigned basecount = (this+baseArray).rows;
-    auto base_iter =
-    + hb_zip (this+baseCoverage, hb_range (basecount))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    hb_sorted_vector_t<unsigned> base_indexes;
-    for (const unsigned row : base_iter)
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (base_indexes)
-      ;
-    }
-    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+markCoverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
-    /* Now we search backwards for a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    do {
-      unsigned unsafe_from;
-      if (!skippy_iter.prev (&unsafe_from))
-      {
-	buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-	return_trace (false);
-      }
-
-      /* We only want to attach to the first of a MultipleSubst sequence.
-       * https://github.com/harfbuzz/harfbuzz/issues/740
-       * Reject others...
-       * ...but stop if we find a mark in the MultipleSubst sequence:
-       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
-      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
-	  0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
-	  (skippy_iter.idx == 0 ||
-	   _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
-	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
-	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
-	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
-	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
-	   ))
-	break;
-      skippy_iter.reject ();
-    } while (true);
-
-    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
-
-    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
-    if (base_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark_iter =
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + mark_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
-
-    unsigned basecount = (this+baseArray).rows;
-    auto base_iter =
-    + hb_zip (this+baseCoverage, hb_range (basecount))
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    new_coverage.reset ();
-    + base_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    hb_sorted_vector_t<unsigned> base_indexes;
-    for (const unsigned row : + base_iter
-			      | hb_map (hb_second))
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (base_indexes)
-      ;
-    }
-
-    out->baseArray.serialize_subset (c, baseArray, this,
-                                     base_iter.len (),
-                                     base_indexes.iter ());
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  markCoverage.sanitize (c, this) &&
-		  baseCoverage.sanitize (c, this) &&
-		  markArray.sanitize (c, this) &&
-		  baseArray.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		markCoverage;		/* Offset to MarkCoverage table--from
-					 * beginning of MarkBasePos subtable */
-  Offset16To<Coverage>
-		baseCoverage;		/* Offset to BaseCoverage table--from
-					 * beginning of MarkBasePos subtable */
-  HBUINT16	classCount;		/* Number of classes defined for marks */
-  Offset16To<MarkArray>
-		markArray;		/* Offset to MarkArray table--from
-					 * beginning of MarkBasePos subtable */
-  Offset16To<BaseArray>
-		baseArray;		/* Offset to BaseArray table--from
-					 * beginning of MarkBasePos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkBasePos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  MarkBasePosFormat1	format1;
-  } u;
-};
-
-
-typedef AnchorMatrix LigatureAttach;	/* component-major--
-					 * in order of writing direction--,
-					 * mark-minor--
-					 * ordered by class--zero-based. */
-
-/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : List16OfOffset16To<LigatureAttach>
-{
-  template <typename Iterator,
-	    hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator		    coverage,
-	       unsigned		    class_count,
-	       const hb_map_t	   *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    for (const auto _ : + hb_zip (coverage, *this)
-		  | hb_filter (glyphset, hb_first))
-    {
-      auto *matrix = out->serialize_append (c->serializer);
-      if (unlikely (!matrix)) return_trace (false);
-
-      const LigatureAttach& src = (this + _.second);
-      auto indexes =
-          + hb_range (src.rows * class_count)
-          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
-          ;
-      matrix->serialize_subset (c,
-				_.second,
-				this,
-                                src.rows,
-                                indexes);
-    }
-    return_trace (this->len);
-  }
-};
-
-struct MarkLigPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+markCoverage).intersects (glyphs) &&
-	   (this+ligatureCoverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
-
-    unsigned ligcount = (this+ligatureArray).len;
-    auto lig_iter =
-    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    const LigatureArray& lig_array = this+ligatureArray;
-    for (const unsigned i : lig_iter)
-    {
-      hb_sorted_vector_t<unsigned> lig_indexes;
-      unsigned row_count = lig_array[i].rows;
-      for (unsigned row : + hb_range (row_count))
-      {
-	+ hb_range ((unsigned) classCount)
-	| hb_filter (klass_mapping)
-	| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-	| hb_sink (lig_indexes)
-	;
-      }
-
-      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
-    }
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+markCoverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return_trace (false);
-
-    /* Now we search backwards for a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
-
-    unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
-    if (lig_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    const LigatureArray& lig_array = this+ligatureArray;
-    const LigatureAttach& lig_attach = lig_array[lig_index];
-
-    /* Find component to attach to */
-    unsigned int comp_count = lig_attach.rows;
-    if (unlikely (!comp_count))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    /* We must now check whether the ligature ID of the current mark glyph
-     * is identical to the ligature ID of the found ligature.  If yes, we
-     * can directly use the component index.  If not, we attach the mark
-     * glyph to the last component of the ligature. */
-    unsigned int comp_index;
-    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
-    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
-    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
-    if (lig_id && lig_id == mark_id && mark_comp > 0)
-      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
-    else
-      comp_index = comp_count - 1;
-
-    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark_iter =
-    + hb_zip (this+markCoverage, this+markArray)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    auto new_mark_coverage =
-    + mark_iter
-    | hb_map_retains_sorting (hb_first)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
-      return_trace (false);
-
-    out->markArray.serialize_subset (c, markArray, this,
-                                     (this+markCoverage).iter (),
-                                     &klass_mapping);
-
-    auto new_ligature_coverage =
-    + hb_iter (this + ligatureCoverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting (glyph_map)
-    ;
-
-    if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
-      return_trace (false);
-
-    out->ligatureArray.serialize_subset (c, ligatureArray, this,
-                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  markCoverage.sanitize (c, this) &&
-		  ligatureCoverage.sanitize (c, this) &&
-		  markArray.sanitize (c, this) &&
-		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		markCoverage;		/* Offset to Mark Coverage table--from
-					 * beginning of MarkLigPos subtable */
-  Offset16To<Coverage>
-		ligatureCoverage;	/* Offset to Ligature Coverage
-					 * table--from beginning of MarkLigPos
-					 * subtable */
-  HBUINT16	classCount;		/* Number of defined mark classes */
-  Offset16To<MarkArray>
-		markArray;		/* Offset to MarkArray table--from
-					 * beginning of MarkLigPos subtable */
-  Offset16To<LigatureArray>
-		ligatureArray;		/* Offset to LigatureArray table--from
-					 * beginning of MarkLigPos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-
-struct MarkLigPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  MarkLigPosFormat1	format1;
-  } u;
-};
-
-
-typedef AnchorMatrix Mark2Array;	/* mark2-major--
-					 * in order of Mark2Coverage Index--,
-					 * mark1-minor--
-					 * ordered by class--zero-based. */
-
-struct MarkMarkPosFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return (this+mark1Coverage).intersects (glyphs) &&
-	   (this+mark2Coverage).intersects (glyphs);
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    + hb_zip (this+mark1Coverage, this+mark1Array)
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
-    ;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
-
-    unsigned mark2_count = (this+mark2Array).rows;
-    auto mark2_iter =
-    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
-    | hb_filter (c->glyph_set, hb_first)
-    | hb_map (hb_second)
-    ;
-
-    hb_sorted_vector_t<unsigned> mark2_indexes;
-    for (const unsigned row : mark2_iter)
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (mark2_indexes)
-      ;
-    }
-    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
-    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
-  }
-
-  const Coverage &get_coverage () const { return this+mark1Coverage; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
-
-    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    unsigned int j = skippy_iter.idx;
-
-    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
-    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
-    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
-    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
-
-    if (likely (id1 == id2))
-    {
-      if (id1 == 0) /* Marks belonging to the same base. */
-	goto good;
-      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
-	goto good;
-    }
-    else
-    {
-      /* If ligature ids don't match, it may be the case that one of the marks
-       * itself is a ligature.  In which case match. */
-      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
-	goto good;
-    }
-
-    /* Didn't match. */
-    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-    return_trace (false);
-
-    good:
-    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
-    if (mark2_index == NOT_COVERED)
-    {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
-      return_trace (false);
-    }
-
-    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_map_t klass_mapping;
-    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
-
-    if (!klass_mapping.get_population ()) return_trace (false);
-    out->classCount = klass_mapping.get_population ();
-
-    auto mark1_iter =
-    + hb_zip (this+mark1Coverage, this+mark1Array)
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + mark1_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    out->mark1Array.serialize_subset (c, mark1Array, this,
-                                      (this+mark1Coverage).iter (),
-                                      &klass_mapping);
-
-    unsigned mark2count = (this+mark2Array).rows;
-    auto mark2_iter =
-    + hb_zip (this+mark2Coverage, hb_range (mark2count))
-    | hb_filter (glyphset, hb_first)
-    ;
-
-    new_coverage.reset ();
-    + mark2_iter
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-
-    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
-      return_trace (false);
-
-    hb_sorted_vector_t<unsigned> mark2_indexes;
-    for (const unsigned row : + mark2_iter
-			      | hb_map (hb_second))
-    {
-      + hb_range ((unsigned) classCount)
-      | hb_filter (klass_mapping)
-      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
-      | hb_sink (mark2_indexes)
-      ;
-    }
-
-    out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
-
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  mark1Coverage.sanitize (c, this) &&
-		  mark2Coverage.sanitize (c, this) &&
-		  mark1Array.sanitize (c, this) &&
-		  mark2Array.sanitize (c, this, (unsigned int) classCount));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		mark1Coverage;		/* Offset to Combining Mark1 Coverage
-					 * table--from beginning of MarkMarkPos
-					 * subtable */
-  Offset16To<Coverage>
-		mark2Coverage;		/* Offset to Combining Mark2 Coverage
-					 * table--from beginning of MarkMarkPos
-					 * subtable */
-  HBUINT16	classCount;		/* Number of defined mark classes */
-  Offset16To<MarkArray>
-		mark1Array;		/* Offset to Mark1Array table--from
-					 * beginning of MarkMarkPos subtable */
-  Offset16To<Mark2Array>
-		mark2Array;		/* Offset to Mark2Array table--from
-					 * beginning of MarkMarkPos subtable */
-  public:
-  DEFINE_SIZE_STATIC (12);
-};
-
-struct MarkMarkPos
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  MarkMarkPosFormat1	format1;
-  } u;
-};
-
-
-struct ContextPos : Context {};
-
-struct ChainContextPos : ChainContext {};
-
-struct ExtensionPos : Extension<ExtensionPos>
-{
-  typedef struct PosLookupSubTable SubTable;
-};
-
-
-
-/*
- * PosLookup
- */
-
-
-struct PosLookupSubTable
-{
-  friend struct Lookup;
-  friend struct PosLookup;
-
-  enum Type {
-    Single		= 1,
-    Pair		= 2,
-    Cursive		= 3,
-    MarkBase		= 4,
-    MarkLig		= 5,
-    MarkMark		= 6,
-    Context		= 7,
-    ChainContext	= 8,
-    Extension		= 9
-  };
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, lookup_type);
-    switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
-    case Pair:			return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
-    case Cursive:		return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkBase:		return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkLig:		return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
-    case MarkMark:		return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...));
-    case Context:		return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
-    case Extension:		return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
-    default:			return_trace (c->default_return_value ());
-    }
-  }
-
-  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c, lookup_type);
-  }
-
-  protected:
-  union {
-  SinglePos		single;
-  PairPos		pair;
-  CursivePos		cursive;
-  MarkBasePos		markBase;
-  MarkLigPos		markLig;
-  MarkMarkPos		markMark;
-  ContextPos		context;
-  ChainContextPos	chainContext;
-  ExtensionPos		extension;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (0);
-};
-
-
-struct PosLookup : Lookup
-{
-  using SubTable = PosLookupSubTable;
-
-  const SubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<SubTable> (i); }
-
-  bool is_reverse () const
-  {
-    return false;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    return_trace (dispatch (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c);
-  }
-
-  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { return dispatch (c); }
-
-  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
-  {
-    if (c->is_lookup_visited (this_index))
-      return hb_closure_lookups_context_t::default_return_value ();
-
-    c->set_lookup_visited (this_index);
-    if (!intersects (c->glyphs))
-    {
-      c->set_lookup_inactive (this_index);
-      return hb_closure_lookups_context_t::default_return_value ();
-    }
-
-    hb_closure_lookups_context_t::return_t ret = dispatch (c);
-    return ret;
-  }
-
-  template <typename set_t>
-  void collect_coverage (set_t *glyphs) const
-  {
-    hb_collect_coverage_context_t<set_t> c (glyphs);
-    dispatch (&c);
-  }
-
-  template <typename context_t>
-  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
-
-  bool subset (hb_subset_context_t *c) const
-  { return Lookup::subset<SubTable> (c); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return Lookup::sanitize<SubTable> (c); }
-};
-
-/*
- * GPOS -- Glyph Positioning
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
- */
-
-struct GPOS : GSUBGPOS
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
-
-  using Lookup = PosLookup;
-
-  const PosLookup& get_lookup (unsigned int i) const
-  { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
-
-  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
-    return GSUBGPOS::subset<PosLookup> (&l);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<PosLookup> (c); }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-				   hb_face_t *face) const;
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  {
-    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
-    {
-      if (!c->gpos_lookups->has (i)) continue;
-      const PosLookup &l = get_lookup (i);
-      l.dispatch (c);
-    }
-  }
-
-  void closure_lookups (hb_face_t      *face,
-			const hb_set_t *glyphs,
-			hb_set_t       *lookup_indexes /* IN/OUT */) const
-  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
-
-  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
-};
-
-
-static void
-reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
-{
-  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
-  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
-    return;
-
-  pos[i].attach_chain() = 0;
-
-  unsigned int j = (int) i + chain;
-
-  /* Stop if we see new parent in the chain. */
-  if (j == new_parent)
-    return;
-
-  reverse_cursive_minor_offset (pos, j, direction, new_parent);
-
-  if (HB_DIRECTION_IS_HORIZONTAL (direction))
-    pos[j].y_offset = -pos[i].y_offset;
-  else
-    pos[j].x_offset = -pos[i].x_offset;
-
-  pos[j].attach_chain() = -chain;
-  pos[j].attach_type() = type;
-}
-static void
-propagate_attachment_offsets (hb_glyph_position_t *pos,
-			      unsigned int len,
-			      unsigned int i,
-			      hb_direction_t direction,
-			      unsigned nesting_level = HB_MAX_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 & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
-
-  if (type & ATTACH_TYPE_CURSIVE)
-  {
-    if (HB_DIRECTION_IS_HORIZONTAL (direction))
-      pos[i].y_offset += pos[j].y_offset;
-    else
-      pos[i].x_offset += pos[j].x_offset;
-  }
-  else /*if (type & ATTACH_TYPE_MARK)*/
-  {
-    pos[i].x_offset += pos[j].x_offset;
-    pos[i].y_offset += pos[j].y_offset;
-
-    assert (j < i);
-    if (HB_DIRECTION_IS_FORWARD (direction))
-      for (unsigned int k = j; k < i; k++) {
-	pos[i].x_offset -= pos[k].x_advance;
-	pos[i].y_offset -= pos[k].y_advance;
-      }
-    else
-      for (unsigned int k = j + 1; k < i + 1; k++) {
-	pos[i].x_offset += pos[k].x_advance;
-	pos[i].y_offset += pos[k].y_advance;
-      }
-  }
-}
-
-void
-GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
-}
-
-void
-GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-  //_hb_buffer_assert_gsubgpos_vars (buffer);
-}
-
-void
-GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
-{
-  _hb_buffer_assert_gsubgpos_vars (buffer);
-
-  unsigned int len;
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
-  hb_direction_t direction = buffer->props.direction;
-
-  /* Handle attachments */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned i = 0; i < len; i++)
-      propagate_attachment_offsets (pos, len, i, direction);
-
-  if (unlikely (font->slant))
-  {
-    for (unsigned i = 0; i < len; i++)
-      if (unlikely (pos[i].y_offset))
-        pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
-  }
-}
-
-
-struct GPOS_accelerator_t : GPOS::accelerator_t {
-  GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {}
-};
-
-
+// TODO(garretrieger): Move into new layout directory.
 /* Out-of-class implementation for methods recursing */
-
 #ifndef HB_NO_OT_LAYOUT
 template <typename context_t>
 /*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
@@ -3146,7 +68,6 @@
 }
 #endif
 
-
 } /* namespace OT */
 
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -55,6 +55,7 @@
 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
 using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
 
 /**
  * SECTION:hb-ot-layout
@@ -400,7 +401,7 @@
 }
 
 bool
-OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face HB_UNUSED) const
 {
 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -1550,7 +1551,7 @@
 }
 
 /*
- * OT::GPOS
+ * GPOS
  */
 
 
@@ -1581,7 +1582,7 @@
 void
 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_start (font, buffer);
+  GPOS::position_start (font, buffer);
 }
 
 
@@ -1596,7 +1597,7 @@
 void
 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish_advances (font, buffer);
+  GPOS::position_finish_advances (font, buffer);
 }
 
 /**
@@ -1610,7 +1611,7 @@
 void
 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish_offsets (font, buffer);
+  GPOS::position_finish_offsets (font, buffer);
 }
 
 
@@ -1645,7 +1646,7 @@
 			      unsigned int    *range_start,       /* OUT.  May be NULL */
 			      unsigned int    *range_end          /* OUT.  May be NULL */)
 {
-  const OT::GPOS &gpos = *face->table.GPOS->table;
+  const GPOS &gpos = *face->table.GPOS->table;
   const hb_tag_t tag = HB_TAG ('s','i','z','e');
 
   unsigned int num_features = gpos.get_feature_count ();
@@ -1817,7 +1818,7 @@
     table (*face->table.GPOS->table),
     accels (face->table.GPOS->accels) {}
 
-  const OT::GPOS &table;
+  const GPOS &table;
   const OT::hb_ot_layout_lookup_accelerator_t *accels;
 };
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-table.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-table.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shaper-indic-table.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -109,9 +109,9 @@
 #define _POS_T   POS_ABOVE_C     /*  22 chars; ABOVE_C */
 #define _POS_A   POS_AFTER_MAIN  /*   3 chars; AFTER_MAIN */
 #define _POS_AP  POS_AFTER_POST  /*  50 chars; AFTER_POST */
-#define _POS_AS  POS_AFTER_SUB   /*  45 chars; AFTER_SUB */
+#define _POS_AS  POS_AFTER_SUB   /*  51 chars; AFTER_SUB */
 #define _POS_C   POS_BASE_C      /* 833 chars; BASE_C */
-#define _POS_BS  POS_BEFORE_SUB  /*  31 chars; BEFORE_SUB */
+#define _POS_BS  POS_BEFORE_SUB  /*  25 chars; BEFORE_SUB */
 #define _POS_B   POS_BELOW_C     /*  13 chars; BELOW_C */
 #define _POS_X   POS_END         /*  71 chars; END */
 #define _POS_R   POS_POST_C      /*  13 chars; POST_C */
@@ -276,7 +276,7 @@
   /* 0C28 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
   /* 0C30 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
   /* 0C38 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,BS), _(M,BS),
-  /* 0C40 */ _(M,BS), _(M,AS), _(M,AS), _(M,AS), _(M,AS),  _(X,X), _(M,BS), _(M,BS),
+  /* 0C40 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS),  _(X,X), _(M,BS), _(M,BS),
   /* 0C48 */ _(M,BS),  _(X,X), _(M,BS), _(M,BS), _(M,BS),  _(H,T),  _(X,X),  _(X,X),
   /* 0C50 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,BS), _(M,BS),  _(X,X),
   /* 0C58 */  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(C,C),  _(X,X),  _(X,X),
@@ -295,9 +295,9 @@
   /* 0CA8 */  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),  _(C,C),
   /* 0CB0 */  _(R,C),  _(C,C),  _(C,C),  _(C,C),  _(X,X),  _(C,C),  _(C,C),  _(C,C),
   /* 0CB8 */  _(C,C),  _(C,C),  _(X,X),  _(X,X),  _(N,X), _(S,SM), _(M,BS), _(M,BS),
-  /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,BS), _(M,BS),  _(X,X), _(M,BS), _(M,BS),
-  /* 0CC8 */ _(M,BS),  _(X,X), _(M,BS), _(M,BS), _(M,BS),  _(H,T),  _(X,X),  _(X,X),
-  /* 0CD0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,BS), _(M,BS),  _(X,X),
+  /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS),  _(X,X), _(M,BS), _(M,AS),
+  /* 0CC8 */ _(M,AS),  _(X,X), _(M,AS), _(M,AS), _(M,BS),  _(H,T),  _(X,X),  _(X,X),
+  /* 0CD0 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X), _(M,AS), _(M,AS),  _(X,X),
   /* 0CD8 */  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(X,X),  _(C,C),  _(C,C),  _(X,X),
   /* 0CE0 */  _(V,C),  _(V,C), _(M,BS), _(M,BS),  _(X,X),  _(X,X), _(GB,C), _(GB,C),
   /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-var-gvar-table.hh	2022-06-29 20:49:55 UTC (rev 63761)
@@ -221,7 +221,7 @@
       {
 	const HBUINT8 *base = &(var_data+var_data->data);
 	const HBUINT8 *p = base;
-	if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
+	if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
 	data_offset = p - base;
       }
       return true;
@@ -271,7 +271,7 @@
 
   static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
 			     hb_vector_t<unsigned int> &points /* OUT */,
-			     const hb_bytes_t &bytes)
+			     const HBUINT8 *end)
   {
     enum packed_point_flag_t
     {
@@ -279,21 +279,21 @@
       POINT_RUN_COUNT_MASK = 0x7F
     };
 
-    if (unlikely (!bytes.check_range (p))) return false;
+    if (unlikely (p + 1 > end)) return false;
 
     uint16_t count = *p++;
     if (count & POINTS_ARE_WORDS)
     {
-      if (unlikely (!bytes.check_range (p))) return false;
+      if (unlikely (p + 1 > end)) return false;
       count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
     }
-    points.resize (count);
+    if (unlikely (!points.resize (count))) return false;
 
     unsigned int n = 0;
     uint16_t i = 0;
     while (i < count)
     {
-      if (unlikely (!bytes.check_range (p))) return false;
+      if (unlikely (p + 1 > end)) return false;
       uint16_t j;
       uint8_t control = *p++;
       uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
@@ -301,8 +301,7 @@
       {
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
-	    return false;
+	  if (unlikely (p + HBUINT16::static_size > end)) return false;
 	  n += *(const HBUINT16 *)p;
 	  points[i] = n;
 	  p += HBUINT16::static_size;
@@ -312,7 +311,7 @@
       {
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.check_range (p))) return false;
+	  if (unlikely (p + 1 > end)) return false;
 	  n += *p++;
 	  points[i] = n;
 	}
@@ -324,7 +323,7 @@
 
   static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
 			     hb_vector_t<int> &deltas /* IN/OUT */,
-			     const hb_bytes_t &bytes)
+			     const HBUINT8 *end)
   {
     enum packed_delta_flag_t
     {
@@ -337,7 +336,7 @@
     unsigned int count = deltas.length;
     while (i < count)
     {
-      if (unlikely (!bytes.check_range (p))) return false;
+      if (unlikely (p + 1 > end)) return false;
       uint8_t control = *p++;
       unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
       unsigned int j;
@@ -347,8 +346,7 @@
       else if (control & DELTAS_ARE_WORDS)
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
-	    return false;
+	  if (unlikely (p + HBUINT16::static_size > end)) return false;
 	  deltas[i] = *(const HBINT16 *) p;
 	  p += HBUINT16::static_size;
 	}
@@ -355,8 +353,7 @@
       else
 	for (j = 0; j < run_count && i < count; j++, i++)
 	{
-	  if (unlikely (!bytes.check_range (p)))
-	    return false;
+	  if (unlikely (p + 1 > end)) return false;
 	  deltas[i] = *(const HBINT8 *) p++;
 	}
       if (j < run_count)
@@ -518,19 +515,17 @@
     ~accelerator_t () { table.destroy (); }
 
     private:
-    struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
-    struct y_getter { static float get (const contour_point_t &p) { return p.y; } };
 
-    template <typename T>
     static float infer_delta (const hb_array_t<contour_point_t> points,
 			      const hb_array_t<contour_point_t> deltas,
-			      unsigned int target, unsigned int prev, unsigned int next)
+			      unsigned int target, unsigned int prev, unsigned int next,
+			      float contour_point_t::*m)
     {
-      float target_val = T::get (points[target]);
-      float prev_val = T::get (points[prev]);
-      float next_val = T::get (points[next]);
-      float prev_delta = T::get (deltas[prev]);
-      float next_delta = T::get (deltas[next]);
+      float target_val = points[target].*m;
+      float prev_val = points[prev].*m;
+      float next_val = points[next].*m;
+      float prev_delta =  deltas[prev].*m;
+      float next_delta =  deltas[next].*m;
 
       if (prev_val == next_val)
 	return (prev_delta == next_delta) ? prev_delta : 0.f;
@@ -541,7 +536,7 @@
 
       /* linear interpolation */
       float r = (target_val - prev_val) / (next_val - prev_val);
-      return (1.f - r) * prev_delta + r * next_delta;
+      return prev_delta + r * (next_delta - prev_delta);
     }
 
     static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
@@ -565,12 +560,12 @@
 
       /* Save original points for inferred delta calculation */
       contour_point_vector_t orig_points;
-      orig_points.resize (points.length);
+      if (unlikely (!orig_points.resize (points.length))) return false;
       for (unsigned int i = 0; i < orig_points.length; i++)
-	orig_points[i] = points[i];
+	orig_points.arrayZ[i] = points.arrayZ[i];
 
       contour_point_vector_t deltas; /* flag is used to indicate referenced point */
-      deltas.resize (points.length);
+      if (unlikely (!deltas.resize (points.length))) return false;
 
       hb_vector_t<unsigned> end_points;
       for (unsigned i = 0; i < points.length; ++i)
@@ -580,6 +575,10 @@
       auto coords = hb_array (font->coords, font->num_coords);
       unsigned num_coords = table->axisCount;
       hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+
+      hb_vector_t<unsigned int> private_indices;
+      hb_vector_t<int> x_deltas;
+      hb_vector_t<int> y_deltas;
       do
       {
 	float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
@@ -589,24 +588,20 @@
 	if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
 	  return false;
 
-	hb_bytes_t bytes ((const char *) p, length);
-	hb_vector_t<unsigned int> private_indices;
+	const HBUINT8 *end = p + length;
+
 	bool has_private_points = iterator.current_tuple->has_private_points ();
 	if (has_private_points &&
-	    !GlyphVariationData::unpack_points (p, private_indices, bytes))
+	    !GlyphVariationData::unpack_points (p, private_indices, end))
 	  return false;
 	const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
 
 	bool apply_to_all = (indices.length == 0);
 	unsigned int num_deltas = apply_to_all ? points.length : indices.length;
-	hb_vector_t<int> x_deltas;
-	x_deltas.resize (num_deltas);
-	if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
-	  return false;
-	hb_vector_t<int> y_deltas;
-	y_deltas.resize (num_deltas);
-	if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
-	  return false;
+	if (unlikely (!x_deltas.resize (num_deltas))) return false;
+	if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
+	if (unlikely (!y_deltas.resize (num_deltas))) return false;
+	if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
 
 	for (unsigned int i = 0; i < deltas.length; i++)
 	  deltas[i].init ();
@@ -613,9 +608,10 @@
 	for (unsigned int i = 0; i < num_deltas; i++)
 	{
 	  unsigned int pt_index = apply_to_all ? i : indices[i];
-	  deltas[pt_index].flag = 1;	/* this point is referenced, i.e., explicit deltas specified */
-	  deltas[pt_index].x += x_deltas[i] * scalar;
-	  deltas[pt_index].y += y_deltas[i] * scalar;
+	  if (unlikely (pt_index >= deltas.length)) continue;
+	  deltas.arrayZ[pt_index].flag = 1;	/* this point is referenced, i.e., explicit deltas specified */
+	  deltas.arrayZ[pt_index].x += x_deltas.arrayZ[i] * scalar;
+	  deltas.arrayZ[pt_index].y += y_deltas.arrayZ[i] * scalar;
 	}
 
 	/* infer deltas for unreferenced points */
@@ -659,12 +655,12 @@
 	    {
 	      i = next_index (i, start_point, end_point);
 	      if (i == next) break;
-	      deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
-	      deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+	      deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::x);
+	      deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::y);
 	      if (--unref_count == 0) goto no_more_gaps;
 	    }
 	  }
-no_more_gaps:
+	no_more_gaps:
 	  start_point = end_point + 1;
 	}
 
@@ -671,8 +667,8 @@
 	/* apply specified / inferred deltas to points */
 	for (unsigned int i = 0; i < points.length; i++)
 	{
-	  points[i].x += deltas[i].x;
-	  points[i].y += deltas[i].y;
+	  points.arrayZ[i].x += deltas.arrayZ[i].x;
+	  points.arrayZ[i].y += deltas.arrayZ[i].y;
 	}
       } while (iterator.move_to_next ());
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-static.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -53,7 +53,10 @@
 const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
 
 
+/* hb_map_t */
 
+const hb_codepoint_t minus_1 = -1;
+
 /* hb_face_t */
 
 #ifndef HB_NO_BORING_EXPANSION

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -41,8 +41,8 @@
 #include "hb-ot-math-table.hh"
 
 using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
 
-
 typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
 #ifndef HB_NO_SUBSET_CFF
 static inline void
@@ -204,7 +204,7 @@
 				     hb_map_t  *layout_variation_idx_map)
 {
   hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face);
-  hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
+  hb_blob_ptr_t<GPOS> gpos = hb_sanitize_context_t ().reference_table<GPOS> (face);
 
   if (!gdef->has_data ())
   {
@@ -403,7 +403,7 @@
         plan->gsub_langsys);
 
   if (close_over_gpos)
-    _closure_glyphs_lookups_features<OT::GPOS> (
+    _closure_glyphs_lookups_features<GPOS> (
         plan->source,
         plan->_glyphset_gsub,
         plan->layout_features,

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc	2022-06-29 20:49:55 UTC (rev 63761)
@@ -56,6 +56,7 @@
 #include "hb-repacker.hh"
 
 using OT::Layout::GSUB::GSUB;
+using OT::Layout::GPOS;
 
 /**
  * SECTION:hb-subset
@@ -432,7 +433,7 @@
 #ifndef HB_NO_SUBSET_LAYOUT
   case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf);
   case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf);
-  case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan, buf);
+  case HB_OT_TAG_GPOS: return _subset<const GPOS> (plan, buf);
   case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf);
   case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
   case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2022-06-29 20:49:55 UTC (rev 63761)
@@ -123,6 +123,35 @@
   '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/GPOS/AnchorFormat1.hh',
+  'OT/Layout/GPOS/MarkLigPosFormat1.hh',
+  'OT/Layout/GPOS/PairPosFormat1.hh',
+  'OT/Layout/GPOS/ExtensionPos.hh',
+  'OT/Layout/GPOS/ChainContextPos.hh',
+  'OT/Layout/GPOS/Common.hh',
+  'OT/Layout/GPOS/ValueFormat.hh',
+  'OT/Layout/GPOS/AnchorMatrix.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/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/MarkRecord.hh',
+  'OT/Layout/GPOS/AnchorFormat2.hh',
+  'OT/Layout/GPOS/ContextPos.hh',
+  'OT/Layout/GPOS/SinglePosFormat2.hh',
+  'OT/Layout/GPOS/SinglePosFormat1.hh',
   'hb-ot-layout-gsubgpos.hh',
   'hb-ot-layout-jstf-table.hh',
   'hb-ot-layout.cc',

Modified: trunk/Build/source/libs/harfbuzz/version.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/version.ac	2022-06-29 20:13:59 UTC (rev 63760)
+++ trunk/Build/source/libs/harfbuzz/version.ac	2022-06-29 20:49:55 UTC (rev 63761)
@@ -8,4 +8,4 @@
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current harfbuzz version
-m4_define([harfbuzz_version], [4.4.0])
+m4_define([harfbuzz_version], [4.4.1])



More information about the tex-live-commits mailing list.