texlive[60451] Build/source/libs: harfbuzz 2.9.1

commits+kakuto at tug.org commits+kakuto at tug.org
Wed Sep 8 04:37:35 CEST 2021


Revision: 60451
          http://tug.org/svn/texlive?view=revision&revision=60451
Author:   kakuto
Date:     2021-09-08 04:37:35 +0200 (Wed, 08 Sep 2021)
Log Message:
-----------
harfbuzz 2.9.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/INSTALL
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/config.h.in
    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/src/Makefile.sources
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cmap-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-cpal-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table-v2subset.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.h
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h
    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/hb-bit-page.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set-invertible.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh

Modified: trunk/Build/source/libs/README
===================================================================
--- trunk/Build/source/libs/README	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/README	2021-09-08 02:37:35 UTC (rev 60451)
@@ -25,8 +25,8 @@
   http://sourceforge.net/projects/silgraphite/files/graphite2/
   (requires C++11)
 
-harfbuzz 2.9.0 - checked 29aug21
-  https://github.com/harfbuzz/harfbuzz/releases/download/2.9.0/
+harfbuzz 2.9.1 - checked 08sep21
+  https://github.com/harfbuzz/harfbuzz/releases/download/2.9.1/
 
 icu 68.2 - checked 13feb21
   http://download.icu-project.org/files/icu4c/

Modified: trunk/Build/source/libs/harfbuzz/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/ChangeLog	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/ChangeLog	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,3 +1,8 @@
+2021-09-08  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Import harfbuzz-2.9.1.
+	* Makefile.am, version.ac: Adjusted.
+
 2021-08-29  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Import harfbuzz-2.9.0.

Modified: trunk/Build/source/libs/harfbuzz/Makefile.am
===================================================================
--- trunk/Build/source/libs/harfbuzz/Makefile.am	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/Makefile.am	2021-09-08 02:37:35 UTC (rev 60451)
@@ -37,6 +37,9 @@
 	@HARFBUZZ_TREE@/src/hb-algs.hh \
 	@HARFBUZZ_TREE@/src/hb-atomic.hh \
 	@HARFBUZZ_TREE@/src/hb-bimap.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-page.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-set-invertible.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-set.hh \
 	@HARFBUZZ_TREE@/src/hb-blob.hh \
 	@HARFBUZZ_TREE@/src/hb-blob.cc \
 	@HARFBUZZ_TREE@/src/hb-buffer.hh \

Modified: trunk/Build/source/libs/harfbuzz/Makefile.in
===================================================================
--- trunk/Build/source/libs/harfbuzz/Makefile.in	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/Makefile.in	2021-09-08 02:37:35 UTC (rev 60451)
@@ -718,8 +718,11 @@
 libharfbuzz_dependencies = $(GRAPHITE2_DEPEND)
 libharfbuzz_a_SOURCES = @HARFBUZZ_TREE@/src/hb-algs.hh \
 	@HARFBUZZ_TREE@/src/hb-atomic.hh \
-	@HARFBUZZ_TREE@/src/hb-bimap.hh @HARFBUZZ_TREE@/src/hb-blob.hh \
-	@HARFBUZZ_TREE@/src/hb-blob.cc \
+	@HARFBUZZ_TREE@/src/hb-bimap.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-page.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-set-invertible.hh \
+	@HARFBUZZ_TREE@/src/hb-bit-set.hh \
+	@HARFBUZZ_TREE@/src/hb-blob.hh @HARFBUZZ_TREE@/src/hb-blob.cc \
 	@HARFBUZZ_TREE@/src/hb-buffer.hh \
 	@HARFBUZZ_TREE@/src/hb-buffer-serialize.cc \
 	@HARFBUZZ_TREE@/src/hb-buffer.cc \

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,3 +1,8 @@
+2021-09-08  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Imported harfbuzz-2.9.1 source tree from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/2.9.1/
+
 2021-08-29  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Imported harfbuzz-2.9.0 source tree from:

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,5 +1,5 @@
-Changes applied to the harfbuzz-2.9.0/ tree as obtained from:
-	https://github.com/harfbuzz/harfbuzz/releases/download/2.9.0/
+Changes applied to the harfbuzz-2.9.1/ tree as obtained from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/2.9.1/
 
 Removed:
 	COPYING

