texlive[61290] Build/source/libs: harfbuzz 3.2.0

commits+kakuto at tug.org commits+kakuto at tug.org
Mon Dec 13 00:55:44 CET 2021


Revision: 61290
          http://tug.org/svn/texlive?view=revision&revision=61290
Author:   kakuto
Date:     2021-12-13 00:55:43 +0100 (Mon, 13 Dec 2021)
Log Message:
-----------
harfbuzz 3.2.0

Modified Paths:
--------------
    trunk/Build/source/libs/README
    trunk/Build/source/libs/harfbuzz/ChangeLog
    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/CONFIG.md
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-tag-table.py
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-fallback-shape.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.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-colr-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-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-layout.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math-table.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc
    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-repacker.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-uniscribe.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc
    trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc
    trunk/Build/source/libs/harfbuzz/version.ac

Modified: trunk/Build/source/libs/README
===================================================================
--- trunk/Build/source/libs/README	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/README	2021-12-12 23:55:43 UTC (rev 61290)
@@ -26,8 +26,8 @@
   http://sourceforge.net/projects/silgraphite/files/graphite2/
   (requires C++11)
 
-harfbuzz 3.1.2 - checked 27nov21
-  https://github.com/harfbuzz/harfbuzz/releases/download/3.1.2/
+harfbuzz 3.2.0 - checked 13dec21
+  https://github.com/harfbuzz/harfbuzz/releases/download/3.2.0/
 
 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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/ChangeLog	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,3 +1,8 @@
+2021-12-13  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Import harfbuzz-3.2.0.
+	* version.ac: Adjusted.
+
 2021-11-27  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Import harfbuzz-3.1.2.

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/ChangeLog	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,3 +1,8 @@
+2021-12-13  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
+
+	Imported harfbuzz-3.2.0 source tree from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/3.2.0/
+
 2021-11-27  Akira Kakuto  <kakuto at jcom.zaq.ne.jp>
 
 	Imported harfbuzz-3.1.2 source tree from:

Modified: trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes
===================================================================
--- trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/TLpatches/TL-Changes	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,5 +1,5 @@
-Changes applied to the harfbuzz-3.1.2/ tree as obtained from:
-	https://github.com/harfbuzz/harfbuzz/releases/download/3.1.2/
+Changes applied to the harfbuzz-3.2.0/ tree as obtained from:
+	https://github.com/harfbuzz/harfbuzz/releases/download/3.2.0/
 
 Removed:
 	COPYING

Modified: trunk/Build/source/libs/harfbuzz/configure
===================================================================
--- trunk/Build/source/libs/harfbuzz/configure	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/configure	2021-12-12 23:55:43 UTC (rev 61290)
@@ -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) 3.1.2.
+# Generated by GNU Autoconf 2.71 for harfbuzz (TeX Live) 3.2.0.
 #
 # 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='3.1.2'
-PACKAGE_STRING='harfbuzz (TeX Live) 3.1.2'
+PACKAGE_VERSION='3.2.0'
+PACKAGE_STRING='harfbuzz (TeX Live) 3.2.0'
 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) 3.1.2 to adapt to many kinds of systems.