Modified: trunk/Build/source/libs/harfbuzz/configure
===================================================================
--- trunk/Build/source/libs/harfbuzz/configure	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/configure	2021-09-08 02:37:35 UTC (rev 60451)
@@ -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) 2.9.0.
+# Generated by GNU Autoconf 2.71 for harfbuzz (TeX Live) 2.9.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='2.9.0'
-PACKAGE_STRING='harfbuzz (TeX Live) 2.9.0'
+PACKAGE_VERSION='2.9.1'
+PACKAGE_STRING='harfbuzz (TeX Live) 2.9.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) 2.9.0 to adapt to many kinds of systems.
+\`configure' configures harfbuzz (TeX Live) 2.9.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) 2.9.0:";;
+     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 2.9.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 2.9.0
+harfbuzz (TeX Live) configure 2.9.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 2.9.0, which was
+It was created by harfbuzz (TeX Live) $as_me 2.9.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='2.9.0'
+ VERSION='2.9.1'
 
 
 # Some tools Automake needs.
@@ -5035,8 +5035,8 @@
 
 HB_VERSION_MAJOR=2
 HB_VERSION_MINOR=9
-HB_VERSION_MICRO=0
-HB_VERSION=2.9.0
+HB_VERSION_MICRO=1
+HB_VERSION=2.9.1
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -8818,7 +8818,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 2.9.0, which was
+This file was extended by harfbuzz (TeX Live) $as_me 2.9.1, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8886,7 +8886,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-harfbuzz (TeX Live) config.status 2.9.0
+harfbuzz (TeX Live) config.status 2.9.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	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,3 +1,1120 @@
+commit 505df5abf8032f3a2295ded417dca9bfb14ea7b8
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Tue Sep 7 13:46:08 2021 +0200
+
+    2.9.1
+
+ NEWS                   | 19 +++++++++++++++++++
+ configure.ac           |  2 +-
+ docs/harfbuzz-docs.xml |  1 +
+ meson.build            |  2 +-
+ src/hb-subset-input.cc |  2 +-
+ src/hb-subset.h        |  2 +-
+ src/hb-version.h       |  4 ++--
+ 7 files changed, 26 insertions(+), 6 deletions(-)
+
+commit 6602cbb7062bf92e6824ae6bc0e5d3aad4b85939
+Author: mahanstreamer <84676642+mahanstreamer at users.noreply.github.com>
+Date:   Mon Aug 23 00:13:25 2021 -0400
+
+    dead link
+
+ docs/usermanual-install-harfbuzz.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 916ffe0c8590b4064cd898ac52dd48e3a343b14e
+Author: mahanstreamer <84676642+mahanstreamer at users.noreply.github.com>
+Date:   Mon Aug 23 00:09:19 2021 -0400
+
+    grammer fix
+
+ docs/usermanual-getting-started.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 195c05df9925c7c4a4982a286ef9c416b2cde3af
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Sat Sep 4 03:41:19 2021 +0200
+
+    Revert "[ot-shape-normalize] Move buffer out of hb_ot_shape_normalize_context_t"
+    
+    This reverts commit 8cdbea5580731c2bf66e56bf619c1fbb2978692e.
+    
+    For some reason this is causing several tests to crash locally for me
+    (on macOS), see:
+    https://github.com/harfbuzz/harfbuzz/commit/8cdbea5580731c2bf66e56bf619c1fbb2978692e#commitcomment-55898088
+
+ src/hb-ot-shape-normalize.cc | 32 ++++++++++++++------------------
+ src/hb-ot-shape-normalize.hh |  1 +
+ 2 files changed, 15 insertions(+), 18 deletions(-)
+
+commit f4559d243560a6f780e8975d7d48cd1bc1f3096a
+Author: David Corbett <corbett.dav at northeastern.edu>
+Date:   Thu Sep 2 17:56:17 2021 -0400
+
+    Update hb-ot-tag-table.hh
+
+ src/hb-ot-tag-table.hh | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+commit 9fddbb3e24469a0cd87de8237a1be52f730809d3
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Fri Sep 3 17:56:08 2021 +0200
+
+    [test] Rename test and split into smaller subtests
+
+ test/shape/data/in-house/Makefile.sources          |  2 +-
+ test/shape/data/in-house/meson.build               |  2 +-
+ .../data/in-house/tests/arabic-decomposition.tests |  4 --
+ .../data/in-house/tests/arabic-normalization.tests | 64 ++++++++++++++++++++++
+ 4 files changed, 66 insertions(+), 6 deletions(-)
+
+commit c6bb719e658573a602eeab184e2c23c5bdc4a284
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Fri Sep 3 16:14:02 2021 +0200
+
+    [test] Add tests for Arabic decomposition
+    
+    Test that both NFC and NFD input produces identical results for fonts
+    that used composed fonts internally (Amiri here) and fonts that
+    decompose internally (Noto Nastaliq Urdu here) and that for the former
+    composed forms are used.
+    
+    See https://github.com/harfbuzz/harfbuzz/issues/3179
+
+ test/shape/data/in-house/Makefile.sources               |   1 +
+ .../fonts/3e46c3b84c1370a06594736c7f8acebf810bbb3b.ttf  | Bin 0 -> 44884 bytes
+ .../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf  | Bin 0 -> 17556 bytes
+ test/shape/data/in-house/meson.build                    |   1 +
+ .../data/in-house/tests/arabic-decomposition.tests      |   4 ++++
+ 5 files changed, 6 insertions(+)
+
+commit a9dc4fbeacac23407e90b050d81ec8cddc9f4ff1
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Fri Sep 3 16:20:06 2021 +0200
+
+    [test] Make shape test names match file names
+    
+    No idea why test names are underscorified but it it just makes calling
+    meson test testname harder than it should being not able to copy file
+    name directly.
+
+ test/shape/meson.build | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 2bd911b8b49ac9e7cb0708b7ff5861cc3705e915
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 26 14:32:17 2021 -0700
+
+    [subset] handle cmap4 overflows.
+    
+    If a cmap4 subtable overflows during serialization drop it and the corresponding EncodingRecord. Don't drop the corresponding cmap12 table if it would have otherwise been removed.
+
+ src/hb-ot-cmap-table.hh | 49 +++++++++++++++++++++++++++++++++++++++----------
+ src/hb-serialize.hh     | 15 +++++++++++++--
+ 2 files changed, 52 insertions(+), 12 deletions(-)
+
+commit bf81bbfb3541ea4a39bacdbe0568e9e170b1b0f7
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Sep 2 00:16:22 2021 -0600
+
+    Revert "[arabic] Do not re-compose Unicode sequences"
+    
+    This reverts commit ff34c240b0a60014a219b8af49c1be2d7e08b388.
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3179#issuecomment-911242833
+
+ src/hb-ot-shape-complex-arabic.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ff34c240b0a60014a219b8af49c1be2d7e08b388
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Sep 1 23:55:00 2021 -0600
+
+    [arabic] Do not re-compose Unicode sequences
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3179
+
+ src/hb-ot-shape-complex-arabic.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5fadf4c85e53a9acc9baa126b5588e4f4aeec2ed
+Author: Alba Mendez <me at alba.sh>
+Date:   Wed Sep 1 14:38:01 2021 +0200
+
+    Small docs improvement
+    
+    Mention that the returned strings are always nul terminated for convenience.
+
+ src/hb-ot-name.cc | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 04cf6212d72ceffb164b2aaf7315711d4227445f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 30 18:35:08 2021 -0600
+
+    [util/hb-subset] Fix --version and --help again
+    
+    https://github.com/harfbuzz/harfbuzz/commit/38ad093216d8204df2dce18a112ee43964031357
+
+ util/hb-subset.cc | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+commit 5c4c173b06e28171f5fafd54ae0c5a70f38d8d8a
+Merge: 41b9f2abc de8563658
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 30 16:44:28 2021 -0600
+
+    Merge pull request #3146 from googlefonts/set_api
+    
+    [subset] proposed update to subset set apis.
+
+commit de85636581f3c7c8f8140624b78efd76e3ecfd4b
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Aug 30 14:36:05 2021 -0700
+
+    [subset] s/REPLACE/REPLACEME/
+
+ src/hb-subset.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3844e58e14f6f528c52df06d49c771dd174730b9
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Aug 30 11:16:51 2021 -0700
+
+    [subset] remove helper functions for accessing subset input sets.
+
+ src/hb-subset-input.cc | 24 ++++++++---------
+ src/hb-subset-input.hh | 70 --------------------------------------------------
+ src/hb-subset-plan.cc  | 20 +++++++--------
+ 3 files changed, 22 insertions(+), 92 deletions(-)
+
+commit 41b9f2abcd63589e541da13e295fdb9d2f78a2bb
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 29 10:47:11 2021 -0600
+
+    [set] Add TODO item
+
+ src/hb-bit-set.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 93ac700da612b70fec9efb15ed97855dc15f4582
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 29 10:32:40 2021 -0600
+
+    [set] Add copy-constructor/assignment again
+
+ src/hb-bit-set.hh | 10 +++++-----
+ src/hb-set.hh     |  5 +++++
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+commit b9a176e268a0dde9ed491130fe4fc5869bcca235
+Author: Garret Rieger <grieger at google.com>
+Date:   Sun Aug 29 10:33:12 2021 -0600
+
+    [subset] speedup cmap4 subsetting for large codepoint counts. (#3178)
+    
+    glyphIdArray generation implementation was O(n^2). Refactored to use a hashmap to reduce complexity. After the change subset time for a 22k codepoint subset went from 7s to 0.7s.
+
+ src/hb-ot-cmap-table.hh | 33 ++++++++++++++-------------------
+ 1 file changed, 14 insertions(+), 19 deletions(-)
+
+commit fdce294120bc7d626321d38df46e4c49823310db
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 29 09:44:52 2021 -0600
+
+    [util/hb-subset] Print error and suggest filing github issue if operation fails
+    
+    https://github.com/harfbuzz/harfbuzz/issues/3173#issuecomment-906715780
+
+ util/batch.hh         | 5 ++++-
+ util/shape-options.hh | 4 ++--
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+commit 38ad093216d8204df2dce18a112ee43964031357
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 29 09:44:07 2021 -0600
+
+    [util/hb-subset] Don't ignore errors during face parsing
+    
+    Was ignoring file-not-found errors.
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 57d6bf82519f39717ddb7b7574ac079e3016757f
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Aug 27 10:59:28 2021 -0700
+
+    [subset] in sets union correctly size the pointer array.
+
+ src/hb-subset-input.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 102666dab7ef649fca0fbd3ce043ab2b166d662c
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Aug 27 10:31:37 2021 -0700
+
+    [subset] add test for hb_subset_input_set (...).
+
+ src/hb-subset-input.cc |  1 -
+ test/api/test-subset.c | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+commit 7194c2a2a370a39d8e41539cb7fde9a9ffed80c3
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Aug 27 08:20:58 2021 -0700
+
+    [subset] use anonymous union to hold the input sets instead of a map.
+
+ src/hb-subset-input.cc | 16 ++++-----------
+ src/hb-subset-input.hh | 56 ++++++++++++++++++++++++++++++++++----------------
+ 2 files changed, 42 insertions(+), 30 deletions(-)
+
+commit 05204d758689751350cf9f14518bfd7fc86db608
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 16:51:26 2021 -0700
+
+    [subset] implement hb_subset_input_set (...).
+    
+    Switch to storing the sets keyed by enum internally.
+
+ src/hb-subset-input.cc | 87 ++++++++++++++++++++++++++------------------
+ src/hb-subset-input.hh | 97 ++++++++++++++++++++++++++++++++++++++++++--------
+ src/hb-subset-plan.cc  | 20 +++++------
+ 3 files changed, 145 insertions(+), 59 deletions(-)
+
+commit 50193262f0d8aa1c2d6a2a2e4b68f8d2771157b3
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 15:10:21 2021 -0700
+
+    [subset] reorder set enums.
+
+ src/hb-subset.h | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 3282f540a967670d8ee6ac2d78193f6bfaa8c68c
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 15:06:42 2021 -0700
+
+    [subset] restore legacy set api methods.
+
+ src/hb-subset.h | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+commit 1457c1f0806ce63051cf48c47b9a03741533fc8f
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 15:01:28 2021 -0700
+
+    [subset] set enum name changes.
+
+ src/hb-subset.h | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+commit 1b5e1593010eb7c79c58bb68ea1200ef6c8cb740
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 14:56:55 2021 -0700
+
+    [subset] Remove HB_SUBSET_SETS_COUNT and flags comment.
+
+ src/hb-subset.h | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 4c389fd9e5c09574651c5dca3917857cc2cf910c
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Aug 13 11:14:52 2021 -0700
+
+    [subset] add unicode and glyph set  enums.
+
+ src/hb-subset.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit e3e1ae876646937302593d37ea68e1e650621fcb
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Aug 13 10:53:20 2021 -0700
+
+    [subset] proposed update to subset set apis.
+
+ src/hb-subset.h | 37 ++++++++++++++++++++++++-------------
+ 1 file changed, 24 insertions(+), 13 deletions(-)
+
+commit 1e1438c4fb7ed6fdcfcd8d6ae53eb9ed8d3a8a93
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 26 14:59:29 2021 -0600
+
+    [subset] fix --*-file options in hb-subset. (#3176)
+    
+    The previous change to add -/+ versions of each set type broke all of the --*-file input options since all of the parse functions now default to replacing the set if the + variant is not being used. This fixes the issue by changing parse_file_for to pass '+' as the name to the parsing function. This triggers the append mode.
+
+ util/hb-subset.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9db494f517a217e4bec709762416777b97b4445d
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 26 10:51:38 2021 -0600
+
+    [subset] Update remaining subset input sets to use inversion for all. (#3172)
+    
+    * [subset] Update remaining subset input sets to use inversion for all.
+    
+    * [subset] Update flag help for remaining sets to mention -=.
+
+ src/hb-subset-input.hh | 14 ++++----
+ util/hb-subset.cc      | 95 +++++++++++++++++++++++++++++---------------------
+ 2 files changed, 62 insertions(+), 47 deletions(-)
+
+commit 99356ea5f0b426137e83b68605cb50045bf42708
+Merge: 1620698bd 4b5a81f13
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 25 17:19:06 2021 -0600
+
+    Merge pull request #3150 from harfbuzz/item-context-tests
+    
+    [test] Add tests for item context
+
+commit 1620698bd51d4a21d4cb2ca9ff3d66d10a1a4cd6
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 25 16:25:08 2021 -0600
+
+    [subset-input] Minor format
+
+ src/hb-subset-plan.cc | 32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+commit 18b4aab6526bdfe1cc595709fbd7586c07a5417a
+Merge: e9e6d66cd 75efade7a
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 25 16:21:07 2021 -0600
+
+    Merge pull request #3171 from googlefonts/unicode_glyph_invert
+    
+    [subset] use inverted set for all unicodes.
+
+commit 75efade7a4290413711c00748b38c547021a6f26
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 14:51:21 2021 -0700
+
+    [subset] format --gids and --unicodes help messages better.
+
+ util/hb-subset.cc | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit cd07070e41eb020be0669780be4a8517cfb0e9a6
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 14:42:00 2021 -0700
+
+    [subset] Move plan unicodes and gids population to end of _populate_unicodes...
+
+ src/hb-subset-plan.cc | 49 +++++++++++++++++++++++++------------------------
+ 1 file changed, 25 insertions(+), 24 deletions(-)
+
+commit fa4bf7cf58e9193981c9f4a6da7f15f7ba4332d2
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 14:31:11 2021 -0700
+
+    [subset] use inverted sets for glyph id input.
+    
+    Adds --gids-=, --glyphs-=, --text-=, --unicodes-= options. Use inverted sets to represent all glyphs and/or all unicodes.
+
+ util/hb-subset.cc | 84 +++++++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 63 insertions(+), 21 deletions(-)
+
+commit 4b5a81f13c326e26f740ca61752f95a9d2afe89c
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 25 15:20:54 2021 -0600
+
+    [buffer] Fix hb_buffer_append() pre/post-context logic
+    
+    Part of https://github.com/harfbuzz/harfbuzz/pull/3150
+
+ src/hb-buffer.cc | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+commit 8f4f47df7c42294c06d6bd4f2d0e1b35c4040eb5
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 25 13:34:05 2021 -0700
+
+    [subset] use inverted set for all unicodes.
+    
+    Modify the code that handles input->unicodes to be safe with possibly inverted sets. Also adds --unicodes-= and --unicodes+= flags.
+
+ src/hb-subset-plan.cc | 45 +++++++++++++++++++++++++++------------------
+ util/hb-subset.cc     | 15 ++++++++++++---
+ 2 files changed, 39 insertions(+), 21 deletions(-)
+
+commit e9e6d66cd6bf00124fa3cffdbeece44dcffb1bbd
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 23:22:49 2021 -0600
+
+    [subset] Minor internal parameter rename
+
+ src/hb-subset-plan.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 955f86a034b11827a5d3bfb6e60f7e00a4bf40db
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 11:17:10 2021 -0600
+
+    [test-set] Fix compiler warnings
+
+ test/api/test-set.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 59deb754b3e199ff47e1ce2c22aab1a3486615ba
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Aug 24 17:06:14 2021 -0700
+
+    [subset] rename _collect_subset_layout to _collect_layout_indices.
+    
+    Better describes what the function does.
+
+ src/hb-subset-plan.cc | 31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+commit f2441a4b65288dfc1c17a52bb31d694fb3e3ce08
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Aug 24 15:53:32 2021 -0700
+
+    [subset] Remove retain all layout features flag.
+    
+    Instead use inverted sets to handle requesting all features. Modifies feature collection in subset plan to intersect the set of requested features against the features in the font. This prevents iterating a fully filled feature tag set.
+
+ src/hb-subset-input.cc | 15 ----------
+ src/hb-subset-plan.cc  | 74 +++++++++++++++++++++++++-------------------------
+ src/hb-subset.h        | 11 --------
+ test/api/test-subset.c |  4 +--
+ util/hb-subset.cc      | 12 ++------
+ 5 files changed, 42 insertions(+), 74 deletions(-)
+
+commit f84daccb4f85e6ec86e2608fbe59c1e92ec0d814
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Aug 24 14:20:26 2021 -0700
+
+    [set] include null pool sets in the permutations tested by inverted_operations.
+
+ test/api/test-set.c | 38 +++++++++++++++++++++++++-------------
+ 1 file changed, 25 insertions(+), 13 deletions(-)
+
+commit c90678cbc5856a425e7b6b50a516bc8287569a39
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 11:11:12 2021 -0600
+
+    [set] One more try to fix things
+    
+    That I don't let a "make check -j10" run finish before pushing things
+    out means either that we need to speed up our build / test process,
+    or I need a faster laptop...
+
+ src/hb-bit-set.hh | 1 -
+ 1 file changed, 1 deletion(-)
+
+commit 357976963ec7228d4790d9524142943f5ecf112e
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 10:55:12 2021 -0600
+
+    [set] One more try at fixing clear() on empty set
+
+ src/hb-bit-set.hh | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+commit fb07f8f8761b12dadaa18bb42d09706bb69c56e3
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Aug 23 15:33:57 2021 -0700
+
+    During subset input creation check for set alloc failures and fail if encountered.
+
+ src/hb-subset-input.cc                                      |  12 ++++++++++++
+ ...estcase-minimized-hb-subset-fuzzer-5141317848530944.fuzz | Bin 0 -> 8 bytes
+ 2 files changed, 12 insertions(+)
+
+commit b5177d21473bdabb16bd9bfe8f4512edc776c1c1
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 10:43:37 2021 -0600
+
+    [set] Fix seam exposed by previous commit
+
+ src/hb-bit-set.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit f0de40dd61dd261cda197383d192ca487408a3f7
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 23 23:52:17 2021 -0600
+
+    Whitespace
+
+ src/hb-ot-shape.cc | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 8cdbea5580731c2bf66e56bf619c1fbb2978692e
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 23 23:44:55 2021 -0600
+
+    [ot-shape-normalize] Move buffer out of hb_ot_shape_normalize_context_t
+
+ src/hb-ot-shape-normalize.cc | 32 ++++++++++++++++++--------------
+ src/hb-ot-shape-normalize.hh |  1 -
+ 2 files changed, 18 insertions(+), 15 deletions(-)
+
+commit 10da9fd20de74411f1a463e17628d8a2395e6eaa
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 23 23:32:02 2021 -0600
+
+    [ot-map] Whitespace
+
+ src/hb-ot-map.cc | 25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+commit d3e09bf4654fe5478b6dbf2b26ebab6271317d81
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 24 10:31:49 2021 -0600
+
+    [set] Make all operators null-safe again
+    
+    Changed my mind.
+    
+    Also for hb_map_clear().
+    
+    Part of https://github.com/harfbuzz/harfbuzz/pull/3162
+
+ src/hb-bit-set-invertible.hh | 38 ++++++++++++++++++++++++++++++--------
+ src/hb-map.cc                |  3 ---
+ src/hb-map.hh                |  2 ++
+ src/hb-set.cc                | 28 +++++++---------------------
+ 4 files changed, 39 insertions(+), 32 deletions(-)
+
+commit 33bfe9edd679d61898209281960ec1a8570a11c7
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Mon Aug 16 17:00:57 2021 +0200
+
+    [test] Add tests for item context
+    
+    Test pre-context and post-context in Arabic shaper, as well as
+    interaction of pre-context with BOT flag.
+
+ test/shape/data/in-house/Makefile.sources                |   1 +
+ .../fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf   | Bin 0 -> 2768 bytes
+ .../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf   | Bin 0 -> 4020 bytes
+ test/shape/data/in-house/meson.build                     |   1 +
+ test/shape/data/in-house/tests/item-context.tests        |  11 +++++++++++
+ 5 files changed, 13 insertions(+)
+
+commit 430224b1a06c6eef04de9b6e1ee5aa2cb7a9a403
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Mon Aug 16 15:40:47 2021 +0200
+
+    [buffer] Handle pre/post-context in buffer_append
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/1843
+
+ src/hb-buffer.cc      | 15 +++++++++++++++
+ util/shape-options.hh |  1 -
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+commit 6ca0ffd42e0a5cea2adc9efaedf7fc6fd333f9d1
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Mon Aug 16 14:52:13 2021 +0200
+
+    [util] Add --unicodes-before/after
+    
+    Parallel to --unicodes for --text-before/after. To be used in tests.
+
+ util/text-options.hh | 156 +++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 126 insertions(+), 30 deletions(-)
+
+commit 65c622c6892dcbe44996962a748f13569600d389
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Mon Aug 23 21:23:30 2021 +0200
+
+    Typo
+
+ docs/usermanual-install-harfbuzz.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c76af4973cc9f9b64f829a81bb6107218cf303f6
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Mon Aug 23 20:50:35 2021 +0200
+
+    [doc] We use GitHub for discussion not the mailing list
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3160
+
+ docs/usermanual-install-harfbuzz.xml | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 33c82c7dad41a7dc7ac007b63a5c3e9a45b6faf4
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 22 22:31:39 2021 -0600
+
+    [ot-shape] Fix unused-var error when building without AAT
+    
+    Fixes https://github.com/harfbuzz/harfbuzzjs/issues/45
+
+ src/hb-ot-shape.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 34e0b28faef0f4157a47cc3e2feb7360f82232fd
+Author: Qunxin Liu <qxliu at google.com>
+Date:   Wed Aug 18 20:46:06 2021 -0700
+
+    [subset] make glyph-names option match fonttools behavior
+    
+    Don't encode psNames that are contained in standard glyph names set
+
+ src/hb-ot-post-table-v2subset.hh                   |  24 +++++++++++++++++----
+ test/subset/data/Makefile.am                       |   1 +
+ test/subset/data/Makefile.sources                  |   1 +
+ ...ular.glyph-names.0x0,0x8,0x9,0x1d,0x20,0xb7.ttf | Bin 0 -> 10172 bytes
+ ...tu-Regular.glyph-names.retain-all-codepoint.ttf | Bin 0 -> 281092 bytes
+ test/subset/data/fonts/Ubuntu-Regular.ttf          | Bin 0 -> 351884 bytes
+ test/subset/data/tests/glyph_names.tests           |   9 ++++++++
+ test/subset/meson.build                            |   1 +
+ 8 files changed, 32 insertions(+), 4 deletions(-)
+
+commit 829b0f33531b3c14b2e08331b8cc5b31fed73129
+Merge: 280366ba6 915550ab1
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Aug 20 01:28:15 2021 -0600
+
+    Merge pull request #3154 from harfbuzz/set-invert
+    
+    Resurrect hb_set_invert()
+
+commit 915550ab19659107acea9e70a7bc699a19fe2f44
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 17:48:38 2021 -0700
+
+    [set] remove inverted test TODO.
+
+ test/api/test-set.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+commit c4ed58299761ac2e5452bec890e44fcb7c9f1cc7
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 17:47:41 2021 -0700
+
+    [set] add test for inverted set operations.
+    
+    This test checks all possible set configurations against each operation type.
+
+ test/api/test-set.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 125 insertions(+)
+
+commit 325fd6ddb85a141507f752f37ab650bb56299247
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 15:54:31 2021 -0700
+
+    [set] add tests for inverted set equality.
+
+ test/api/test-set.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 55 insertions(+), 1 deletion(-)
+
+commit 287032af6cf3609bb9ca88cf622d478fc77698e3
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 15:45:28 2021 -0700
+
+    [set] update set test TODO list.
+
+ test/api/test-set.c | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+commit 5c003d80a680ec619f0922318244e7d41ca709ba
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 15:41:12 2021 -0700
+
+    [set] add tests for inverted previous iteration.
+
+ test/api/test-set.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 108 insertions(+)
+
+commit 84c2a30214eed8e9cabc1efa7460c74e0ca4f214
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 16:33:48 2021 -0600
+
+    [bit-set-invertible] Second try fixing previous()
+
+ src/hb-bit-set-invertible.hh | 25 +++++++++++++------------
+ 1 file changed, 13 insertions(+), 12 deletions(-)
+
+commit 8f88747a5e100adc3f722baf573143cbb812ac48
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 16:30:48 2021 -0600
+
+    [bit-set-invertible] Fix previous() iteration
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 3f2cc582f283319a5f98469b993403c6f79f3ef9
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Aug 19 15:00:07 2021 -0700
+
+    [set] add basic and iteration set inverion tests.
+
+ test/api/test-set.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 220 insertions(+)
+
+commit 1d832693e17935e025201905236b9fa34e1f310d
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 16:02:30 2021 -0600
+
+    [set] Protect against immutible null set with invertible addition
+
+ src/hb-map.cc |  2 ++
+ src/hb-set.cc | 22 ++++++++++++++++++++++
+ 2 files changed, 24 insertions(+)
+
+commit 7115af23ebe4a896174d1a246fcfb3b4d0fe6806
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 15:55:21 2021 -0600
+
+    [util] Fix glib deprecation warning re g_memdup()
+
+ util/hb-subset.cc | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit dc800ffd6c0b806b5b0db9d48cd57528d1fae3eb
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 15:35:51 2021 -0600
+
+    [bit-set] Remove TODO items we don't intend to finish
+
+ src/hb-bit-set.hh | 8 --------
+ 1 file changed, 8 deletions(-)
+
+commit 92908c122bb578d502bdaa2fbf7a9a3b41540ae0
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 15:28:26 2021 -0600
+
+    [bit-set-invertible] Remove extra check
+    
+    We don't expect immutable / null set in this code.
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1babe80ed2506b36c22275b4c511296c8d9b4096
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 15:18:32 2021 -0600
+
+    [bit-set-invertible] Fix last remaining corner-case
+
+ src/hb-bit-set-invertible.hh | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+commit e8911d137ca1e367a41143ece02149a62779cdf0
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 14:59:57 2021 -0600
+
+    [bit-set-invertible] Implement a couple other missing corner cases
+    
+    Also, in bit-set, don't compute population in is_equal/is_subset()
+    if we don't have it computed already.
+
+ src/hb-bit-set-invertible.hh |  7 +++----
+ src/hb-bit-set.hh            | 14 +++++++++-----
+ 2 files changed, 12 insertions(+), 9 deletions(-)
+
+commit 2579dc648f940c7c66ac0ef2cc75c7b6754c6892
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 14:48:27 2021 -0600
+
+    [bit-set-invertible] Move code around
+
+ src/hb-bit-set-invertible.hh | 31 +++++++++++++++----------------
+ 1 file changed, 15 insertions(+), 16 deletions(-)
+
+commit 2dfc104236395f224b6834ab52263fbafbe92651
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 14:47:33 2021 -0600
+
+    [bit-set-invertible] Implement is_empty() for inverted case as well
+
+ src/hb-bit-set-invertible.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit ec4812a7d4031c2a579f0d49f526f0a9b418e063
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:32:44 2021 -0600
+
+    [bit-page] Remove unused inverted code
+
+ src/hb-bit-page.hh | 47 +++++++++++++++++------------------------------
+ 1 file changed, 17 insertions(+), 30 deletions(-)
+
+commit 87885e6f02fef1d8289050c1c939d5a5566b5ee2
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:26:25 2021 -0600
+
+    [bit-set-invertible] Fix next/previous() logic
+
+ src/hb-bit-set-invertible.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit ee4e331a6e05ce5e99671a401e986c0fcdd2a691
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:23:22 2021 -0600
+
+    [bit-set] Remove unused get_min(inverted)
+
+ src/hb-bit-set.hh | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+commit eec1a25e7169a2958a4f739d98cca4ae6e38605f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:22:36 2021 -0600
+
+    [bit-set-invertible] Rewrite get_min/max() in terms of next/previous()
+
+ src/hb-bit-set-invertible.hh | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit f09d5ed0f52987f4af39d0a577762d4dda99509c
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:06:10 2021 -0600
+
+    [algs] Remove hb_bitwise_non()
+
+ src/hb-algs.hh | 6 ------
+ 1 file changed, 6 deletions(-)
+
+commit f4fd7baf7ec8ff5954e226f2e7ea2697e84a39dd
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:05:12 2021 -0600
+
+    [bit-set-invertible] Fix subtract() logic
+
+ src/hb-bit-set-invertible.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f317d8e4261e6fef1a7d5682bd62a4562588b322
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 13:01:07 2021 -0600
+
+    [bit-set-invertible] Fix intersect() logic
+
+ src/hb-bit-set-invertible.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b21038d91de7f67bbfec549f618b0238c3ca7735
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 11:24:17 2021 -0600
+
+    [bit-set-invertible] Rewrite next/previous_range() in terms of s.next/previous()
+
+ src/hb-bit-set-invertible.hh | 26 ++++++++------------------
+ 1 file changed, 8 insertions(+), 18 deletions(-)
+
+commit eb98bc1e322c0675de7f7b00e4e1932ec593277d
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 11:19:24 2021 -0600
+
+    [bit-set-invertible] Rewrite next/previous() using s.next/previous_range()
+
+ src/hb-bit-set-invertible.hh | 54 ++++++++++++++++++++++++--------------------
+ 1 file changed, 30 insertions(+), 24 deletions(-)
+
+commit 248ad3bce5b5e7190e174929bf1892f1a2bafb44
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 10:17:51 2021 -0600
+
+    [bit-set-invertible] Implement next/previous
+    
+    This makes invertible set functionality complete.
+
+ src/hb-bit-set-invertible.hh | 48 ++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 44 insertions(+), 4 deletions(-)
+
+commit c27f5b1288e4786c27bd010a1f6b41c29ab37992
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 10:01:24 2021 -0600
+
+    [bit-set-invertible] Plug in next_range()/previous_range()
+
+ src/hb-bit-set-invertible.hh | 34 ++++++++++++++++++++++++++++++----
+ 1 file changed, 30 insertions(+), 4 deletions(-)
+
+commit f6aa37159bf1f4b3a2b83c7e263f4642959af73a
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 01:12:25 2021 -0600
+
+    [bit-set-invertible] Fix process logic for inverted
+    [# On branch set-invert
+
+ src/hb-bit-set-invertible.hh | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+commit 060de189ecdf2327c6583b97f02c33c21889ca15
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 00:58:34 2021 -0600
+
+    [bit-page] Fix sanitizer error
+    
+    This essentially reverts 9449cfeefd7e3b761c8035c45330abd7a5201604
+    
+    Problem was dereferencing pointer at end of array...
+
+ src/hb-bit-page.hh | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit b119b48079ab4bece6bb0cf75c6606d25c49ee5e
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 00:51:24 2021 -0600
+
+    [bit-set-invertible] Add unlikely() around inverted checks
+
+ src/hb-bit-set-invertible.hh | 36 +++++++++++++++++++-----------------
+ 1 file changed, 19 insertions(+), 17 deletions(-)
+
+commit b94f24ec79877d57a17e8e8b9961127d590afa34
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 00:48:00 2021 -0600
+
+    [bit-set-invertible] Implement set algebra
+
+ src/hb-algs.hh               | 32 +++++++++++++++++++-
+ src/hb-bit-set-invertible.hh | 71 +++++++++++++++++++++++++++++++++++++-------
+ src/hb-bit-set.hh            |  2 +-
+ 3 files changed, 93 insertions(+), 12 deletions(-)
+
+commit 6afefe1dc3f7aedc1f355bfa70bfee1a15829ec1
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Thu Aug 19 00:27:03 2021 -0600
+
+    [algs] Remove unnecessary struct tag names
+
+ src/hb-algs.hh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+commit 8aa92ff8f054a1b7b8d06618a6366a44cba8fe87
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 23:01:06 2021 -0600
+
+    [bit-set-invertible] Implement get_min/max
+
+ src/hb-bit-set-invertible.hh |  4 ++--
+ src/hb-bit-set.hh            | 16 +++++++++++++---
+ 2 files changed, 15 insertions(+), 5 deletions(-)
+
+commit 18f50275ed2b66c9316d68138572b84ee713f0cc
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 22:08:06 2021 -0600
+
+    [bit-set] Restructure get_min/max() in prep for adding inverted
+
+ src/hb-bit-set.hh | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+commit 669b97d949173ceb691ece4c71c606f90c2f3e3f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 21:39:04 2021 -0600
+
+    [bit-set-invertible] Implement iterator
+
+ src/hb-bit-set-invertible.hh | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+commit c66894d7c9f7883032fbe92aa33c49cb689b1230
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 21:24:29 2021 -0600
+
+    [bit-set-invertible] Write a subset branch as dagger
+
+ src/hb-bit-set-invertible.hh | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+commit c39d2f7a76807cfa8198eb931ff6c58e6bb7fc67
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 21:20:54 2021 -0600
+
+    [bit-set-invertible] Implement add_array / add_sorted_array / intersects
+
+ src/hb-bit-set-invertible.hh | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit 0efa614c04a237722ca6a63a7b0c481fee11be97
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 21:16:05 2021 -0600
+
+    [bit-set] Add del_array/del_sorted_array()
+
+ src/hb-bit-set.hh | 35 +++++++++++++++++++++++++++++------
+ 1 file changed, 29 insertions(+), 6 deletions(-)
+
+commit 48ad9eef1eb5e5226fcfdb86f3cf5be925456a57
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Aug 18 21:05:21 2021 -0600
+
+    [bit-set] Merge page_for_insert() into page_for()
+
+ src/hb-bit-set.hh | 27 +++++++++++----------------
+ 1 file changed, 11 insertions(+), 16 deletions(-)
+
+commit 280366ba6af14fbcacbc49e6aa1c12d83e531ad1
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 18 15:50:49 2021 -0700
+
+    Add TODO to update NN offsets to allow nulls.
+
+ src/hb-ot-color-cpal-table.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit dc31920bbe3a35c565f89aaeca43e2a5fdb5b606
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Aug 18 14:20:14 2021 -0700
+
+    Don't serialize null offsets in CPAL.
+    
+    Fixes https://oss-fuzz.com/testcase-detail/5443213648330752
+
+ src/hb-ot-color-cpal-table.hh                             |  11 ++++++++---
+ ...z-testcase-minimized-hb-subset-fuzzer-5443213648330752 | Bin 0 -> 567 bytes
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+commit e29f56354a62683bc461d4dfba48de4173ccd538
+Author: Simon Cozens <simon at simon-cozens.org>
+Date:   Wed Aug 18 08:51:41 2021 +0100
+
+    Replace "langstr" with more helpful help.
+
+ util/shape-options.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 7f9173d67f14dd273f6366cfcbf3498e6a8b2f56
+Author: Caleb Maclennan <caleb at alerque.com>
+Date:   Wed Aug 18 14:43:54 2021 +0300
+
+    [ci] Fix workflow so ‘publish-*’ dependencies can run
+    
+    This is a documented but bizarre quirk on Circle CI: in order for a job
+    to run as a dependency of another job that has a filter it must also
+    have at least one filter of its own, even if the filter is a noop.
+    
+    https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag
+
+ .circleci/config.yml | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit a997f8918ea4e748657b4feb60dda84044c50ffd
+Author: Caleb Maclennan <caleb at alerque.com>
+Date:   Wed Aug 18 13:23:19 2021 +0300
+
+    [ci] Bump ghr tool used to post release artifacts to v0.14.0
+    
+    Also make sure we only download it once per CI run, not three times...
+
+ .ci/publish_release_artifact.sh | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 80ff72f39dc833118426521f82f6bf614ef274d5
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Aug 18 13:09:03 2021 +0200
+
+    [doc] Misc fixes
+
+ docs/harfbuzz-docs.xml     | 1 +
+ docs/harfbuzz-sections.txt | 6 +++---
+ src/hb-subset-input.cc     | 6 ++++--
+ 3 files changed, 8 insertions(+), 5 deletions(-)
+
 commit 9aa6f8a93f035dd0a1e3978da495d830049480c8
 Author: Khaled Hosny <khaled at aliftype.com>
 Date:   Wed Aug 18 09:32:04 2021 +0200
@@ -33,6 +1150,75 @@
  NEWS | 20 ++++++++++++++++++++
  1 file changed, 20 insertions(+)
 
+commit f0c3804fa292ef3be41cc8d1cdea8239f00e2295
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 17 15:37:19 2021 -0600
+
+    [set] Add hb_bit_set_invertible_t and resurrect hb_set_invert()
+    
+    Implementation is NOT complete yet.
+
+ docs/harfbuzz-sections.txt   |   2 +-
+ src/Makefile.sources         |   1 +
+ src/hb-bit-set-invertible.hh | 168 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-bit-set.hh            |  15 ++--
+ src/hb-deprecated.h          |   3 -
+ src/hb-set.cc                |   9 +--
+ src/hb-set.h                 |   3 +
+ src/hb-set.hh                |  40 +++++------
+ 8 files changed, 201 insertions(+), 40 deletions(-)
+
+commit b5cdbdc030dc700134f41b67b5a42ab54806a9a3
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Tue Aug 17 10:53:08 2021 -0600
+
+    [set] Turn hb_set_t into instance of template taking implementation t
+
+ src/hb-set.hh | 32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+commit fad452bffb4047b84aad3e2684244ce0385742ff
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 16 20:48:24 2021 -0600
+
+    [set] Move main functionality into hb_bit_set_t
+    
+    To add inversion on top in hb_invertible_set_t and use that as hb_set_t.
+
+ src/Makefile.sources         |   1 +
+ src/hb-bit-set.hh            | 787 +++++++++++++++++++++++++++++++++++++++++++
+ src/hb-ot-layout-gsubgpos.hh |   5 +-
+ src/hb-set.cc                |   2 +-
+ src/hb-set.hh                | 737 ++--------------------------------------
+ 5 files changed, 828 insertions(+), 704 deletions(-)
+
+commit 9cc4da962f53c2a9883742a0d9e9fd24222bd7b4
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 16 20:17:53 2021 -0600
+
+    [object] Remove hb_object_is_inert()
+
+ src/hb-object.hh | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+commit 2d5ef05d67d9a352d620e9d9e781e25717ab3a31
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 16 20:13:58 2021 -0600
+
+    Use !g_object_is_valid() instead of g_object_is_inert()
+
+ src/hb-shape-plan.cc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit f6d6eff6a2f996df3144b9c03326c8efdcbf10bf
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Mon Aug 16 19:41:44 2021 -0600
+
+    [object] Remove unused HB_REFERENCE_COUNT_INIT
+
+ src/hb-object.hh | 2 --
+ 1 file changed, 2 deletions(-)
+
 commit 57d86950c3f913805a5527a54eb735ef9360c8d5
 Author: Khaled Hosny <khaled at aliftype.com>
 Date:   Mon Aug 16 21:54:26 2021 +0200
@@ -42,6 +1228,99 @@
  subprojects/freetype2.wrap | 8 +++-----
  1 file changed, 3 insertions(+), 5 deletions(-)
 
+commit f245dc4db86483be3ede773e0bc8ba68065e2380
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 12:40:36 2021 -0600
+
+    [set] Whitespace
+
+ src/hb-set.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9b390f8c40eb80871778b13de7e987bd0e8bedad
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 12:34:55 2021 -0600
+
+    [set] Move page_t into hb-bit-page.hh
+
+ src/Makefile.sources |   1 +
+ src/hb-bit-page.hh   | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/hb-set.hh        | 190 ++-------------------------------------------
+ src/meson.build      |   1 +
+ 4 files changed, 221 insertions(+), 183 deletions(-)
+
+commit 0c3e02ee2d0b24d7fbed92ab2b51c3e98bbe69e8
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 12:10:13 2021 -0600
+
+    [set] Add "inverted" to page_t::is_empty()
+
+ src/hb-set.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 9bd64fa077ed1133ec96341335c62f91b3f9b9ce
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:42:16 2021 -0600
+
+    [set] Add "inverted" to page_t::next/prev()
+
+ src/hb-set.hh | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+commit c88e7ec935caf31ca7db6b90ab0db514c1b65e45
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:39:31 2021 -0600
+
+    [set] Add page_t::elt_maybe_invert()
+
+ src/hb-set.hh | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit 9449cfeefd7e3b761c8035c45330abd7a5201604
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:35:33 2021 -0600
+
+    [set] Simplify page_t::next/prev()
+
+ src/hb-set.hh | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+commit 4394ee1f1dd355b4e8c4e4ad8f310ed624c64e01
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:28:09 2021 -0600
+
+    [set] Add inverted to page_t::get_min/max()
+
+ src/hb-set.hh | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+commit 0dcd9b15d964c7eee3344525313c15a2ff4a16e4
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:11:10 2021 -0600
+
+    [set] Add page_t::set_range()
+
+ src/hb-set.hh | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit cb273fd17c436ada2b88aaecc585b62eb5203691
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:09:08 2021 -0600
+
+    [set] Add page_t::set()
+
+ src/hb-set.hh | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 32bbf53d9c860c32fb9109a11459ccba6eba7110
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sun Aug 15 11:06:52 2021 -0600
+
+    [set] Minor rewrite one cmp() in term of other
+
+ src/hb-set.hh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
 commit 5b4dbf5af361161194d815fd97d616429f6bf81c
 Merge: cb05c363d d203267e5
 Author: Behdad Esfahbod <behdad at behdad.org>

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/INSTALL
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/INSTALL	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/INSTALL	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,8 +1,8 @@
 Installation Instructions
 *************************
 
-   Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free
-Software Foundation, Inc.
+   Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
+Foundation, Inc.
 
    Copying and distribution of this file, with or without modification,
 are permitted in any medium without royalty provided the copyright
@@ -225,7 +225,7 @@
 
 and if that doesn't work, install pre-built binaries of GCC for HP-UX.
 
-   HP-UX 'make' updates targets which have the same timestamps as their
+   HP-UX 'make' updates targets which have the same time stamps as their
 prerequisites, which makes it generally unusable when shipped generated
 files such as 'configure' are involved.  Use GNU 'make' instead.
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,3 +1,19 @@
+Overview of changes leading to 2.9.1
+Tuesday, September 7, 2021
+====================================
+- Final subset API is in place and if no issues are discovered, it will be the
+  stable subset API of HarfBuzz 3.0.0. Old API is kept to ease transition, but
+  will be removed in 3.0.0.
+- Various fuzzer-found bug fixes.
+- hb_buffer_append() now handles the pre- and post-context which previously
+  were left unchanged in the destination buffer.
+- hb-view / hb-shape now accept following new arguments:
+  o --unicodes: takes a list of hex numbers that represent Unicode
+    codepoints.
+- Undeprecated API:
+  hb_set_invert()
+
+
 Overview of changes leading to 2.9.0
 Wednesday, August 18, 2021
 History Repeats Itself (Afghanistan)
@@ -18,6 +34,7 @@
   --glyphs-file, --unicodes-file, supporting ranges in --unicodes.
 - Various bug fixes.
 
+
 Overview of changes leading to 2.8.2
 Tuesday, July 8, 2021
 ====================================
@@ -34,6 +51,7 @@
 +hb_blob_create_from_file_or_fail()
 +hb_set_copy()
 
+
 Overview of changes leading to 2.8.1
 Tuesday, May 4, 2021
 ====================================
@@ -65,6 +83,7 @@
   tarball.
 - Documentation updates.
 
+
 Overview of changes leading to 2.7.3
 Wednesday, December 23, 2020
 ====================================

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/config.h.in
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/config.h.in	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/config.h.in	2021-09-08 02:37:35 UTC (rev 60451)
@@ -69,6 +69,9 @@
 /* Define to 1 if you have the `isatty' function. */
 #undef HAVE_ISATTY
 
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
 /* Define to 1 if you have the `mmap' function. */
 #undef HAVE_MMAP
 
@@ -87,9 +90,6 @@
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
-/* Define to 1 if you have the <stdio.h> header file. */
-#undef HAVE_STDIO_H
-
 /* Define to 1 if you have the <stdlib.h> header file. */
 #undef HAVE_STDLIB_H
 
@@ -148,11 +148,14 @@
    your system. */
 #undef PTHREAD_CREATE_JOINABLE
 
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
-   required in a freestanding environment). This macro is provided for
-   backward compatibility; new code need not use it. */
+/* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [2.9.0],
+        [2.9.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	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,6 +1,6 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.47.0',
-  version: '2.9.0',
+  version: '2.9.1',
   default_options: [
     'cpp_eh=none',          # Just to support msvc, we are passing -fno-rtti also anyway
     'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/Makefile.sources	2021-09-08 02:37:35 UTC (rev 60451)
@@ -19,6 +19,9 @@
 	hb-array.hh \
 	hb-atomic.hh \
 	hb-bimap.hh \
+	hb-bit-page.hh \
+	hb-bit-set.hh \
+	hb-bit-set-invertible.hh \
 	hb-blob.cc \
 	hb-blob.hh \
 	hb-buffer-serialize.cc \

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-algs.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1159,31 +1159,49 @@
 
 /* Operators. */
 
-struct hb_bitwise_and
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
 }
 HB_FUNCOBJ (hb_bitwise_and);
-struct hb_bitwise_or
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
 }
 HB_FUNCOBJ (hb_bitwise_or);
-struct hb_bitwise_xor
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
 }
 HB_FUNCOBJ (hb_bitwise_xor);
-struct hb_bitwise_sub
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
+}
+HB_FUNCOBJ (hb_bitwise_lt);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
 }
-HB_FUNCOBJ (hb_bitwise_sub);
+HB_FUNCOBJ (hb_bitwise_gt); // aka sub
 struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