+\`configure' configures harfbuzz (TeX Live) 3.2.0 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) 3.1.2:";;
+     short | recursive ) echo "Configuration of harfbuzz (TeX Live) 3.2.0:";;
    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 3.1.2
+harfbuzz (TeX Live) configure 3.2.0
 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 3.1.2, which was
+It was created by harfbuzz (TeX Live) $as_me 3.2.0, 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='3.1.2'
+ VERSION='3.2.0'
 
 
 # Some tools Automake needs.
@@ -5034,9 +5034,9 @@
 
 
 HB_VERSION_MAJOR=3
-HB_VERSION_MINOR=1
-HB_VERSION_MICRO=2
-HB_VERSION=3.1.2
+HB_VERSION_MINOR=2
+HB_VERSION_MICRO=0
+HB_VERSION=3.2.0
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -8817,7 +8817,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by harfbuzz (TeX Live) $as_me 3.1.2, which was
+This file was extended by harfbuzz (TeX Live) $as_me 3.2.0, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8885,7 +8885,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-harfbuzz (TeX Live) config.status 3.1.2
+harfbuzz (TeX Live) config.status 3.2.0
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/CONFIG.md
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/CONFIG.md	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/CONFIG.md	2021-12-12 23:55:43 UTC (rev 61290)
@@ -135,12 +135,19 @@
 Most of the time, one of the pre-defined configuration is exactly what one needs.
 Sometimes, however, the pre-defined configuration cuts out features that might
 be desired in the library.  Unfortunately there is no quick way to undo those
-configurations from the command-line.  But one can add a header file called
-`config-override.h` to undefine certain `HB_NO_*` symbols as desired.  Then
-define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
-overrides at the end.
+configurations from the command-line.
 
+However, configuration can still be overridden from a file.  To do that, add your
+override instructions (mostly `undef` instructions) to a header file and define
+the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's
+name.  HarfBuzz will then include that file at appropriate right place during
+configuration.
 
+Up until HarfBuzz 3.1.2 the the configuration override header file's name was
+fixed and called `config-override.h`, and was activated by defining the macro
+`HAVE_CONFIG_OVERRIDE_H`.  That still works.
+
+
 ## Notes
 
 Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/ChangeLog	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,3 +1,602 @@
+commit be91d2917d9860326cb5fd1d03ffe1042a72f6d3
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Sun Dec 12 04:45:54 2021 +0200
+
+    3.2.0
+
+ NEWS             | 16 ++++++++++++++++
+ configure.ac     |  2 +-
+ meson.build      |  2 +-
+ src/hb-version.h |  6 +++---
+ 4 files changed, 21 insertions(+), 5 deletions(-)
+
+commit 77507a1d8d872d8cd4f62b807e933cd3e2cdb110
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Dec 10 14:10:04 2021 -0800
+
+    [subset] Don't double count visit lookups in closure_lookups
+    
+    Each recursed lookup was getting counted once in closure_lookups() and then again in hb_closure_lookups_context_t::recurse.
+
+ src/hb-ot-layout-gsubgpos.hh | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+commit d67025705f0c4993cdd756bc47d942e14ceed0a1
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Dec 10 13:52:05 2021 -0800
+
+    [subset] reset the visited lookup count before each closure iteration.
+
+ src/hb-ot-layout-gsubgpos.hh | 3 +++
+ src/hb-ot-layout.cc          | 1 +
+ 2 files changed, 4 insertions(+)
+
+commit 23159084b43c1ce429d9e98035bf845919fd8a89
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 15:00:16 2021 -0700
+
+    [morx] Reverse graphemese, not whole buffer
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3314
+    Supersedes https://github.com/harfbuzz/harfbuzz/pull/3315
+
+ src/hb-aat-layout-morx-table.hh            |  4 ++--
+ src/hb-ot-layout.hh                        |  6 ++++++
+ src/hb-ot-shape.cc                         | 15 +--------------
+ test/shape/data/in-house/tests/macos.tests |  3 +++
+ 4 files changed, 12 insertions(+), 16 deletions(-)
+
+commit 5b995526f7d0d1e688f68005b410a93cf1685544
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 14:59:56 2021 -0700
+
+    [buffer] Fix reverse_group() to reverse() at the end
+
+ src/hb-buffer.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 21c4fc1011854547edf564573fdbec4687e76e04
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 13:02:43 2021 -0700
+
+    [buffer] Add optional merge_clusters arg to reverse_groups()
+
+ src/hb-buffer.hh | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit e949e512181d04da1add14f6133a6d68f7a60fc2
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 12:58:27 2021 -0700
+
+    [ot-layout] Port foreach_grapheme to buffer foreach_group
+
+ src/hb-ot-layout.hh | 22 ++++++----------------
+ 1 file changed, 6 insertions(+), 16 deletions(-)
+
+commit eb96e69d18aa45a623c05bf69e562b3918724f6f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 12:55:29 2021 -0700
+
+    [buffer] Add foreach_group()
+
+ src/hb-buffer.hh | 40 ++++++++++++++++++++--------------------
+ 1 file changed, 20 insertions(+), 20 deletions(-)
+
+commit 1b78e04c78338266c200226bccb21188355046ca
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 12:45:43 2021 -0700
+
+    [buffer] Add ::reverse_groups()
+
+ src/hb-buffer.cc | 23 -----------------------
+ src/hb-buffer.hh | 26 +++++++++++++++++++++++++-
+ 2 files changed, 25 insertions(+), 24 deletions(-)
+
+commit 4cd96e73e40acfa65b7d0726a7186bf31c169b2a
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 10 12:33:21 2021 -0700
+
+    [buffer] Inline revers_range() / reverse()
+
+ src/hb-buffer.cc | 23 -----------------------
+ src/hb-buffer.hh | 10 ++++++++--
+ 2 files changed, 8 insertions(+), 25 deletions(-)
+
+commit 5914acb3cbb3634e9e94e0e571d96b806b7ecacf
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Dec 10 10:05:47 2021 -0800
+
+    [repacker] Clear distance and position cache when assigning a new space.
+    
+    A change in space will effect the distance assigned to the node and any of it's children so clear the distance cache.
+
+ src/hb-repacker.hh | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 706014f69dc2cde140e17faf32d32a1cbd5d0000
+Author: Qunxin Liu <qxliu at google.com>
+Date:   Wed Dec 1 20:20:12 2021 -0800
+
+    [subset] (Chain)ContextSubst glyph_closure fix
+    
+    - When pos_glyphs is empty, use current full glyphs set as input for
+    subsequent recursive closure process
+    - Also increase max_lookup_visit_count to 35000 cause a real font file hit
+    previous limit 20000 and some lookups are dropped unexpectedly
+
+ src/hb-ot-layout-common.hh                         |   6 +++---
+ src/hb-ot-layout-gsubgpos.hh                       |  24 +++++++++++++--------
+ ...Bold.default.627,644,623,62D,644,627,645,2E.ttf | Bin 11372 -> 19032 bytes
+ ...toNastaliqUrdu-Bold.default.627,644,62D,628.ttf | Bin 17640 -> 25608 bytes
+ .../NotoNastaliqUrdu-Bold.default.627,644.ttf      | Bin 3512 -> 8040 bytes
+ ...rdu-Bold.default.633,645,627,621,20,644,627.ttf | Bin 12360 -> 22776 bytes
+ .../NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf  | Bin 19340 -> 27772 bytes
+ ...taliqUrdu-Bold.default.retain-all-codepoint.ttf | Bin 0 -> 543364 bytes
+ ....retain-gids.627,644,623,62D,644,627,645,2E.ttf | Bin 18208 -> 25868 bytes
+ ...staliqUrdu-Bold.retain-gids.627,644,62D,628.ttf | Bin 23704 -> 31676 bytes
+ .../NotoNastaliqUrdu-Bold.retain-gids.627,644.ttf  | Bin 9160 -> 13688 bytes
+ ...Bold.retain-gids.633,645,627,621,20,644,627.ttf | Bin 18164 -> 28580 bytes
+ ...toNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf | Bin 25392 -> 33824 bytes
+ ...qUrdu-Bold.retain-gids.retain-all-codepoint.ttf | Bin 0 -> 543364 bytes
+ test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf   | Bin 459600 -> 589224 bytes
+ .../data/tests/layout.notonastaliqurdu.tests       |   1 +
+ 16 files changed, 19 insertions(+), 12 deletions(-)
+
+commit 441877f56aa09bc848a8860007232a7be5e179d9
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Dec 9 16:38:05 2021 -0800
+
+    [repacker] add test case for using max priority to resolve an overflow.
+
+ src/test-repacker.cc | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+commit be2c488e5d20db18e3ee82dee6a22056ed526add
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Dec 9 15:44:06 2021 -0800
+
+    [repacker] Improve vertex priority packing.
+    
+    Previous priority implementation would move a node further back within it's layer, but at max priority was unable to move any further up than that. This updates the implementation to have 3 priority levels:
+    1. Distance is reduced by half of table size.
+    2. Distance is reduced by full table size (move to beginning of the layer).
+    3. Distance is set to 0. Vertex will be packed as soon as possible.
+    
+    Also makes the iterative resolutions aware of max priority, so it won't keep trying to raise priority beyond the maximum.
+
+ src/hb-repacker.hh | 38 +++++++++++++++++++++++++++++---------
+ 1 file changed, 29 insertions(+), 9 deletions(-)
+
+commit 2404617a605cd8c419fe67afa012ddc90a24c685
+Author: David Corbett <corbett.dav at northeastern.edu>
+Date:   Wed Dec 8 21:10:22 2021 -0500
+
+    Update language system tag registry to OT 1.9
+
+ src/gen-tag-table.py   | 11 +++++++++--
+ src/hb-ot-tag-table.hh | 14 +++++++++++++-
+ 2 files changed, 22 insertions(+), 3 deletions(-)
+
+commit 002a1f70b81d56b882bd5a68ebdc22c015e88f7f
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Dec 8 10:45:30 2021 -0800
+
+    [ft] Disable vertical funcs if HB_NO_VERTICAL
+
+ src/hb-ft.cc | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+commit ef14cad736e499f42281e09d3835ad667245e4be
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Dec 8 10:43:52 2021 -0800
+
+    [GPOS] Disable vertical advance if HB_NO_VERTICAL
+
+ src/hb-ot-layout-gpos-table.hh | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 6ed22de1279f7e68666bd9f024a80a4a48a1a467
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Dec 8 10:40:40 2021 -0800
+
+    [CONFIG] Fix HB_NO_VERTICAL build without HB_TINY
+
+ src/hb-ot-glyf-table.hh | 12 ++++++++++--
+ src/hb-ot-metrics.cc    |  2 ++
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+commit 53eebc7cd2680a41c3e7c7ac363b7ecc1355d655
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Dec 8 08:32:41 2021 -0800
+
+    [CONFIG] Add HB_NO_VERTICAL
+
+ src/hb-ot-face-table-list.hh |  2 ++
+ src/hb-ot-font.cc            | 18 +++++++++++++++---
+ src/hb-ot-glyf-table.hh      | 25 ++++++++++++++++++++++---
+ src/hb-ot-hmtx-table.hh      |  9 ++++++++-
+ src/hb-ot-metrics.cc         |  5 +++++
+ src/hb-ot-shape.cc           |  4 ++++
+ 6 files changed, 56 insertions(+), 7 deletions(-)
+
+commit 9bc5d2903a6c1669a3bd8aa47f42d34c6bbcf763
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Wed Dec 8 08:16:17 2021 -0800
+
+    [TINY] Don't disable VORG table in any config profile
+    
+    Is needed for vertical layout of CFF fonts.
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/discussions/3294#discussioncomment-1770313
+
+ src/hb-ot-face-table-list.hh | 2 +-
+ src/hb-ot-font.cc            | 2 --
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+commit 3e4a25098df348c459f57829d84c4b0ebb3efc97
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Dec 6 16:00:15 2021 -0800
+
+    [repacker] add a maximum number of roots that can be moved in one iteration.
+    
+    Set to half of the roots in a space. This prevents the repacker from moving all roots in a space to a new space if their are overflows in every root.
+
+ src/hb-repacker.hh | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+commit 02b12d7965710de93fa4b42617113e66ddf19add
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Dec 6 15:23:35 2021 -0800
+
+    [repacker] Move all overflowing roots to a new space simultaneously.
+
+ src/hb-repacker.hh | 69 +++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 47 insertions(+), 22 deletions(-)
+
+commit fa966bcc29e84a579fc32af7663a50bfe7814b1a
+Author: Garret Rieger <grieger at google.com>
+Date:   Mon Dec 6 12:54:19 2021 -0800
+
+    [repacker] create repacker output buffer after final length is known.
+    
+    Don't rely on a buffer provided by the caller, as it may not be large enough.
+
+ src/hb-repacker.hh   | 60 ++++++++++++++++++++++++++----------
+ src/hb-subset.cc     | 18 +++++------
+ src/test-repacker.cc | 87 ++++++++++++++++++----------------------------------
+ 3 files changed, 80 insertions(+), 85 deletions(-)
+
+commit 51655a078e599c532b739c1e58556d873dabf6b0
+Author: Qunxin Liu <qxliu at google.com>
+Date:   Sun Dec 5 19:27:57 2021 -0800
+
+    [subset] COLR : only include glyphs after COLR closure
+
+ src/hb-ot-color-colr-table.hh                         |  18 ++++++++++++------
+ src/hb-subset-plan.cc                                 |   4 +++-
+ src/hb-subset-plan.hh                                 |   1 +
+ test/subset/data/Makefile.am                          |   1 +
+ test/subset/data/Makefile.sources                     |   1 +
+ .../colr_glyphs/BungeeColor-Regular.default.41.ttf    | Bin 0 -> 1664 bytes
+ .../BungeeColor-Regular.drop-hints-retain-gids.41.ttf | Bin 0 -> 3384 bytes
+ .../colr_glyphs/BungeeColor-Regular.drop-hints.41.ttf | Bin 0 -> 1656 bytes
+ .../BungeeColor-Regular.retain-gids.41.ttf            | Bin 0 -> 3392 bytes
+ test/subset/data/fonts/BungeeColor-Regular.ttf        | Bin 0 -> 75348 bytes
+ test/subset/data/tests/colr_glyphs.tests              |  11 +++++++++++
+ test/subset/meson.build                               |   1 +
+ 12 files changed, 30 insertions(+), 7 deletions(-)
+
+commit 70f8c57e5c72697bdd2dc84b3573e1e90a94d681
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sat Dec 4 19:49:23 2021 -0800
+
+    [buffer] Rename find_min_cluster
+
+ src/hb-buffer.cc | 7 ++++---
+ src/hb-buffer.hh | 8 ++++----
+ 2 files changed, 8 insertions(+), 7 deletions(-)
+
+commit 94d43c008ab4ec2281b693af1f4014b1ebce1b14
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Sat Dec 4 16:56:39 2021 -0800
+
+    [buffer] Merge and rename clear_glyph_flags()
+
+ src/hb-buffer.hh               | 5 ++---
+ src/hb-coretext.cc             | 2 +-
+ src/hb-directwrite.cc          | 2 +-
+ src/hb-fallback-shape.cc       | 2 +-
+ src/hb-graphite2.cc            | 2 +-
+ src/hb-ot-layout-gsub-table.hh | 2 +-
+ src/hb-uniscribe.cc            | 2 +-
+ 7 files changed, 8 insertions(+), 9 deletions(-)
+
+commit b95d252fabca73ded3c7529ba726499ec6dcda5d
+Author: Behdad Esfahbod <behdad at behdad.org>
+Date:   Fri Dec 3 11:49:55 2021 -0700
+
+    [CONFIG] Add HB_CONFIG_OVERRIDE_H to simplify config overrides
+
+ CONFIG.md        | 15 +++++++++++----
+ src/hb-config.hh |  7 +++++--
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+commit 74b46b29e7ebb8521fdbf92325a3798083381237
+Author: Qunxin Liu <qxliu at google.com>
+Date:   Thu Dec 2 19:50:16 2021 -0800
+
+    [subset] MATH: don't serialize coverage table when iterator is empty
+    
+    when iterator is empty, just set coverage offset to 0.
+    serialize() in coverage will at lease write out a 16-bit format header.
+
+ src/hb-ot-math-table.hh                                |  10 +++++++---
+ test/subset/data/Makefile.am                           |   1 +
+ test/subset/data/Makefile.sources                      |   1 +
+ .../Caudex-Regular.default.retain-all-codepoint.ttf    | Bin 0 -> 417604 bytes
+ ...Caudex-Regular.glyph-names.retain-all-codepoint.ttf | Bin 0 -> 436712 bytes
+ ...r.keep-all-layout-features.retain-all-codepoint.ttf | Bin 0 -> 417604 bytes
+ ...dex-Regular.notdef-outline.retain-all-codepoint.ttf | Bin 0 -> 417780 bytes
+ ...Caudex-Regular.retain-gids.retain-all-codepoint.ttf | Bin 0 -> 417620 bytes
+ test/subset/data/fonts/Caudex-Regular.ttf              | Bin 0 -> 466324 bytes
+ test/subset/data/tests/math_coverage_offset.tests      |  12 ++++++++++++
+ test/subset/meson.build                                |   1 +
+ 11 files changed, 22 insertions(+), 3 deletions(-)
+
+commit 1d9ef3a75a445a52d084e805d4abdbaaa4c782d7
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Dec 1 10:30:27 2021 -0800
+
+    [subset] Actually fix end_cp unitialized warning.
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit d8635dfe5a06d1112ea563dcef788097b7b124af
+Author: Garret Rieger <grieger at google.com>
+Date:   Wed Dec 1 10:14:10 2021 -0800
+
+    [subset] Fix warning about uninitialized use of end_cp.
+
+ src/hb-ot-cmap-table.hh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 6c81cd9543f35cbc54e938b402355990a3b0859c
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Dec 1 19:29:34 2021 +0200
+
+    [tests] Add tests for platform shapers
+    
+    Fixes https://github.com/harfbuzz/harfbuzz/issues/3115
+
+ test/shape/data/in-house/meson.build             | 14 +++++++++++++-
+ test/shape/data/in-house/tests/coretext.tests    |  1 +
+ test/shape/data/in-house/tests/directwrite.tests |  1 +
+ test/shape/data/in-house/tests/uniscribe.tests   |  1 +
+ test/shape/meson.build                           | 11 +++++++++++
+ 5 files changed, 27 insertions(+), 1 deletion(-)
+
+commit 7608b191672972efdc69ce49c22001346f5470c0
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Dec 1 18:57:21 2021 +0200
+
+    [directwrite] Set unsafe to break flag
+    
+    Like the rest of platform shapers. Otherwise hb-shape --verify goes
+    crazy.
+
+ src/hb-directwrite.cc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 361a438658dcddea29d7c8b9c68bf2bc88109bde
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Dec 1 03:16:46 2021 +0200
+
+    Revert "Revert "[hb-directwrite] Don't load dwrit.dll dynamically""
+    
+    This reverts commit ecbe224743c205c99aa459b27e7fb241cc4b1dc5.
+    
+    It was causing directwrite shaper to crash in MSVC builds.
+
+ src/hb-directwrite.cc | 36 ++----------------------------------
+ 1 file changed, 2 insertions(+), 34 deletions(-)
+
+commit 549e2b7038282e34f83b54b36fabf02de0cbfcae
+Author: Khaled Hosny <khaled at aliftype.com>
+Date:   Wed Dec 1 03:16:26 2021 +0200
+
+    Revert "Remove direct link to dwrite from meson scripts"
+    
+    This reverts commit 6ea6c581edb3cecf1b4b42854e37b40d6d067cd3.
+
+ meson.build     | 7 ++++++-
+ src/meson.build | 1 +
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+commit 071aea42c28e84e89b550de03cbd0094382f634c
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Nov 30 16:16:06 2021 -0800
+
+    [iter] add specialized implementation for hb_concat forward when iterators are not random access.
+
+ src/hb-iter.hh   | 20 +++++++++++++++-----
+ src/test-iter.cc | 19 +++++++++++++++++++
+ 2 files changed, 34 insertions(+), 5 deletions(-)
+
+commit 2e935514d9790f6f8a7f6639c9564b3d7237d6d3
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Nov 30 16:02:05 2021 -0800
+
+    [iter] fix forward implementation in hb_concat().
+    
+    Add test coverage for forward.
+
+ src/hb-iter.hh   |  6 ++++--
+ src/test-iter.cc | 22 ++++++++++++++++++++++
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+commit 39e76af19ed6ab798d4671ff3e7a4b71e2abe6cf
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Nov 30 15:25:40 2021 -0800
+
+    [subset] add all_links () to object_t.
+    
+    Helper to provide easy access to concatenated real and virtual links iterator.
+
+ src/hb-repacker.hh  | 44 +++++++++++++++-----------------------------
+ src/hb-serialize.hh |  5 +++++
+ 2 files changed, 20 insertions(+), 29 deletions(-)
+
+commit 9121ed0cecab2296ee2a18042ed89c0ce95dbbaa
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Nov 30 13:45:22 2021 -0800
+
+    [subset] Improve sharing of Ligature subtables.
+    
+    Ligature subtables use virtual links to enforce an ordering constraint between the subtables and the coverage table. Unfortunately this has the sideeffect of prevent the subtables from being shared by another Ligature with a different coverage table since object equality compares all links real and virtual. This change makes virtual links stored separately from real links and updates the equality check to only check real links. If an object is de-duped any virtual links it has are merged into the object that replaces it.
+
+ src/hb-repacker.hh                                 |  84 +++++++-----
+ src/hb-serialize.hh                                |  50 ++++---
+ src/test-repacker.cc                               | 150 +++++++++++++--------
+ ...ic-Regular.layout-test.retain-all-codepoint.ttf | Bin 46544 -> 46524 bytes
+ ...Howrah-Regular.default.retain-all-codepoint.ttf | Bin 174024 -> 173756 bytes
+ ...rah-Regular.drop-hints.retain-all-codepoint.ttf | Bin 99288 -> 99020 bytes
+ ...ah-Regular.retain-gids.retain-all-codepoint.ttf | Bin 174324 -> 174056 bytes
+ ...toNastaliqUrdu-Bold.default.627,644,62D,628.ttf | Bin 17732 -> 17640 bytes
+ .../NotoNastaliqUrdu-Bold.default.63A,64A,631.ttf  | Bin 19432 -> 19340 bytes
+ ...staliqUrdu-Bold.retain-gids.627,644,62D,628.ttf | Bin 23792 -> 23704 bytes
+ ...toNastaliqUrdu-Bold.retain-gids.63A,64A,631.ttf | Bin 25484 -> 25392 bytes
+ ...hnadevaraya-Regular.default.c30,c36,c40,c4d.ttf | Bin 10860 -> 10848 bytes
+ ...varaya-Regular.default.retain-all-codepoint.ttf | Bin 572812 -> 572104 bytes
+ ...evaraya-Regular.glyph-names.c30,c36,c40,c4d.ttf | Bin 11292 -> 11280 bytes
+ ...ya-Regular.glyph-names.retain-all-codepoint.ttf | Bin 608460 -> 607752 bytes
+ ...raya-Regular.notdef-outline.c30,c36,c40,c4d.ttf | Bin 10940 -> 10928 bytes
+ ...Regular.notdef-outline.retain-all-codepoint.ttf | Bin 572892 -> 572184 bytes
+ ...evaraya-Regular.retain-gids.c30,c36,c40,c4d.ttf | Bin 16880 -> 16868 bytes
+ ...ya-Regular.retain-gids.retain-all-codepoint.ttf | Bin 572824 -> 572116 bytes
+ 19 files changed, 181 insertions(+), 103 deletions(-)
+
+commit ca227411102b615edb40a78d2355d2f6cf5291c5
+Author: Garret Rieger <grieger at google.com>
+Date:   Tue Nov 30 12:53:15 2021 -0800
+
+    [iter] add hb_concat (a, b).
+    
+    Iterates over a, and then over b.
+
+ src/hb-iter.hh   | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/test-iter.cc | 33 +++++++++++++++++++++++++
+ 2 files changed, 106 insertions(+)
+
+commit 95329081c2c6e7f763b466ea3cfc9630ddb23dcf
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Nov 26 16:18:42 2021 -0800
+
+    [subset] further optimize cmap4 packing.
+
+ src/hb-ot-cmap-table.hh                            |  48 +++++++++++++++------
+ ...aa-Regular-new.default.retain-all-codepoint.ttf | Bin 222692 -> 222684 bytes
+ ...drop-hints-retain-gids.retain-all-codepoint.ttf | Bin 191568 -> 191560 bytes
+ ...Regular-new.drop-hints.retain-all-codepoint.ttf | Bin 191520 -> 191512 bytes
+ ...ortaa-Regular-new.gids.retain-all-codepoint.ttf | Bin 222692 -> 222684 bytes
+ ...egular-new.glyph-names.retain-all-codepoint.ttf | Bin 229684 -> 229676 bytes
+ ...ep-all-layout-features.retain-all-codepoint.ttf | Bin 223388 -> 223380 bytes
+ ...ar-new.layout-features.retain-all-codepoint.ttf | Bin 220884 -> 220876 bytes
+ ...a-Regular-new.name-ids.retain-all-codepoint.ttf | Bin 222432 -> 222424 bytes
+ ...lar-new.name-languages.retain-all-codepoint.ttf | Bin 222692 -> 222684 bytes
+ ...egular-new.name-legacy.retain-all-codepoint.ttf | Bin 222692 -> 222684 bytes
+ ...o-prune-unicode-ranges.retain-all-codepoint.ttf | Bin 222692 -> 222684 bytes
+ ...lar-new.notdef-outline.retain-all-codepoint.ttf | Bin 223288 -> 223280 bytes
+ ...egular-new.retain-gids.retain-all-codepoint.ttf | Bin 222740 -> 222732 bytes
+ ...tu-Regular.glyph-names.retain-all-codepoint.ttf | Bin 280064 -> 280056 bytes
+ ...traLightItalic.default.retain-all-codepoint.ttf | Bin 134364 -> 134344 bytes
+ ...ightItalic.glyph-names.retain-all-codepoint.ttf | Bin 145640 -> 145620 bytes
+ ...tItalic.notdef-outline.retain-all-codepoint.ttf | Bin 134492 -> 134472 bytes
+ ...ns-BlackItalic.default.retain-all-codepoint.ttf | Bin 120040 -> 120020 bytes
+ ...lackItalic.glyph-names.retain-all-codepoint.ttf | Bin 132284 -> 132264 bytes
+ ...kItalic.notdef-outline.retain-all-codepoint.ttf | Bin 120040 -> 120020 bytes
+ .../Tinos-Italic.default.retain-all-codepoint.ttf  | Bin 410180 -> 410092 bytes
+ ...nos-Italic.glyph-names.retain-all-codepoint.ttf | Bin 435008 -> 434920 bytes
+ ...-Italic.notdef-outline.retain-all-codepoint.ttf | Bin 410180 -> 410092 bytes
+ ...nos-Italic.retain-gids.retain-all-codepoint.ttf | Bin 412556 -> 412468 bytes
+ ...wLatin-Regular.default.retain-all-codepoint.ttf | Bin 130076 -> 129952 bytes
+ ...in-Regular.layout-test.retain-all-codepoint.ttf | Bin 152052 -> 151928 bytes
+ ...in-Regular.retain-gids.retain-all-codepoint.ttf | Bin 133180 -> 133056 bytes
+ ...woMath-Regular.default.retain-all-codepoint.ttf | Bin 1033572 -> 1033528 bytes
+ ...th-Regular.glyph-names.retain-all-codepoint.ttf | Bin 1086348 -> 1086304 bytes
+ ...Regular.notdef-outline.retain-all-codepoint.ttf | Bin 1033820 -> 1033776 bytes
+ ...th-Regular.retain-gids.retain-all-codepoint.ttf | Bin 1048752 -> 1048716 bytes
+ 32 files changed, 36 insertions(+), 12 deletions(-)
+
+commit 599143824c39b3cf37c3cb714364b58d45fc0d3d
+Author: Garret Rieger <grieger at google.com>
+Date:   Fri Nov 26 14:19:39 2021 -0800
+
+    [subset] Don't pad glyphs when using long loca.
+
+ src/hb-ot-glyf-table.hh                            |  36 +++++++++++++--------
+ ...tu-Regular.glyph-names.retain-all-codepoint.ttf | Bin 280296 -> 280064 bytes
+ ...Howrah-Regular.default.retain-all-codepoint.ttf | Bin 174308 -> 174024 bytes
+ ...ah-Regular.retain-gids.retain-all-codepoint.ttf | Bin 174608 -> 174324 bytes
+ .../Tinos-Italic.default.retain-all-codepoint.ttf  | Bin 410932 -> 410180 bytes
+ ...nos-Italic.glyph-names.retain-all-codepoint.ttf | Bin 435760 -> 435008 bytes
+ ...-Italic.notdef-outline.retain-all-codepoint.ttf | Bin 410932 -> 410180 bytes
+ ...nos-Italic.retain-gids.retain-all-codepoint.ttf | Bin 413308 -> 412556 bytes
+ ...woMath-Regular.default.retain-all-codepoint.ttf | Bin 1035756 -> 1033572 bytes
+ ...th-Regular.glyph-names.retain-all-codepoint.ttf | Bin 1088532 -> 1086348 bytes
+ ...Regular.notdef-outline.retain-all-codepoint.ttf | Bin 1036004 -> 1033820 bytes
+ ...th-Regular.retain-gids.retain-all-codepoint.ttf | Bin 1050936 -> 1048752 bytes
+ ...varaya-Regular.default.retain-all-codepoint.ttf | Bin 573428 -> 572812 bytes
+ ...ya-Regular.glyph-names.retain-all-codepoint.ttf | Bin 609076 -> 608460 bytes
+ ...Regular.notdef-outline.retain-all-codepoint.ttf | Bin 573508 -> 572892 bytes
+ ...ya-Regular.retain-gids.retain-all-codepoint.ttf | Bin 573440 -> 572824 bytes
+ 16 files changed, 22 insertions(+), 14 deletions(-)
+
+commit d9660fd58a3ade1c8962e5cd3f7538a5b5189262
+Author: Garret Rieger <grieger at google.com>
+Date:   Thu Nov 25 18:15:35 2021 -0800
+
+    [subset] Make cmap4 packing more optimal.
+    
+    The current CMAP4 implementation uses whatever the current codepoint ranges are and then encodes them as indivudal glyph ids or as a delta if possible. However, it's often possible to save bytes by splitting up existing ranges and encoding parts of them using deltas where the cost of splitting the range is less than encoding each glyph individual.
+
+ src/hb-ot-cmap-table.hh                            | 246 ++++++++++++---------
+ ...aa-Regular-new.default.retain-all-codepoint.ttf | Bin 222756 -> 222692 bytes
+ ...drop-hints-retain-gids.retain-all-codepoint.ttf | Bin 191632 -> 191568 bytes
+ ...Regular-new.drop-hints.retain-all-codepoint.ttf | Bin 191584 -> 191520 bytes
+ ...ortaa-Regular-new.gids.retain-all-codepoint.ttf | Bin 222756 -> 222692 bytes
+ ...egular-new.glyph-names.retain-all-codepoint.ttf | Bin 229748 -> 229684 bytes
+ ...ep-all-layout-features.retain-all-codepoint.ttf | Bin 223452 -> 223388 bytes
+ ...ar-new.layout-features.retain-all-codepoint.ttf | Bin 220948 -> 220884 bytes
+ ...a-Regular-new.name-ids.retain-all-codepoint.ttf | Bin 222496 -> 222432 bytes
+ ...lar-new.name-languages.retain-all-codepoint.ttf | Bin 222756 -> 222692 bytes
+ ...egular-new.name-legacy.retain-all-codepoint.ttf | Bin 222756 -> 222692 bytes
+ ...o-prune-unicode-ranges.retain-all-codepoint.ttf | Bin 222756 -> 222692 bytes
+ ...lar-new.notdef-outline.retain-all-codepoint.ttf | Bin 223352 -> 223288 bytes
+ ...egular-new.retain-gids.retain-all-codepoint.ttf | Bin 222804 -> 222740 bytes
+ ...tu-Regular.glyph-names.retain-all-codepoint.ttf | Bin 281092 -> 280296 bytes
+ ...Gothic-Regular.default.retain-all-codepoint.ttf | Bin 44584 -> 44544 bytes
+ ...ic-Regular.layout-test.retain-all-codepoint.ttf | Bin 46584 -> 46544 bytes
+ ...ic-Regular.retain-gids.retain-all-codepoint.ttf | Bin 44592 -> 44552 bytes
+ ...traLightItalic.default.retain-all-codepoint.ttf | Bin 134520 -> 134364 bytes
+ ...ightItalic.glyph-names.retain-all-codepoint.ttf | Bin 145796 -> 145640 bytes
+ ...tItalic.notdef-outline.retain-all-codepoint.ttf | Bin 134648 -> 134492 bytes
+ ...ns-BlackItalic.default.retain-all-codepoint.ttf | Bin 120236 -> 120040 bytes
+ ...lackItalic.glyph-names.retain-all-codepoint.ttf | Bin 132480 -> 132284 bytes
+ ...kItalic.notdef-outline.retain-all-codepoint.ttf | Bin 120236 -> 120040 bytes
+ .../Tinos-Italic.default.retain-all-codepoint.ttf  | Bin 412764 -> 410932 bytes
+ ...nos-Italic.glyph-names.retain-all-codepoint.ttf | Bin 437592 -> 435760 bytes
+ ...-Italic.notdef-outline.retain-all-codepoint.ttf | Bin 412764 -> 410932 bytes
+ ...nos-Italic.retain-gids.retain-all-codepoint.ttf | Bin 415140 -> 413308 bytes
+ ...wLatin-Regular.default.retain-all-codepoint.ttf | Bin 131672 -> 130076 bytes
+ ...in-Regular.layout-test.retain-all-codepoint.ttf | Bin 153648 -> 152052 bytes
+ ...in-Regular.retain-gids.retain-all-codepoint.ttf | Bin 134776 -> 133180 bytes
+ ...woMath-Regular.default.retain-all-codepoint.ttf | Bin 1038580 -> 1035756 bytes
+ ...th-Regular.glyph-names.retain-all-codepoint.ttf | Bin 1091356 -> 1088532 bytes
+ ...Regular.notdef-outline.retain-all-codepoint.ttf | Bin 1038828 -> 1036004 bytes
+ ...th-Regular.retain-gids.retain-all-codepoint.ttf | Bin 1053656 -> 1050936 bytes
+ 35 files changed, 143 insertions(+), 103 deletions(-)
+
 commit 8aed5c21a31eece6a9f3cd775fda8facb6c28b9b
 Author: Khaled Hosny <khaled at aliftype.com>
 Date:   Fri Nov 26 17:54:18 2021 +0200

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/NEWS	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,3 +1,19 @@
+Overview of changes leading to 3.2.0
+Friday, November 26, 2021
+====================================
+
+“harfbuzz” library improvements:
+- Fixed shaping of Apple Color Emoji flags in right-to-left context. (Behdad Esfahbod)
+- Fixed positioning of CFF fonts in HB_TINY profile. (Behdad Esfahbod)
+- OpenType 1.9 language tags update. (David Corbett)
+- Add HB_NO_VERTICAL config option.
+- Add HB_CONFIG_OVERRIDE_H for easier configuration. (Behdad Esfahbod)
+
+“harfbuzz-subset” library improvements:
+- Improved packing of cmap, loca, and Ligature tables. (Garret Rieger)
+- Significantly improved overflow-resolution strategy in the repacker. (Garret Rieger)
+
+
 Overview of changes leading to 3.1.2
 Friday, November 26, 2021
 ====================================

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/configure.ac	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [3.1.2],
+        [3.2.0],
         [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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/meson.build	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1,6 +1,6 @@
 project('harfbuzz', 'c', 'cpp',
   meson_version: '>= 0.55.0',
-  version: '3.1.2',
+  version: '3.2.0',
   default_options: [
     'cpp_rtti=false',       # Just to support msvc, we are passing -fno-exceptions also anyway
     'cpp_std=c++11',
@@ -239,12 +239,17 @@
 endif
 
 # DirectWrite (Windows)
+directwrite_dep = null_dep
 if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
   if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
     error('DirectWrite was enabled explicitly, but required header is missing.')
   endif
 
-  conf.set('HAVE_DIRECTWRITE', 1)
+  directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
+
+  if directwrite_dep.found()
+    conf.set('HAVE_DIRECTWRITE', 1)
+  endif
 endif
 
 # CoreText (macOS)

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-tag-table.py
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-tag-table.py	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/gen-tag-table.py	2021-12-12 23:55:43 UTC (rev 61290)
@@ -340,11 +340,15 @@
 		self.from_bcp_47 = collections.defaultdict (set)
 		# Whether the parser is in a <td> element
 		self._td = False
+		# Whether the parser is after a <br> element within the current <tr> element
+		self._br = False
 		# The text of the <td> elements of the current <tr> element.
 		self._current_tr = []
 
 	def handle_starttag (self, tag, attrs):
-		if tag == 'meta':
+		if tag == 'br':
+			self._br = True
+		elif tag == 'meta':
 			for attr, value in attrs:
 				if attr == 'name' and value == 'updated_at':
 					self.header = self.get_starttag_text ()
@@ -353,6 +357,7 @@
 			self._td = True
 			self._current_tr.append ('')
 		elif tag == 'tr':
+			self._br = False
 			self._current_tr = []
 
 	def handle_endtag (self, tag):
@@ -377,7 +382,7 @@
 			self.ranks[tag] = rank
 
 	def handle_data (self, data):
-		if self._td:
+		if self._td and not self._br:
 			self._current_tr[-1] += data
 
 	def handle_charref (self, name):
@@ -704,6 +709,8 @@
 bcp_47.names['mhv'] = 'Arakanese'
 bcp_47.scopes['mhv'] = ' (retired code)'
 
+ot.add_language ('mnw-TH', 'MONT')
+
 ot.add_language ('no', 'NOR')
 
 ot.add_language ('oc-provenc', 'PRO')

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1038,12 +1038,12 @@
 	goto skip;
 
       if (reverse)
-	c->buffer->reverse ();
+	_hb_ot_layout_reverse_graphemes (c->buffer);
 
       subtable->apply (c);
 
       if (reverse)
-	c->buffer->reverse ();
+	_hb_ot_layout_reverse_graphemes (c->buffer);
 
       (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -396,52 +396,6 @@
 }
 
 void
-hb_buffer_t::reverse_range (unsigned int start,
-			    unsigned int end)
-{
-  if (end - start < 2)
-    return;
-
-  hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
-
-  if (have_positions) {
-    hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
-  }
-}
-
-void
-hb_buffer_t::reverse ()
-{
-  if (unlikely (!len))
-    return;
-
-  reverse_range (0, len);
-}
-
-void
-hb_buffer_t::reverse_clusters ()
-{
-  unsigned int i, start, count, last_cluster;
-
-  if (unlikely (!len))
-    return;
-
-  reverse ();
-
-  count = len;
-  start = 0;
-  last_cluster = info[0].cluster;
-  for (i = 1; i < count; i++) {
-    if (last_cluster != info[i].cluster) {
-      reverse_range (start, i);
-      start = i;
-      last_cluster = info[i].cluster;
-    }
-  }
-  reverse_range (start, i);
-}
-
-void
 hb_buffer_t::merge_clusters_impl (unsigned int start,
 				  unsigned int end)
 {
@@ -543,7 +497,7 @@
 hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
 {
   unsigned int cluster = UINT_MAX;
-  cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
+  cluster = _infos_find_min_cluster (info, start, end, cluster);
   _unsafe_to_break_set_mask (info, start, end, cluster);
 }
 void
@@ -559,8 +513,9 @@
   assert (idx <= end);
 
   unsigned int cluster = UINT_MAX;
-  cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
-  cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
+  cluster = _infos_find_min_cluster (out_info, start, out_len, cluster);
+  cluster = _infos_find_min_cluster (info, idx, end, cluster);
+
   _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
   _unsafe_to_break_set_mask (info, idx, end, cluster);
 }

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-buffer.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -201,9 +201,55 @@
 			unsigned int    cluster);
   HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
 
-  HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
-  HB_INTERNAL void reverse ();
-  HB_INTERNAL void reverse_clusters ();
+  void reverse_range (unsigned start, unsigned end)
+  {
+    hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
+    if (have_positions)
+      hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
+  }
+  void reverse () { reverse_range (0, len); }
+
+  template <typename FuncType>
+  void reverse_groups (const FuncType& group,
+		       bool merge_clusters = false)
+  {
+    if (unlikely (!len))
+      return;
+
+    unsigned start = 0;
+    unsigned i;
+    for (i = 1; i < len; i++)
+    {
+      if (!group (info[i - 1], info[i]))
+      {
+	if (merge_clusters)
+	  this->merge_clusters (start, i);
+	reverse_range (start, i);
+	start = i;
+      }
+    }
+    if (merge_clusters)
+      this->merge_clusters (start, i);
+    reverse_range (start, i);
+
+    reverse ();
+  }
+
+  template <typename FuncType>
+  unsigned group_end (unsigned start, const FuncType& group) const
+  {
+    while (++start < len && group (info[start - 1], info[start]))
+      ;
+
+    return start;
+  }
+
+  static bool _cluster_group_func (const hb_glyph_info_t& a,
+				   const hb_glyph_info_t& b)
+  { return a.cluster == b.cluster; }
+
+  void reverse_clusters () { reverse_groups (_cluster_group_func); }
+
   HB_INTERNAL void guess_segment_properties ();
 
   HB_INTERNAL void swap_buffers ();
@@ -428,10 +474,10 @@
     inf.cluster = cluster;
   }
 
-  unsigned int
-  _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
-				     unsigned int start, unsigned int end,
-				     unsigned int cluster) const
+  static unsigned
+  _infos_find_min_cluster (const hb_glyph_info_t *infos,
+			   unsigned start, unsigned end,
+			   unsigned cluster)
   {
     for (unsigned int i = start; i < end; i++)
       cluster = hb_min (cluster, infos[i].cluster);
@@ -450,38 +496,26 @@
       }
   }
 
-  void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
-  void safe_to_break_all ()
+  void clear_glyph_flags (hb_mask_t mask = 0)
   {
     for (unsigned int i = 0; i < len; i++)
-      info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+      info[i].mask = (info[i].mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
   }
 };
 DECLARE_NULL_INSTANCE (hb_buffer_t);
 
 
-/* Loop over clusters. Duplicated in foreach_syllable(). */
-#define foreach_cluster(buffer, start, end) \
+#define foreach_group(buffer, start, end, group_func) \
   for (unsigned int \
        _count = buffer->len, \
-       start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
+       start = 0, end = _count ? buffer->group_end (0, group_func) : 0; \
        start < _count; \
-       start = end, end = _next_cluster (buffer, start))
+       start = end, end = buffer->group_end (start, group_func))
 
-static inline unsigned int
-_next_cluster (hb_buffer_t *buffer, unsigned int start)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
+#define foreach_cluster(buffer, start, end) \
+	foreach_group (buffer, start, end, hb_buffer_t::_cluster_group_func)
 
-  unsigned int cluster = info[start].cluster;
-  while (++start < count && cluster == info[start].cluster)
-    ;
 
-  return start;
-}
-
-
 #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
 	   sizeof (b->info[0].var))

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-config.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -86,9 +86,12 @@
 #define HB_NO_LEGACY
 #endif
 
-#ifdef HAVE_CONFIG_OVERRIDE_H
-#include "config-override.h"
+#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
+#ifndef HB_CONFIG_OVERRIDE_H
+#define HB_CONFIG_OVERRIDE_H "config-override.h"
 #endif
+#include HB_CONFIG_OVERRIDE_H
+#endif
 
 /* Closure of options. */
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-coretext.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1213,7 +1213,7 @@
     }
   }
 
-  buffer->unsafe_to_break_all ();
+  buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK);
 
 #undef FAIL
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-directwrite.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -43,14 +43,6 @@
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
-/* Declare object creator for dynamic support of DWRITE */
-typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID              iid,
-  IUnknown            **factory
-);
-
-
 /*
  * DirectWrite font stream helpers
  */
@@ -145,7 +137,6 @@
 
 struct hb_directwrite_face_data_t
 {
-  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   DWriteFontFileStream *fontFileStream;
@@ -167,33 +158,12 @@
     return nullptr; \
   } HB_STMT_END
 
-  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
-  if (unlikely (!data->dwrite_dll))
-    FAIL ("Cannot find DWrite.DLL");
-
-  t_DWriteCreateFactory p_DWriteCreateFactory;
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-
-  p_DWriteCreateFactory = (t_DWriteCreateFactory)
-			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-
-  if (unlikely (!p_DWriteCreateFactory))
-    FAIL ("Cannot find DWriteCreateFactory().");
-
   HRESULT hr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
-  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-			      (IUnknown**) &dwriteFactory);
+  hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+			    (IUnknown**) &dwriteFactory);
 
   if (unlikely (hr != S_OK))
     FAIL ("Failed to run DWriteCreateFactory().");
@@ -257,8 +227,6 @@
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
-  if (data->dwrite_dll)
-    FreeLibrary (data->dwrite_dll);
   if (data)
     delete data;
 }
@@ -794,6 +762,8 @@
 
   if (isRightToLeft) hb_buffer_reverse (buffer);
 
+  buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK);
+
   delete [] clusterMap;
   delete [] glyphIndices;
   delete [] textProperties;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-fallback-shape.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-fallback-shape.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-fallback-shape.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -117,7 +117,7 @@
   if (HB_DIRECTION_IS_BACKWARD (direction))
     hb_buffer_reverse (buffer);
 
-  buffer->safe_to_break_all ();
+  buffer->clear_glyph_flags ();
 
   return true;
 }

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ft.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -361,6 +361,7 @@
   }
 }
 
+#ifndef HB_NO_VERTICAL
 static hb_position_t
 hb_ft_get_glyph_v_advance (hb_font_t *font,
 			   void *font_data,
@@ -381,7 +382,9 @@
    * have a Y growing upward.  Hence the extra negation. */
   return (-v + (1<<9)) >> 10;
 }
+#endif
 
+#ifndef HB_NO_VERTICAL
 static hb_bool_t
 hb_ft_get_glyph_v_origin (hb_font_t *font,
 			  void *font_data,
@@ -409,6 +412,7 @@
 
   return true;
 }
+#endif
 
 #ifndef HB_NO_OT_SHAPE_FALLBACK
 static hb_position_t
@@ -569,15 +573,20 @@
   {
     hb_font_funcs_t *funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
     hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
 #ifndef HB_NO_OT_SHAPE_FALLBACK
     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
 #endif

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-graphite2.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -439,7 +439,7 @@
   if (feats) gr_featureval_destroy (feats);
   gr_seg_destroy (seg);
 
-  buffer->unsafe_to_break_all ();
+  buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK);
 
   return true;
 }

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-iter.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -581,6 +581,91 @@
 }
 HB_FUNCOBJ (hb_zip);
 
+/* hb_concat() */
+
+template <typename A, typename B>
+struct hb_concat_iter_t :
+    hb_iter_t<hb_concat_iter_t<A, B>, typename A::item_t>
+{
+  hb_concat_iter_t () {}
+  hb_concat_iter_t (A& a, B& b) : a (a), b (b) {}
+  hb_concat_iter_t (const A& a, const B& b) : a (a), b (b) {}
+
+
+  typedef typename A::item_t __item_t__;
+  static constexpr bool is_random_access_iterator =
+    A::is_random_access_iterator &&
+    B::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator = false;
+
+  __item_t__ __item__ () const
+  {
+    if (!a)
+      return *b;
+    return *a;
+  }
+
+  __item_t__ __item_at__ (unsigned i) const
+  {
+    unsigned a_len = a.len ();
+    if (i < a_len)
+      return a[i];
+    return b[i - a_len];
+  }
+
+  bool __more__ () const { return bool (a) || bool (b); }
+
+  unsigned __len__ () const { return a.len () + b.len (); }
+
+  void __next__ ()
+  {
+    if (a)
+      ++a;
+    else
+      ++b;
+  }
+
+  void __forward__ (unsigned n)
+  {
+    if (!n) return;
+    if (!is_random_access_iterator) {
+      while (n-- && *this) {
+        (*this)++;
+      }
+      return;
+    }
+
+    unsigned a_len = a.len ();
+    if (n > a_len) {
+      n -= a_len;
+      a.__forward__ (a_len);
+      b.__forward__ (n);
+    } else {
+      a.__forward__ (n);
+    }
+  }
+
+  hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); }
+  bool operator != (const hb_concat_iter_t& o) const
+  {
+    return a != o.a
+        || b != o.b;
+  }
+
+  private:
+  A a;
+  B b;
+};
+struct
+{ HB_PARTIALIZE(2);
+  template <typename A, typename B,
+	    hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
+  hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>>
+  operator () (A&& a, B&& b) const
+  { return hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
+}
+HB_FUNCOBJ (hb_concat);
+
 /* hb_apply() */
 
 template <typename Appl>

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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-cmap-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -93,120 +93,192 @@
 struct CmapSubtableFormat4
 {
 
+
   template<typename Iterator,
+      typename Writer,
 	   hb_requires (hb_is_iterator (Iterator))>
-  HBUINT16* serialize_endcode_array (hb_serialize_context_t *c,
-				     Iterator it)
+  void to_ranges (Iterator it, Writer& range_writer)
   {
-    HBUINT16 *endCode = c->start_embed<HBUINT16> ();
-    hb_codepoint_t prev_endcp = 0xFFFF;
+    hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
+    int run_length = 0 , delta = 0, prev_delta = 0;
 
-    for (const auto& _ : +it)
-    {
-      if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
-      {
-	HBUINT16 end_code;
-	end_code = prev_endcp;
-	c->copy<HBUINT16> (end_code);
+    enum {
+      FIRST_SUB_RANGE,
+      FOLLOWING_SUB_RANGE,
+    } mode;
+
+    while (it) {
+      // Start a new range
+      start_cp = (*it).first;
+      prev_run_start_cp = (*it).first;
+      run_start_cp = (*it).first;
+      end_cp = (*it).first;
+      last_gid = (*it).second;
+      run_length = 1;
+      prev_delta = 0;
+
+      delta = (*it).second - (*it).first;
+      mode = FIRST_SUB_RANGE;
+      it++;
+
+      while (it) {
+        // Process range
+        hb_codepoint_t next_cp = (*it).first;
+        hb_codepoint_t next_gid = (*it).second;
+        if (next_cp != end_cp + 1) {
+          // Current range is over, stop processing.
+          break;
+        }
+
+        if (next_gid == last_gid + 1) {
+          // The current run continues.
+          end_cp = next_cp;
+          run_length++;
+          last_gid = next_gid;
+          it++;
+          continue;
+        }
+
+        // A new run is starting, decide if we want to commit the current run.
+        int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
+        int run_cost = run_length * 2;
+        if (run_cost >= split_cost) {
+          commit_current_range(start_cp,
+                               prev_run_start_cp,
+                               run_start_cp,
+                               end_cp,
+                               delta,
+                               prev_delta,
+                               split_cost,
+                               range_writer);
+          start_cp = next_cp;
+        }
+
+        // Start the new run
+        mode = FOLLOWING_SUB_RANGE;
+        prev_run_start_cp = run_start_cp;
+        run_start_cp = next_cp;
+        end_cp = next_cp;
+        prev_delta = delta;
+        delta = next_gid - run_start_cp;
+        run_length = 1;
+        last_gid = next_gid;
+        it++;
       }
-      prev_endcp = _.first;
+
+      // Finalize range
+      commit_current_range (start_cp,
+                            prev_run_start_cp,
+                            run_start_cp,
+                            end_cp,
+                            delta,
+                            prev_delta,
+                            8,
+                            range_writer);
     }
 
-    {
-      // last endCode
-      HBUINT16 endcode;
-      endcode = prev_endcp;
-      if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr;
-      // There must be a final entry with end_code == 0xFFFF.
-      if (prev_endcp != 0xFFFF)
-      {
-	HBUINT16 finalcode;
-	finalcode = 0xFFFF;
-	if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
-      }
+    if (likely (end_cp != 0xFFFF)) {
+      range_writer (0xFFFF, 0xFFFF, 1);
     }
-
-    return endCode;
   }
 
-  template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
-  HBUINT16* serialize_startcode_array (hb_serialize_context_t *c,
-				       Iterator it)
-  {
-    HBUINT16 *startCode = c->start_embed<HBUINT16> ();
-    hb_codepoint_t prev_cp = 0xFFFF;
-
-    for (const auto& _ : +it)
-    {
-      if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
-      {
-	HBUINT16 start_code;
-	start_code = _.first;
-	c->copy<HBUINT16> (start_code);
+  /*
+   * Writes the current range as either one or two ranges depending on what is most efficient.
+   */
+  template<typename Writer>
+  void commit_current_range (hb_codepoint_t start,
+                             hb_codepoint_t prev_run_start,
+                             hb_codepoint_t run_start,
+                             hb_codepoint_t end,
+                             int run_delta,
+                             int previous_run_delta,
+                             int split_cost,
+                             Writer& range_writer) {
+    bool should_split = false;
+    if (start < run_start && run_start < end) {
+      int run_cost = (end - run_start + 1) * 2;
+      if (run_cost >= split_cost) {
+        should_split = true;
       }
+    }
 
-      prev_cp = _.first;
+    // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
+    if (should_split) {
+      if (start == prev_run_start)
+        range_writer (start, run_start - 1, previous_run_delta);
+      else
+        range_writer (start, run_start - 1, 0);
+      range_writer (run_start, end, run_delta);
+      return;
     }
 
-    // There must be a final entry with end_code == 0xFFFF.
-    if (it.len () == 0 || prev_cp != 0xFFFF)
-    {
-      HBUINT16 finalcode;
-      finalcode = 0xFFFF;
-      if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
+
+    if (start == run_start) {
+      // Range is only a run
+      range_writer (start, end, run_delta);
+      return;
     }
 
-    return startCode;
+    // Write only a single non-run range.
+    range_writer (start, end, 0);
   }
 
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
-  HBINT16* serialize_idDelta_array (hb_serialize_context_t *c,
-				    Iterator it,
-				    HBUINT16 *endCode,
-				    HBUINT16 *startCode,
-				    unsigned segcount)
-  {
-    unsigned i = 0;
-    hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF;
-    bool use_delta = true;
+  unsigned serialize_find_segcount (Iterator it) {
+    struct Counter {
+      unsigned segcount = 0;
 
-    HBINT16 *idDelta = c->start_embed<HBINT16> ();
-    if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
-      return nullptr;
-
-    for (const auto& _ : +it)
-    {
-      if (_.first == startCode[i])
-      {
-	use_delta = true;
-	start_gid = _.second;
+      void operator() (hb_codepoint_t start,
+                       hb_codepoint_t end,
+                       int delta) {
+        segcount++;
       }
-      else if (_.second != last_gid + 1) use_delta = false;
+    } counter;
 
-      if (_.first == endCode[i])
-      {
-	HBINT16 delta;
-	if (use_delta) delta = (int)start_gid - (int)startCode[i];
-	else delta = 0;
-	c->copy<HBINT16> (delta);
+    to_ranges (+it, counter);
+    return counter.segcount;
+  }
 
-	i++;
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
+                                         Iterator it,
+                                         int segcount)
+  {
+    struct Writer {
+      hb_serialize_context_t *serializer_;
+      HBUINT16* end_code_;
+      HBUINT16* start_code_;
+      HBINT16* id_delta_;
+      int index_;
+
+      Writer(hb_serialize_context_t *serializer)
+          : serializer_(serializer),
+            end_code_(nullptr),
+            start_code_(nullptr),
+            id_delta_(nullptr),
+            index_ (0) {}
+      void operator() (hb_codepoint_t start,
+                       hb_codepoint_t end,
+                       int delta) {
+        start_code_[index_] = start;
+        end_code_[index_] = end;
+        id_delta_[index_] = delta;
+        index_++;
       }
+    } writer(c);
 
-      last_gid = _.second;
-      last_cp = _.first;
-    }
+    writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+    c->allocate_size<HBUINT16> (2); // padding
+    writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+    writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
 
-    if (it.len () == 0 || last_cp != 0xFFFF)
-    {
-      HBINT16 delta;
-      delta = 1;
-      if (unlikely (!c->copy<HBINT16> (delta))) return nullptr;
-    }
+    if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
 
-    return idDelta;
+    to_ranges (+it, writer);
+    return true;
   }
 
   template<typename Iterator,
@@ -257,23 +329,15 @@
     if (unlikely (!c->extend_min (this))) return;
     this->format = 4;
 
-    //serialize endCode[]
-    HBUINT16 *endCode = serialize_endcode_array (c, format4_iter);
-    if (unlikely (!endCode)) return;
+    //serialize endCode[], startCode[], idDelta[]
+    HBUINT16* endCode = c->start_embed<HBUINT16> ();
+    unsigned segcount = serialize_find_segcount (format4_iter);
+    if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount)))
+      return;
 
-    unsigned segcount = (c->length () - min_size) / HBUINT16::static_size;
+    HBUINT16 *startCode = endCode + segcount + 1;
+    HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
 
-    // 2 bytes of padding.
-    if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding.
-
-   // serialize startCode[]
-    HBUINT16 *startCode = serialize_startcode_array (c, format4_iter);
-    if (unlikely (!startCode)) return;
-
-    //serialize idDelta[]
-    HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount);
-    if (unlikely (!idDelta)) return;
-
     HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return;
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-color-colr-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1025,7 +1025,7 @@
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
 
-    const hb_set_t& glyphset = *c->plan->_glyphset;
+    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
     hb_map_t new_gid_offset_map;
@@ -1193,7 +1193,7 @@
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-    const hb_set_t* glyphset = c->plan->_glyphset;
+    const hb_set_t* glyphset = c->plan->_glyphset_colred;
 
     for (const auto& _ : as_array ())
     {
@@ -1411,10 +1411,9 @@
 
   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
   {
-    if ((unsigned int) gid == 0) // Ignore notdef.
-      return nullptr;
     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
-    if ((record && (hb_codepoint_t) record->glyphId != gid))
+    if (record == &Null (BaseGlyphRecord) ||
+        (record && (hb_codepoint_t) record->glyphId != gid))
       record = nullptr;
     return record;
   }
@@ -1432,9 +1431,16 @@
     TRACE_SUBSET (this);
 
     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
 
     auto base_it =
     + hb_range (c->plan->num_output_glyphs ())
+    | hb_filter ([&](hb_codepoint_t new_gid)
+		 {
+		    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+		    if (glyphset.has (old_gid)) return true;
+		    return false;
+		 })
     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
 			      {
 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
@@ -1442,7 +1448,6 @@
 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
 				if (unlikely (!old_record))
 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
-
 				BaseGlyphRecord new_record = {};
 				new_record.glyphId = new_gid;
 				new_record.numLayers = old_record->numLayers;
@@ -1455,6 +1460,7 @@
     auto layer_it =
     + hb_range (c->plan->num_output_glyphs ())
     | hb_map (reverse_glyph_map)
+    | hb_filter (glyphset)
     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
 			      {
 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-face-table-list.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -67,8 +67,11 @@
 #endif
 
 /* Vertical layout. */
+#ifndef HB_NO_VERTICAL
 HB_OT_TABLE (OT, vhea)
 HB_OT_ACCELERATOR (OT, vmtx)
+HB_OT_TABLE (OT, VORG)
+#endif
 
 /* TrueType outlines. */
 HB_OT_ACCELERATOR (OT, glyf)
@@ -77,7 +80,6 @@
 #ifndef HB_NO_CFF
 HB_OT_ACCELERATOR (OT, cff1)
 HB_OT_ACCELERATOR (OT, cff2)
-HB_OT_TABLE (OT, VORG)
 #endif
 
 /* OpenType variations. */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-font.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -118,6 +118,7 @@
   }
 }
 
+#ifndef HB_NO_VERTICAL
 static void
 hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
 			    unsigned count,
@@ -137,7 +138,9 @@
     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
+#endif
 
+#ifndef HB_NO_VERTICAL
 static hb_bool_t
 hb_ot_get_glyph_v_origin (hb_font_t *font,
 			  void *font_data,
@@ -150,7 +153,6 @@
 
   *x = font->get_glyph_h_advance (glyph) / 2;
 
-#ifndef HB_NO_OT_FONT_CFF
   const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
@@ -157,7 +159,6 @@
     *y = font->em_scale_y (VORG.get_y_origin (glyph));
     return true;
   }
-#endif
 
   hb_glyph_extents_t extents = {0};
   if (ot_face->glyf->get_extents (font, glyph, &extents))
@@ -174,6 +175,7 @@
 
   return true;
 }
+#endif
 
 static hb_bool_t
 hb_ot_get_glyph_extents (hb_font_t *font,
@@ -242,6 +244,7 @@
 	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
 }
 
+#ifndef HB_NO_VERTICAL
 static hb_bool_t
 hb_ot_get_font_v_extents (hb_font_t *font,
 			  void *font_data HB_UNUSED,
@@ -252,6 +255,7 @@
 	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
 	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
 }
+#endif
 
 static inline void free_static_ot_funcs ();
 
@@ -261,17 +265,23 @@
   {
     hb_font_funcs_t *funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
-    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
     hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
     hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
+
 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
     hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -93,22 +93,16 @@
   template<typename Iterator,
 	   hb_requires (hb_is_source_of (Iterator, unsigned int))>
   static bool
-  _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
+  _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
   {
-    unsigned max_offset =
-    + padded_offsets
-    | hb_reduce (hb_add, 0)
-    ;
     unsigned num_offsets = padded_offsets.len () + 1;
-    bool use_short_loca = max_offset < 0x1FFFF;
     unsigned entry_size = use_short_loca ? 2 : 4;
     char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
 
     if (unlikely (!loca_prime_data)) return false;
 
-    DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d "
-				"max_offset %d size %d",
-	       entry_size, num_offsets, max_offset, entry_size * num_offsets);
+    DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
+	       entry_size, num_offsets, entry_size * num_offsets);
 
     if (use_short_loca)
       _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
@@ -151,11 +145,12 @@
   template <typename Iterator>
   bool serialize (hb_serialize_context_t *c,
 		  Iterator it,
+                  bool use_short_loca,
 		  const hb_subset_plan_t *plan)
   {
     TRACE_SERIALIZE (this);
     unsigned init_len = c->length ();
-    for (const auto &_ : it) _.serialize (c, plan);
+    for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
 
     /* As a special case when all glyph in the font are empty, add a zero byte
      * to the table, so that OTS doesn’t reject it, and to make the table work
@@ -183,16 +178,28 @@
     hb_vector_t<SubsetGlyph> glyphs;
     _populate_subset_glyphs (c->plan, &glyphs);
 
-    glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
-
     auto padded_offsets =
     + hb_iter (glyphs)
     | hb_map (&SubsetGlyph::padded_size)
     ;
 
+    unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
+    bool use_short_loca = max_offset < 0x1FFFF;
+
+
+    glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
+    if (!use_short_loca) {
+      padded_offsets =
+          + hb_iter (glyphs)
+          | hb_map (&SubsetGlyph::length)
+          ;
+    }
+
+
     if (unlikely (c->serializer->in_error ())) return_trace (false);
     return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
-								    padded_offsets)));
+								    padded_offsets,
+                                                                    use_short_loca)));
   }
 
   template <typename SubsetGlyph>
@@ -792,10 +799,23 @@
       hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
       {
 	for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
-	int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid);
-	int v_orig  = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid);
+	int h_delta = (int) header->xMin -
+		      glyf_accelerator.hmtx->get_side_bearing (gid);
+	int v_orig  = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+		      glyf_accelerator.vmtx->get_side_bearing (gid)
+#else
+		      0
+#endif
+		      ;
 	unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
-	unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid);
+	unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+			 glyf_accelerator.vmtx->get_advance (gid)
+#else
+			 - font->face->get_upem ()
+#endif
+			 ;
 	phantoms[PHANTOM_LEFT].x = h_delta;
 	phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
 	phantoms[PHANTOM_TOP].y = v_orig;
@@ -910,7 +930,9 @@
       gvar = nullptr;
 #endif
       hmtx = nullptr;
+#ifndef HB_NO_VERTICAL
       vmtx = nullptr;
+#endif
       face = face_;
       const OT::head &head = *face->table.head;
       if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
@@ -924,7 +946,9 @@
       gvar = face->table.gvar;
 #endif
       hmtx = face->table.hmtx;
+#ifndef HB_NO_VERTICAL
       vmtx = face->table.vmtx;
+#endif
 
       num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
       num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
@@ -1037,7 +1061,11 @@
 	success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
 
       if (unlikely (!success))
-	return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid);
+	return
+#ifndef HB_NO_VERTICAL
+	  is_vertical ? vmtx->get_advance (gid) :
+#endif
+	  hmtx->get_advance (gid);
 
       float result = is_vertical
 		   ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y
@@ -1053,7 +1081,11 @@
 
       contour_point_t phantoms[PHANTOM_COUNT];
       if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
-	return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid);
+	return
+#ifndef HB_NO_VERTICAL
+	  is_vertical ? vmtx->get_side_bearing (gid) :
+#endif
+	  hmtx->get_side_bearing (gid);
 
       return is_vertical
 	   ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing
@@ -1250,7 +1282,9 @@
     const gvar_accelerator_t *gvar;
 #endif
     const hmtx_accelerator_t *hmtx;
+#ifndef HB_NO_VERTICAL
     const vmtx_accelerator_t *vmtx;
+#endif
 
     private:
     bool short_offset;
@@ -1269,6 +1303,7 @@
     hb_bytes_t dest_end;    /* region of source_glyph to copy second */
 
     bool serialize (hb_serialize_context_t *c,
+                    bool use_short_loca,
 		    const hb_subset_plan_t *plan) const
     {
       TRACE_SERIALIZE (this);
@@ -1275,7 +1310,7 @@
 
       hb_bytes_t dest_glyph = dest_start.copy (c);
       dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
-      unsigned int pad_length = padding ();
+      unsigned int pad_length = use_short_loca ? padding () : 0;
       DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
 
       HBUINT8 pad;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-hmtx-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -165,7 +165,14 @@
     {
       default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
 
-      num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
+      num_advances = T::is_horizontal ?
+		     face->table.hhea->numberOfLongMetrics :
+#ifndef HB_NO_VERTICAL
+		     face->table.vhea->numberOfLongMetrics
+#else
+		     0
+#endif
+		     ;
 
       table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
 

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-common.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -68,8 +68,8 @@
 #define HB_MAX_FEATURE_INDICES	1500
 #endif
 
-#ifndef HB_MAX_LOOKUP_INDICES
-#define HB_MAX_LOOKUP_INDICES	20000
+#ifndef HB_MAX_LOOKUP_VISIT_COUNT
+#define HB_MAX_LOOKUP_VISIT_COUNT	35000
 #endif
 
 
@@ -173,7 +173,7 @@
   bool visitLookupIndex()
   {
     lookup_index_count++;
-    return lookup_index_count < HB_MAX_LOOKUP_INDICES;
+    return lookup_index_count < HB_MAX_LOOKUP_VISIT_COUNT;
   }
 
   hb_subset_context_t *subset_context;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gpos-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -118,7 +118,13 @@
     if (!format) return ret;
 
     hb_font_t *font = c->font;
-    bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
+    bool horizontal =
+#ifndef HB_NO_VERTICAL
+      HB_DIRECTION_IS_HORIZONTAL (c->direction)
+#else
+      true
+#endif
+      ;
 
     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsub-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -566,7 +566,7 @@
     {
       /* Maybe we can do better than unsafe-to-break all; but since we are
        * changing random state, it would be hard to track that.  Good 'nough. */
-      c->buffer->unsafe_to_break_all ();
+      c->buffer->unsafe_to_break (0, c->buffer->len);
       alt_index = c->random_number () % count + 1;
     }
 

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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout-gsubgpos.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -81,12 +81,15 @@
     nesting_level_left++;
   }
 
+  void reset_lookup_visit_count ()
+  { lookup_count = 0; }
+
   bool lookup_limit_exceeded ()
-  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+  { return lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; }
 
   bool should_visit_lookup (unsigned int lookup_index)
   {
-    if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+    if (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT)
       return false;
 
     if (is_lookup_done (lookup_index))
@@ -211,7 +214,11 @@
       return;
 
     /* Return if new lookup was recursed to before. */
-    if (is_lookup_visited (lookup_index))
+    if (lookup_limit_exceeded ()
+        || visited_lookups->in_error ()
+        || visited_lookups->has (lookup_index))
+      // Don't increment lookup count here, that will be done in the call to closure_lookups()
+      // made by recurse_func.
       return;
 
     nesting_level_left--;
@@ -226,12 +233,20 @@
   { inactive_lookups->add (lookup_index); }
 
   bool lookup_limit_exceeded ()
-  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+  {
+    bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT;
+    if (ret)
+      DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!");
+    return ret; }
 
   bool is_lookup_visited (unsigned lookup_index)
   {
-    if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
+    if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT))
+    {
+      DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.",
+                 lookup_count, lookup_index);
       return true;
+    }
 
     if (unlikely (visited_lookups->in_error ()))
       return true;
@@ -1303,8 +1318,7 @@
     }
 
     hb_set_add (covered_seq_indicies, seqIndex);
-    if (pos_glyphs)
-      c->push_cur_active_glyphs (pos_glyphs);
+    c->push_cur_active_glyphs (pos_glyphs ? pos_glyphs : c->glyphs);
 
     unsigned endIndex = inputCount;
     if (context_format == ContextFormat::CoverageBasedContext)
@@ -1312,10 +1326,9 @@
 
     c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
 
-    if (pos_glyphs) {
-      c->pop_cur_done_glyphs ();
+    c->pop_cur_done_glyphs ();
+    if (pos_glyphs)
       hb_set_destroy (pos_glyphs);
-    }
   }
 
   hb_set_destroy (covered_seq_indicies);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -1530,6 +1530,7 @@
   unsigned int glyphs_length;
   do
   {
+    c.reset_lookup_visit_count ();
     glyphs_length = glyphs->get_population ();
     if (lookups)
     {

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -350,24 +350,20 @@
 {
   return info->unicode_props() & UPROPS_MASK_CONTINUATION;
 }
-/* Loop over grapheme. Based on foreach_cluster(). */
+
+static inline bool
+_hb_grapheme_group_func (const hb_glyph_info_t& a HB_UNUSED,
+			 const hb_glyph_info_t& b)
+{ return _hb_glyph_info_is_continuation (&b); }
+
 #define foreach_grapheme(buffer, start, end) \
-  for (unsigned int \
-       _count = buffer->len, \
-       start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \
-       start < _count; \
-       start = end, end = _hb_next_grapheme (buffer, start))
+	foreach_group (buffer, start, end, _hb_grapheme_group_func)
 
-static inline unsigned int
-_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start)
+static inline void
+_hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer)
 {
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-
-  while (++start < count && _hb_glyph_info_is_continuation (&info[start]))
-    ;
-
-  return start;
+  buffer->reverse_groups (_hb_grapheme_group_func,
+			  buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 }
 
 static inline bool

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math-table.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math-table.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-math-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -511,7 +511,8 @@
     | hb_map_retains_sorting (glyph_map)
     ;
 
-    out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
+    if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
+    else out->extendedShapeCoverage = 0;
 
     out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
     return_trace (true);
@@ -884,8 +885,11 @@
       if (!o) return_trace (false);
       o->serialize_subset (c, glyphConstruction[i], this);
     }
-
-    out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
+    
+    if (new_vert_coverage)
+      out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
+    
+    if (new_hori_coverage)
     out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
     return_trace (true);
   }

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-metrics.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -77,6 +77,7 @@
   (face->table.TABLE->has_data () && \
     (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
       face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+
   case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
     return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
 	   GET_METRIC_Y (hhea, ascender);
@@ -86,9 +87,13 @@
   case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
     return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) ||
 	   GET_METRIC_Y (hhea, lineGap);
+
+#ifndef HB_NO_VERTICAL
   case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:  return GET_METRIC_X (vhea, ascender);
   case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender);
   case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:  return GET_METRIC_X (vhea, lineGap);
+#endif
+
 #undef GET_METRIC_Y
 #undef GET_METRIC_X
 #undef GET_VAR
@@ -158,9 +163,11 @@
   case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:       return GET_METRIC_Y (hhea, caretSlopeRise);
   case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:        return GET_METRIC_X (hhea, caretSlopeRun);
   case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:     return GET_METRIC_X (hhea, caretOffset);
+#ifndef HB_NO_VERTICAL
   case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:         return GET_METRIC_X (vhea, caretSlopeRise);
   case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:          return GET_METRIC_Y (vhea, caretSlopeRun);
   case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:       return GET_METRIC_Y (vhea, caretOffset);
+#endif
   case HB_OT_METRICS_TAG_X_HEIGHT:                    return GET_METRIC_Y (OS2->v2 (), sxHeight);
   case HB_OT_METRICS_TAG_CAP_HEIGHT:                  return GET_METRIC_Y (OS2->v2 (), sCapHeight);
   case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:         return GET_METRIC_X (OS2, ySubscriptXSize);

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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-shape.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -628,20 +628,7 @@
       (HB_DIRECTION_IS_VERTICAL   (direction) &&
        direction != HB_DIRECTION_TTB))
   {
-
-    if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
-      foreach_grapheme (buffer, start, end)
-      {
-	buffer->merge_clusters (start, end);
-	buffer->reverse_range (start, end);
-      }
-    else
-      foreach_grapheme (buffer, start, end)
-	/* form_clusters() merged clusters already, we don't merge. */
-	buffer->reverse_range (start, end);
-
-    buffer->reverse ();
-
+    _hb_ot_layout_reverse_graphemes (buffer);
     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
   }
 }
@@ -651,6 +638,7 @@
  * Substitute
  */
 
+#ifndef HB_NO_VERTICAL
 static hb_codepoint_t
 hb_vert_char_for (hb_codepoint_t u)
 {
@@ -701,6 +689,7 @@
 
   return u;
 }
+#endif
 
 static inline void
 hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
@@ -723,6 +712,7 @@
     }
   }
 
+#ifndef HB_NO_VERTICAL
   if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
   {
     for (unsigned int i = 0; i < count; i++) {
@@ -731,6 +721,7 @@
 	info[i].codepoint = codepoint;
     }
   }
+#endif
 }
 
 static inline void

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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-tag-table.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -6,7 +6,7 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2021-09-02 09:40 PM" />
+ * <meta name="updated_at" content="2021-12-09 12:01 AM" />
  * File-Date: 2021-08-06
  */
 
@@ -933,6 +933,7 @@
   {"mnp",	HB_TAG('Z','H','S',' ')},	/* Min Bei Chinese -> Chinese, Simplified */
   {"mns",	HB_TAG('M','A','N',' ')},	/* Mansi */
   {"mnw",	HB_TAG('M','O','N',' ')},	/* Mon */
+  {"mnw",	HB_TAG('M','O','N','T')},	/* Mon -> Thailand Mon */
   {"mnx",	HB_TAG_NONE	       },	/* Manikion != Manx */
   {"mo",	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) */
   {"mod",	HB_TAG('C','P','P',' ')},	/* Mobilian -> Creoles */
@@ -1422,6 +1423,7 @@
   {"tia",	HB_TAG('B','B','R',' ')},	/* Tidikelt Tamazight -> Berber */
   {"tig",	HB_TAG('T','G','R',' ')},	/* Tigre */
 /*{"tiv",	HB_TAG('T','I','V',' ')},*/	/* Tiv */
+/*{"tjl",	HB_TAG('T','J','L',' ')},*/	/* Tai Laing */
   {"tjo",	HB_TAG('B','B','R',' ')},	/* Temacine Tamazight -> Berber */
   {"tk",	HB_TAG('T','K','M',' ')},	/* Turkmen */
   {"tkg",	HB_TAG('M','L','G',' ')},	/* Tesaka Malagasy -> Malagasy */
@@ -2521,6 +2523,14 @@
       *count = 1;
       return true;
     }
+    if (0 == strncmp (&lang_str[1], "nw-", 3)
+	&& subtag_matches (lang_str, limit, "-th"))
+    {
+      /* Mon; Thailand */
+      tags[0] = HB_TAG('M','O','N','T');  /* Thailand Mon */
+      *count = 1;
+      return true;
+    }
     break;
   case 'n':
     if (lang_matches (&lang_str[1], "an-hant-hk"))
@@ -2884,6 +2894,8 @@
     return hb_language_from_string ("man", -1);  /* Mandingo [macrolanguage] */
   case HB_TAG('M','O','L',' '):  /* Moldavian */
     return hb_language_from_string ("ro-MD", -1);  /* Romanian; Moldova */
+  case HB_TAG('M','O','N','T'):  /* Thailand Mon */
+    return hb_language_from_string ("mnw-TH", -1);  /* Mon; Thailand */
   case HB_TAG('M','Y','N',' '):  /* Mayan */
     return hb_language_from_string ("myn", -1);  /* Mayan [family] */
   case HB_TAG('N','A','H',' '):  /* Nahuatl */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-repacker.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -100,14 +100,20 @@
 
     bool is_leaf () const
     {
-      return !obj.links.length;
+      return !obj.real_links.length && !obj.virtual_links.length;
     }
 
-    void raise_priority ()
+    bool raise_priority ()
     {
+      if (has_max_priority ()) return false;
       priority++;
+      return true;
     }
 
+    bool has_max_priority () const {
+      return priority >= 3;
+    }
+
     int64_t modified_distance (unsigned order) const
     {
       // TODO(garretrieger): once priority is high enough, should try
@@ -115,8 +121,11 @@
       // it's parent where possible.
 
       int64_t modified_distance =
-          hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFF);
-      return (modified_distance << 22) | (0x003FFFFF & order);
+          hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
+      if (has_max_priority ()) {
+        modified_distance = 0;
+      }
+      return (modified_distance << 18) | (0x003FFFF & order);
     }
 
     int64_t distance_modifier () const
@@ -123,7 +132,11 @@
     {
       if (!priority) return 0;
       int64_t table_size = obj.tail - obj.head;
-      return -(table_size - table_size / (1 << hb_min(priority, 16u)));
+
+      if (priority == 1)
+        return -table_size / 2;
+
+      return -table_size;
     }
   };
 
@@ -164,9 +177,10 @@
       if (check_success (!vertices_.in_error ()))
         v->obj = *objects[i];
       if (!removed_nil) continue;
-      for (unsigned i = 0; i < v->obj.links.length; i++)
-        // Fix indices to account for removed nil object.
-        v->obj.links[i].objidx--;
+      // Fix indices to account for removed nil object.
+      for (auto& l : v->obj.all_links_writer ()) {
+        l.objidx--;
+      }
     }
   }
 
@@ -203,26 +217,46 @@
   /*
    * serialize graph into the provided serialization buffer.
    */
-  void serialize (hb_serialize_context_t* c) const
+  hb_blob_t* serialize () const
   {
-    c->start_serialize<void> ();
+    hb_vector_t<char> buffer;
+    size_t size = serialized_length ();
+    if (!buffer.alloc (size)) {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
+      return nullptr;
+    }
+    hb_serialize_context_t c((void *) buffer, size);
+
+    c.start_serialize<void> ();
     for (unsigned i = 0; i < vertices_.length; i++) {
-      c->push ();
+      c.push ();
 
       size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
-      char* start = c->allocate_size <char> (size);
-      if (!start) return;
+      char* start = c.allocate_size <char> (size);
+      if (!start) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
+        return nullptr;
+      }
 
       memcpy (start, vertices_[i].obj.head, size);
 
-      for (const auto& link : vertices_[i].obj.links)
-        serialize_link (link, start, c);
+      // Only real links needs to be serialized.
+      for (const auto& link : vertices_[i].obj.real_links)
+        serialize_link (link, start, &c);
 
       // All duplications are already encoded in the graph, so don't
       // enable sharing during packing.
-      c->pop_pack (false);
+      c.pop_pack (false);
     }
-    c->end_serialize ();
+    c.end_serialize ();
+
+    if (c.in_error ()) {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
+                 c.errors);
+      return nullptr;
+    }
+
+    return c.copy_blob ();
   }
 
   /*
@@ -260,7 +294,7 @@
       sorted_graph[new_id] = next;
       id_map[next_id] = new_id--;
 
-      for (const auto& link : next.obj.links) {
+      for (const auto& link : next.obj.all_links ()) {
         removed_edges[link.objidx]++;
         if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
           queue.push (link.objidx);
@@ -314,7 +348,7 @@
       sorted_graph[new_id] = next;
       id_map[next_id] = new_id--;
 
-      for (const auto& link : next.obj.links) {
+      for (const auto& link : next.obj.all_links ()) {
         removed_edges[link.objidx]++;
         if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
           // Add the order that the links were encountered to the priority.
@@ -348,7 +382,8 @@
     hb_set_t roots;
     for (unsigned i = 0; i <= root_index; i++)
     {
-      for (auto& l : vertices_[i].obj.links)
+      // Only real links can form 32 bit spaces
+      for (auto& l : vertices_[i].obj.real_links)
       {
         if (l.width == 4 && !l.is_signed)
         {
@@ -466,7 +501,7 @@
 
   void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
   {
-    for (const auto& link : vertices_[node_idx].obj.links)
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
     {
       if (subgraph.has (link.objidx))
       {
@@ -482,7 +517,7 @@
   {
     if (subgraph.has (node_idx)) return;
     subgraph.add (node_idx);
-    for (const auto& link : vertices_[node_idx].obj.links)
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
       find_subgraph (link.objidx, subgraph);
   }
 
@@ -497,7 +532,7 @@
       return;
 
     index_map.set (node_idx, duplicate (node_idx));
-    for (const auto& l : object (node_idx).links) {
+    for (const auto& l : object (node_idx).all_links ()) {
       duplicate_subgraph (l.objidx, index_map);
     }
   }
@@ -523,13 +558,19 @@
     clone->parents.reset ();
 
     unsigned clone_idx = vertices_.length - 2;
-    for (const auto& l : child.obj.links)
+    for (const auto& l : child.obj.real_links)
     {
-      clone->obj.links.push (l);
+      clone->obj.real_links.push (l);
       vertices_[l.objidx].parents.push (clone_idx);
     }
+    for (const auto& l : child.obj.virtual_links)
+    {
+      clone->obj.virtual_links.push (l);
+      vertices_[l.objidx].parents.push (clone_idx);
+    }
 
-    check_success (!clone->obj.links.in_error ());
+    check_success (!clone->obj.real_links.in_error ());
+    check_success (!clone->obj.virtual_links.in_error ());
 
     // The last object is the root of the graph, so swap back the root to the end.
     // The root's obj idx does change, however since it's root nothing else refers to it.
@@ -539,7 +580,7 @@
     vertices_[vertices_.length - 1] = root;
 
     // Since the root moved, update the parents arrays of all children on the root.
-    for (const auto& l : root.obj.links)
+    for (const auto& l : root.obj.all_links ())
       vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
 
     return clone_idx;
@@ -555,7 +596,7 @@
     update_parents ();
 
     unsigned links_to_child = 0;
-    for (const auto& l : vertices_[parent_idx].obj.links)
+    for (const auto& l : vertices_[parent_idx].obj.all_links ())
     {
       if (l.objidx == child_idx) links_to_child++;
     }
@@ -578,9 +619,8 @@
     if (parent_idx == clone_idx) parent_idx++;
 
     auto& parent = vertices_[parent_idx];
-    for (unsigned i = 0; i < parent.obj.links.length; i++)
+    for (auto& l : parent.obj.all_links_writer ())
     {
-      auto& l = parent.obj.links[i];
       if (l.objidx != child_idx)
         continue;
 
@@ -593,7 +633,7 @@
   /*
    * Raises the sorting priority of all children.
    */
-  void raise_childrens_priority (unsigned parent_idx)
+  bool raise_childrens_priority (unsigned parent_idx)
   {
     DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %d",
                parent_idx);
@@ -601,8 +641,10 @@
     // to invalidate positions. It does not change graph structure so no need
     // to update distances or edge counts.
     auto& parent = vertices_[parent_idx].obj;
-    for (unsigned i = 0; i < parent.links.length; i++)
-      vertices_[parent.links[i].objidx].raise_priority ();
+    bool made_change = false;
+    for (auto& l : parent.all_links_writer ())
+      made_change |= vertices_[l.objidx].raise_priority ();
+    return made_change;
   }
 
   /*
@@ -615,7 +657,8 @@
 
     for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
     {
-      for (const auto& link : vertices_[parent_idx].obj.links)
+      // Don't need to check virtual links for overflow
+      for (const auto& link : vertices_[parent_idx].obj.real_links)
       {
         int64_t offset = compute_offset (parent_idx, link);
         if (is_valid_offset (offset, link))
@@ -655,8 +698,10 @@
     if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
 
     update_parents ();
+    int limit = 10;
     for (const auto& o : overflows)
     {
+      if (!limit--) break;
       const auto& parent = vertices_[o.parent];
       const auto& child = vertices_[o.child];
       DEBUG_MSG (SUBSET_REPACK, nullptr,
@@ -665,13 +710,16 @@
                  "%4d (%4d in, %4d out, space %2d)",
                  o.parent,
                  parent.incoming_edges (),
-                 parent.obj.links.length,
+                 parent.obj.real_links.length + parent.obj.virtual_links.length,
                  space_for (o.parent),
                  o.child,
                  child.incoming_edges (),
-                 child.obj.links.length,
+                 child.obj.real_links.length + child.obj.virtual_links.length,
                  space_for (o.child));
     }
+    if (overflows.length > 10) {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %d more overflows.", overflows.length - 10);
+    }
   }
 
   unsigned num_roots_for_space (unsigned space) const
@@ -684,12 +732,19 @@
     return num_roots_for_space_.length;
   }
 
-  void move_to_new_space (unsigned index)
+  void move_to_new_space (const hb_set_t& indices)
   {
-    auto& node = vertices_[index];
-    num_roots_for_space_.push (1);
-    num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
-    node.space = num_roots_for_space_.length - 1;
+    num_roots_for_space_.push (0);
+    unsigned new_space = num_roots_for_space_.length - 1;
+
+    for (unsigned index : indices) {
+      auto& node = vertices_[index];
+      num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
+      num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
+      node.space = new_space;
+      distance_invalid = true;
+      positions_invalid = true;
+    }
   }
 
   unsigned space_for (unsigned index, unsigned* root = nullptr) const
@@ -716,6 +771,15 @@
 
  private:
 
+  size_t serialized_length () const {
+    size_t total_size = 0;
+    for (unsigned i = 0; i < vertices_.length; i++) {
+      size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
+      total_size += size;
+    }
+    return total_size;
+  }
+
   /*
    * Returns the numbers of incoming edges that are 32bits wide.
    */
@@ -728,7 +792,8 @@
       if (visited.has (p)) continue;
       visited.add (p);
 
-      for (const auto& l : vertices_[p].obj.links)
+      // Only real links can be wide
+      for (const auto& l : vertices_[p].obj.real_links)
       {
         if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
         {
@@ -755,7 +820,7 @@
 
     for (unsigned p = 0; p < vertices_.length; p++)
     {
-      for (auto& l : vertices_[p].obj.links)
+      for (auto& l : vertices_[p].obj.all_links ())
       {
         vertices_[l.objidx].parents.push (p);
       }
@@ -823,7 +888,7 @@
       int64_t next_distance = vertices_[next_idx].distance;
       visited[next_idx] = true;
 
-      for (const auto& link : next.obj.links)
+      for (const auto& link : next.obj.all_links ())
       {
         if (visited[link.objidx]) continue;
 
@@ -922,9 +987,8 @@
     if (!id_map) return;
     for (unsigned i : subgraph)
     {
-      for (unsigned j = 0; j < vertices_[i].obj.links.length; j++)
+      for (auto& link : vertices_[i].obj.all_links_writer ())
       {
-        auto& link = vertices_[i].obj.links[j];
         if (!id_map.has (link.objidx)) continue;
         if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
 
@@ -942,9 +1006,8 @@
     for (unsigned i = 0; i < sorted_graph->length; i++)
     {
       (*sorted_graph)[i].remap_parents (id_map);
-      for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
+      for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
       {
-        auto& link = (*sorted_graph)[i].obj.links[j];
         link.objidx = id_map[link.objidx];
       }
     }
@@ -1023,7 +1086,7 @@
     const auto& v = vertices_[start_idx];
 
     // Graph is treated as undirected so search children and parents of start_idx
-    for (const auto& l : v.obj.links)
+    for (const auto& l : v.obj.all_links ())
       find_connected_nodes (l.objidx, targets, visited, connected);
 
     for (unsigned p : v.parents)
@@ -1044,27 +1107,50 @@
 static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
                                       graph_t& sorted_graph)
 {
+  unsigned space = 0;
+  hb_set_t roots_to_isolate;
+
   for (int i = overflows.length - 1; i >= 0; i--)
   {
     const graph_t::overflow_record_t& r = overflows[i];
-    unsigned root = 0;
-    unsigned space = sorted_graph.space_for (r.parent, &root);
-    if (!space) continue;
-    if (sorted_graph.num_roots_for_space (space) <= 1) continue;
 
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "Overflow in space %d moving subgraph %d to space %d.",
-               space,
-               root,
-               sorted_graph.next_space ());
+    unsigned root;
+    unsigned overflow_space = sorted_graph.space_for (r.parent, &root);
+    if (!overflow_space) continue;
+    if (sorted_graph.num_roots_for_space (overflow_space) <= 1) continue;
 
-    hb_set_t roots;
-    roots.add (root);
-    sorted_graph.isolate_subgraph (roots);
-    for (unsigned new_root : roots)
-      sorted_graph.move_to_new_space (new_root);
-    return true;
+    if (!space) {
+      space = overflow_space;
+    }
+
+    if (space == overflow_space)
+      roots_to_isolate.add(root);
   }
-  return false;
+
+  if (!roots_to_isolate) return false;
+
+  unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u);
+  if (roots_to_isolate.get_population () > maximum_to_move) {
+    // Only move at most half of the roots in a space at a time.
+    unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
+    while (extra--) {
+      unsigned root = HB_SET_VALUE_INVALID;
+      roots_to_isolate.previous (&root);
+      roots_to_isolate.del (root);
+    }
+  }
+
+  DEBUG_MSG (SUBSET_REPACK, nullptr,
+             "Overflow in space %d (%d roots). Moving %d roots to space %d.",
+             space,
+             sorted_graph.num_roots_for_space (space),
+             roots_to_isolate.get_population (),
+             sorted_graph.next_space ());
+
+  sorted_graph.isolate_subgraph (roots_to_isolate);
+  sorted_graph.move_to_new_space (roots_to_isolate);
+
+  return true;
 }
 
 static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
@@ -1093,7 +1179,6 @@
       // TODO(garretrieger): initially limiting this to leaf's since they can be
       //                     moved closer with fewer consequences. However, this can
       //                     likely can be used for non-leafs as well.
-      // TODO(garretrieger): add a maximum priority, don't try to raise past this.
       // TODO(garretrieger): also try lowering priority of the parent. Make it
       //                     get placed further up in the ordering, closer to it's children.
       //                     this is probably preferable if the total size of the parent object
@@ -1100,9 +1185,10 @@
       //                     is < then the total size of the children (and the parent can be moved).
       //                     Since in that case moving the parent will cause a smaller increase in
       //                     the length of other offsets.
-      sorted_graph.raise_childrens_priority (r.parent);
-      priority_bumped_parents.add (r.parent);
-      resolution_attempted = true;
+      if (sorted_graph.raise_childrens_priority (r.parent)) {
+        priority_bumped_parents.add (r.parent);
+        resolution_attempted = true;
+      }
       continue;
     }
 
@@ -1127,11 +1213,10 @@
  * For a detailed writeup describing how the algorithm operates see:
  * docs/repacker.md
  */
-inline void
+inline hb_blob_t*
 hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed,
                       hb_tag_t table_tag,
-                      hb_serialize_context_t* c,
-                      unsigned max_rounds = 10) {
+                      unsigned max_rounds = 20) {
   // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts
   // so try it first to save time.
   graph_t sorted_graph (packed);
@@ -1138,8 +1223,7 @@
   sorted_graph.sort_kahn ();
   if (!sorted_graph.will_overflow ())
   {
-    sorted_graph.serialize (c);
-    return;
+    return sorted_graph.serialize ();
   }
 
   sorted_graph.sort_shortest_distance ();
@@ -1178,17 +1262,17 @@
 
   if (sorted_graph.in_error ())
   {
-    c->err (HB_SERIALIZE_ERROR_OTHER);
-    return;
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state.");
+    return nullptr;
   }
 
   if (sorted_graph.will_overflow ())
   {
-    c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
-    return;
+    return nullptr;
   }
-  sorted_graph.serialize (c);
+
+  return sorted_graph.serialize ();
 }
 
 #endif /* HB_REPACKER_HH */

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-serialize.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -65,19 +65,26 @@
 
   struct object_t
   {
-    void fini () { links.fini (); }
+    void fini () {
+      real_links.fini ();
+      virtual_links.fini ();
+    }
 
     bool operator == (const object_t &o) const
     {
+      // Virtual links aren't considered for equality since they don't affect the functionality
+      // of the object.
       return (tail - head == o.tail - o.head)
-	  && (links.length == o.links.length)
+	  && (real_links.length == o.real_links.length)
 	  && 0 == hb_memcmp (head, o.head, tail - head)
-	  && links.as_bytes () == o.links.as_bytes ();
+	  && real_links.as_bytes () == o.real_links.as_bytes ();
     }
     uint32_t hash () const
     {
+      // Virtual links aren't considered for equality since they don't affect the functionality
+      // of the object.
       return hb_bytes_t (head, tail - head).hash () ^
-	     links.as_bytes ().hash ();
+          real_links.as_bytes ().hash ();
     }
 
     struct link_t
@@ -92,8 +99,14 @@
 
     char *head;
     char *tail;
-    hb_vector_t<link_t> links;
+    hb_vector_t<link_t> real_links;
+    hb_vector_t<link_t> virtual_links;
     object_t *next;
+
+    auto all_links () const HB_AUTO_RETURN
+        (( hb_concat (this->real_links, this->virtual_links) ));
+    auto all_links_writer () HB_AUTO_RETURN
+        (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
   };
 
   struct snapshot_t
@@ -101,12 +114,14 @@
     char *head;
     char *tail;
     object_t *current; // Just for sanity check
-    unsigned num_links;
+    unsigned num_real_links;
+    unsigned num_virtual_links;
     hb_serialize_error_t errors;
   };
 
   snapshot_t snapshot ()
-  { return snapshot_t { head, tail, current, current->links.length, errors }; }
+  { return snapshot_t {
+      head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
 
   hb_serialize_context_t (void *start_, unsigned int size) :
     start ((char *) start_),
@@ -282,7 +297,8 @@
 
     if (!len)
     {
-      assert (!obj->links.length);
+      assert (!obj->real_links.length);
+      assert (!obj->virtual_links.length);
       return 0;
     }
 
@@ -292,6 +308,7 @@
       objidx = packed_map.get (obj);
       if (objidx)
       {
+        merge_virtual_links (obj, objidx);
 	obj->fini ();
 	return objidx;
       }
@@ -327,7 +344,8 @@
     // 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);
+    current->real_links.shrink (snap.num_real_links);
+    current->virtual_links.shrink (snap.num_virtual_links);
     errors = snap.errors;
     revert (snap.head, snap.tail);
   }
@@ -375,8 +393,8 @@
 
     assert (current);
 
-    auto& link = *current->links.push ();
-    if (current->links.in_error ())
+    auto& link = *current->virtual_links.push ();
+    if (current->virtual_links.in_error ())
       err (HB_SERIALIZE_ERROR_OTHER);
 
     link.width = 0;
@@ -400,8 +418,8 @@
     assert (current);
     assert (current->head <= (const char *) &ofs);
 
-    auto& link = *current->links.push ();
-    if (current->links.in_error ())
+    auto& link = *current->real_links.push ();
+    if (current->real_links.in_error ())
       err (HB_SERIALIZE_ERROR_OTHER);
 
     link.width = sizeof (T);
@@ -440,10 +458,8 @@
     assert (packed.length > 1);
 
     for (const object_t* parent : ++hb_iter (packed))
-      for (const object_t::link_t &link : parent->links)
+      for (const object_t::link_t &link : parent->real_links)
       {
-        if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets
-
 	const object_t* child = packed[link.objidx];
 	if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
 	unsigned offset = 0;
@@ -642,6 +658,13 @@
 
   private:
 
+  void merge_virtual_links (const object_t* from, objidx_t to_idx) {
+    object_t* to = packed[to_idx];
+    for (const auto& l : from->virtual_links) {
+      to->virtual_links.push (l);
+    }
+  }
+
   /* Object memory pool. */
   hb_pool_t<object_t> object_pool;
 

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-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -248,7 +248,6 @@
   unsigned glyphs_num;
   {
     glyphs_num = glyphs_colred->get_population ();
-
     // Collect all glyphs referenced by COLRv0
     hb_set_t glyphset_colrv0;
     for (hb_codepoint_t gid : glyphs_colred->iter ())
@@ -397,6 +396,7 @@
   _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
   _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
 
+  hb_set_set (plan->_glyphset_colred, &cur_glyphset);
   // Populate a full set of glyphs to retain by adding all referenced
   // composite glyphs.
   for (hb_codepoint_t gid : cur_glyphset.iter ())
@@ -511,6 +511,7 @@
   plan->_glyphset = hb_set_create ();
   plan->_glyphset_gsub = hb_set_create ();
   plan->_glyphset_mathed = hb_set_create ();
+  plan->_glyphset_colred = hb_set_create ();
   plan->codepoint_to_glyph = hb_map_create ();
   plan->glyph_map = hb_map_create ();
   plan->reverse_glyph_map = hb_map_create ();
@@ -579,6 +580,7 @@
   hb_set_destroy (plan->_glyphset);
   hb_set_destroy (plan->_glyphset_gsub);
   hb_set_destroy (plan->_glyphset_mathed);
+  hb_set_destroy (plan->_glyphset_colred);
   hb_map_destroy (plan->gsub_lookups);
   hb_map_destroy (plan->gpos_lookups);
   hb_map_destroy (plan->gsub_features);

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset-plan.hh	2021-12-12 23:55:43 UTC (rev 61290)
@@ -78,6 +78,7 @@
   hb_set_t *_glyphset;
   hb_set_t *_glyphset_gsub;
   hb_set_t *_glyphset_mathed;
+  hb_set_t *_glyphset_colred;
 
   //active lookups we'd like to retain
   hb_map_t *gsub_lookups;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-subset.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -104,20 +104,16 @@
   if (!c.offset_overflow ())
     return c.copy_blob ();
 
-  hb_vector_t<char> buf;
-  int buf_size = c.end - c.start;
-  if (unlikely (!buf.alloc (buf_size)))
-    return nullptr;
+  hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag);
 
-  hb_serialize_context_t repacked ((void *) buf, buf_size);
-  hb_resolve_overflows (c.object_graph (), tag, &repacked);
-
-  if (unlikely (repacked.in_error ()))
-    // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset
-    //                     portion.
+  if (unlikely (!result))
+  {
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.",
+               HB_UNTAG (tag));
     return nullptr;
+  }
 
-  return repacked.copy_blob ();
+  return result;
 }
 
 template<typename TableType>

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-uniscribe.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-uniscribe.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-uniscribe.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -878,7 +878,7 @@
   if (backward)
     hb_buffer_reverse (buffer);
 
-  buffer->unsafe_to_break_all ();
+  buffer->clear_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK);
 
   /* Wow, done! */
   return true;

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/meson.build	2021-12-12 23:55:43 UTC (rev 61290)
@@ -363,6 +363,7 @@
 if conf.get('HAVE_DIRECTWRITE', 0) == 1
   hb_sources += hb_directwrite_sources
   hb_headers += hb_directwrite_headers
+  harfbuzz_deps += directwrite_dep
   # hb-directwrite needs a C++ linker
   libharfbuzz_link_language = 'cpp'
 endif

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-iter.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -114,6 +114,78 @@
   test_iterator (lst.iter ());
 }
 
+template <typename It>
+static void check_sequential (It it)
+{
+  int i = 1;
+  for (int v : +it) {
+    assert (v == i++);
+  }
+}
+
+static void test_concat ()
+{
+  hb_vector_t<int> a = {1, 2, 3};
+  hb_vector_t<int> b = {4, 5};
+
+  hb_vector_t<int> c = {};
+  hb_vector_t<int> d = {1, 2, 3, 4, 5};
+
+  auto it1 = hb_concat (a, b);
+  assert (it1.len () == 5);
+  assert (it1.is_random_access_iterator);
+  auto it2 = hb_concat (c, d);
+  assert (it2.len () == 5);
+  auto it3 = hb_concat (d, c);
+  assert (it3.len () == 5);
+  for (int i = 0; i < 5; i++) {
+    assert(it1[i] == i + 1);
+    assert(it2[i] == i + 1);
+    assert(it3[i] == i + 1);
+  }
+
+  check_sequential (it1);
+  check_sequential (it2);
+  check_sequential (it3);
+
+  auto it4 = +it1;
+  it4 += 0;
+  assert (*it4 == 1);
+
+  it4 += 2;
+  assert (*it4 == 3);
+  assert (it4);
+  assert (it4.len () == 3);
+
+  it4 += 2;
+  assert (*it4 == 5);
+  assert (it4);
+  assert (it4.len () == 1);
+
+  it4++;
+  assert (!it4);
+  assert (it4.len () == 0);
+
+  auto it5 = +it1;
+  it5 += 3;
+  assert (*it5 == 4);
+
+  hb_set_t s_a = {1, 2, 3};
+  hb_set_t s_b = {4, 5};
+  auto it6 = hb_concat (s_a, s_b);
+  assert (!it6.is_random_access_iterator);
+  check_sequential (it6);
+  assert (it6.len () == 5);
+
+  it6 += 0;
+  assert (*it6 == 1);
+
+  it6 += 3;
+  assert (*it6 == 4);
+  assert (it6);
+  assert (it6.len () == 2);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -282,5 +354,7 @@
   assert (hb_range (-2, -8, -3).len () == 2);
   assert (hb_range (-2, -7, -3).len () == 2);
 
+  test_concat ();
+
   return 0;
 }

Modified: trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc
===================================================================
--- trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/harfbuzz-src/src/test-repacker.cc	2021-12-12 23:55:43 UTC (rev 61290)
@@ -74,15 +74,14 @@
 
   graph_t graph (overflowing.object_graph ());
 
-  unsigned buffer_size = overflowing.end - overflowing.start;
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
 
   assert (overflowing.offset_overflow ());
-  hb_resolve_overflows (overflowing.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, num_iterations);
-  assert (!out.offset_overflow ());
-  hb_bytes_t result = out.copy_bytes ();
+  hb_blob_t* out = hb_resolve_overflows (overflowing.object_graph (),
+                                         HB_TAG ('G', 'S', 'U', 'B'), num_iterations);
+  assert (out);
 
+  hb_bytes_t result = out->as_bytes ();
+
   assert (!expected.offset_overflow ());
   hb_bytes_t expected_result = expected.copy_bytes ();
 
@@ -92,9 +91,8 @@
     assert (result[i] == expected_result[i]);
   }
 
-  result.fini ();
   expected_result.fini ();
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
 static void add_virtual_offset (unsigned id,
@@ -139,6 +137,58 @@
 }
 
 static void
+populate_serializer_with_priority_overflow (hb_serialize_context_t* c)
+{
+  std::string large_string(50000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_e = add_object ("e", 1, c);
+  unsigned obj_d = add_object ("d", 1, c);
+
+  start_object (large_string.c_str (), 50000, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  start_object (large_string.c_str (), 20000, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+static void
+populate_serializer_with_priority_overflow_expected (hb_serialize_context_t* c)
+{
+  std::string large_string(50000, 'a');
+  c->start_serialize<char> ();
+
+  unsigned obj_e = add_object ("e", 1, c);
+
+  start_object (large_string.c_str (), 50000, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack (false);
+
+  unsigned obj_d = add_object ("d", 1, c);
+
+  start_object (large_string.c_str (), 20000, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack (false);
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_offset (obj_c, c);
+  c->pop_pack (false);
+
+  c->end_serialize();
+}
+
+
+static void
 populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
 {
   std::string large_string(70000, 'a');
@@ -763,20 +813,20 @@
 
   start_object ("b", 1, c);
   add_offset (obj_d, c);
-  unsigned obj_b = c->pop_pack ();
+  unsigned obj_b = c->pop_pack (false);
 
   start_object ("e", 1, c);
   add_virtual_offset (obj_b, c);
-  unsigned obj_e = c->pop_pack();
+  unsigned obj_e = c->pop_pack (false);
 
   start_object ("c", 1, c);
   add_offset (obj_e, c);
-  unsigned obj_c = c->pop_pack ();
+  unsigned obj_c = c->pop_pack (false);
 
   start_object ("a", 1, c);
   add_offset (obj_b, c);
   add_offset (obj_c, c);
-  c->pop_pack ();
+  c->pop_pack (false);
 
   c->end_serialize();
 }
@@ -792,19 +842,19 @@
   graph.sort_kahn ();
 
   assert(strncmp (graph.object (3).head, "abc", 3) == 0);
-  assert(graph.object (3).links.length == 2);
-  assert(graph.object (3).links[0].objidx == 2);
-  assert(graph.object (3).links[1].objidx == 1);
+  assert(graph.object (3).real_links.length == 2);
+  assert(graph.object (3).real_links[0].objidx == 2);
+  assert(graph.object (3).real_links[1].objidx == 1);
 
   assert(strncmp (graph.object (2).head, "def", 3) == 0);
-  assert(graph.object (2).links.length == 1);
-  assert(graph.object (2).links[0].objidx == 0);
+  assert(graph.object (2).real_links.length == 1);
+  assert(graph.object (2).real_links[0].objidx == 0);
 
   assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
-  assert(graph.object (1).links.length == 0);
+  assert(graph.object (1).real_links.length == 0);
 
   assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
-  assert(graph.object (0).links.length == 0);
+  assert(graph.object (0).real_links.length == 0);
 
   free (buffer);
 }
@@ -821,24 +871,24 @@
 
 
   assert(strncmp (graph.object (4).head, "abc", 3) == 0);
-  assert(graph.object (4).links.length == 3);
-  assert(graph.object (4).links[0].objidx == 3);
-    assert(graph.object (4).links[1].objidx == 0);
-  assert(graph.object (4).links[2].objidx == 2);
+  assert(graph.object (4).real_links.length == 3);
+  assert(graph.object (4).real_links[0].objidx == 3);
+    assert(graph.object (4).real_links[1].objidx == 0);
+  assert(graph.object (4).real_links[2].objidx == 2);
 
   assert(strncmp (graph.object (3).head, "def", 3) == 0);
-  assert(graph.object (3).links.length == 1);
-  assert(graph.object (3).links[0].objidx == 1);
+  assert(graph.object (3).real_links.length == 1);
+  assert(graph.object (3).real_links[0].objidx == 1);
 
   assert(strncmp (graph.object (2).head, "mn", 2) == 0);
-  assert(graph.object (2).links.length == 0);
+  assert(graph.object (2).real_links.length == 0);
 
   assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
-  assert(graph.object (1).links.length == 1);
-  assert(graph.object (1).links[0].objidx == 0);
+  assert(graph.object (1).real_links.length == 1);
+  assert(graph.object (1).real_links[0].objidx == 0);
 
   assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
-  assert(graph.object (0).links.length == 0);
+  assert(graph.object (0).real_links.length == 0);
 
   free (buffer);
 }
@@ -854,24 +904,24 @@
   graph.sort_shortest_distance ();
 
   assert(strncmp (graph.object (4).head, "abc", 3) == 0);
-  assert(graph.object (4).links.length == 3);
-  assert(graph.object (4).links[0].objidx == 2);
-  assert(graph.object (4).links[1].objidx == 0);
-  assert(graph.object (4).links[2].objidx == 3);
+  assert(graph.object (4).real_links.length == 3);
+  assert(graph.object (4).real_links[0].objidx == 2);
+  assert(graph.object (4).real_links[1].objidx == 0);
+  assert(graph.object (4).real_links[2].objidx == 3);
 
   assert(strncmp (graph.object (3).head, "mn", 2) == 0);
-  assert(graph.object (3).links.length == 0);
+  assert(graph.object (3).real_links.length == 0);
 
   assert(strncmp (graph.object (2).head, "def", 3) == 0);
-  assert(graph.object (2).links.length == 1);
-  assert(graph.object (2).links[0].objidx == 1);
+  assert(graph.object (2).real_links.length == 1);
+  assert(graph.object (2).real_links[0].objidx == 1);
 
   assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
-  assert(graph.object (1).links.length == 1);
-  assert(graph.object (1).links[0].objidx == 0);
+  assert(graph.object (1).real_links.length == 1);
+  assert(graph.object (1).real_links[0].objidx == 0);
 
   assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
-  assert(graph.object (0).links.length == 0);
+  assert(graph.object (0).real_links.length == 0);
 
   free (buffer);
 }
@@ -887,27 +937,27 @@
   graph.duplicate (4, 1);
 
   assert(strncmp (graph.object (5).head, "abc", 3) == 0);
-  assert(graph.object (5).links.length == 3);
-  assert(graph.object (5).links[0].objidx == 3);
-  assert(graph.object (5).links[1].objidx == 4);
-  assert(graph.object (5).links[2].objidx == 0);
+  assert(graph.object (5).real_links.length == 3);
+  assert(graph.object (5).real_links[0].objidx == 3);
+  assert(graph.object (5).real_links[1].objidx == 4);
+  assert(graph.object (5).real_links[2].objidx == 0);
 
   assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
-  assert(graph.object (4).links.length == 0);
+  assert(graph.object (4).real_links.length == 0);
 
   assert(strncmp (graph.object (3).head, "def", 3) == 0);
-  assert(graph.object (3).links.length == 1);
-  assert(graph.object (3).links[0].objidx == 2);
+  assert(graph.object (3).real_links.length == 1);
+  assert(graph.object (3).real_links[0].objidx == 2);
 
   assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
-  assert(graph.object (2).links.length == 1);
-  assert(graph.object (2).links[0].objidx == 1);
+  assert(graph.object (2).real_links.length == 1);
+  assert(graph.object (2).real_links[0].objidx == 1);
 
   assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
-  assert(graph.object (1).links.length == 0);
+  assert(graph.object (1).real_links.length == 0);
 
   assert(strncmp (graph.object (0).head, "mn", 2) == 0);
-  assert(graph.object (0).links.length == 0);
+  assert(graph.object (0).real_links.length == 0);
 
   free (buffer);
 }
@@ -923,32 +973,32 @@
   graph.duplicate (3, 2);
 
   assert(strncmp (graph.object (6).head, "abc", 3) == 0);
-  assert(graph.object (6).links.length == 3);
-  assert(graph.object (6).links[0].objidx == 4);
-  assert(graph.object (6).links[1].objidx == 2);
-  assert(graph.object (6).links[2].objidx == 1);
+  assert(graph.object (6).real_links.length == 3);
+  assert(graph.object (6).real_links[0].objidx == 4);
+  assert(graph.object (6).real_links[1].objidx == 2);
+  assert(graph.object (6).real_links[2].objidx == 1);
 
   assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
-  assert(graph.object (5).links.length == 1);
-  assert(graph.object (5).links[0].objidx == 0);
+  assert(graph.object (5).real_links.length == 1);
+  assert(graph.object (5).real_links[0].objidx == 0);
 
   assert(strncmp (graph.object (4).head, "def", 3) == 0);
-  assert(graph.object (4).links.length == 1);
-  assert(graph.object (4).links[0].objidx == 3);
+  assert(graph.object (4).real_links.length == 1);
+  assert(graph.object (4).real_links[0].objidx == 3);
 
   assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
-  assert(graph.object (3).links.length == 1);
-  assert(graph.object (3).links[0].objidx == 5);
+  assert(graph.object (3).real_links.length == 1);
+  assert(graph.object (3).real_links[0].objidx == 5);
 
   assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
-  assert(graph.object (2).links.length == 1);
-  assert(graph.object (2).links[0].objidx == 0);
+  assert(graph.object (2).real_links.length == 1);
+  assert(graph.object (2).real_links[0].objidx == 0);
 
   assert(strncmp (graph.object (1).head, "mn", 2) == 0);
-  assert(graph.object (1).links.length == 0);
+  assert(graph.object (1).real_links.length == 0);
 
   assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
-  assert(graph.object (0).links.length == 0);
+  assert(graph.object (0).real_links.length == 0);
 
   free (buffer);
 }
@@ -962,19 +1012,14 @@
   populate_serializer_simple (&c1);
   hb_bytes_t expected = c1.copy_bytes ();
 
-  void* buffer_2 = malloc (buffer_size);
-  hb_serialize_context_t c2 (buffer_2, buffer_size);
-
   graph_t graph (c1.object_graph ());
-  graph.serialize (&c2);
-  hb_bytes_t actual = c2.copy_bytes ();
+  hb_blob_t* out = graph.serialize ();
+  free (buffer_1);
 
+  hb_bytes_t actual = out->as_bytes ();
   assert (actual == expected);
-
-  actual.fini ();
   expected.fini ();
-  free (buffer_1);
-  free (buffer_2);
+  hb_blob_destroy (out);
 }
 
 static void test_will_overflow_1 ()
@@ -1024,17 +1069,13 @@
   populate_serializer_with_overflow (&c);
   graph_t graph (c.object_graph ());
 
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
-
-  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
-  assert (!out.offset_overflow ());
-  hb_bytes_t result = out.copy_bytes ();
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
   assert (result.length == (80000 + 3 + 3 * 2));
 
-  result.fini ();
   free (buffer);
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
 static void test_resolve_overflows_via_duplication ()
@@ -1045,17 +1086,13 @@
   populate_serializer_with_dedup_overflow (&c);
   graph_t graph (c.object_graph ());
 
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
-
-  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
-  assert (!out.offset_overflow ());
-  hb_bytes_t result = out.copy_bytes ();
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
   assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
 
-  result.fini ();
   free (buffer);
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
 static void test_resolve_overflows_via_space_assignment ()
@@ -1085,19 +1122,15 @@
   populate_serializer_with_isolation_overflow (&c);
   graph_t graph (c.object_graph ());
 
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
-
   assert (c.offset_overflow ());
-  hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
-  assert (!out.offset_overflow ());
-  hb_bytes_t result = out.copy_bytes ();
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
   assert (result.length == (1 + 10000 + 60000 + 1 + 1
                             + 4 + 3 * 2));
 
-  result.fini ();
   free (buffer);
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
 static void test_resolve_overflows_via_isolation_with_recursive_duplication ()
@@ -1164,21 +1197,17 @@
   populate_serializer_with_isolation_overflow_spaces (&c);
   graph_t graph (c.object_graph ());
 
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
-
   assert (c.offset_overflow ());
-  hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
-  assert (!out.offset_overflow ());
-  hb_bytes_t result = out.copy_bytes ();
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+  assert (out);
+  hb_bytes_t result = out->as_bytes ();
 
   unsigned expected_length = 3 + 2 * 60000; // objects
   expected_length += 2 * 4 + 2 * 2; // links
   assert (result.length == expected_length);
 
-  result.fini ();
   free (buffer);
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
 static void test_resolve_overflows_via_splitting_spaces ()
@@ -1221,6 +1250,26 @@
   free (expected_buffer);
 }
 
+static void test_resolve_overflows_via_priority ()
+{
+  size_t buffer_size = 160000;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+  populate_serializer_with_priority_overflow (&c);
+
+  void* expected_buffer = malloc (buffer_size);
+  hb_serialize_context_t e (expected_buffer, buffer_size);
+  populate_serializer_with_priority_overflow_expected (&e);
+
+  run_resolve_overflow_test ("test_resolve_overflows_via_priority",
+                             c,
+                             e,
+                             3);
+  free (buffer);
+  free (expected_buffer);
+}
+
+
 static void test_virtual_link ()
 {
   size_t buffer_size = 100;
@@ -1228,13 +1277,10 @@
   hb_serialize_context_t c (buffer, buffer_size);
   populate_serializer_virtual_link (&c);
 
-  void* out_buffer = malloc (buffer_size);
-  hb_serialize_context_t out (out_buffer, buffer_size);
+  hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+  assert (out);
 
-  hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
-  assert (!out.offset_overflow ());
-
-  hb_bytes_t result = out.copy_bytes ();
+  hb_bytes_t result = out->as_bytes ();
   assert (result.length == 5 + 4 * 2);
   assert (result[0]  == 'a');
   assert (result[5]  == 'c');
@@ -1242,11 +1288,47 @@
   assert (result[9]  == 'b');
   assert (result[12] == 'd');
 
-  result.fini ();
   free (buffer);
-  free (out_buffer);
+  hb_blob_destroy (out);
 }
 
+static void
+test_shared_node_with_virtual_links ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  hb_serialize_context_t c (buffer, buffer_size);
+
+  c.start_serialize<char> ();
+
+  unsigned obj_b = add_object ("b", 1, &c);
+  unsigned obj_c = add_object ("c", 1, &c);
+
+  start_object ("d", 1, &c);
+  add_virtual_offset (obj_b, &c);
+  unsigned obj_d_1 = c.pop_pack ();
+
+  start_object ("d", 1, &c);
+  add_virtual_offset (obj_c, &c);
+  unsigned obj_d_2 = c.pop_pack ();
+
+  assert (obj_d_1 == obj_d_2);
+
+  start_object ("a", 1, &c);
+  add_offset (obj_b, &c);
+  add_offset (obj_c, &c);
+  add_offset (obj_d_1, &c);
+  add_offset (obj_d_2, &c);
+  c.pop_pack ();
+  c.end_serialize ();
+
+  assert(c.object_graph() [obj_d_1]->virtual_links.length == 2);
+  assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b);
+  assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c);
+  free(buffer);
+}
+
+
 // TODO(garretrieger): update will_overflow tests to check the overflows array.
 // TODO(garretrieger): add tests for priority raising.
 
@@ -1262,6 +1344,7 @@
   test_will_overflow_3 ();
   test_resolve_overflows_via_sort ();
   test_resolve_overflows_via_duplication ();
+  test_resolve_overflows_via_priority ();
   test_resolve_overflows_via_space_assignment ();
   test_resolve_overflows_via_isolation ();
   test_resolve_overflows_via_isolation_with_recursive_duplication ();
@@ -1273,4 +1356,5 @@
   test_duplicate_leaf ();
   test_duplicate_interior ();
   test_virtual_link ();
+  test_shared_node_with_virtual_links ();
 }

Modified: trunk/Build/source/libs/harfbuzz/version.ac
===================================================================
--- trunk/Build/source/libs/harfbuzz/version.ac	2021-12-12 22:31:41 UTC (rev 61289)
+++ trunk/Build/source/libs/harfbuzz/version.ac	2021-12-12 23:55:43 UTC (rev 61290)
@@ -8,4 +8,4 @@
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current harfbuzz version
-m4_define([harfbuzz_version], [3.1.2])
+m4_define([harfbuzz_version], [3.2.0])



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