+}
+HB_FUNCOBJ (hb_bitwise_le);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
+}
+HB_FUNCOBJ (hb_bitwise_ge);
+struct
 {
   template <typename T> constexpr auto
   operator () (const T &a) const HB_AUTO_RETURN (~a)
@@ -1205,6 +1223,12 @@
 struct
 { HB_PARTIALIZE(2);
   template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
+}
+HB_FUNCOBJ (hb_rsub);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
 }
 HB_FUNCOBJ (hb_mul);

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-page.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BIT_PAGE_HH
+#define HB_BIT_PAGE_HH
+
+#include "hb.hh"
+
+struct hb_bit_page_t
+{
+  void init0 () { v.clear (); }
+  void init1 () { v.clear (0xFF); }
+
+  constexpr unsigned len () const
+  { return ARRAY_LENGTH_CONST (v); }
+
+  bool is_empty () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return false;
+    return true;
+  }
+
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+  void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+  bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
+
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la |= (mask (b) << 1) - mask(a);
+    else
+    {
+      *la |= ~(mask (a) - 1);
+      la++;
+
+      memset (la, 0xff, (char *) lb - (char *) la);
+
+      *lb |= ((mask (b) << 1) - 1);
+    }
+  }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la &= ~((mask (b) << 1) - mask(a));
+    else
+    {
+      *la &= mask (a) - 1;
+      la++;
+
+      memset (la, 0, (char *) lb - (char *) la);
+
+      *lb &= ~((mask (b) << 1) - 1);
+    }
+  }
+  void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
+  { if (v) add_range (a, b); else del_range (a, b); }
+
+  bool is_equal (const hb_bit_page_t &other) const
+  {
+    return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+  }
+  bool is_subset (const hb_bit_page_t &larger_page) const
+  {
+    for (unsigned i = 0; i < len (); i++)
+      if (~larger_page.v[i] & v[i])
+	return false;
+    return true;
+  }
+
+  unsigned int get_population () const
+  {
+    unsigned int pop = 0;
+    for (unsigned int i = 0; i < len (); i++)
+      pop += hb_popcount (v[i]);
+    return pop;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint + 1) & MASK;
+    if (!m)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
+    for (const elt_t *p = &vv; i < len (); p = &v[++i])
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_min (*p);
+	return true;
+      }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint - 1) & MASK;
+    if (m == MASK)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
+    const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
+		       ((elt_t (1) << (j + 1)) - 1) :
+		       (elt_t) -1;
+    const elt_t vv = v[i] & mask;
+    const elt_t *p = &vv;
+    while (true)
+    {
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_max (*p);
+	return true;
+      }
+      if ((int) i <= 0) break;
+      p = &v[--i];
+    }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  hb_codepoint_t get_min () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return i * ELT_BITS + elt_get_min (v[i]);
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    for (int i = len () - 1; i >= 0; i--)
+      if (v[i])
+	return i * ELT_BITS + elt_get_max (v[i]);
+    return 0;
+  }
+
+  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+  typedef unsigned long long elt_t;
+  static constexpr unsigned PAGE_BITS = 512;
+  static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+
+  static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
+  static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
+
+  typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
+
+  static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+  static constexpr unsigned BITS = sizeof (vector_t) * 8;
+  static constexpr unsigned MASK = BITS - 1;
+  static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
+
+  elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
+  const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
+  static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
+
+  vector_t v;
+};
+static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
+
+
+#endif /* HB_BIT_PAGE_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set-invertible.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set-invertible.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set-invertible.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -0,0 +1,354 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BIT_SET_INVERTIBLE_HH
+#define HB_BIT_SET_INVERTIBLE_HH
+
+#include "hb.hh"
+#include "hb-bit-set.hh"
+
+
+struct hb_bit_set_invertible_t
+{
+  hb_bit_set_t s;
+  bool inverted;
+
+  hb_bit_set_invertible_t () { init (); }
+  ~hb_bit_set_invertible_t () { fini (); }
+
+  void init () { s.init (); inverted = false; }
+  void fini () { s.fini (); }
+  void err () { s.err (); }
+  bool in_error () const { return s.in_error (); }
+  explicit operator bool () const { return !is_empty (); }
+
+  void reset ()
+  {
+    s.reset ();
+    inverted = false;
+  }
+  void clear ()
+  {
+    s.clear ();
+    if (likely (s.successful))
+      inverted = false;
+  }
+  void invert ()
+  {
+    if (likely (s.successful))
+      inverted = !inverted;
+  }
+
+  bool is_empty () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v == INVALID;
+  }
+  hb_codepoint_t get_min () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v;
+  }
+  hb_codepoint_t get_max () const
+  {
+    hb_codepoint_t v = INVALID;
+    previous (&v);
+    return v;
+  }
+  unsigned int get_population () const
+  { return inverted ? INVALID - s.get_population () : s.get_population (); }
+
+
+  void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  { return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return inverted ? s.del_sorted_array (array, count, stride) : s.add_sorted_array (array, count, stride); }
+  template <typename T>
+  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+
+  void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  { unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
+
+  bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
+  { add (v); return *this; }
+  hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+
+  void set (const hb_bit_set_invertible_t &other)
+  {
+    s.set (other.s);
+    if (likely (s.successful))
+      inverted = other.inverted;
+  }
+
+  bool is_equal (const hb_bit_set_invertible_t &other) const
+  {
+    if (likely (inverted == other.inverted))
+      return s.is_equal (other.s);
+    else
+    {
+      /* TODO Add iter_ranges() and use here. */
+      auto it1 = iter ();
+      auto it2 = other.iter ();
+      return hb_all (+ hb_zip (it1, it2)
+		     | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
+    }
+  }
+
+  bool is_subset (const hb_bit_set_invertible_t &larger_set) const
+  {
+    if (unlikely (inverted != larger_set.inverted))
+      return hb_all (hb_iter (s) | hb_map (larger_set.s));
+    else
+      return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
+  }
+
+  protected:
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_invertible_t &other)
+  { s.process (op, other.s); }
+  public:
+  void union_ (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_and, other);
+      else
+	process (hb_bitwise_or, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_gt, other);
+      else
+	process (hb_bitwise_lt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted || other.inverted;
+  }
+  void intersect (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && other.inverted;
+  }
+  void subtract (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && !other.inverted;
+  }
+  void symmetric_difference (const hb_bit_set_invertible_t &other)
+  {
+    process (hb_bitwise_xor, other);
+    if (likely (s.successful))
+      inverted = inverted ^ other.inverted;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.next (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old + 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.next (&v);
+    if (old + 1 < v)
+    {
+      *codepoint = old + 1;
+      return true;
+    }
+
+    v = old;
+    s.next_range (&old, &v);
+
+    *codepoint = v + 1;
+    return *codepoint != INVALID;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.previous (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old - 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.previous (&v);
+
+    if (old - 1 > v || v == INVALID)
+    {
+      *codepoint = old - 1;
+      return true;
+    }
+
+    v = old;
+    s.previous_range (&v, &old);
+
+    *codepoint = v - 1;
+    return *codepoint != INVALID;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.next_range (first, last);
+
+    if (!next (last))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *first = *last;
+    s.next (last);
+    --*last;
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.previous_range (first, last);
+
+    if (!previous (first))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *last = *first;
+    s.previous (first);
+    ++*first;
+    return true;
+  }
+
+  static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
+	    bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
+
+    protected:
+    const hb_bit_set_invertible_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+};
+
+
+#endif /* HB_BIT_SET_INVERTIBLE_HH */

Added: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh	                        (rev 0)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-bit-set.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -0,0 +1,808 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BIT_SET_HH
+#define HB_BIT_SET_HH
+
+#include "hb.hh"
+#include "hb-bit-page.hh"
+#include "hb-machinery.hh"
+
+
+struct hb_bit_set_t
+{
+  hb_bit_set_t () { init (); }
+  ~hb_bit_set_t () { fini (); }
+
+  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
+  void operator= (const hb_bit_set_t& other) { set (other); }
+  // TODO Add move construtor/assign
+  // TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
+
+  void init ()
+  {
+    successful = true;
+    population = 0;
+    last_page_lookup = 0;
+    page_map.init ();
+    pages.init ();
+  }
+  void fini ()
+  {
+    page_map.fini ();
+    pages.fini ();
+  }
+
+  using page_t = hb_bit_page_t;
+  struct page_map_t
+  {
+    int cmp (const page_map_t &o) const { return cmp (o.major); }
+    int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
+
+    uint32_t major;
+    uint32_t index;
+  };
+
+  bool successful; /* Allocations successful */
+  mutable unsigned int population;
+  mutable unsigned int last_page_lookup;
+  hb_sorted_vector_t<page_map_t> page_map;
+  hb_vector_t<page_t> pages;
+
+  void err () { if (successful) successful = false; } /* TODO Remove */
+  bool in_error () const { return !successful; }
+
+  bool resize (unsigned int count)
+  {
+    if (unlikely (!successful)) return false;
+    if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+    {
+      pages.resize (page_map.length);
+      successful = false;
+      return false;
+    }
+    return true;
+  }
+
+  void reset ()
+  {
+    successful = true;
+    clear ();
+  }
+
+  void clear ()
+  {
+    resize (0);
+    if (likely (successful))
+      population = 0;
+  }
+  bool is_empty () const
+  {
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      if (!pages[i].is_empty ())
+	return false;
+    return true;
+  }
+  explicit operator bool () const { return !is_empty (); }
+
+  private:
+  void dirty () { population = UINT_MAX; }
+  public:
+
+  void add (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (g == INVALID)) return;
+    dirty ();
+    page_t *page = page_for (g, true); if (unlikely (!page)) return;
+    page->add (g);
+  }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    if (ma == mb)
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, b);
+    }
+    else
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, major_start (ma + 1) - 1);
+
+      for (unsigned int m = ma + 1; m < mb; m++)
+      {
+	page = page_for (major_start (m), true); if (unlikely (!page)) return false;
+	page->init1 ();
+      }
+
+      page = page_for (b, true); if (unlikely (!page)) return false;
+      page->add_range (major_start (mb), b);
+    }
+    return true;
+  }
+
+  template <typename T>
+  void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (!successful)) return;
+    if (!count) return;
+    dirty ();
+    hb_codepoint_t g = *array;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
+      unsigned int start = major_start (m);
+      unsigned int end = major_start (m + 1);
+      do
+      {
+        if (v || page) /* The v check is to optimize out the page check if v is true. */
+	  page->set (g, v);
+
+	array = &StructAtOffsetUnaligned<T> (array, stride);
+	count--;
+      }
+      while (count && (g = *array, start <= g && g < end));
+    }
+  }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (true, array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  template <typename T>
+  void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (false, array, count, stride); }
+  template <typename T>
+  void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (!count) return true;
+    dirty ();
+    hb_codepoint_t g = *array;
+    hb_codepoint_t last_g = g;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
+      unsigned int end = major_start (m + 1);
+      do
+      {
+	/* If we try harder we can change the following comparison to <=;
+	 * Not sure if it's worth it. */
+	if (g < last_g) return false;
+	last_g = g;
+
+        if (v || page) /* The v check is to optimize out the page check if v is true. */
+	  page->add (g);
+
+	array = (const T *) ((const char *) array + stride);
+	count--;
+      }
+      while (count && (g = *array, g < end));
+    }
+    return true;
+  }
+
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (true, array, count, stride); }
+  template <typename T>
+  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+
+  template <typename T>
+  bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (false, array, count, stride); }
+  template <typename T>
+  bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
+
+  void del (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    page_t *page = page_for (g);
+    if (!page)
+      return;
+    dirty ();
+    page->del (g);
+  }
+
+  private:
+  void del_pages (int ds, int de)
+  {
+    if (ds <= de)
+    {
+      // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+      // before attempting to rewrite the page map.
+      hb_vector_t<unsigned> compact_workspace;
+      if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+      unsigned int write_index = 0;
+      for (unsigned int i = 0; i < page_map.length; i++)
+      {
+	int m = (int) page_map[i].major;
+	if (m < ds || de < m)
+	  page_map[write_index++] = page_map[i];
+      }
+      compact (compact_workspace, write_index);
+      resize (write_index);
+    }
+  }
+
+
+  public:
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (a > b || a == INVALID)) return;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    /* Delete pages from ds through de if ds <= de. */
+    int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
+    int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
+    if (ds > de || (int) ma < ds)
+    {
+      page_t *page = page_for (a);
+      if (page)
+      {
+	if (ma == mb)
+	  page->del_range (a, b);
+	else
+	  page->del_range (a, major_start (ma + 1) - 1);
+      }
+    }
+    if (de < (int) mb && ma != mb)
+    {
+      page_t *page = page_for (b);
+      if (page)
+	page->del_range (major_start (mb), b);
+    }
+    del_pages (ds, de);
+  }
+
+  bool get (hb_codepoint_t g) const
+  {
+    const page_t *page = page_for (g);
+    if (!page)
+      return false;
+    return page->get (g);
+  }
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_bit_set_t& operator << (hb_codepoint_t v)
+  { add (v); return *this; }
+  hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+  void set (const hb_bit_set_t &other)
+  {
+    if (unlikely (!successful)) return;
+    unsigned int count = other.pages.length;
+    if (unlikely (!resize (count)))
+      return;
+    population = other.population;
+
+    /* TODO switch to vector operator =. */
+    hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
+    hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
+  }
+
+  bool is_equal (const hb_bit_set_t &other) const
+  {
+    if (has_population () && other.has_population () &&
+	get_population () != other.get_population ())
+      return false;
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_at (a).is_empty ()) { a++; continue; }
+      if (other.page_at (b).is_empty ()) { b++; continue; }
+      if (page_map[a].major != other.page_map[b].major ||
+	  !page_at (a).is_equal (other.page_at (b)))
+	return false;
+      a++;
+      b++;
+    }
+    for (; a < na; a++)
+      if (!page_at (a).is_empty ()) { return false; }
+    for (; b < nb; b++)
+      if (!other.page_at (b).is_empty ()) { return false; }
+
+    return true;
+  }
+
+  bool is_subset (const hb_bit_set_t &larger_set) const
+  {
+    if (has_population () && larger_set.has_population () &&
+	get_population () != larger_set.get_population ())
+      return false;
+
+    uint32_t spi = 0;
+    for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
+    {
+      uint32_t spm = page_map[spi].major;
+      uint32_t lpm = larger_set.page_map[lpi].major;
+      auto sp = page_at (spi);
+      auto lp = larger_set.page_at (lpi);
+
+      if (spm < lpm && !sp.is_empty ())
+        return false;
+
+      if (lpm < spm)
+        continue;
+
+      if (!sp.is_subset (lp))
+        return false;
+
+      spi++;
+    }
+
+    while (spi < page_map.length)
+      if (!page_at (spi++).is_empty ())
+        return false;
+
+    return true;
+  }
+
+  private:
+  bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
+  {
+    if (unlikely (!workspace.resize (pages.length)))
+    {
+      successful = false;
+      return false;
+    }
+
+    return true;
+  }
+
+  /*
+   * workspace should be a pre-sized vector allocated to hold at exactly pages.length
+   * elements.
+   */
+  void compact (hb_vector_t<unsigned>& workspace,
+                unsigned int length)
+  {
+    assert(workspace.length == pages.length);
+    hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
+
+    hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
+    for (unsigned i = 0; i < length; i++)
+      old_index_to_page_map_index[page_map[i].index] =  i;
+
+    compact_pages (old_index_to_page_map_index);
+  }
+  void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
+  {
+    unsigned int write_index = 0;
+    for (unsigned int i = 0; i < pages.length; i++)
+    {
+      if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
+
+      if (write_index < i)
+	pages[write_index] = pages[i];
+
+      page_map[old_index_to_page_map_index[i]].index = write_index;
+      write_index++;
+    }
+  }
+  public:
+
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_t &other)
+  {
+    const bool passthru_left = op (1, 0);
+    const bool passthru_right = op (0, 1);
+
+    if (unlikely (!successful)) return;
+
+    dirty ();
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+    unsigned int next_page = na;
+
+    unsigned int count = 0, newCount = 0;
+    unsigned int a = 0, b = 0;
+    unsigned int write_index = 0;
+
+    // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+    // before attempting to rewrite the page map.
+    hb_vector_t<unsigned> compact_workspace;
+    if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+    for (; a < na && b < nb; )
+    {
+      if (page_map[a].major == other.page_map[b].major)
+      {
+	if (!passthru_left)
+	{
+	  // Move page_map entries that we're keeping from the left side set
+	  // to the front of the page_map vector. This isn't necessary if
+	  // passthru_left is set since no left side pages will be removed
+	  // in that case.
+	  if (write_index < a)
+	    page_map[write_index] = page_map[a];
+	  write_index++;
+	}
+
+	count++;
+	a++;
+	b++;
+      }
+      else if (page_map[a].major < other.page_map[b].major)
+      {
+	if (passthru_left)
+	  count++;
+	a++;
+      }
+      else
+      {
+	if (passthru_right)
+	  count++;
+	b++;
+      }
+    }
+    if (passthru_left)
+      count += na - a;
+    if (passthru_right)
+      count += nb - b;
+
+    if (!passthru_left)
+    {
+      na  = write_index;
+      next_page = write_index;
+      compact (compact_workspace, write_index);
+    }
+
+    if (unlikely (!resize (count)))
+      return;
+
+    newCount = count;
+
+    /* Process in-place backward. */
+    a = na;
+    b = nb;
+    for (; a && b; )
+    {
+      if (page_map[a - 1].major == other.page_map[b - 1].major)
+      {
+	a--;
+	b--;
+	count--;
+	page_map[count] = page_map[a];
+	page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+      }
+      else if (page_map[a - 1].major > other.page_map[b - 1].major)
+      {
+	a--;
+	if (passthru_left)
+	{
+	  count--;
+	  page_map[count] = page_map[a];
+	}
+      }
+      else
+      {
+	b--;
+	if (passthru_right)
+	{
+	  count--;
+	  page_map[count].major = other.page_map[b].major;
+	  page_map[count].index = next_page++;
+	  page_at (count).v = other.page_at (b).v;
+	}
+      }
+    }
+    if (passthru_left)
+      while (a)
+      {
+	a--;
+	count--;
+	page_map[count] = page_map [a];
+      }
+    if (passthru_right)
+      while (b)
+      {
+	b--;
+	count--;
+	page_map[count].major = other.page_map[b].major;
+	page_map[count].index = next_page++;
+	page_at (count).v = other.page_at (b).v;
+      }
+    assert (!count);
+    resize (newCount);
+  }
+
+  void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
+  void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
+  void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
+  void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    // TODO: this should be merged with prev() as both implementations
+    //       are very similar.
+    if (unlikely (*codepoint == INVALID)) {
+      *codepoint = get_min ();
+      return *codepoint != INVALID;
+    }
+
+    const auto* page_map_array = page_map.arrayZ;
+    unsigned int major = get_major (*codepoint);
+    unsigned int i = last_page_lookup;
+
+    if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+    {
+      page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+      if (i >= page_map.length) {
+        *codepoint = INVALID;
+        return false;
+      }
+    }
+
+    const auto* pages_array = pages.arrayZ;
+    const page_map_t &current = page_map_array[i];
+    if (likely (current.major == major))
+    {
+      if (pages_array[current.index].next (codepoint))
+      {
+        *codepoint += current.major * page_t::PAGE_BITS;
+        last_page_lookup = i;
+        return true;
+      }
+      i++;
+    }
+
+    for (; i < page_map.length; i++)
+    {
+      const page_map_t &current = page_map.arrayZ[i];
+      hb_codepoint_t m = pages_array[current.index].get_min ();
+      if (m != INVALID)
+      {
+	*codepoint = current.major * page_t::PAGE_BITS + m;
+        last_page_lookup = i;
+	return true;
+      }
+    }
+    last_page_lookup = 0;
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (unlikely (*codepoint == INVALID)) {
+      *codepoint = get_max ();
+      return *codepoint != INVALID;
+    }
+
+    page_map_t map = {get_major (*codepoint), 0};
+    unsigned int i;
+    page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
+    if (i < page_map.length && page_map[i].major == map.major)
+    {
+      if (pages[page_map[i].index].previous (codepoint))
+      {
+	*codepoint += page_map[i].major * page_t::PAGE_BITS;
+	return true;
+      }
+    }
+    i--;
+    for (; (int) i >= 0; i--)
+    {
+      hb_codepoint_t m = pages[page_map[i].index].get_max ();
+      if (m != INVALID)
+      {
+	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+	return true;
+      }
+    }
+    *codepoint = INVALID;
+    return false;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *first;
+    if (!previous (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (previous (&i) && i == *first - 1)
+      (*first)--;
+
+    return true;
+  }
+
+  bool has_population () const { return population != UINT_MAX; }
+  unsigned int get_population () const
+  {
+    if (has_population ())
+      return population;
+
+    unsigned int pop = 0;
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      pop += pages[i].get_population ();
+
+    population = pop;
+    return pop;
+  }
+  hb_codepoint_t get_min () const
+  {
+    unsigned count = pages.length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      const auto& map = page_map[i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_min ();
+    }
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    unsigned count = pages.length;
+    for (signed i = count - 1; i >= 0; i--)
+    {
+      const auto& map = page_map[(unsigned) i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_max ();
+    }
+    return INVALID;
+  }
+
+  static constexpr hb_codepoint_t INVALID = page_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
+	    bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
+
+    protected:
+    const hb_bit_set_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+
+  protected:
+
+  page_t *page_for (hb_codepoint_t g, bool insert = false)
+  {
+    page_map_t map = {get_major (g), pages.length};
+    unsigned int i;
+    if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
+    {
+      if (!insert)
+        return nullptr;
+
+      if (unlikely (!resize (pages.length + 1)))
+	return nullptr;
+
+      pages[map.index].init0 ();
+      memmove (page_map + i + 1,
+	       page_map + i,
+	       (page_map.length - 1 - i) * page_map.item_size);
+      page_map[i] = map;
+    }
+    return &pages[page_map[i].index];
+  }
+  const page_t *page_for (hb_codepoint_t g) const
+  {
+    page_map_t key = {get_major (g)};
+    const page_map_t *found = page_map.bsearch (key);
+    if (found)
+      return &pages[found->index];
+    return nullptr;
+  }
+  page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
+  const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
+  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
+};
+
+
+#endif /* HB_BIT_SET_HH */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1755,6 +1755,28 @@
   memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
   if (buffer->have_positions)
     memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+
+  if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
+  {
+    /* See similar logic in add_utf. */
+
+    /* pre-context */
+    if (!orig_len && start + source->context_len[0] > 0)
+    {
+      buffer->clear_context (0);
+      while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+	buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
+      for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
+	buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
+    }
+
+    /* post-context */
+    buffer->clear_context (1);
+    while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+      buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
+    for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
+      buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
+  }
 }
 
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-deprecated.h	2021-09-08 02:37:35 UTC (rev 60451)
@@ -107,9 +107,6 @@
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
-HB_EXTERN HB_DEPRECATED void
-hb_set_invert (hb_set_t *set);
-
 /**
  * hb_unicode_eastasian_width_func_t:
  * @ufuncs: A Unicode-functions structure

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -188,6 +188,7 @@
 	    hb_codepoint_t  key,
 	    hb_codepoint_t  value)
 {
+  /* Immutable-safe. */
   map->set (key, value);
 }
 
@@ -220,6 +221,7 @@
 hb_map_del (hb_map_t       *map,
 	    hb_codepoint_t  key)
 {
+  /* Immutable-safe. */
   map->del (key);
 }
 
@@ -253,9 +255,6 @@
 void
 hb_map_clear (hb_map_t *map)
 {
-  if (unlikely (hb_object_is_immutable (map)))
-    return;
-
   return map->clear ();
 }
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-map.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -169,6 +169,8 @@
 
   void clear ()
   {
+    if (unlikely (!successful)) return;
+
     if (items)
       for (auto &_ : hb_iter (items, mask + 1))
 	_.clear ();

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-object.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -140,8 +140,6 @@
  * Reference-count.
  */
 
-#define HB_REFERENCE_COUNT_INIT {0}
-
 struct hb_reference_count_t
 {
   mutable hb_atomic_int_t ref_count;
@@ -197,6 +195,8 @@
   hb_reference_count_t ref_count;
   mutable hb_atomic_int_t writable = 0;
   hb_atomic_ptr_t<hb_user_data_array_t> user_data;
+
+  bool is_inert () const { return !ref_count.get_relaxed (); }
 };
 #define HB_OBJECT_HEADER_STATIC {}
 
@@ -234,11 +234,6 @@
   obj->header.user_data.init ();
 }
 template <typename Type>
-static inline bool hb_object_is_inert (const Type *obj)
-{
-  return unlikely (obj->header.ref_count.is_inert ());
-}
-template <typename Type>
 static inline bool hb_object_is_valid (const Type *obj)
 {
   return likely (obj->header.ref_count.is_valid ());
@@ -257,7 +252,7 @@
 static inline Type *hb_object_reference (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return obj;
   assert (hb_object_is_valid (obj));
   obj->header.ref_count.inc ();
@@ -267,7 +262,7 @@
 static inline bool hb_object_destroy (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
   if (obj->header.ref_count.dec () != 1)
@@ -295,7 +290,7 @@
 					    hb_destroy_func_t   destroy,
 					    hb_bool_t           replace)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
 
@@ -322,7 +317,7 @@
 static inline void *hb_object_get_user_data (Type               *obj,
 					     hb_user_data_key_t *key)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return nullptr;
   assert (hb_object_is_valid (obj));
   hb_user_data_array_t *user_data = obj->header.user_data.get ();

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cmap-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cmap-table.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cmap-table.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -218,30 +218,25 @@
 					 HBINT16 *idDelta,
 					 unsigned segcount)
   {
+    hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
+    + it | hb_sink (cp_to_gid);
+
     HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
     if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
 
-    + hb_range (segcount)
-    | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
-    | hb_apply ([&] (const unsigned i)
-		{
-		  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+    for (unsigned i : + hb_range (segcount)
+             | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
+    {
+      idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+      for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
+      {
+        HBUINT16 gid;
+        gid = cp_to_gid[cp];
+        c->copy<HBUINT16> (gid);
+      }
+    }
 
-		  + it
-		  | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
-		  | hb_apply ([&] (const hb_item_type<Iterator> _)
-			      {
-				HBUINT16 glyID;
-				glyID = _.second;
-				c->copy<HBUINT16> (glyID);
-			      })
-		  ;
-
-
-		})
-    ;
-
     return idRangeOffset;
   }
 
@@ -282,9 +277,17 @@
     HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return;
 
-    if (unlikely (!c->check_assign(this->length,
-                                   c->length () - table_initpos,
-                                   HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+    this->length = c->length () - table_initpos;
+    if ((long long) this->length != (long long) c->length () - table_initpos)
+    {
+      // Length overflowed. Discard the current object before setting the error condition, otherwise
+      // discard is a noop which prevents the higher level code from reverting the serializer to the
+      // pre-error state in cmap4 overflow handling code.
+      c->pop_discard ();
+      c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return;
+    }
+
     this->segCountX2 = segcount * 2;
     this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
     this->searchRange = 2 * (1u << this->entrySelector);
@@ -1389,19 +1392,24 @@
 
   template<typename Iterator, typename EncodingRecIter,
 	   hb_requires (hb_is_iterator (EncodingRecIter))>
-  void serialize (hb_serialize_context_t *c,
+  bool serialize (hb_serialize_context_t *c,
 		  Iterator it,
 		  EncodingRecIter encodingrec_iter,
 		  const void *base,
-		  const hb_subset_plan_t *plan)
+		  const hb_subset_plan_t *plan,
+                  bool drop_format_4 = false)
   {
-    if (unlikely (!c->extend_min ((*this))))  return;
+    if (unlikely (!c->extend_min ((*this))))  return false;
     this->version = 0;
 
     unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
+    auto snap = c->snapshot ();
 
     for (const EncodingRecord& _ : encodingrec_iter)
     {
+      if (c->in_error ())
+        return false;
+
       unsigned format = (base+_.subtable).u.format;
       if (format != 4 && format != 12 && format != 14) continue;
 
@@ -1408,7 +1416,21 @@
       hb_set_t unicodes_set;
       (base+_.subtable).collect_unicodes (&unicodes_set);
 
-      if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+      if (!drop_format_4 && format == 4)
+      {
+        c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+        if (c->in_error () && c->only_overflow ())
+        {
+          // cmap4 overflowed, reset and retry serialization without format 4 subtables.
+          c->revert (snap);
+          return serialize (c, it,
+                            encodingrec_iter,
+                            base,
+                            plan,
+                            true);
+        }
+      }
+
       else if (format == 12)
       {
         if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
@@ -1416,10 +1438,12 @@
       }
       else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
     }
-
     c->check_assign(this->encodingRecord.len,
                     (c->length () - cmap::min_size)/EncodingRecord::static_size,
                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    // Fail if format 4 was dropped and there is no cmap12.
+    return !drop_format_4 || format12objidx;
   }
 
   template<typename Iterator, typename EncodingRecordIterator,
@@ -1540,8 +1564,8 @@
     | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
 		 { return (_.second != HB_MAP_VALUE_INVALID); })
     ;
-    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
-    return_trace (true);
+
+    return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-cpal-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-cpal-table.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-cpal-table.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -83,9 +83,14 @@
     auto *out = c->allocate_size<CPALV1Tail> (static_size);
     if (unlikely (!out)) return_trace (false);
 
-    out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
-    out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+    out->paletteFlagsZ = 0;
+    if (paletteFlagsZ)
+      out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
 
+    out->paletteLabelsZ = 0;
+    if (paletteLabelsZ)
+      out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+
     const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
     if (colorLabelsZ)
     {
@@ -119,6 +124,8 @@
   }
 
   protected:
+  // TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
+  //                     here. Currently they are needed since UnsizedArrayOf doesn't define null_size
   NNOffset32To<UnsizedArrayOf<HBUINT32>>
 		paletteFlagsZ;		/* Offset from the beginning of CPAL table to
 					 * the Palette Type Array. Set to 0 if no array
@@ -234,7 +241,7 @@
 
     auto *out = c->serializer->start_embed (*this);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    
+
     out->version = version;
     out->numColors = retained_color_indices.get_population ();
     out->numPalettes = numPalettes;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -3719,8 +3719,9 @@
     hb_set_t alternate_feature_indices;
     if (version.to_int () >= 0x00010001u)
       (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
-    if (unlikely (alternate_feature_indices.in_error())) {
-      feature_indices->successful = false;
+    if (unlikely (alternate_feature_indices.in_error()))
+    {
+      feature_indices->err ();
       return;
     }
 #endif

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-map.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -54,7 +54,6 @@
   face = face_;
   props = *props_;
 
-
   /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
    * features not available in either table and not waste precious bits for them. */
 
@@ -63,12 +62,28 @@
   hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
   hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
 
-  hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
+  hb_ot_tags_from_script_and_language (props.script,
+				       props.language,
+				       &script_count,
+				       script_tags,
+				       &language_count,
+				       language_tags);
 
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
     hb_tag_t table_tag = table_tags[table_index];
-    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
-    hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
+    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face,
+									 table_tag,
+									 script_count,
+									 script_tags,
+									 &script_index[table_index],
+									 &chosen_script[table_index]);
+    hb_ot_layout_script_select_language (face,
+					 table_tag,
+					 script_index[table_index],
+					 language_count,
+					 language_tags,
+					 &language_index[table_index]);
   }
 }
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-name.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -156,7 +156,8 @@
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-8 encoding.
+ * Returns string in UTF-8 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -183,7 +184,8 @@
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-16 encoding.
+ * Returns string in UTF-16 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -209,7 +211,8 @@
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-32 encoding.
+ * Returns string in UTF-32 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table-v2subset.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table-v2subset.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-post-table-v2subset.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -76,6 +76,9 @@
   hb_map_t old_new_index_map, old_gid_new_index_map;
   unsigned i = 0;
 
+  post::accelerator_t _post;
+  _post.init (c->plan->source);
+
   for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
   {
     hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
@@ -86,9 +89,24 @@
     else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
     else
     {
-      new_index = 258 + i;
+      hb_bytes_t s = _post.find_glyph_name (old_gid);
+      int standard_glyph_index = -1;
+      for (unsigned i = 0; i < format1_names_length; i++)
+      {
+        if (s == format1_names (i))
+        {
+          standard_glyph_index = i;
+          break;
+        }
+      }
+      if (standard_glyph_index == -1)
+      {
+        new_index = 258 + i;
+        i++;
+      }
+      else
+      { new_index = standard_glyph_index; }
       old_new_index_map.set (old_index, new_index);
-      i++;
     }
     old_gid_new_index_map.set (old_gid, new_index);
   }
@@ -103,8 +121,6 @@
                             })
   ;
 
-  post::accelerator_t _post;
-  _post.init (c->plan->source);
   bool ret = serialize (c->serializer, index_iter, &_post);
   _post.fini ();
   return_trace (ret);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -149,7 +149,9 @@
    * Decide who does positioning. GPOS, kerx, kern, or fallback.
    */
 
+#ifndef HB_NO_AAT_SHAPE
   bool has_gsub = hb_ot_layout_has_substitution (face);
+#endif
   bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
   if (false)
     ;
@@ -317,9 +319,9 @@
 };
 
 static void
-hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
-			      const hb_feature_t             *user_features,
-			      unsigned int                    num_user_features)
+hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
+			      const hb_feature_t    *user_features,
+			      unsigned int           num_user_features)
 {
   hb_ot_map_builder_t *map = &planner->map;
 
@@ -326,7 +328,8 @@
   map->enable_feature (HB_TAG('r','v','r','n'));
   map->add_gsub_pause (nullptr);
 
-  switch (planner->props.direction) {
+  switch (planner->props.direction)
+  {
     case HB_DIRECTION_LTR:
       map->enable_feature (HB_TAG ('l','t','r','a'));
       map->enable_feature (HB_TAG ('l','t','r','m'));

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag-table.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag-table.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -6,8 +6,8 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2021-02-12 04:08 PM" />
- * File-Date: 2021-03-05
+ * <meta name="updated_at" content="2021-09-02 09:40 PM" />
+ * File-Date: 2021-08-06
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
@@ -93,6 +93,7 @@
   {"auz",	HB_TAG('A','R','A',' ')},	/* Uzbeki Arabic -> Arabic */
   {"av",	HB_TAG('A','V','R',' ')},	/* Avaric -> Avar */
   {"avl",	HB_TAG('A','R','A',' ')},	/* Eastern Egyptian Bedawi Arabic -> Arabic */
+/*{"avn",	HB_TAG('A','V','N',' ')},*/	/* Avatime */
 /*{"awa",	HB_TAG('A','W','A',' ')},*/	/* Awadhi */
   {"ay",	HB_TAG('A','Y','M',' ')},	/* Aymara [macrolanguage] */
   {"ayc",	HB_TAG('A','Y','M',' ')},	/* Southern Aymara -> Aymara */
@@ -345,6 +346,7 @@
   {"cth",	HB_TAG('Q','I','N',' ')},	/* Thaiphum Chin -> Chin */
   {"ctl",	HB_TAG('C','C','H','N')},	/* Tlacoatzintepec Chinantec -> Chinantec */
   {"cts",	HB_TAG('B','I','K',' ')},	/* Northern Catanduanes Bikol -> Bikol */
+/*{"ctt",	HB_TAG('C','T','T',' ')},*/	/* Wayanad Chetti */
   {"ctu",	HB_TAG('M','Y','N',' ')},	/* Chol -> Mayan */
   {"cu",	HB_TAG('C','S','L',' ')},	/* Church Slavonic */
   {"cuc",	HB_TAG('C','C','H','N')},	/* Usila Chinantec -> Chinantec */
@@ -537,17 +539,20 @@
   {"ha",	HB_TAG('H','A','U',' ')},	/* Hausa */
   {"haa",	HB_TAG('A','T','H',' ')},	/* Han -> Athapaskan */
   {"hae",	HB_TAG('O','R','O',' ')},	/* Eastern Oromo -> Oromo */
-  {"hai",	HB_TAG_NONE	       },	/* Haida [macrolanguage] != Haitian (Haitian Creole) */
+  {"hai",	HB_TAG('H','A','I','0')},	/* Haida [macrolanguage] */
   {"hak",	HB_TAG('Z','H','S',' ')},	/* Hakka Chinese -> Chinese, Simplified */
   {"hal",	HB_TAG_NONE	       },	/* Halang != Halam (Falam Chin) */
   {"har",	HB_TAG('H','R','I',' ')},	/* Harari */
 /*{"haw",	HB_TAG('H','A','W',' ')},*/	/* Hawaiian */
+  {"hax",	HB_TAG('H','A','I','0')},	/* Southern Haida -> Haida */
 /*{"hay",	HB_TAG('H','A','Y',' ')},*/	/* Haya */
 /*{"haz",	HB_TAG('H','A','Z',' ')},*/	/* Hazaragi */
   {"hbn",	HB_TAG_NONE	       },	/* Heiban != Hammer-Banna */
   {"hca",	HB_TAG('C','P','P',' ')},	/* Andaman Creole Hindi -> Creoles */
+  {"hdn",	HB_TAG('H','A','I','0')},	/* Northern Haida -> Haida */
   {"he",	HB_TAG('I','W','R',' ')},	/* Hebrew */
   {"hea",	HB_TAG('H','M','N',' ')},	/* Northern Qiandong Miao -> Hmong */
+/*{"hei",	HB_TAG('H','E','I',' ')},*/	/* Heiltsuk */
   {"hi",	HB_TAG('H','I','N',' ')},	/* Hindi */
 /*{"hil",	HB_TAG('H','I','L',' ')},*/	/* Hiligaynon */
   {"hji",	HB_TAG('M','L','Y',' ')},	/* Haji -> Malay */
@@ -554,6 +559,7 @@
   {"hlt",	HB_TAG('Q','I','N',' ')},	/* Matu Chin -> Chin */
   {"hma",	HB_TAG('H','M','N',' ')},	/* Southern Mashan Hmong -> Hmong */
   {"hmc",	HB_TAG('H','M','N',' ')},	/* Central Huishui Hmong -> Hmong */
+  {"hmd",	HB_TAG('H','M','D',' ')},	/* Large Flowery Miao -> A-Hmao */
   {"hmd",	HB_TAG('H','M','N',' ')},	/* Large Flowery Miao -> Hmong */
   {"hme",	HB_TAG('H','M','N',' ')},	/* Eastern Huishui Hmong -> Hmong */
   {"hmg",	HB_TAG('H','M','N',' ')},	/* Southwestern Guiyang Hmong -> Hmong */
@@ -569,6 +575,7 @@
   {"hms",	HB_TAG('H','M','N',' ')},	/* Southern Qiandong Miao -> Hmong */
   {"hmw",	HB_TAG('H','M','N',' ')},	/* Western Mashan Hmong -> Hmong */
   {"hmy",	HB_TAG('H','M','N',' ')},	/* Southern Guiyang Hmong -> Hmong */
+  {"hmz",	HB_TAG('H','M','Z',' ')},	/* Hmong Shua -> Hmong Shuat */
   {"hmz",	HB_TAG('H','M','N',' ')},	/* Hmong Shua -> Hmong */
 /*{"hnd",	HB_TAG('H','N','D',' ')},*/	/* Southern Hindko -> Hindko */
   {"hne",	HB_TAG('C','H','H',' ')},	/* Chhattisgarhi -> Chattisgarhi */
@@ -625,6 +632,7 @@
   {"inh",	HB_TAG('I','N','G',' ')},	/* Ingush */
   {"io",	HB_TAG('I','D','O',' ')},	/* Ido */
   {"iri",	HB_TAG_NONE	       },	/* Rigwe != Irish */
+/*{"iru",	HB_TAG('I','R','U',' ')},*/	/* Irula */
   {"is",	HB_TAG('I','S','L',' ')},	/* Icelandic */
   {"ism",	HB_TAG_NONE	       },	/* Masimasi != Inari Sami */
   {"it",	HB_TAG('I','T','A',' ')},	/* Italian */
@@ -660,6 +668,7 @@
   {"kac",	HB_TAG_NONE	       },	/* Kachin != Kachchi */
   {"kam",	HB_TAG('K','M','B',' ')},	/* Kamba (Kenya) */
   {"kar",	HB_TAG('K','R','N',' ')},	/* Karen [family] */
+/*{"kaw",	HB_TAG('K','A','W',' ')},*/	/* Kawi (Old Javanese) */
   {"kbd",	HB_TAG('K','A','B',' ')},	/* Kabardian */
   {"kby",	HB_TAG('K','N','R',' ')},	/* Manga Kanuri -> Kanuri */
   {"kca",	HB_TAG('K','H','K',' ')},	/* Khanty -> Khanty-Kazim */
@@ -779,6 +788,7 @@
   {"kvu",	HB_TAG('K','R','N',' ')},	/* Yinbaw Karen -> Karen */
   {"kvy",	HB_TAG('K','R','N',' ')},	/* Yintale Karen -> Karen */
   {"kw",	HB_TAG('C','O','R',' ')},	/* Cornish */
+/*{"kwk",	HB_TAG('K','W','K',' ')},*/	/* Kwakiutl -> Kwakʼwala */
   {"kww",	HB_TAG('C','P','P',' ')},	/* Kwinti -> Creoles */
   {"kwy",	HB_TAG('K','O','N','0')},	/* San Salvador Kongo -> Kongo */
   {"kxc",	HB_TAG('K','M','S',' ')},	/* Konso -> Komso */
@@ -806,6 +816,7 @@
   {"lcf",	HB_TAG('M','L','Y',' ')},	/* Lubu -> Malay */
   {"ldi",	HB_TAG('K','O','N','0')},	/* Laari -> Kongo */
   {"ldk",	HB_TAG_NONE	       },	/* Leelau != Ladakhi */
+/*{"lef",	HB_TAG('L','E','F',' ')},*/	/* Lelemi */
 /*{"lez",	HB_TAG('L','E','Z',' ')},*/	/* Lezghian -> Lezgi */
   {"lg",	HB_TAG('L','U','G',' ')},	/* Ganda */
   {"li",	HB_TAG('L','I','M',' ')},	/* Limburgish */
@@ -832,6 +843,7 @@
   {"lo",	HB_TAG('L','A','O',' ')},	/* Lao */
 /*{"lom",	HB_TAG('L','O','M',' ')},*/	/* Loma (Liberia) */
   {"lou",	HB_TAG('C','P','P',' ')},	/* Louisiana Creole -> Creoles */
+/*{"lpo",	HB_TAG('L','P','O',' ')},*/	/* Lipo */
 /*{"lrc",	HB_TAG('L','R','C',' ')},*/	/* Northern Luri -> Luri */
   {"lri",	HB_TAG('L','U','H',' ')},	/* Marachi -> Luyia */
   {"lrm",	HB_TAG('L','U','H',' ')},	/* Marama -> Luyia */
@@ -1231,6 +1243,7 @@
   {"rbl",	HB_TAG('B','I','K',' ')},	/* Miraya Bikol -> Bikol */
   {"rcf",	HB_TAG('C','P','P',' ')},	/* Réunion Creole French -> Creoles */
 /*{"rej",	HB_TAG('R','E','J',' ')},*/	/* Rejang */
+/*{"rhg",	HB_TAG('R','H','G',' ')},*/	/* Rohingya */
 /*{"ria",	HB_TAG('R','I','A',' ')},*/	/* Riang (India) */
   {"rif",	HB_TAG('R','I','F',' ')},	/* Tarifit */
   {"rif",	HB_TAG('B','B','R',' ')},	/* Tarifit -> Berber */
@@ -1286,6 +1299,7 @@
   {"sek",	HB_TAG('A','T','H',' ')},	/* Sekani -> Athapaskan */
 /*{"sel",	HB_TAG('S','E','L',' ')},*/	/* Selkup */
   {"sez",	HB_TAG('Q','I','N',' ')},	/* Senthang Chin -> Chin */
+  {"sfm",	HB_TAG('S','F','M',' ')},	/* Small Flowery Miao */
   {"sfm",	HB_TAG('H','M','N',' ')},	/* Small Flowery Miao -> Hmong */
   {"sg",	HB_TAG('S','G','O',' ')},	/* Sango */
 /*{"sga",	HB_TAG('S','G','A',' ')},*/	/* Old Irish (to 900) */
@@ -1413,6 +1427,7 @@
   {"tkg",	HB_TAG('M','L','G',' ')},	/* Tesaka Malagasy -> Malagasy */
   {"tkm",	HB_TAG_NONE	       },	/* Takelma != Turkmen */
   {"tl",	HB_TAG('T','G','L',' ')},	/* Tagalog */
+/*{"tli",	HB_TAG('T','L','I',' ')},*/	/* Tlingit */
   {"tmg",	HB_TAG('C','P','P',' ')},	/* Ternateño -> Creoles */
   {"tmh",	HB_TAG('T','M','H',' ')},	/* Tamashek [macrolanguage] */
   {"tmh",	HB_TAG('B','B','R',' ')},	/* Tamashek [macrolanguage] -> Berber */
@@ -1499,6 +1514,7 @@
   {"wbm",	HB_TAG('W','A',' ',' ')},	/* Wa */
   {"wbr",	HB_TAG('W','A','G',' ')},	/* Wagdi */
   {"wbr",	HB_TAG('R','A','J',' ')},	/* Wagdi -> Rajasthani */
+/*{"wci",	HB_TAG('W','C','I',' ')},*/	/* Waci Gbe */
   {"wea",	HB_TAG('K','R','N',' ')},	/* Wewaw -> Karen */
   {"wes",	HB_TAG('C','P','P',' ')},	/* Cameroon Pidgin -> Creoles */
   {"weu",	HB_TAG('Q','I','N',' ')},	/* Rawngtu Chin -> Chin */
@@ -1533,6 +1549,8 @@
   {"xsl",	HB_TAG('S','L','A',' ')},	/* South Slavey -> Slavey */
   {"xsl",	HB_TAG('A','T','H',' ')},	/* South Slavey -> Athapaskan */
   {"xst",	HB_TAG('S','I','G',' ')},	/* Silt'e (retired code) -> Silte Gurage */
+/*{"xub",	HB_TAG('X','U','B',' ')},*/	/* Betta Kurumba -> Bette Kuruma */
+/*{"xuj",	HB_TAG('X','U','J',' ')},*/	/* Jennu Kurumba -> Jennu Kuruma */
   {"xup",	HB_TAG('A','T','H',' ')},	/* Upper Umpqua -> Athapaskan */
   {"xwo",	HB_TAG('T','O','D',' ')},	/* Written Oirat -> Todo */
   {"yaj",	HB_TAG('B','A','D','0')},	/* Banda-Yangere -> Banda */
@@ -1543,13 +1561,16 @@
   {"ybb",	HB_TAG('B','M','L',' ')},	/* Yemba -> Bamileke */
   {"ybd",	HB_TAG('A','R','K',' ')},	/* Yangbye (retired code) -> Rakhine */
   {"ydd",	HB_TAG('J','I','I',' ')},	/* Eastern Yiddish -> Yiddish */
+/*{"ygp",	HB_TAG('Y','G','P',' ')},*/	/* Gepo */
   {"yi",	HB_TAG('J','I','I',' ')},	/* Yiddish [macrolanguage] */
   {"yih",	HB_TAG('J','I','I',' ')},	/* Western Yiddish -> Yiddish */
   {"yim",	HB_TAG_NONE	       },	/* Yimchungru Naga != Yi Modern */
+/*{"yna",	HB_TAG('Y','N','A',' ')},*/	/* Aluo */
   {"yo",	HB_TAG('Y','B','A',' ')},	/* Yoruba */
   {"yos",	HB_TAG('Q','I','N',' ')},	/* Yos (retired code) -> Chin */
   {"yua",	HB_TAG('M','Y','N',' ')},	/* Yucateco -> Mayan */
   {"yue",	HB_TAG('Z','H','H',' ')},	/* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
+/*{"ywq",	HB_TAG('Y','W','Q',' ')},*/	/* Wuding-Luquan Yi */
   {"za",	HB_TAG('Z','H','A',' ')},	/* Zhuang [macrolanguage] */
   {"zch",	HB_TAG('Z','H','A',' ')},	/* Central Hongshuihe Zhuang -> Zhuang */
   {"zdj",	HB_TAG('C','M','R',' ')},	/* Ngazidja Comorian -> Comorian */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -102,10 +102,11 @@
     char *tail;
     object_t *current; // Just for sanity check
     unsigned num_links;
+    hb_serialize_error_t errors;
   };
 
   snapshot_t snapshot ()
-  { return snapshot_t { head, tail, current, current->links.length }; }
+  { return snapshot_t { head, tail, current, current->links.length, errors }; }
 
   hb_serialize_context_t (void *start_, unsigned int size) :
     start ((char *) start_),
@@ -136,6 +137,12 @@
   HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
   HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
   HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
+  HB_NODISCARD bool only_overflow () const
+  {
+    return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
+        || errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
+        || errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
+  }
 
   void reset (void *start_, unsigned int size)
   {
@@ -317,9 +324,11 @@
 
   void revert (snapshot_t snap)
   {
-    if (unlikely (in_error ())) return;
+    // Overflows that happened after the snapshot will be erased by the revert.
+    if (unlikely (in_error () && !only_overflow ())) return;
     assert (snap.current == current);
     current->links.shrink (snap.num_links);
+    errors = snap.errors;
     revert (snap.head, snap.tail);
   }
 
@@ -363,6 +372,8 @@
     assert (current->head <= (const char *) &ofs);
 
     auto& link = *current->links.push ();
+    if (current->links.in_error ())
+      err (HB_SERIALIZE_ERROR_OTHER);
 
     link.width = sizeof (T);
     link.is_signed = hb_is_signed (hb_unwrap_type (T));

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -169,7 +169,7 @@
 hb_bool_t
 hb_set_allocation_successful (const hb_set_t  *set)
 {
-  return set->successful;
+  return !set->in_error ();
 }
 
 /**
@@ -201,9 +201,7 @@
 void
 hb_set_clear (hb_set_t *set)
 {
-  if (unlikely (hb_object_is_immutable (set)))
-    return;
-
+  /* Immutible-safe. */
   set->clear ();
 }
 
@@ -254,6 +252,7 @@
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
+  /* Immutible-safe. */
   set->add (codepoint);
 }
 
@@ -273,6 +272,7 @@
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
+  /* Immutible-safe. */
   set->add_range (first, last);
 }
 
@@ -289,6 +289,7 @@
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
+  /* Immutible-safe. */
   set->del (codepoint);
 }
 
@@ -311,6 +312,7 @@
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
+  /* Immutible-safe. */
   set->del_range (first, last);
 }
 
@@ -364,6 +366,7 @@
 hb_set_set (hb_set_t       *set,
 	    const hb_set_t *other)
 {
+  /* Immutible-safe. */
   set->set (*other);
 }
 
@@ -380,6 +383,7 @@
 hb_set_union (hb_set_t       *set,
 	      const hb_set_t *other)
 {
+  /* Immutible-safe. */
   set->union_ (*other);
 }
 
@@ -396,6 +400,7 @@
 hb_set_intersect (hb_set_t       *set,
 		  const hb_set_t *other)
 {
+  /* Immutible-safe. */
   set->intersect (*other);
 }
 
@@ -412,6 +417,7 @@
 hb_set_subtract (hb_set_t       *set,
 		 const hb_set_t *other)
 {
+  /* Immutible-safe. */
   set->subtract (*other);
 }
 
@@ -429,10 +435,10 @@
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other)
 {
+  /* Immutible-safe. */
   set->symmetric_difference (*other);
 }
 
-#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_set_invert:
  * @set: A set
@@ -439,15 +445,14 @@
  *
  * Inverts the contents of @set.
  *
- * Since: 0.9.10
- *
- * Deprecated: 1.6.1
+ * Since: 3.0.0
  **/
 void
-hb_set_invert (hb_set_t *set HB_UNUSED)
+hb_set_invert (hb_set_t *set)
 {
+  /* Immutible-safe. */
+  set->invert ();
 }
-#endif
 
 /**
  * hb_set_get_population:

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.h
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.h	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.h	2021-09-08 02:37:35 UTC (rev 60451)
@@ -94,6 +94,9 @@
 HB_EXTERN hb_bool_t
 hb_set_is_empty (const hb_set_t *set);
 
+HB_EXTERN void
+hb_set_invert (hb_set_t *set);
+
 HB_EXTERN hb_bool_t
 hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-set.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -28,227 +29,30 @@
 #define HB_SET_HH
 
 #include "hb.hh"
-#include "hb-machinery.hh"
+#include "hb-bit-set-invertible.hh"
 
 
-/*
- * hb_set_t
- */
+template <typename impl_t>
+struct hb_sparseset_t
+{
+  hb_object_header_t header;
+  impl_t s;
 
-/* TODO Keep a freelist so we can release pages that are completely zeroed.  At that
- * point maybe also use a sentinel value for "all-1" pages? */
+  hb_sparseset_t () { init (); }
+  ~hb_sparseset_t () { fini (); }
 
-struct hb_set_t
-{
-  hb_set_t ()  { init (); }
-  ~hb_set_t () { fini (); }
-
-  hb_set_t (const hb_set_t& other) : hb_set_t () { set (other); }
-  void operator= (const hb_set_t& other) { set (other); }
+  hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
+  void operator= (const hb_sparseset_t& other) { set (other); }
   // TODO Add move construtor/assign
-  // TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
+  // TODO Add constructor for Iterator
 
-  struct page_map_t
-  {
-    int cmp (const page_map_t &o) const { return (int) o.major - (int) major; }
-    int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
-
-    uint32_t major;
-    uint32_t index;
-  };
-
-  struct page_t
-  {
-    void init0 () { v.clear (); }
-    void init1 () { v.clear (0xFF); }
-
-    constexpr unsigned len () const
-    { return ARRAY_LENGTH_CONST (v); }
-
-    bool is_empty () const
-    {
-      for (unsigned int i = 0; i < len (); i++)
-	if (v[i])
-	  return false;
-      return true;
-    }
-
-    void add (hb_codepoint_t g) { elt (g) |= mask (g); }
-    void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-    bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
-
-    void add_range (hb_codepoint_t a, hb_codepoint_t b)
-    {
-      elt_t *la = &elt (a);
-      elt_t *lb = &elt (b);
-      if (la == lb)
-	*la |= (mask (b) << 1) - mask(a);
-      else
-      {
-	*la |= ~(mask (a) - 1);
-	la++;
-
-	memset (la, 0xff, (char *) lb - (char *) la);
-
-	*lb |= ((mask (b) << 1) - 1);
-      }
-    }
-
-    void del_range (hb_codepoint_t a, hb_codepoint_t b)
-    {
-      elt_t *la = &elt (a);
-      elt_t *lb = &elt (b);
-      if (la == lb)
-	*la &= ~((mask (b) << 1) - mask(a));
-      else
-      {
-	*la &= mask (a) - 1;
-	la++;
-
-	memset (la, 0, (char *) lb - (char *) la);
-
-	*lb &= ~((mask (b) << 1) - 1);
-      }
-    }
-
-    bool is_equal (const page_t &other) const
-    {
-      return 0 == hb_memcmp (&v, &other.v, sizeof (v));
-    }
-    bool is_subset (const page_t &larger_page) const
-    {
-      for (unsigned i = 0; i < len (); i++)
-        if (~larger_page.v[i] & v[i])
-	  return false;
-      return true;
-    }
-
-    unsigned int get_population () const
-    {
-      unsigned int pop = 0;
-      for (unsigned int i = 0; i < len (); i++)
-	pop += hb_popcount (v[i]);
-      return pop;
-    }
-
-    bool next (hb_codepoint_t *codepoint) const
-    {
-      unsigned int m = (*codepoint + 1) & MASK;
-      if (!m)
-      {
-	*codepoint = INVALID;
-	return false;
-      }
-      unsigned int i = m / ELT_BITS;
-      unsigned int j = m & ELT_MASK;
-
-      const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
-      for (const elt_t *p = &vv; i < len (); p = &v[++i])
-	if (*p)
-	{
-	  *codepoint = i * ELT_BITS + elt_get_min (*p);
-	  return true;
-	}
-
-      *codepoint = INVALID;
-      return false;
-    }
-    bool previous (hb_codepoint_t *codepoint) const
-    {
-      unsigned int m = (*codepoint - 1) & MASK;
-      if (m == MASK)
-      {
-	*codepoint = INVALID;
-	return false;
-      }
-      unsigned int i = m / ELT_BITS;
-      unsigned int j = m & ELT_MASK;
-
-      /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
-      const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
-			 ((elt_t (1) << (j + 1)) - 1) :
-			 (elt_t) -1;
-      const elt_t vv = v[i] & mask;
-      const elt_t *p = &vv;
-      while (true)
-      {
-	if (*p)
-	{
-	  *codepoint = i * ELT_BITS + elt_get_max (*p);
-	  return true;
-	}
-	if ((int) i <= 0) break;
-	p = &v[--i];
-      }
-
-      *codepoint = INVALID;
-      return false;
-    }
-    hb_codepoint_t get_min () const
-    {
-      for (unsigned int i = 0; i < len (); i++)
-	if (v[i])
-	  return i * ELT_BITS + elt_get_min (v[i]);
-      return INVALID;
-    }
-    hb_codepoint_t get_max () const
-    {
-      for (int i = len () - 1; i >= 0; i--)
-	if (v[i])
-	  return i * ELT_BITS + elt_get_max (v[i]);
-      return 0;
-    }
-
-    typedef unsigned long long elt_t;
-    static constexpr unsigned PAGE_BITS = 512;
-    static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
-
-    static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
-    static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
-
-    typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
-
-    static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
-    static constexpr unsigned ELT_MASK = ELT_BITS - 1;
-    static constexpr unsigned BITS = sizeof (vector_t) * 8;
-    static constexpr unsigned MASK = BITS - 1;
-    static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
-
-    elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
-    const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
-    static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
-
-    vector_t v;
-  };
-  static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
-
-  hb_object_header_t header;
-  bool successful; /* Allocations successful */
-  mutable unsigned int population;
-  mutable unsigned int last_page_lookup;
-  hb_sorted_vector_t<page_map_t> page_map;
-  hb_vector_t<page_t> pages;
-
-  void init_shallow ()
-  {
-    successful = true;
-    population = 0;
-    last_page_lookup = 0;
-    page_map.init ();
-    pages.init ();
-  }
+  void init_shallow () { s.init (); }
   void init ()
   {
     hb_object_init (this);
     init_shallow ();
   }
-  void fini_shallow ()
-  {
-    population = 0;
-    last_page_lookup = 0;
-    page_map.fini ();
-    pages.fini ();
-  }
+  void fini_shallow () { s.fini (); }
   void fini ()
   {
     hb_object_fini (this);
@@ -255,103 +59,22 @@
     fini_shallow ();
   }
 
-  bool in_error () const { return !successful; }
-
-  bool resize (unsigned int count)
-  {
-    if (unlikely (count > pages.length && !successful)) return false;
-    if (!pages.resize (count) || !page_map.resize (count))
-    {
-      pages.resize (page_map.length);
-      successful = false;
-      return false;
-    }
-    return true;
-  }
-
-  void reset ()
-  {
-    successful = true;
-    clear ();
-  }
-
-  void clear ()
-  {
-    if (resize (0))
-      population = 0;
-  }
-  bool is_empty () const
-  {
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!pages[i].is_empty ())
-	return false;
-    return true;
-  }
   explicit operator bool () const { return !is_empty (); }
 
-  void dirty () { population = UINT_MAX; }
+  void err () { s.err (); }
+  bool in_error () const { return s.in_error (); }
 
-  void add (hb_codepoint_t g)
-  {
-    if (unlikely (!successful)) return;
-    if (unlikely (g == INVALID)) return;
-    dirty ();
-    page_t *page = page_for_insert (g); if (unlikely (!page)) return;
-    page->add (g);
-  }
-  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
-  {
-    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
-    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
-    dirty ();
-    unsigned int ma = get_major (a);
-    unsigned int mb = get_major (b);
-    if (ma == mb)
-    {
-      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
-      page->add_range (a, b);
-    }
-    else
-    {
-      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
-      page->add_range (a, major_start (ma + 1) - 1);
+  void reset () { s.reset (); }
+  void clear () { s.clear (); }
+  void invert () { s.invert (); }
+  bool is_empty () const { return s.is_empty (); }
 
-      for (unsigned int m = ma + 1; m < mb; m++)
-      {
-	page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
-	page->init1 ();
-      }
+  void add (hb_codepoint_t g) { s.add (g); }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); }
 
-      page = page_for_insert (b); if (unlikely (!page)) return false;
-      page->add_range (major_start (mb), b);
-    }
-    return true;
-  }
-
   template <typename T>
   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
-  {
-    if (unlikely (!successful)) return;
-    if (!count) return;
-    dirty ();
-    hb_codepoint_t g = *array;
-    while (count)
-    {
-      unsigned int m = get_major (g);
-      page_t *page = page_for_insert (g); if (unlikely (!page)) return;
-      unsigned int start = major_start (m);
-      unsigned int end = major_start (m + 1);
-      do
-      {
-	page->add (g);
-
-	array = &StructAtOffsetUnaligned<T> (array, stride);
-	count--;
-      }
-      while (count && (g = *array, start <= g && g < end));
-    }
-  }
+  { s.add_array (array, count, stride); }
   template <typename T>
   void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
 
@@ -359,109 +82,15 @@
    * Used for faster rejection of corrupt data. */
   template <typename T>
   bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
-  {
-    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
-    if (!count) return true;
-    dirty ();
-    hb_codepoint_t g = *array;
-    hb_codepoint_t last_g = g;
-    while (count)
-    {
-      unsigned int m = get_major (g);
-      page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
-      unsigned int end = major_start (m + 1);
-      do
-      {
-	/* If we try harder we can change the following comparison to <=;
-	 * Not sure if it's worth it. */
-	if (g < last_g) return false;
-	last_g = g;
-	page->add (g);
-
-	array = (const T *) ((const char *) array + stride);
-	count--;
-      }
-      while (count && (g = *array, g < end));
-    }
-    return true;
-  }
+  { return s.add_sorted_array (array, count, stride); }
   template <typename T>
   bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
 
-  void del (hb_codepoint_t g)
-  {
-    /* TODO perform op even if !successful. */
-    if (unlikely (!successful)) return;
-    page_t *page = page_for (g);
-    if (!page)
-      return;
-    dirty ();
-    page->del (g);
-  }
+  void del (hb_codepoint_t g) { s.del (g); }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b) { s.del_range (a, b); }
 
-  private:
-  void del_pages (int ds, int de)
-  {
-    if (ds <= de)
-    {
-      // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
-      // before attempting to rewrite the page map.
-      hb_vector_t<unsigned> compact_workspace;
-      if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+  bool get (hb_codepoint_t g) const { return s.get (g); }
 
-      unsigned int write_index = 0;
-      for (unsigned int i = 0; i < page_map.length; i++)
-      {
-	int m = (int) page_map[i].major;
-	if (m < ds || de < m)
-	  page_map[write_index++] = page_map[i];
-      }
-      compact (compact_workspace, write_index);
-      resize (write_index);
-    }
-  }
-
-
-  public:
-  void del_range (hb_codepoint_t a, hb_codepoint_t b)
-  {
-    /* TODO perform op even if !successful. */
-    if (unlikely (!successful)) return;
-    if (unlikely (a > b || a == INVALID)) return;
-    dirty ();
-    unsigned int ma = get_major (a);
-    unsigned int mb = get_major (b);
-    /* Delete pages from ds through de if ds <= de. */
-    int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
-    int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
-    if (ds > de || (int) ma < ds)
-    {
-      page_t *page = page_for (a);
-      if (page)
-      {
-	if (ma == mb)
-	  page->del_range (a, b);
-	else
-	  page->del_range (a, major_start (ma + 1) - 1);
-      }
-    }
-    if (de < (int) mb && ma != mb)
-    {
-      page_t *page = page_for (b);
-      if (page)
-	page->del_range (major_start (mb), b);
-    }
-    del_pages (ds, de);
-  }
-
-  bool get (hb_codepoint_t g) const
-  {
-    const page_t *page = page_for (g);
-    if (!page)
-      return false;
-    return page->get (g);
-  }
-
   /* Has interface. */
   static constexpr bool SENTINEL = false;
   typedef bool value_t;
@@ -471,503 +100,49 @@
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
   /* Sink interface. */
-  hb_set_t& operator << (hb_codepoint_t v)
+  hb_sparseset_t& operator << (hb_codepoint_t v)
   { add (v); return *this; }
-  hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
   { add_range (range.first, range.second); return *this; }
 
   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
-  {
-    hb_codepoint_t c = first - 1;
-    return next (&c) && c <= last;
-  }
-  void set (const hb_set_t &other)
-  {
-    if (unlikely (!successful)) return;
-    unsigned int count = other.pages.length;
-    if (!resize (count))
-      return;
-    population = other.population;
+  { return s.intersects (first, last); }
 
-    hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
-    hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
-  }
+  void set (const hb_sparseset_t &other) { s.set (other.s); }
 
-  bool is_equal (const hb_set_t &other) const
-  {
-    if (get_population () != other.get_population ())
-      return false;
+  bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); }
 
-    unsigned int na = pages.length;
-    unsigned int nb = other.pages.length;
+  bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); }
 
-    unsigned int a = 0, b = 0;
-    for (; a < na && b < nb; )
-    {
-      if (page_at (a).is_empty ()) { a++; continue; }
-      if (other.page_at (b).is_empty ()) { b++; continue; }
-      if (page_map[a].major != other.page_map[b].major ||
-	  !page_at (a).is_equal (other.page_at (b)))
-	return false;
-      a++;
-      b++;
-    }
-    for (; a < na; a++)
-      if (!page_at (a).is_empty ()) { return false; }
-    for (; b < nb; b++)
-      if (!other.page_at (b).is_empty ()) { return false; }
+  void union_ (const hb_sparseset_t &other) { s.union_ (other.s); }
+  void intersect (const hb_sparseset_t &other) { s.intersect (other.s); }
+  void subtract (const hb_sparseset_t &other) { s.subtract (other.s); }
+  void symmetric_difference (const hb_sparseset_t &other) { s.symmetric_difference (other.s); }
 
-    return true;
-  }
-
-  bool is_subset (const hb_set_t &larger_set) const
-  {
-    /* TODO: Merge this and is_equal() into something like process(). */
-    if (unlikely(larger_set.is_empty ()))
-      return is_empty ();
-
-    uint32_t spi = 0;
-    for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
-    {
-      uint32_t spm = page_map[spi].major;
-      uint32_t lpm = larger_set.page_map[lpi].major;
-      auto sp = page_at (spi);
-      auto lp = larger_set.page_at (lpi);
-
-      if (spm < lpm && !sp.is_empty ())
-        return false;
-
-      if (lpm < spm)
-        continue;
-
-      if (!sp.is_subset (lp))
-        return false;
-
-      spi++;
-    }
-
-    while (spi < page_map.length)
-      if (!page_at (spi++).is_empty ())
-        return false;
-
-    return true;
-  }
-
-  bool allocate_compact_workspace(hb_vector_t<unsigned>& workspace)
-  {
-    if (unlikely(!workspace.resize (pages.length)))
-    {
-      successful = false;
-      return false;
-    }
-
-    return true;
-  }
-
-
-  /*
-   * workspace should be a pre-sized vector allocated to hold at exactly pages.length
-   * elements.
-   */
-  void compact (hb_vector_t<unsigned>& workspace,
-                unsigned int length)
-  {
-    assert(workspace.length == pages.length);
-    hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
-
-    hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
-    /* TODO(iter) Rewrite as dagger? */
-    for (unsigned i = 0; i < length; i++)
-      old_index_to_page_map_index[page_map[i].index] =  i;
-
-    compact_pages (old_index_to_page_map_index);
-  }
-
-  void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
-  {
-    unsigned int write_index = 0;
-    for (unsigned int i = 0; i < pages.length; i++)
-    {
-      if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
-
-      if (write_index < i)
-	pages[write_index] = pages[i];
-
-      page_map[old_index_to_page_map_index[i]].index = write_index;
-      write_index++;
-    }
-  }
-
-  template <typename Op>
-  void process (const Op& op, const hb_set_t &other)
-  {
-    const bool passthru_left = op (1, 0);
-    const bool passthru_right = op (0, 1);
-
-    if (unlikely (!successful)) return;
-
-    dirty ();
-
-    unsigned int na = pages.length;
-    unsigned int nb = other.pages.length;
-    unsigned int next_page = na;
-
-    unsigned int count = 0, newCount = 0;
-    unsigned int a = 0, b = 0;
-    unsigned int write_index = 0;
-
-    // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
-    // before attempting to rewrite the page map.
-    hb_vector_t<unsigned> compact_workspace;
-    if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
-
-    for (; a < na && b < nb; )
-    {
-      if (page_map[a].major == other.page_map[b].major)
-      {
-	if (!passthru_left)
-	{
-	  // Move page_map entries that we're keeping from the left side set
-	  // to the front of the page_map vector. This isn't necessary if
-	  // passthru_left is set since no left side pages will be removed
-	  // in that case.
-	  if (write_index < a)
-	    page_map[write_index] = page_map[a];
-	  write_index++;
-	}
-
-	count++;
-	a++;
-	b++;
-      }
-      else if (page_map[a].major < other.page_map[b].major)
-      {
-	if (passthru_left)
-	  count++;
-	a++;
-      }
-      else
-      {
-	if (passthru_right)
-	  count++;
-	b++;
-      }
-    }
-    if (passthru_left)
-      count += na - a;
-    if (passthru_right)
-      count += nb - b;
-
-    if (!passthru_left)
-    {
-      na  = write_index;
-      next_page = write_index;
-      compact (compact_workspace, write_index);
-    }
-
-    if (!resize (count))
-      return;
-
-    newCount = count;
-
-    /* Process in-place backward. */
-    a = na;
-    b = nb;
-    for (; a && b; )
-    {
-      if (page_map[a - 1].major == other.page_map[b - 1].major)
-      {
-	a--;
-	b--;
-	count--;
-	page_map[count] = page_map[a];
-	page_at (count).v = op (page_at (a).v, other.page_at (b).v);
-      }
-      else if (page_map[a - 1].major > other.page_map[b - 1].major)
-      {
-	a--;
-	if (passthru_left)
-	{
-	  count--;
-	  page_map[count] = page_map[a];
-	}
-      }
-      else
-      {
-	b--;
-	if (passthru_right)
-	{
-	  count--;
-	  page_map[count].major = other.page_map[b].major;
-	  page_map[count].index = next_page++;
-	  page_at (count).v = other.page_at (b).v;
-	}
-      }
-    }
-    if (passthru_left)
-      while (a)
-      {
-	a--;
-	count--;
-	page_map[count] = page_map [a];
-      }
-    if (passthru_right)
-      while (b)
-      {
-	b--;
-	count--;
-	page_map[count].major = other.page_map[b].major;
-	page_map[count].index = next_page++;
-	page_at (count).v = other.page_at (b).v;
-      }
-    assert (!count);
-    if (pages.length > newCount)
-      // This resize() doesn't need to be checked because we can't get here
-      // if the set is currently in_error() and this only resizes downwards
-      // which will always succeed if the set is not in_error().
-      resize (newCount);
-  }
-
-  void union_ (const hb_set_t &other)
-  {
-    process (hb_bitwise_or, other);
-  }
-  void intersect (const hb_set_t &other)
-  {
-    process (hb_bitwise_and, other);
-  }
-  void subtract (const hb_set_t &other)
-  {
-    process (hb_bitwise_sub, other);
-  }
-  void symmetric_difference (const hb_set_t &other)
-  {
-    process (hb_bitwise_xor, other);
-  }
-  bool next (hb_codepoint_t *codepoint) const
-  {
-    // TODO: this should be merged with prev() as both implementations
-    //       are very similar.
-    if (unlikely (*codepoint == INVALID)) {
-      *codepoint = get_min ();
-      return *codepoint != INVALID;
-    }
-
-    const auto* page_map_array = page_map.arrayZ;
-    unsigned int major = get_major (*codepoint);
-    unsigned int i = last_page_lookup;
-
-    if (unlikely (i >= page_map.length || page_map_array[i].major != major))
-    {
-      page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
-      if (i >= page_map.length) {
-        *codepoint = INVALID;
-        return false;
-      }
-    }
-
-    const auto* pages_array = pages.arrayZ;
-    const page_map_t &current = page_map_array[i];
-    if (likely (current.major == major))
-    {
-      if (pages_array[current.index].next (codepoint))
-      {
-        *codepoint += current.major * page_t::PAGE_BITS;
-        last_page_lookup = i;
-        return true;
-      }
-      i++;
-    }
-
-    for (; i < page_map.length; i++)
-    {
-      const page_map_t &current = page_map.arrayZ[i];
-      hb_codepoint_t m = pages_array[current.index].get_min ();
-      if (m != INVALID)
-      {
-	*codepoint = current.major * page_t::PAGE_BITS + m;
-        last_page_lookup = i;
-	return true;
-      }
-    }
-    last_page_lookup = 0;
-    *codepoint = INVALID;
-    return false;
-  }
-  bool previous (hb_codepoint_t *codepoint) const
-  {
-    if (unlikely (*codepoint == INVALID)) {
-      *codepoint = get_max ();
-      return *codepoint != INVALID;
-    }
-
-    page_map_t map = {get_major (*codepoint), 0};
-    unsigned int i;
-    page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.length && page_map[i].major == map.major)
-    {
-      if (pages[page_map[i].index].previous (codepoint))
-      {
-	*codepoint += page_map[i].major * page_t::PAGE_BITS;
-	return true;
-      }
-    }
-    i--;
-    for (; (int) i >= 0; i--)
-    {
-      hb_codepoint_t m = pages[page_map[i].index].get_max ();
-      if (m != INVALID)
-      {
-	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
-	return true;
-      }
-    }
-    *codepoint = INVALID;
-    return false;
-  }
+  bool next (hb_codepoint_t *codepoint) const { return s.next (codepoint); }
+  bool previous (hb_codepoint_t *codepoint) const { return s.previous (codepoint); }
   bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
-  {
-    hb_codepoint_t i;
-
-    i = *last;
-    if (!next (&i))
-    {
-      *last = *first = INVALID;
-      return false;
-    }
-
-    /* TODO Speed up. */
-    *last = *first = i;
-    while (next (&i) && i == *last + 1)
-      (*last)++;
-
-    return true;
-  }
+  { return s.next_range (first, last); }
   bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
-  {
-    hb_codepoint_t i;
+  { return s.previous_range (first, last); }
 
-    i = *first;
-    if (!previous (&i))
-    {
-      *last = *first = INVALID;
-      return false;
-    }
+  unsigned int get_population () const { return s.get_population (); }
+  hb_codepoint_t get_min () const { return s.get_min (); }
+  hb_codepoint_t get_max () const { return s.get_max (); }
 
-    /* TODO Speed up. */
-    *last = *first = i;
-    while (previous (&i) && i == *first - 1)
-      (*first)--;
+  static constexpr hb_codepoint_t INVALID = impl_t::INVALID;
 
-    return true;
-  }
-
-  unsigned int get_population () const
-  {
-    if (population != UINT_MAX)
-      return population;
-
-    unsigned int pop = 0;
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      pop += pages[i].get_population ();
-
-    population = pop;
-    return pop;
-  }
-  hb_codepoint_t get_min () const
-  {
-    unsigned int count = pages.length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!page_at (i).is_empty ())
-	return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
-    return INVALID;
-  }
-  hb_codepoint_t get_max () const
-  {
-    unsigned int count = pages.length;
-    for (int i = count - 1; i >= 0; i--)
-      if (!page_at (i).is_empty ())
-	return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max ();
-    return INVALID;
-  }
-
-  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
-
   /*
    * Iterator implementation.
    */
-  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
-  {
-    static constexpr bool is_sorted_iterator = true;
-    iter_t (const hb_set_t &s_ = Null (hb_set_t),
-	    bool init = true) : s (&s_), v (INVALID), l(0)
-    {
-      if (init)
-      {
-	l = s->get_population () + 1;
-	__next__ ();
-      }
-    }
-
-    typedef hb_codepoint_t __item_t__;
-    hb_codepoint_t __item__ () const { return v; }
-    bool __more__ () const { return v != INVALID; }
-    void __next__ () { s->next (&v); if (l) l--; }
-    void __prev__ () { s->previous (&v); }
-    unsigned __len__ () const { return l; }
-    iter_t end () const { return iter_t (*s, false); }
-    bool operator != (const iter_t& o) const
-    { return s != o.s || v != o.v; }
-
-    protected:
-    const hb_set_t *s;
-    hb_codepoint_t v;
-    unsigned l;
-  };
-  iter_t iter () const { return iter_t (*this); }
+  using iter_t = typename impl_t::iter_t;
+  iter_t iter () const { return iter_t (this->s); }
   operator iter_t () const { return iter (); }
+};
 
-  protected:
+struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> {};
 
-  page_t *page_for_insert (hb_codepoint_t g)
-  {
-    page_map_t map = {get_major (g), pages.length};
-    unsigned int i;
-    if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
-    {
-      if (!resize (pages.length + 1))
-	return nullptr;
+static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, "");
 
-      pages[map.index].init0 ();
-      memmove (page_map + i + 1,
-	       page_map + i,
-	       (page_map.length - 1 - i) * page_map.item_size);
-      page_map[i] = map;
-    }
-    return &pages[page_map[i].index];
-  }
-  page_t *page_for (hb_codepoint_t g)
-  {
-    page_map_t key = {get_major (g)};
-    const page_map_t *found = page_map.bsearch (key);
-    if (found)
-      return &pages[found->index];
-    return nullptr;
-  }
-  const page_t *page_for (hb_codepoint_t g) const
-  {
-    page_map_t key = {get_major (g)};
-    const page_map_t *found = page_map.bsearch (key);
-    if (found)
-      return &pages[found->index];
-    return nullptr;
-  }
-  page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
-  const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
-  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
-  hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
-};
 
-
 #endif /* HB_SET_HH */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-shape-plan.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -404,7 +404,7 @@
 
   buffer->assert_unicode ();
 
-  if (unlikely (hb_object_is_inert (shape_plan)))
+  if (unlikely (!hb_object_is_valid (shape_plan)))
     return false;
 
   assert (shape_plan->face_unsafe == font->face);
@@ -529,7 +529,7 @@
 retry:
   hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
 
-  bool dont_cache = hb_object_is_inert (face);
+  bool dont_cache = !hb_object_is_valid (face);
 
   if (likely (!dont_cache))
   {

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -45,18 +45,20 @@
   if (unlikely (!input))
     return nullptr;
 
-  input->unicodes = hb_set_create ();
-  input->glyphs = hb_set_create ();
-  input->name_ids = hb_set_create ();
-  hb_set_add_range (input->name_ids, 0, 6);
-  input->name_languages = hb_set_create ();
-  hb_set_add (input->name_languages, 0x0409);
-  input->layout_features = hb_set_create ();
-  input->drop_tables = hb_set_create ();
-  input->no_subset_tables = hb_set_create ();
+  for (auto& set : input->sets_iter ())
+    set = hb_set_create ();
 
+  if (input->in_error ())
+  {
+    hb_subset_input_destroy (input);
+    return nullptr;
+  }
+
   input->flags = HB_SUBSET_FLAGS_DEFAULT;
 
+  hb_set_add_range (input->sets.name_ids, 0, 6);
+  hb_set_add (input->sets.name_languages, 0x0409);
+
   hb_tag_t default_drop_tables[] = {
     // Layout disabled by default
     HB_TAG ('m', 'o', 'r', 'x'),
@@ -81,7 +83,7 @@
     HB_TAG ('S', 'i', 'l', 'f'),
     HB_TAG ('S', 'i', 'l', 'l'),
   };
-  input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
+  input->sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
 
   hb_tag_t default_no_subset_tables[] = {
     HB_TAG ('a', 'v', 'a', 'r'),
@@ -96,8 +98,8 @@
     HB_TAG ('c', 'v', 'a', 'r'),
     HB_TAG ('S', 'T', 'A', 'T'),
   };
-  input->no_subset_tables->add_array (default_no_subset_tables,
-				      ARRAY_LENGTH (default_no_subset_tables));
+  input->sets.no_subset_tables->add_array (default_no_subset_tables,
+                                         ARRAY_LENGTH (default_no_subset_tables));
 
   //copied from _layout_features_groups in fonttools
   hb_tag_t default_layout_features[] = {
@@ -186,7 +188,13 @@
     HB_TAG ('b', 'l', 'w', 'm'),
   };
 
-  input->layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
+  input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
+
+  if (input->in_error ())
+  {
+    hb_subset_input_destroy (input);
+    return nullptr;
+  }
   return input;
 }
 
@@ -220,13 +228,8 @@
 {
   if (!hb_object_destroy (input)) return;
 
-  hb_set_destroy (input->unicodes);
-  hb_set_destroy (input->glyphs);
-  hb_set_destroy (input->name_ids);
-  hb_set_destroy (input->name_languages);
-  hb_set_destroy (input->drop_tables);
-  hb_set_destroy (input->layout_features);
-  hb_set_destroy (input->no_subset_tables);
+  for (hb_set_t* set : input->sets_iter ())
+    hb_set_destroy (set);
 
   hb_free (input);
 }
@@ -246,7 +249,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_unicode_set (hb_subset_input_t *input)
 {
-  return input->unicodes;
+  return input->sets.unicodes;
 }
 
 /**
@@ -263,7 +266,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_glyph_set (hb_subset_input_t *input)
 {
-  return input->glyphs;
+  return input->sets.glyphs;
 }
 
 /**
@@ -280,7 +283,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_nameid_set (hb_subset_input_t *input)
 {
-  return input->name_ids;
+  return input->sets.name_ids;
 }
 
 /**
@@ -297,7 +300,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_namelangid_set (hb_subset_input_t *input)
 {
-  return input->name_languages;
+  return input->sets.name_languages;
 }
 
 
@@ -315,7 +318,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_layout_features_set (hb_subset_input_t *input)
 {
-  return input->layout_features;
+  return input->sets.layout_features;
 }
 
 /**
@@ -332,10 +335,27 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_drop_tables_set (hb_subset_input_t *input)
 {
-  return input->drop_tables;
+  return input->sets.drop_tables;
 }
 
 /**
+ * hb_subset_input_set:
+ * @input: a #hb_subset_input_t object.
+ * @set_type: a #hb_subset_sets_t set type.
+ *
+ * Gets the set of the specified type.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of the specified type.
+ *
+ * Since: 2.9.1
+ **/
+HB_EXTERN hb_set_t *
+hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type)
+{
+  return input->sets_iter () [set_type];
+}
+
+/**
  * hb_subset_input_no_subset_tables_set:
  * @input: a #hb_subset_input_t object.
  *
@@ -349,7 +369,7 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_no_subset_tables_set (hb_subset_input_t *input)
 {
-  return input->no_subset_tables;
+  return input->sets.no_subset_tables;
 }
 
 
@@ -357,6 +377,8 @@
  * hb_subset_input_get_flags:
  * @input: a #hb_subset_input_t object.
  *
+ * Gets all of the subsetting flags in the input object.
+ *
  * Return value: the subsetting flags bit field.
  *
  * Since: 2.9.0
@@ -372,8 +394,8 @@
  * @input: a #hb_subset_input_t object.
  * @value: bit field of flags
  *
- * Set all of the flags in the input object to the values
- * specified by the bit field.
+ * Sets all of the flags in the input object to the values specified by the bit
+ * field.
  *
  * Since: 2.9.0
  **/
@@ -437,21 +459,6 @@
 }
 
 void
-hb_subset_input_set_retain_all_features (hb_subset_input_t *subset_input,
-                                         hb_bool_t value)
-{
-  return set_flag_value (subset_input,
-                         HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
-                         value);
-}
-
-hb_bool_t
-hb_subset_input_get_retain_all_features (hb_subset_input_t *subset_input)
-{
-  return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES);
-}
-
-void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
 				hb_bool_t drop_hints)
 {

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-input.hh	2021-09-08 02:37:35 UTC (rev 60451)
@@ -31,6 +31,8 @@
 #include "hb.hh"
 
 #include "hb-subset.h"
+#include "hb-map.hh"
+#include "hb-set.hh"
 
 #include "hb-font.hh"
 
@@ -40,23 +42,40 @@
 {
   hb_object_header_t header;
 
-  hb_set_t *unicodes;
-  hb_set_t *glyphs;
-  hb_set_t *name_ids;
-  hb_set_t *name_languages;
-  hb_set_t *no_subset_tables;
-  hb_set_t *drop_tables;
-  hb_set_t *layout_features;
+  union {
+    struct {
+      hb_set_t *glyphs;
+      hb_set_t *unicodes;
+      hb_set_t *no_subset_tables;
+      hb_set_t *drop_tables;
+      hb_set_t *name_ids;
+      hb_set_t *name_languages;
+      hb_set_t *layout_features;
+    } sets;
+    hb_set_t* set_ptrs[sizeof (sets) / sizeof (hb_set_t*)];
+  };
 
   unsigned flags;
 
-  /* TODO
-   *
-   * features
-   * lookups
-   * name_ids
-   * ...
-   */
+  inline unsigned num_sets () const
+  {
+    return sizeof (set_ptrs) / sizeof (hb_set_t*);
+  }
+
+  inline hb_array_t<hb_set_t*> sets_iter ()
+  {
+    return hb_array_t<hb_set_t*> (set_ptrs, num_sets ());
+  }
+
+  bool in_error () const
+  {
+    for (unsigned i = 0; i < num_sets (); i++)
+    {
+      if (unlikely (set_ptrs[i]->in_error ()))
+        return true;
+    }
+    return false;
+  }
 };
 
 

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	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc	2021-09-08 02:37:35 UTC (rev 60451)
@@ -87,43 +87,49 @@
 #ifndef HB_NO_SUBSET_LAYOUT
 typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */);
 
-static void _collect_subset_layout (hb_face_t		 *face,
-				    hb_tag_t		  table_tag,
-				    const hb_set_t	 *layout_features_to_retain,
-				    bool		  retain_all_features,
-				    layout_collect_func_t layout_collect_func,
-				    hb_set_t		 *lookup_indices /* OUT */)
+
+template <typename T>
+static void _collect_layout_indices (hb_face_t		  *face,
+                                     const T&              table,
+                                     const hb_set_t	  *layout_features_to_retain,
+                                     layout_collect_func_t layout_collect_func,
+                                     hb_set_t		  *indices /* OUT */)
 {
-  if (retain_all_features)
+  hb_vector_t<hb_tag_t> features;
+  if (!features.alloc (table.get_feature_count () + 1))
+    return;
+
+  for (unsigned i = 0; i < table.get_feature_count (); i++)
   {
-    layout_collect_func (face,
-			 table_tag,
-			 nullptr,
-			 nullptr,
-			 nullptr,
-			 lookup_indices);
-    return;
+    hb_tag_t tag = table.get_feature_tag (i);
+    if (tag && layout_features_to_retain->has (tag))
+      features.push (tag);
   }
 
-  if (hb_set_is_empty (layout_features_to_retain)) return;
-  unsigned num = layout_features_to_retain->get_population () + 1;
-  hb_tag_t *features = (hb_tag_t *) hb_malloc (num * sizeof (hb_tag_t));
-  if (!features) return;
+  if (!features)
+    return;
 
-  unsigned i = 0;
-  for (hb_tag_t f : layout_features_to_retain->iter ())
-    features[i++] = f;
+  // The collect function needs a null element to signal end of the array.
+  features.push (0);
 
-  features[i] = 0;
+  if (features.get_size () == table.get_feature_count () + 1)
+  {
+    // Looking for all features, trigger the faster collection method.
+    layout_collect_func (face,
+                         T::tableTag,
+                         nullptr,
+                         nullptr,
+                         nullptr,
+                         indices);
+    return;
+  }
 
   layout_collect_func (face,
-		       table_tag,
+                       T::tableTag,
 		       nullptr,
 		       nullptr,
-		       features,
-		       lookup_indices);
-
-  hb_free (features);
+		       features.arrayZ,
+		       indices);
 }
 
 template <typename T>
@@ -131,7 +137,6 @@
 _closure_glyphs_lookups_features (hb_face_t	     *face,
 				  hb_set_t	     *gids_to_retain,
 				  const hb_set_t     *layout_features_to_retain,
-				  bool		      retain_all_features,
 				  hb_map_t	     *lookups,
 				  hb_map_t	     *features,
 				  script_langsys_map *langsys_map)
@@ -139,12 +144,11 @@
   hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
   hb_tag_t table_tag = table->tableTag;
   hb_set_t lookup_indices;
-  _collect_subset_layout (face,
-			  table_tag,
-			  layout_features_to_retain,
-			  retain_all_features,
-			  hb_ot_layout_collect_lookups,
-			  &lookup_indices);
+  _collect_layout_indices<T> (face,
+                              *table,
+                              layout_features_to_retain,
+                              hb_ot_layout_collect_lookups,
+                              &lookup_indices);
 
   if (table_tag == HB_OT_TAG_GSUB)
     hb_ot_layout_lookups_substitute_closure (face,
@@ -157,12 +161,11 @@
 
   // Collect and prune features
   hb_set_t feature_indices;
-  _collect_subset_layout (face,
-			  table_tag,
-			  layout_features_to_retain,
-			  retain_all_features,
-			  hb_ot_layout_collect_features,
-			  &feature_indices);
+  _collect_layout_indices<T> (face,
+                              *table,
+                              layout_features_to_retain,
+                              hb_ot_layout_collect_features,
+                              &feature_indices);
 
   table->prune_features (lookups, &feature_indices);
   hb_map_t duplicate_feature_map;
@@ -238,41 +241,58 @@
   OT::cmap::accelerator_t cmap;
   cmap.init (plan->source);
 
-  for (hb_codepoint_t cp : *unicodes)
+  constexpr static const int size_threshold = 4096;
+
+  if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
   {
-    hb_codepoint_t gid;
-    if (!cmap.get_nominal_glyph (cp, &gid))
+    /* This is the fast path if it's anticipated that size of unicodes
+     * is << than the number of codepoints in the font. */
+    for (hb_codepoint_t cp : *unicodes)
     {
-      DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-      continue;
+      hb_codepoint_t gid;
+      if (!cmap.get_nominal_glyph (cp, &gid))
+      {
+        DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+        continue;
+      }
+
+      plan->codepoint_to_glyph->set (cp, gid);
     }
-    plan->unicodes->add (cp);
-    plan->codepoint_to_glyph->set (cp, gid);
-    plan->_glyphset_gsub->add (gid);
   }
+  else
+  {
+    hb_map_t unicode_glyphid_map;
+    cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
 
-  if (glyphs->is_empty ())
-  {
-    cmap.fini ();
-    return;
+    for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
+	 + unicode_glyphid_map.iter ())
+    {
+      if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second))
+	continue;
+
+      plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
+    }
+
+    /* Add gids which where requested, but not mapped in cmap */
+    // TODO(garretrieger):
+    // Once https://github.com/harfbuzz/harfbuzz/issues/3169
+    // is implemented, this can be done with union and del_range
+    for (hb_codepoint_t gid : glyphs->iter ())
+    {
+      if (gid >= plan->source->get_num_glyphs ())
+	break;
+      plan->_glyphset_gsub->add (gid);
+    }
   }
 
-  hb_map_t unicode_glyphid_map;
-  cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
+  + plan->codepoint_to_glyph->keys ()   | hb_sink (plan->unicodes);
+  + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub);
+
   cmap.fini ();
-
-  for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
-       + unicode_glyphid_map.iter () | hb_filter (glyphs, hb_second))
-  {
-    plan->unicodes->add (cp_gid.first);
-    plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
-  }
 }
 
 static void
 _populate_gids_to_retain (hb_subset_plan_t* plan,
-			  const hb_set_t *unicodes,
-			  const hb_set_t *input_glyphs_to_retain,
 			  bool close_over_gsub,
 			  bool close_over_gpos,
 			  bool close_over_gdef)
@@ -289,7 +309,6 @@
   colr.init (plan->source);
 
   plan->_glyphset_gsub->add (0); // Not-def
-  hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
 
   _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
 
@@ -300,7 +319,6 @@
         plan->source,
         plan->_glyphset_gsub,
         plan->layout_features,
-        plan->flags & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
         plan->gsub_lookups,
         plan->gsub_features,
         plan->gsub_langsys);
@@ -310,7 +328,6 @@
         plan->source,
         plan->_glyphset_gsub,
         plan->layout_features,
-        plan->flags & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
         plan->gpos_lookups,
         plan->gpos_features,
         plan->gpos_langsys);
@@ -439,13 +456,13 @@
   plan->successful = true;
   plan->flags = input->flags;
   plan->unicodes = hb_set_create ();
-  plan->name_ids = hb_set_copy (input->name_ids);
+  plan->name_ids = hb_set_copy (input->sets.name_ids);
   _nameid_closure (face, plan->name_ids);
-  plan->name_languages = hb_set_copy (input->name_languages);
-  plan->layout_features = hb_set_copy (input->layout_features);
-  plan->glyphs_requested = hb_set_copy (input->glyphs);
-  plan->drop_tables = hb_set_copy (input->drop_tables);
-  plan->no_subset_tables = hb_set_copy (input->no_subset_tables);
+  plan->name_languages = hb_set_copy (input->sets.name_languages);
+  plan->layout_features = hb_set_copy (input->sets.layout_features);
+  plan->glyphs_requested = hb_set_copy (input->sets.glyphs);
+  plan->drop_tables = hb_set_copy (input->sets.drop_tables);
+  plan->no_subset_tables = hb_set_copy (input->sets.no_subset_tables);
   plan->source = hb_face_reference (face);
   plan->dest = hb_face_builder_create ();
 
@@ -473,14 +490,12 @@
     return plan;
   }
 
-  _populate_unicodes_to_retain (input->unicodes, input->glyphs, plan);
+  _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
 
   _populate_gids_to_retain (plan,
-			    input->unicodes,
-			    input->glyphs,
-			    !input->drop_tables->has (HB_OT_TAG_GSUB),
-			    !input->drop_tables->has (HB_OT_TAG_GPOS),
-			    !input->drop_tables->has (HB_OT_TAG_GDEF));
+			    !input->sets.drop_tables->has (HB_OT_TAG_GSUB),
+			    !input->sets.drop_tables->has (HB_OT_TAG_GPOS),
+			    !input->sets.drop_tables->has (HB_OT_TAG_GDEF));
 
   _create_old_gid_to_new_gid_map (face,
                                   input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.h	2021-09-08 02:37:35 UTC (rev 60451)
@@ -61,10 +61,6 @@
  * in the final subset.
  * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
  * OS/2 will not be recalculated.
- * @HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES: If set all layout features will be
- * retained. If unset then the set accessed by
- * hb_subset_input_layout_features_set() will be used to determine the features
- * to be retained.
  *
  * List of boolean properties that can be configured on the subset input.
  *
@@ -81,9 +77,35 @@
   HB_SUBSET_FLAGS_NOTDEF_OUTLINE =	     0x00000040u,
   HB_SUBSET_FLAGS_GLYPH_NAMES =		     0x00000080u,
   HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES =  0x00000100u,
-  HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES =	     0x00000200u,
 } hb_subset_flags_t;
 
+/**
+ * hb_subset_sets_t:
+ * HB_SUBSET_SETS_GLYPH_INDEX: the set of glyph indexes to retain in the subset.
+ * HB_SUBSET_SETS_UNICODE: the set of unicode codepoints to retain in the subset.
+ * @HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG: the set of table tags which specifies tables that should not be
+ * subsetted.
+ * @HB_SUBSET_SETS_DROP_TABLE_TAG: the set of table tags which specifies tables which will be dropped
+ * in the subset.
+ * @HB_SUBSET_SETS_NAME_ID: the set of name ids that will be retained.
+ * @HB_SUBSET_SETS_NAME_LANG_ID: the set of name lang ids that will be retained.
+ * @HB_SUBSET_SETS_LAYOUT_FEATURE_TAG: the set of layout feature tags that will be retained
+ * in the subset.
+ *
+ * List of sets that can be configured on the subset input.
+ *
+ * Since: 2.9.1
+ **/
+typedef enum {
+  HB_SUBSET_SETS_GLYPH_INDEX = 0,
+  HB_SUBSET_SETS_UNICODE,
+  HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG,
+  HB_SUBSET_SETS_DROP_TABLE_TAG,
+  HB_SUBSET_SETS_NAME_ID,
+  HB_SUBSET_SETS_NAME_LANG_ID,
+  HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
+} hb_subset_sets_t;
+
 HB_EXTERN hb_subset_input_t *
 hb_subset_input_create_or_fail (void);
 
@@ -125,6 +147,9 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_drop_tables_set (hb_subset_input_t *input);
 
+HB_EXTERN hb_set_t *
+hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type);
+
 HB_EXTERN hb_subset_flags_t
 hb_subset_input_get_flags (hb_subset_input_t *input);
 
@@ -143,12 +168,6 @@
  */
 
 HB_EXTERN void
-hb_subset_input_set_retain_all_features (hb_subset_input_t *subset_input,
-                                         hb_bool_t value);
-HB_EXTERN hb_bool_t
-hb_subset_input_get_retain_all_features (hb_subset_input_t *subset_input);
-
-HB_EXTERN void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
 				hb_bool_t drop_hints);
 HB_EXTERN hb_bool_t

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2021-09-08 02:37:35 UTC (rev 60451)
@@ -25,6 +25,7 @@
   'hb-array.hh',
   'hb-atomic.hh',
   'hb-bimap.hh',
+  'hb-bit-page.hh',
   'hb-blob.cc',
   'hb-blob.hh',
   'hb-buffer-serialize.cc',

Modified: trunk/Build/source/libs/harfbuzz/version.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/version.ac	2021-09-07 23:48:19 UTC (rev 60450)
+++ trunk/Build/source/libs/harfbuzz/version.ac	2021-09-08 02:37:35 UTC (rev 60451)
@@ -8,4 +8,4 @@
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current harfbuzz version
-m4_define([harfbuzz_version], [2.9.0])
+m4_define([harfbuzz_version], [2.9.1])



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