فهرست منبع

Update HarfBuzz to 10.0.1

bruvzg 11 ماه پیش
والد
کامیت
b6a369de79
85فایلهای تغییر یافته به همراه4358 افزوده شده و 2430 حذف شده
  1. 1 0
      modules/text_server_adv/SCsub
  2. 1 0
      modules/text_server_adv/gdextension_build/SConstruct
  3. 1 1
      thirdparty/README.md
  4. 9 7
      thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
  5. 9 9
      thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
  6. 1 7
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
  7. 346 0
      thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc
  8. 193 0
      thirdparty/harfbuzz/src/OT/Var/VARC/VARC.hh
  9. 37 0
      thirdparty/harfbuzz/src/OT/Var/VARC/coord-setter.hh
  10. 4 131
      thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
  11. 1 12
      thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
  12. 11 2
      thirdparty/harfbuzz/src/OT/glyf/glyf.hh
  13. 2 2
      thirdparty/harfbuzz/src/graph/graph.hh
  14. 35 25
      thirdparty/harfbuzz/src/hb-aat-layout-common.hh
  15. 6 6
      thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
  16. 38 6
      thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
  17. 35 2
      thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
  18. 4 4
      thirdparty/harfbuzz/src/hb-aat-layout-opbd-table.hh
  19. 1 1
      thirdparty/harfbuzz/src/hb-buffer-verify.cc
  20. 43 0
      thirdparty/harfbuzz/src/hb-buffer.cc
  21. 7 0
      thirdparty/harfbuzz/src/hb-buffer.h
  22. 2 0
      thirdparty/harfbuzz/src/hb-buffer.hh
  23. 0 1
      thirdparty/harfbuzz/src/hb-cff-interp-common.hh
  24. 1 1
      thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh
  25. 18 0
      thirdparty/harfbuzz/src/hb-common.h
  26. 4 0
      thirdparty/harfbuzz/src/hb-config.hh
  27. 51 1
      thirdparty/harfbuzz/src/hb-coretext.cc
  28. 1 1
      thirdparty/harfbuzz/src/hb-draw.hh
  29. 56 5
      thirdparty/harfbuzz/src/hb-face-builder.cc
  30. 59 13
      thirdparty/harfbuzz/src/hb-face.cc
  31. 28 0
      thirdparty/harfbuzz/src/hb-face.h
  32. 7 3
      thirdparty/harfbuzz/src/hb-face.hh
  33. 0 119
      thirdparty/harfbuzz/src/hb-features.h
  34. 1 1
      thirdparty/harfbuzz/src/hb-ft-colr.hh
  35. 40 0
      thirdparty/harfbuzz/src/hb-ft.cc
  36. 284 0
      thirdparty/harfbuzz/src/hb-geometry.hh
  37. 10 0
      thirdparty/harfbuzz/src/hb-iter.hh
  38. 8 9
      thirdparty/harfbuzz/src/hb-limits.hh
  39. 3 3
      thirdparty/harfbuzz/src/hb-open-file.hh
  40. 729 12
      thirdparty/harfbuzz/src/hb-open-type.hh
  41. 8 249
      thirdparty/harfbuzz/src/hb-ot-cff-common.hh
  42. 25 26
      thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
  43. 6 1
      thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
  44. 11 11
      thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
  45. 172 54
      thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
  46. 3 0
      thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
  47. 8 0
      thirdparty/harfbuzz/src/hb-ot-font.cc
  48. 1 0
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  49. 9 9
      thirdparty/harfbuzz/src/hb-ot-kern-table.hh
  50. 10 10
      thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
  51. 750 62
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  52. 51 36
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  53. 5 1
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  54. 9 6
      thirdparty/harfbuzz/src/hb-ot-layout.hh
  55. 15 6
      thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
  56. 1 1
      thirdparty/harfbuzz/src/hb-ot-post-table.hh
  57. 13 23
      thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
  58. 33 1
      thirdparty/harfbuzz/src/hb-ot-shape-normalize.hh
  59. 25 1
      thirdparty/harfbuzz/src/hb-ot-shape.cc
  60. 4 4
      thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh
  61. 15 8
      thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh
  62. 0 3
      thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
  63. 1 1
      thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc
  64. 19 9
      thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc
  65. 285 258
      thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
  66. 2 2
      thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
  67. 23 13
      thirdparty/harfbuzz/src/hb-ot-shaper.hh
  68. 23 23
      thirdparty/harfbuzz/src/hb-ot-stat-table.hh
  69. 56 10
      thirdparty/harfbuzz/src/hb-ot-tag-table.hh
  70. 41 441
      thirdparty/harfbuzz/src/hb-ot-var-common.hh
  71. 2 2
      thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh
  72. 13 7
      thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
  73. 32 0
      thirdparty/harfbuzz/src/hb-ot-var-varc-table.hh
  74. 5 163
      thirdparty/harfbuzz/src/hb-paint-extents.hh
  75. 2 2
      thirdparty/harfbuzz/src/hb-style.cc
  76. 0 3
      thirdparty/harfbuzz/src/hb-subset-cff2.cc
  77. 2 1
      thirdparty/harfbuzz/src/hb-subset-input.cc
  78. 1 1
      thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc
  79. 71 65
      thirdparty/harfbuzz/src/hb-subset-plan.cc
  80. 8 2
      thirdparty/harfbuzz/src/hb-subset.cc
  81. 499 523
      thirdparty/harfbuzz/src/hb-ucd-table.hh
  82. 4 4
      thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
  83. 3 0
      thirdparty/harfbuzz/src/hb-unicode.hh
  84. 4 4
      thirdparty/harfbuzz/src/hb-version.h
  85. 1 0
      thirdparty/harfbuzz/src/hb.hh

+ 1 - 0
modules/text_server_adv/SCsub

@@ -126,6 +126,7 @@ if env["builtin_harfbuzz"]:
         "src/hb-ucd.cc",
         "src/hb-unicode.cc",
         # "src/hb-uniscribe.cc",
+        "src/OT/Var/VARC/VARC.cc",
     ]
 
     if freetype_enabled:

+ 1 - 0
modules/text_server_adv/gdextension_build/SConstruct

@@ -387,6 +387,7 @@ thirdparty_harfbuzz_sources = [
     "src/hb-ucd.cc",
     "src/hb-unicode.cc",
     # "src/hb-uniscribe.cc",
+    "src/OT/Var/VARC/VARC.cc",
 ]
 
 if env["freetype_enabled"]:

+ 1 - 1
thirdparty/README.md

@@ -388,7 +388,7 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 8.5.0 (30485ee8c3d43c553afb9d78b9924cb71c8d2f19, 2024)
+- Version: 10.0.1 (a1d9bfe62818ef0fa9cf63b6e6d51436b1c93cbc, 2024)
 - License: MIT
 
 Files extracted from upstream source:

+ 9 - 7
thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh

@@ -72,7 +72,7 @@ public:
   hb_map_t current_glyphs;
   hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
-  int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
+  int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
 
   hb_paint_context_t (const void *base_,
 		      hb_paint_funcs_t *funcs_,
@@ -2339,7 +2339,11 @@ struct COLR
                                   c->plan->colrv1_varstore_inner_maps.as_array ()))
         return_trace (false);
 
-      if (!out->varStore.serialize_serialize (c->serializer,
+      /* do not serialize varStore if there's no variation data after
+       * instancing: region_list or var_data is empty */
+      if (item_vars.get_region_list () &&
+          item_vars.get_vardata_encodings () &&
+          !out->varStore.serialize_serialize (c->serializer,
                                               item_vars.has_long_word (),
                                               c->plan->axis_tags,
                                               item_vars.get_region_list (),
@@ -2347,7 +2351,9 @@ struct COLR
         return_trace (false);
 
       /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
-       * subset plan */
+       * subset plan.
+       * If varstore is empty after instancing, varidx_map would be empty and
+       * all var_idxes will be updated to VarIdx::NO_VARIATION */
       if (optimize)
       {
         const hb_map_t &varidx_map = item_vars.get_varidx_map ();
@@ -2579,10 +2585,6 @@ struct COLR
       {
         // COLRv1 glyph
 
-	ItemVarStoreInstancer instancer (&(this+varStore),
-				     &(this+varIdxMap),
-				     hb_array (font->coords, font->num_coords));
-
 	bool is_bounded = true;
 	if (clip)
 	{

+ 9 - 9
thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh

@@ -633,8 +633,8 @@ struct GDEFVersion1_2
 		  ligCaretList.sanitize (c, this) &&
 		  markAttachClassDef.sanitize (c, this) &&
 		  hb_barrier () &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
-		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+		  ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
+		  ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
   }
 
   static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
@@ -668,13 +668,13 @@ struct GDEFVersion1_2
     // the end of the GDEF table.
     // See: https://github.com/harfbuzz/harfbuzz/issues/4636
     auto snapshot_version0 = c->serializer->snapshot ();
-    if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
+    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
       return_trace (false);
 
     bool subset_varstore = false;
     unsigned varstore_index = (unsigned) -1;
     auto snapshot_version2 = c->serializer->snapshot ();
-    if (version.to_int () >= 0x00010003u)
+    if (version.to_int () >= 0x00010003u && hb_barrier ())
     {
       if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
       if (c->plan->all_axes_pinned)
@@ -712,7 +712,7 @@ struct GDEFVersion1_2
     }
 
     bool subset_markglyphsetsdef = false;
-    if (version.to_int () >= 0x00010002u)
+    if (version.to_int () >= 0x00010002u && hb_barrier ())
     {
       subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
     }
@@ -875,7 +875,7 @@ struct GDEF
   bool has_mark_glyph_sets () const
   {
     switch (u.version.major) {
-    case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
 #ifndef HB_NO_BEYOND_64K
     case 2: return u.version2.markGlyphSetsDef != 0;
 #endif
@@ -885,7 +885,7 @@ struct GDEF
   const MarkGlyphSets &get_mark_glyph_sets () const
   {
     switch (u.version.major) {
-    case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
 #ifndef HB_NO_BEYOND_64K
     case 2: return this+u.version2.markGlyphSetsDef;
 #endif
@@ -895,7 +895,7 @@ struct GDEF
   bool has_var_store () const
   {
     switch (u.version.major) {
-    case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
 #ifndef HB_NO_BEYOND_64K
     case 2: return u.version2.varStore != 0;
 #endif
@@ -905,7 +905,7 @@ struct GDEF
   const ItemVariationStore &get_var_store () const
   {
     switch (u.version.major) {
-    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
+    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
 #ifndef HB_NO_BEYOND_64K
     case 2: return this+u.version2.varStore;
 #endif

+ 1 - 7
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh

@@ -139,14 +139,8 @@ struct PairPosFormat2_4 : ValueBase
       return_trace (false);
     }
 
-    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
-    if (!klass2)
-    {
-      buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
-      return_trace (false);
-    }
-
     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
     {
       buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);

+ 346 - 0
thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc

@@ -0,0 +1,346 @@
+#include "VARC.hh"
+
+#ifndef HB_NO_VAR_COMPOSITES
+
+#include "../../../hb-draw.hh"
+#include "../../../hb-geometry.hh"
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-layout-gdef-table.hh"
+
+namespace OT {
+
+//namespace Var {
+
+
+struct hb_transforming_pen_context_t
+{
+  hb_transform_t transform;
+  hb_draw_funcs_t *dfuncs;
+  void *data;
+  hb_draw_state_t *st;
+};
+
+static void
+hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+			     void *data,
+			     hb_draw_state_t *st,
+			     float to_x, float to_y,
+			     void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->move_to (c->data, *c->st, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+			     void *data,
+			     hb_draw_state_t *st,
+			     float to_x, float to_y,
+			     void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->line_to (c->data, *c->st, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+				  void *data,
+				  hb_draw_state_t *st,
+				  float control_x, float control_y,
+				  float to_x, float to_y,
+				  void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (control_x, control_y);
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+			      void *data,
+			      hb_draw_state_t *st,
+			      float control1_x, float control1_y,
+			      float control2_x, float control2_y,
+			      float to_x, float to_y,
+			      void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->transform.transform_point (control1_x, control1_y);
+  c->transform.transform_point (control2_x, control2_y);
+  c->transform.transform_point (to_x, to_y);
+
+  c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+}
+
+static void
+hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
+				void *data,
+				hb_draw_state_t *st,
+				void *user_data HB_UNUSED)
+{
+  hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
+
+  c->dfuncs->close_path (c->data, *c->st);
+}
+
+static inline void free_static_transforming_pen_funcs ();
+
+static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);
+    hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_transforming_pen_funcs);
+
+    return funcs;
+  }
+} static_transforming_pen_funcs;
+
+static inline
+void free_static_transforming_pen_funcs ()
+{
+  static_transforming_pen_funcs.free_instance ();
+}
+
+static hb_draw_funcs_t *
+hb_transforming_pen_get_funcs ()
+{
+  return static_transforming_pen_funcs.get_unconst ();
+}
+
+
+hb_ubytes_t
+VarComponent::get_path_at (hb_font_t *font,
+			   hb_codepoint_t parent_gid,
+			   hb_draw_session_t &draw_session,
+			   hb_array_t<const int> coords,
+			   hb_ubytes_t total_record,
+			   hb_set_t *visited,
+			   signed *edges_left,
+			   signed depth_left,
+			   VarRegionList::cache_t *cache) const
+{
+  const unsigned char *end = total_record.arrayZ + total_record.length;
+  const unsigned char *record = total_record.arrayZ;
+
+  auto &VARC = *font->face->table.VARC;
+  auto &varStore = &VARC+VARC.varStore;
+  auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
+
+#define READ_UINT32VAR(name) \
+  HB_STMT_START { \
+    if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \
+    hb_barrier (); \
+    auto &varint = * (const HBUINT32VAR *) record; \
+    unsigned size = varint.get_size (); \
+    if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \
+    name = (uint32_t) varint; \
+    record += size; \
+  } HB_STMT_END
+
+  uint32_t flags;
+  READ_UINT32VAR (flags);
+
+  // gid
+
+  hb_codepoint_t gid = 0;
+  if (flags & (unsigned) flags_t::GID_IS_24BIT)
+  {
+    if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))
+      return hb_ubytes_t ();
+    hb_barrier ();
+    gid = * (const HBGlyphID24 *) record;
+    record += HBGlyphID24::static_size;
+  }
+  else
+  {
+    if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))
+      return hb_ubytes_t ();
+    hb_barrier ();
+    gid = * (const HBGlyphID16 *) record;
+    record += HBGlyphID16::static_size;
+  }
+
+  // Condition
+  bool show = true;
+  if (flags & (unsigned) flags_t::HAVE_CONDITION)
+  {
+    unsigned conditionIndex;
+    READ_UINT32VAR (conditionIndex);
+    const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
+    show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
+  }
+
+  // Axis values
+
+  hb_vector_t<unsigned> axisIndices;
+  hb_vector_t<float> axisValues;
+  if (flags & (unsigned) flags_t::HAVE_AXES)
+  {
+    unsigned axisIndicesIndex;
+    READ_UINT32VAR (axisIndicesIndex);
+    axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
+    axisValues.resize (axisIndices.length);
+    const HBUINT8 *p = (const HBUINT8 *) record;
+    TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
+    record += (const unsigned char *) p - record;
+  }
+
+  // Apply variations if any
+  if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)
+  {
+    uint32_t axisValuesVarIdx;
+    READ_UINT32VAR (axisValuesVarIdx);
+    if (show && coords && !axisValues.in_error ())
+      varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);
+  }
+
+  auto component_coords = coords;
+  /* Copying coords is expensive; so we have put an arbitrary
+   * limit on the max number of coords for now. */
+  if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
+      coords.length > HB_VAR_COMPOSITE_MAX_AXES)
+    component_coords = hb_array<int> (font->coords, font->num_coords);
+
+  // Transform
+
+  uint32_t transformVarIdx = VarIdx::NO_VARIATION;
+  if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)
+    READ_UINT32VAR (transformVarIdx);
+
+#define PROCESS_TRANSFORM_COMPONENTS \
+	HB_STMT_START { \
+	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_X, translateX); \
+	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_Y, translateY); \
+	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_ROTATION, rotation); \
+	PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_X, scaleX); \
+	PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_Y, scaleY); \
+	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_X, skewX); \
+	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_Y, skewY); \
+	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_X, tCenterX); \
+	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_Y, tCenterY); \
+	} HB_STMT_END
+
+  hb_transform_decomposed_t transform;
+
+  // Read transform components
+#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
+	if (flags & (unsigned) flags_t::flag) \
+	{ \
+	  static_assert (type::static_size == HBINT16::static_size, ""); \
+	  if (unlikely (unsigned (end - record) < HBINT16::static_size)) \
+	    return hb_ubytes_t (); \
+	  hb_barrier (); \
+	  transform.name = * (const HBINT16 *) record; \
+	  record += HBINT16::static_size; \
+	}
+  PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+
+  // Read reserved records
+  unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;
+  while (i)
+  {
+    HB_UNUSED uint32_t discard;
+    READ_UINT32VAR (discard);
+    i &= i - 1;
+  }
+
+  /* Parsing is over now. */
+
+  if (show)
+  {
+    // Only use coord_setter if there's actually any axis overrides.
+    coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());
+    // Go backwards, to reduce coord_setter vector reallocations.
+    for (unsigned i = axisIndices.length; i; i--)
+      coord_setter[axisIndices[i - 1]] = axisValues[i - 1];
+    if (axisIndices)
+      component_coords = coord_setter.get_coords ();
+
+    // Apply transform variations if any
+    if (transformVarIdx != VarIdx::NO_VARIATION && coords)
+    {
+      float transformValues[9];
+      unsigned numTransformValues = 0;
+#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
+	  if (flags & (unsigned) flags_t::flag) \
+	    transformValues[numTransformValues++] = transform.name;
+      PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+      varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);
+      numTransformValues = 0;
+#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
+	  if (flags & (unsigned) flags_t::flag) \
+	    transform.name = transformValues[numTransformValues++];
+      PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+    }
+
+    // Divide them by their divisors
+#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
+	  if (flags & (unsigned) flags_t::flag) \
+	  { \
+	    HBINT16 int_v; \
+	    int_v = roundf (transform.name); \
+	    type typed_v = * (const type *) &int_v; \
+	    float float_v = (float) typed_v; \
+	    transform.name = float_v; \
+	  }
+    PROCESS_TRANSFORM_COMPONENTS;
+#undef PROCESS_TRANSFORM_COMPONENT
+
+    if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
+      transform.scaleY = transform.scaleX;
+
+    // Scale the transform by the font's scale
+    float x_scale = font->x_multf;
+    float y_scale = font->y_multf;
+    transform.translateX *= x_scale;
+    transform.translateY *= y_scale;
+    transform.tCenterX *= x_scale;
+    transform.tCenterY *= y_scale;
+
+    // Build a transforming pen to apply the transform.
+    hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
+    hb_transforming_pen_context_t context {transform.to_transform (),
+					   draw_session.funcs,
+					   draw_session.draw_data,
+					   &draw_session.st};
+    hb_draw_session_t transformer_session {transformer_funcs, &context};
+
+    VARC.get_path_at (font, gid,
+		      transformer_session, component_coords,
+		      parent_gid,
+		      visited, edges_left, depth_left - 1);
+  }
+
+#undef PROCESS_TRANSFORM_COMPONENTS
+#undef READ_UINT32VAR
+
+  return hb_ubytes_t (record, end - record);
+}
+
+//} // namespace Var
+} // namespace OT
+
+#endif

+ 193 - 0
thirdparty/harfbuzz/src/OT/Var/VARC/VARC.hh

@@ -0,0 +1,193 @@
+#ifndef OT_VAR_VARC_VARC_HH
+#define OT_VAR_VARC_VARC_HH
+
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-glyf-table.hh"
+#include "../../../hb-ot-cff2-table.hh"
+#include "../../../hb-ot-cff1-table.hh"
+
+#include "coord-setter.hh"
+
+namespace OT {
+
+//namespace Var {
+
+/*
+ * VARC -- Variable Composites
+ * https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md
+ */
+
+#ifndef HB_NO_VAR_COMPOSITES
+
+struct VarComponent
+{
+  enum class flags_t : uint32_t
+  {
+    RESET_UNSPECIFIED_AXES	= 1u << 0,
+    HAVE_AXES			= 1u << 1,
+    AXIS_VALUES_HAVE_VARIATION	= 1u << 2,
+    TRANSFORM_HAS_VARIATION	= 1u << 3,
+    HAVE_TRANSLATE_X		= 1u << 4,
+    HAVE_TRANSLATE_Y		= 1u << 5,
+    HAVE_ROTATION		= 1u << 6,
+    HAVE_CONDITION		= 1u << 7,
+    HAVE_SCALE_X		= 1u << 8,
+    HAVE_SCALE_Y		= 1u << 9,
+    HAVE_TCENTER_X		= 1u << 10,
+    HAVE_TCENTER_Y		= 1u << 11,
+    GID_IS_24BIT		= 1u << 12,
+    HAVE_SKEW_X			= 1u << 13,
+    HAVE_SKEW_Y			= 1u << 14,
+    RESERVED_MASK		= ~((1u << 15) - 1),
+  };
+
+  HB_INTERNAL hb_ubytes_t
+  get_path_at (hb_font_t *font,
+	       hb_codepoint_t parent_gid,
+	       hb_draw_session_t &draw_session,
+	       hb_array_t<const int> coords,
+	       hb_ubytes_t record,
+	       hb_set_t *visited,
+	       signed *edges_left,
+	       signed depth_left,
+	       VarRegionList::cache_t *cache = nullptr) const;
+};
+
+struct VarCompositeGlyph
+{
+  static void
+  get_path_at (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_draw_session_t &draw_session,
+	       hb_array_t<const int> coords,
+	       hb_ubytes_t record,
+	       hb_set_t *visited,
+	       signed *edges_left,
+	       signed depth_left,
+	       VarRegionList::cache_t *cache = nullptr)
+  {
+    while (record)
+    {
+      const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
+      record = comp.get_path_at (font, glyph,
+				 draw_session, coords,
+				 record,
+				 visited, edges_left, depth_left, cache);
+    }
+  }
+};
+
+HB_MARK_AS_FLAG_T (VarComponent::flags_t);
+
+struct VARC
+{
+  friend struct VarComponent;
+
+  static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
+
+  bool
+  get_path_at (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_draw_session_t &draw_session,
+	       hb_array_t<const int> coords,
+	       hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID,
+	       hb_set_t *visited = nullptr,
+	       signed *edges_left = nullptr,
+	       signed depth_left = HB_MAX_NESTING_LEVEL) const
+  {
+    hb_set_t stack_set;
+    if (visited == nullptr)
+      visited = &stack_set;
+    signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT;
+    if (edges_left == nullptr)
+      edges_left = &stack_edges;
+
+    // Don't recurse on the same glyph.
+    unsigned idx = glyph == parent_glyph ?
+		   NOT_COVERED :
+		   (this+coverage).get_coverage (glyph);
+    if (idx == NOT_COVERED)
+    {
+      if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords))
+#ifndef HB_NO_CFF
+      if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords))
+      if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations
+#endif
+	return false;
+      return true;
+    }
+
+    if (depth_left <= 0)
+      return true;
+
+    if (*edges_left <= 0)
+      return true;
+    (*edges_left)--;
+
+    if (visited->has (glyph) || visited->in_error ())
+      return true;
+    visited->add (glyph);
+
+    hb_ubytes_t record = (this+glyphRecords)[idx];
+
+    VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
+				   (this+varStore).create_cache ()
+				   : nullptr;
+
+    VarCompositeGlyph::get_path_at (font, glyph,
+				    draw_session, coords,
+				    record,
+				    visited, edges_left, depth_left,
+				    cache);
+
+    (this+varStore).destroy_cache (cache);
+
+    visited->del (glyph);
+
+    return true;
+  }
+
+  bool
+  get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
+  { return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); }
+
+  bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+  {
+    funcs->push_clip_glyph (data, gid, font);
+    funcs->color (data, true, foreground);
+    funcs->pop_clip (data);
+
+    return true;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  hb_barrier () &&
+		  version.major == 1 &&
+		  coverage.sanitize (c, this) &&
+		  varStore.sanitize (c, this) &&
+		  conditionList.sanitize (c, this) &&
+		  axisIndicesList.sanitize (c, this) &&
+		  glyphRecords.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion<> version; /* Version identifier */
+  Offset32To<Coverage> coverage;
+  Offset32To<MultiItemVariationStore> varStore;
+  Offset32To<ConditionList> conditionList;
+  Offset32To<TupleList> axisIndicesList;
+  Offset32To<CFF2Index/*Of<VarCompositeGlyph>*/> glyphRecords;
+  public:
+  DEFINE_SIZE_STATIC (24);
+};
+
+#endif
+
+//}
+
+}
+
+#endif  /* OT_VAR_VARC_VARC_HH */

+ 37 - 0
thirdparty/harfbuzz/src/OT/Var/VARC/coord-setter.hh

@@ -0,0 +1,37 @@
+#ifndef OT_VAR_VARC_COORD_SETTER_HH
+#define OT_VAR_VARC_COORD_SETTER_HH
+
+
+#include "../../../hb.hh"
+
+
+namespace OT {
+//namespace Var {
+
+
+struct coord_setter_t
+{
+  coord_setter_t (hb_array_t<const int> coords) :
+    coords (coords) {}
+
+  int& operator [] (unsigned idx)
+  {
+    if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
+      return Crap(int);
+    if (coords.length < idx + 1)
+      coords.resize (idx + 1);
+    return coords[idx];
+  }
+
+  hb_array_t<int> get_coords ()
+  { return coords.as_array (); }
+
+  hb_vector_t<int> coords;
+};
+
+
+//} // namespace Var
+
+} // namespace OT
+
+#endif /* OT_VAR_VARC_COORD_SETTER_HH */

+ 4 - 131
thirdparty/harfbuzz/src/OT/glyf/Glyph.hh

@@ -7,8 +7,6 @@
 #include "GlyphHeader.hh"
 #include "SimpleGlyph.hh"
 #include "CompositeGlyph.hh"
-#include "VarCompositeGlyph.hh"
-#include "coord-setter.hh"
 
 
 namespace OT {
@@ -33,9 +31,6 @@ struct Glyph
     EMPTY,
     SIMPLE,
     COMPOSITE,
-#ifndef HB_NO_VAR_COMPOSITES
-    VAR_COMPOSITE,
-#endif
   };
 
   public:
@@ -44,22 +39,10 @@ struct Glyph
     if (type != COMPOSITE) return composite_iter_t ();
     return CompositeGlyph (*header, bytes).iter ();
   }
-  var_composite_iter_t get_var_composite_iterator () const
-  {
-#ifndef HB_NO_VAR_COMPOSITES
-    if (type != VAR_COMPOSITE) return var_composite_iter_t ();
-    return VarCompositeGlyph (*header, bytes).iter ();
-#else
-    return var_composite_iter_t ();
-#endif
-  }
 
   const hb_bytes_t trim_padding () const
   {
     switch (type) {
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
-#endif
     case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
     case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
     case EMPTY:     return bytes;
@@ -70,9 +53,6 @@ struct Glyph
   void drop_hints ()
   {
     switch (type) {
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE: return; // No hinting
-#endif
     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
     case EMPTY:     return;
@@ -82,9 +62,6 @@ struct Glyph
   void set_overlaps_flag ()
   {
     switch (type) {
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE: return; // No overlaps flag
-#endif
     case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
     case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
     case EMPTY:     return;
@@ -94,9 +71,6 @@ struct Glyph
   void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
   {
     switch (type) {
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE: return; // No hinting
-#endif
     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
     case EMPTY:     return;
@@ -120,14 +94,6 @@ struct Glyph
         if (unlikely (!item.get_points (points))) return false;
       break;
     }
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE:
-    {
-      for (auto &item : get_var_composite_iterator ())
-        if (unlikely (!item.get_points (points))) return false;
-      break;
-    }
-#endif
     case EMPTY:
       break;
     }
@@ -303,13 +269,6 @@ struct Glyph
     {
       switch (type)
       {
-#ifndef HB_NO_VAR_COMPOSITES
-      case VAR_COMPOSITE:
-	// TODO
-	dest_end = hb_bytes_t ();
-	break;
-#endif
-
       case COMPOSITE:
         if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
                                                                         points_with_deltas,
@@ -352,7 +311,7 @@ struct Glyph
 		   bool shift_points_hori = true,
 		   bool use_my_metrics = true,
 		   bool phantom_only = false,
-		   hb_array_t<int> coords = hb_array_t<int> (),
+		   hb_array_t<const int> coords = hb_array_t<const int> (),
 		   hb_map_t *current_glyphs = nullptr,
 		   unsigned int depth = 0,
 		   unsigned *edge_count = nullptr) const
@@ -360,7 +319,7 @@ struct Glyph
     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
     unsigned stack_edge_count = 0;
     if (!edge_count) edge_count = &stack_edge_count;
-    if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
+    if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
     (*edge_count)++;
 
     hb_map_t current_glyphs_stack;
@@ -394,14 +353,6 @@ struct Glyph
         if (unlikely (!item.get_points (points))) return false;
       break;
     }
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE:
-    {
-      for (auto &item : get_var_composite_iterator ())
-        if (unlikely (!item.get_points (points))) return false;
-      break;
-    }
-#endif
     case EMPTY:
       break;
     }
@@ -542,81 +493,6 @@ struct Glyph
       }
       all_points.extend (phantoms);
     } break;
-#ifndef HB_NO_VAR_COMPOSITES
-    case VAR_COMPOSITE:
-    {
-      hb_array_t<contour_point_t> points_left = points.as_array ();
-      for (auto &item : get_var_composite_iterator ())
-      {
-	hb_codepoint_t item_gid = item.get_gid ();
-
-        if (unlikely (current_glyphs->has (item_gid)))
-	  continue;
-
-	current_glyphs->add (item_gid);
-
-	unsigned item_num_points = item.get_num_points ();
-	hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
-	assert (record_points.length == item_num_points);
-
-	auto component_coords = coords;
-	/* Copying coords is expensive; so we have put an arbitrary
-	 * limit on the max number of coords for now. */
-	if (item.is_reset_unspecified_axes () ||
-	    coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
-	  component_coords = hb_array<int> ();
-
-	coord_setter_t coord_setter (component_coords);
-	item.set_variations (coord_setter, record_points);
-
-	unsigned old_count = all_points.length;
-
-	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
-		      !glyf_accelerator.glyph_for_gid (item_gid)
-				       .get_points (font,
-						    glyf_accelerator,
-						    all_points,
-						    points_with_deltas,
-						    head_maxp_info,
-						    nullptr,
-						    shift_points_hori,
-						    use_my_metrics,
-						    phantom_only,
-						    coord_setter.get_coords (),
-						    current_glyphs,
-						    depth + 1,
-						    edge_count)))
-	{
-	  current_glyphs->del (item_gid);
-	  return false;
-	}
-
-	auto comp_points = all_points.as_array ().sub_array (old_count);
-
-	/* Apply component transformation */
-	if (comp_points) // Empty in case of phantom_only
-	  item.transform_points (record_points, comp_points);
-
-	/* Copy phantom points from component if USE_MY_METRICS flag set */
-	if (use_my_metrics && item.is_use_my_metrics ())
-	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
-	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
-
-	all_points.resize (all_points.length - PHANTOM_COUNT);
-
-	if (all_points.length > HB_GLYF_MAX_POINTS)
-	{
-	  current_glyphs->del (item_gid);
-	  return false;
-	}
-
-	points_left += item_num_points;
-
-        current_glyphs->del (item_gid);
-      }
-      all_points.extend (phantoms);
-    } break;
-#endif
     case EMPTY:
       all_points.extend (phantoms);
       break;
@@ -627,7 +503,7 @@ struct Glyph
       /* Undocumented rasterizer behavior:
        * Shift points horizontally by the updated left side bearing
        */
-      int v = -phantoms[PHANTOM_LEFT].x;
+      float v = -phantoms[PHANTOM_LEFT].x;
       if (v)
         for (auto &point : all_points)
 	  point.x += v;
@@ -661,10 +537,7 @@ struct Glyph
     int num_contours = header->numberOfContours;
     if (unlikely (num_contours == 0)) type = EMPTY;
     else if (num_contours > 0) type = SIMPLE;
-    else if (num_contours == -1) type = COMPOSITE;
-#ifndef HB_NO_VAR_COMPOSITES
-    else if (num_contours == -2) type = VAR_COMPOSITE;
-#endif
+    else if (num_contours <= -1) type = COMPOSITE;
     else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
   }
 

+ 1 - 12
thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh

@@ -53,23 +53,12 @@ struct SubsetGlyph
       if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
 	const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
     }
-#ifndef HB_NO_VAR_COMPOSITES
-    for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
-    {
-      hb_codepoint_t new_gid;
-      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
-	const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
-    }
-#endif
 
 #ifndef HB_NO_BEYOND_64K
     auto it = Glyph (dest_glyph).get_composite_iterator ();
     if (it)
     {
-      /* lower GID24 to GID16 in components if possible.
-       *
-       * TODO: VarComposite. Not as critical, since VarComposite supports
-       * gid24 from the first version. */
+      /* lower GID24 to GID16 in components if possible. */
       char *p = it ? (char *) &*it : nullptr;
       char *q = p;
       const char *end = dest_glyph.arrayZ + dest_glyph.length;

+ 11 - 2
thirdparty/harfbuzz/src/OT/glyf/glyf.hh

@@ -205,8 +205,12 @@ struct glyf_accelerator_t
 
   protected:
   template<typename T>
-  bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
+  bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
+		   hb_array_t<const int> coords = hb_array_t<const int> ()) const
   {
+    if (!coords)
+      coords = hb_array (font->coords, font->num_coords);
+
     if (gid >= num_glyphs) return false;
 
     /* Making this allocfree is not that easy
@@ -216,7 +220,7 @@ struct glyf_accelerator_t
     contour_point_vector_t all_points;
 
     bool phantom_only = !consumer.is_consuming_contour_points ();
-    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
+    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
       return false;
 
     unsigned count = all_points.length;
@@ -408,6 +412,11 @@ struct glyf_accelerator_t
   get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
   { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
 
+  bool
+  get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
+	       hb_array_t<const int> coords) const
+  { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
+
 #ifndef HB_NO_VAR
   const gvar_accelerator_t *gvar;
 #endif

+ 2 - 2
thirdparty/harfbuzz/src/graph/graph.hh

@@ -368,7 +368,7 @@ struct graph_t
       // it's parent where possible.
 
       int64_t modified_distance =
-          hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF);
+          hb_clamp (distance + distance_modifier (), (int64_t) 0, 0x7FFFFFFFFFF);
       if (has_max_priority ()) {
         modified_distance = 0;
       }
@@ -1141,7 +1141,7 @@ struct graph_t
 
     unsigned clone_idx = duplicate (child_idx);
     if (clone_idx == (unsigned) -1) return false;
-    
+
     for (unsigned parent_idx : *parents) {
       // duplicate shifts the root node idx, so if parent_idx was root update it.
       if (parent_idx == clone_idx) parent_idx++;

+ 35 - 25
thirdparty/harfbuzz/src/hb-aat-layout-common.hh

@@ -39,6 +39,7 @@ namespace AAT {
 
 using namespace OT;
 
+#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
 
 struct ankr;
 
@@ -60,6 +61,7 @@ struct hb_aat_apply_context_t :
   const ankr *ankr_table;
   const OT::GDEF *gdef_table;
   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+  hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
   hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
   hb_set_digest_t left_set = hb_set_digest_t::full ();
   hb_set_digest_t right_set = hb_set_digest_t::full ();
@@ -466,11 +468,11 @@ struct Lookup
   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
   {
     switch (u.format) {
-    case 0: return u.format0.get_value (glyph_id, num_glyphs);
-    case 2: return u.format2.get_value (glyph_id);
-    case 4: return u.format4.get_value (glyph_id);
-    case 6: return u.format6.get_value (glyph_id);
-    case 8: return u.format8.get_value (glyph_id);
+    case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs);
+    case 2: hb_barrier (); return u.format2.get_value (glyph_id);
+    case 4: hb_barrier (); return u.format4.get_value (glyph_id);
+    case 6: hb_barrier (); return u.format6.get_value (glyph_id);
+    case 8: hb_barrier (); return u.format8.get_value (glyph_id);
     default:return nullptr;
     }
   }
@@ -479,7 +481,7 @@ struct Lookup
   {
     switch (u.format) {
       /* Format 10 cannot return a pointer. */
-      case 10: return u.format10.get_value_or_null (glyph_id);
+      case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id);
       default:
       const T *v = get_value (glyph_id, num_glyphs);
       return v ? *v : Null (T);
@@ -490,12 +492,12 @@ struct Lookup
   void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
   {
     switch (u.format) {
-    case 0: u.format0.collect_glyphs (glyphs, num_glyphs); return;
-    case 2: u.format2.collect_glyphs (glyphs); return;
-    case 4: u.format4.collect_glyphs (glyphs); return;
-    case 6: u.format6.collect_glyphs (glyphs); return;
-    case 8: u.format8.collect_glyphs (glyphs); return;
-    case 10: u.format10.collect_glyphs (glyphs); return;
+    case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return;
+    case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return;
+    case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return;
+    case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return;
+    case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return;
+    case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return;
     default:return;
     }
   }
@@ -514,12 +516,12 @@ struct Lookup
     if (!u.format.sanitize (c)) return_trace (false);
     hb_barrier ();
     switch (u.format) {
-    case 0: return_trace (u.format0.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 4: return_trace (u.format4.sanitize (c));
-    case 6: return_trace (u.format6.sanitize (c));
-    case 8: return_trace (u.format8.sanitize (c));
-    case 10: return_trace (u.format10.sanitize (c));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
+    case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
+    case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
+    case 6: hb_barrier (); return_trace (u.format6.sanitize (c));
+    case 8: hb_barrier (); return_trace (u.format8.sanitize (c));
+    case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
     default:return_trace (true);
     }
   }
@@ -529,11 +531,11 @@ struct Lookup
     if (!u.format.sanitize (c)) return_trace (false);
     hb_barrier ();
     switch (u.format) {
-    case 0: return_trace (u.format0.sanitize (c, base));
-    case 2: return_trace (u.format2.sanitize (c, base));
-    case 4: return_trace (u.format4.sanitize (c, base));
-    case 6: return_trace (u.format6.sanitize (c, base));
-    case 8: return_trace (u.format8.sanitize (c, base));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base));
+    case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base));
+    case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base));
+    case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base));
+    case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base));
     case 10: return_trace (false); /* We don't support format10 here currently. */
     default:return_trace (true);
     }
@@ -927,7 +929,15 @@ struct StateTableDriver
 	      machine (machine_),
 	      num_glyphs (face_->get_num_glyphs ()) {}
 
-  template <typename context_t, typename set_t = hb_set_digest_t>
+  template <typename context_t>
+  bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
+  {
+    const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
+    return !c->is_actionable (ac->buffer, this, entry) &&
+	    machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
+  }
+
+  template <typename context_t>
   void drive (context_t *c, hb_aat_apply_context_t *ac)
   {
     hb_buffer_t *buffer = ac->buffer;
@@ -1005,7 +1015,7 @@ struct StateTableDriver
       const auto is_safe_to_break_extra = [&]()
       {
           /* 2c. */
-          const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
+          const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
 
           /* 2c'. */
           if (c->is_actionable (buffer, this, wouldbe_entry))

+ 6 - 6
thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh

@@ -189,12 +189,12 @@ struct ActionSubrecord
 
     switch (u.header.actionType)
     {
-    case 0:  return_trace (u.decompositionAction.sanitize (c));
-    case 1:  return_trace (u.unconditionalAddGlyphAction.sanitize (c));
-    case 2:  return_trace (u.conditionalAddGlyphAction.sanitize (c));
-    // case 3: return_trace (u.stretchGlyphAction.sanitize (c));
-    case 4:  return_trace (u.decompositionAction.sanitize (c));
-    case 5:  return_trace (u.decompositionAction.sanitize (c));
+    case 0: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
+    case 1: hb_barrier ();  return_trace (u.unconditionalAddGlyphAction.sanitize (c));
+    case 2: hb_barrier ();  return_trace (u.conditionalAddGlyphAction.sanitize (c));
+    // case 3: hb_barrier (); return_trace (u.stretchGlyphAction.sanitize (c));
+    case 4: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
+    case 5: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
     default: return_trace (true);
     }
   }

+ 38 - 6
thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh

@@ -107,10 +107,14 @@ struct KerxSubTableFormat0
     TRACE_APPLY (this);
 
     if (!c->plan->requested_kerning)
-      return false;
+      return_trace (false);
 
     if (header.coverage & header.Backwards)
-      return false;
+      return_trace (false);
+
+    if (!(c->buffer_digest.may_have (c->left_set) &&
+	  c->buffer_digest.may_have (c->right_set)))
+      return_trace (false);
 
     accelerator_t accel (*this, c);
     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@@ -367,6 +371,12 @@ struct KerxSubTableFormat1
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->font->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!(c->buffer_digest.may_have (c->left_set) &&
+	  c->buffer_digest.may_have (c->right_set)))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (true);
@@ -425,10 +435,14 @@ struct KerxSubTableFormat2
     TRACE_APPLY (this);
 
     if (!c->plan->requested_kerning)
-      return false;
+      return_trace (false);
 
     if (header.coverage & header.Backwards)
-      return false;
+      return_trace (false);
+
+    if (!(c->buffer_digest.may_have (c->left_set) &&
+	  c->buffer_digest.may_have (c->right_set)))
+      return_trace (false);
 
     accelerator_t accel (*this, c);
     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@@ -635,6 +649,12 @@ struct KerxSubTableFormat4
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->font->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!(c->buffer_digest.may_have (c->left_set) &&
+	  c->buffer_digest.may_have (c->right_set)))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (true);
@@ -710,10 +730,14 @@ struct KerxSubTableFormat6
     TRACE_APPLY (this);
 
     if (!c->plan->requested_kerning)
-      return false;
+      return_trace (false);
 
     if (header.coverage & header.Backwards)
-      return false;
+      return_trace (false);
+
+    if (!(c->buffer_digest.may_have (c->left_set) &&
+	  c->buffer_digest.may_have (c->right_set)))
+      return_trace (false);
 
     accelerator_t accel (*this, c);
     hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@@ -919,6 +943,9 @@ struct KerxTable
     {
       if (st->get_type () == 1)
 	return true;
+
+      // TODO: What about format 4? What's this API used for anyway?
+
       st = &StructAfter<SubTable> (*st);
     }
     return false;
@@ -962,6 +989,11 @@ struct KerxTable
   {
     c->buffer->unsafe_to_concat ();
 
+    if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
+      c->buffer_digest = c->buffer->digest ();
+    else
+      c->buffer_digest = hb_set_digest_t::full ();
+
     typedef typename T::SubTable SubTable;
 
     bool ret = false;

+ 35 - 2
thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh

@@ -170,6 +170,11 @@ struct RearrangementSubtable
     driver_context_t dc (this);
 
     StateTableDriver<Types, EntryData> driver (machine, c->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!c->buffer_digest.may_have (c->machine_glyph_set))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -267,6 +272,7 @@ struct ContextualSubtable
       {
 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
 	buffer->info[mark].codepoint = *replacement;
+	c->buffer_digest.add (*replacement);
 	if (has_glyph_classes)
 	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
 					  gdef.get_glyph_props (*replacement));
@@ -296,6 +302,7 @@ struct ContextualSubtable
       if (replacement)
       {
 	buffer->info[idx].codepoint = *replacement;
+	c->buffer_digest.add (*replacement);
 	if (has_glyph_classes)
 	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
 					  gdef.get_glyph_props (*replacement));
@@ -328,6 +335,11 @@ struct ContextualSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!c->buffer_digest.may_have (c->machine_glyph_set))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -586,6 +598,11 @@ struct LigatureSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!c->buffer_digest.may_have (c->machine_glyph_set))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -654,6 +671,7 @@ struct NoncontextualSubtable
       if (replacement)
       {
 	info[i].codepoint = *replacement;
+	c->buffer_digest.add (*replacement);
 	if (has_glyph_classes)
 	  _hb_glyph_info_set_glyph_props (&info[i],
 					  gdef.get_glyph_props (*replacement));
@@ -788,6 +806,9 @@ struct InsertionSubtable
 	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
 	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
+	for (unsigned int i = 0; i < count; i++)
+	  c->buffer_digest.add (glyphs[i]);
+	ret = true;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
@@ -853,6 +874,11 @@ struct InsertionSubtable
     driver_context_t dc (this, c);
 
     StateTableDriver<Types, EntryData> driver (machine, c->face);
+
+    if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
+	!c->buffer_digest.may_have (c->machine_glyph_set))
+      return_trace (false);
+
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -1036,7 +1062,8 @@ struct ChainSubtable
   bool apply (hb_aat_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_sanitize_with_object_t with (&c->sanitizer, this);
+    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
+    //hb_sanitize_with_object_t with (&c->sanitizer, this);
     return_trace (dispatch (c));
   }
 
@@ -1049,7 +1076,8 @@ struct ChainSubtable
 	  c->check_range (this, length)))
       return_trace (false);
 
-    hb_sanitize_with_object_t with (c, this);
+    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
+    //hb_sanitize_with_object_t with (c, this);
     return_trace (dispatch (c));
   }
 
@@ -1348,6 +1376,11 @@ struct mortmorx
 
     c->buffer->unsafe_to_concat ();
 
+    if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
+      c->buffer_digest = c->buffer->digest ();
+    else
+      c->buffer_digest = hb_set_digest_t::full ();
+
     c->set_lookup_index (0);
     const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;

+ 4 - 4
thirdparty/harfbuzz/src/hb-aat-layout-opbd-table.hh

@@ -133,8 +133,8 @@ struct opbd
   {
     switch (format)
     {
-    case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
-    case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
+    case 0: hb_barrier (); return u.format0.get_bounds (font, glyph_id, extents, this);
+    case 1: hb_barrier (); return u.format1.get_bounds (font, glyph_id, extents, this);
     default:return false;
     }
   }
@@ -148,8 +148,8 @@ struct opbd
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, this));
-    case 1: return_trace (u.format1.sanitize (c, this));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, this));
+    case 1: hb_barrier (); return_trace (u.format1.sanitize (c, this));
     default:return_trace (true);
     }
   }

+ 1 - 1
thirdparty/harfbuzz/src/hb-buffer-verify.cc

@@ -412,7 +412,7 @@ hb_buffer_t::verify (hb_buffer_t        *text_buffer,
 				   &len,
 				   HB_BUFFER_SERIALIZE_FORMAT_TEXT,
 				   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
-      buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
+      buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ ? bytes.arrayZ : "");
     }
 #endif
   }

+ 43 - 0
thirdparty/harfbuzz/src/hb-buffer.cc

@@ -271,6 +271,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
   replacement = src.replacement;
   invisible = src.invisible;
   not_found = src.not_found;
+  not_found_variation_selector = src.not_found_variation_selector;
 }
 
 void
@@ -283,6 +284,7 @@ hb_buffer_t::reset ()
   replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
   invisible = 0;
   not_found = 0;
+  not_found_variation_selector = HB_CODEPOINT_INVALID;
 
   clear ();
 }
@@ -705,6 +707,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
   HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
   0, /* invisible */
   0, /* not_found */
+  HB_CODEPOINT_INVALID, /* not_found_variation_selector */
 
 
   HB_BUFFER_CONTENT_TYPE_INVALID,
@@ -1360,6 +1363,46 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
   return buffer->not_found;
 }
 
+/**
+ * hb_buffer_set_not_found_variation_selector_glyph:
+ * @buffer: An #hb_buffer_t
+ * @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t
+ *
+ * Sets the #hb_codepoint_t that replaces variation-selector characters not resolved
+ * in the font during shaping.
+ *
+ * The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID,
+ * in which case an unresolved variation-selector will be removed from the glyph
+ * string during shaping. This API allows for changing that and retaining a glyph,
+ * such that the situation can be detected by the client and handled accordingly
+ * (e.g. by using a different font).
+ *
+ * Since: 10.0.0
+ **/
+void
+hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t    *buffer,
+						  hb_codepoint_t  not_found_variation_selector)
+{
+  buffer->not_found_variation_selector = not_found_variation_selector;
+}
+
+/**
+ * hb_buffer_get_not_found_variation_selector_glyph:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_not_found_variation_selector_glyph().
+ *
+ * Return value:
+ * The @buffer not-found-variation-selector #hb_codepoint_t
+ *
+ * Since: 10.0.0
+ **/
+hb_codepoint_t
+hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer)
+{
+  return buffer->not_found_variation_selector;
+}
+
 /**
  * hb_buffer_set_random_state:
  * @buffer: An #hb_buffer_t

+ 7 - 0
thirdparty/harfbuzz/src/hb-buffer.h

@@ -487,6 +487,13 @@ hb_buffer_set_not_found_glyph (hb_buffer_t    *buffer,
 HB_EXTERN hb_codepoint_t
 hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
 
+HB_EXTERN void
+hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t    *buffer,
+						  hb_codepoint_t  not_found_variation_selector);
+
+HB_EXTERN hb_codepoint_t
+hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer);
+
 HB_EXTERN void
 hb_buffer_set_random_state (hb_buffer_t    *buffer,
 			    unsigned        state);

+ 2 - 0
thirdparty/harfbuzz/src/hb-buffer.hh

@@ -52,6 +52,7 @@ enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_HAS_CGJ			= 0x00000010u,
   HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS		= 0x00000020u,
   HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE		= 0x00000040u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u,
 
   /* Reserved for shapers' internal use. */
   HB_BUFFER_SCRATCH_FLAG_SHAPER0			= 0x01000000u,
@@ -80,6 +81,7 @@ struct hb_buffer_t
   hb_codepoint_t replacement; /* U+FFFD or something else. */
   hb_codepoint_t invisible; /* 0 or something else. */
   hb_codepoint_t not_found; /* 0 or something else. */
+  hb_codepoint_t not_found_variation_selector; /* HB_CODEPOINT_INVALID or something else. */
 
   /*
    * Buffer contents

+ 0 - 1
thirdparty/harfbuzz/src/hb-cff-interp-common.hh

@@ -624,7 +624,6 @@ struct opset_t
 	} else {
 	  /* invalid unknown operator */
 	  env.clear_args ();
-	  env.set_error ();
 	}
 	break;
     }

+ 1 - 1
thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh

@@ -84,7 +84,7 @@ struct dict_opset_t : opset_t<number_t>
 
     enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
 
-    char buf[32];
+    char buf[32] = {0};
     unsigned char byte = 0;
     for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
     {

+ 18 - 0
thirdparty/harfbuzz/src/hb-common.h

@@ -504,6 +504,13 @@ hb_language_matches (hb_language_t language,
  * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
  * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
  * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
+ * @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0
+ * @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0
+ * @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0
+ * @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0
+ * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
+ * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
+ * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
  * @HB_SCRIPT_INVALID: No script set
  *
  * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -731,6 +738,17 @@ typedef enum
   HB_SCRIPT_KAWI			= HB_TAG ('K','a','w','i'), /*15.0*/
   HB_SCRIPT_NAG_MUNDARI			= HB_TAG ('N','a','g','m'), /*15.0*/
 
+  /*
+   * Since 10.0.0
+   */
+  HB_SCRIPT_GARAY			= HB_TAG ('G','a','r','a'), /*16.0*/
+  HB_SCRIPT_GURUNG_KHEMA		= HB_TAG ('G','u','k','h'), /*16.0*/
+  HB_SCRIPT_KIRAT_RAI			= HB_TAG ('K','r','a','i'), /*16.0*/
+  HB_SCRIPT_OL_ONAL			= HB_TAG ('O','n','a','o'), /*16.0*/
+  HB_SCRIPT_SUNUWAR			= HB_TAG ('S','u','n','u'), /*16.0*/
+  HB_SCRIPT_TODHRI			= HB_TAG ('T','o','d','r'), /*16.0*/
+  HB_SCRIPT_TULU_TIGALARI		= HB_TAG ('T','u','t','g'), /*16.0*/
+
   /* No script set. */
   HB_SCRIPT_INVALID			= HB_TAG_NONE,
 

+ 4 - 0
thirdparty/harfbuzz/src/hb-config.hh

@@ -118,6 +118,10 @@
 #define HB_NO_VAR_COMPOSITES
 #endif
 
+#ifdef HB_NO_VAR
+#define HB_NO_VAR_COMPOSITES
+#endif
+
 #ifdef HB_DISABLE_DEPRECATED
 #define HB_IF_NOT_DEPRECATED(x)
 #else

+ 51 - 1
thirdparty/harfbuzz/src/hb-coretext.cc

@@ -48,6 +48,8 @@
 /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
 #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
 
+static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
+
 static void
 release_table_data (void *user_data)
 {
@@ -76,6 +78,52 @@ _hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
 			 release_table_data);
 }
 
+static unsigned
+_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
+		       unsigned int start_offset,
+		       unsigned int *table_count,
+		       hb_tag_t *table_tags,
+		       void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+
+  CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
+
+  auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
+
+  unsigned population = (unsigned) CFArrayGetCount (arr);
+  unsigned end_offset;
+
+  if (!table_count)
+    goto done;
+
+  if (unlikely (start_offset >= population))
+  {
+    *table_count = 0;
+    goto done;
+  }
+
+  end_offset = start_offset + *table_count;
+  if (unlikely (end_offset < start_offset))
+  {
+    *table_count = 0;
+    goto done;
+  }
+  end_offset= hb_min (end_offset, (unsigned) population);
+
+  *table_count = end_offset - start_offset;
+  for (unsigned i = start_offset; i < end_offset; i++)
+  {
+    CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
+    table_tags[i - start_offset] = tag;
+  }
+
+done:
+  CFRelease (arr);
+  CFRelease (ct_font);
+  return population;
+}
+
 static void
 _hb_cg_font_release (void *data)
 {
@@ -294,7 +342,9 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
 hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font)
 {
-  return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+  hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+  hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
+  return face;
 }
 
 /**

+ 1 - 1
thirdparty/harfbuzz/src/hb-draw.hh

@@ -232,7 +232,7 @@ struct hb_draw_session_t
     funcs->close_path (draw_data, st);
   }
 
-  protected:
+  public:
   float slant;
   bool not_slanted;
   hb_draw_funcs_t *funcs;

+ 56 - 5
thirdparty/harfbuzz/src/hb-face-builder.cc

@@ -42,7 +42,7 @@
 struct face_table_info_t
 {
   hb_blob_t* data;
-  signed order;
+  unsigned order;
 };
 
 struct hb_face_builder_data_t
@@ -153,6 +153,50 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
   return hb_blob_reference (data->tables[tag].data);
 }
 
+static unsigned
+_hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED,
+				 unsigned int start_offset,
+				 unsigned int *table_count,
+				 hb_tag_t *table_tags,
+				 void *user_data)
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
+
+  unsigned population = data->tables.get_population ();
+
+  if (!table_count)
+    return population;
+
+  if (unlikely (start_offset >= population))
+  {
+    if (table_count)
+      *table_count = 0;
+    return population;
+  }
+
+  // Sort the tags.
+  hb_vector_t<hb_tag_t> sorted_tags;
+  data->tables.keys () | hb_sink (sorted_tags);
+  if (unlikely (sorted_tags.in_error ()))
+  {
+    // Not much to do...
+  }
+  sorted_tags.qsort ([] (const void* a, const void* b) {
+    return * (hb_tag_t *) a <  * (hb_tag_t *) b ? -1 :
+	   * (hb_tag_t *) a == * (hb_tag_t *) b ?  0 :
+	                                          +1;
+  });
+
+  auto array = sorted_tags.as_array ().sub_array (start_offset, table_count);
+  auto out = hb_array (table_tags, *table_count);
+
+  + array.iter ()
+  | hb_sink (out)
+  ;
+
+  return population;
+}
+
 
 /**
  * hb_face_builder_create:
@@ -171,9 +215,16 @@ hb_face_builder_create ()
   hb_face_builder_data_t *data = _hb_face_builder_data_create ();
   if (unlikely (!data)) return hb_face_get_empty ();
 
-  return hb_face_create_for_tables (_hb_face_builder_reference_table,
-				    data,
-				    _hb_face_builder_data_destroy);
+  hb_face_t *face = hb_face_create_for_tables (_hb_face_builder_reference_table,
+					       data,
+					       _hb_face_builder_data_destroy);
+
+  hb_face_set_get_table_tags_func (face,
+				   _hb_face_builder_get_table_tags,
+				   data,
+				   nullptr);
+
+  return face;
 }
 
 /**
@@ -199,7 +250,7 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
 
   hb_blob_t* previous = data->tables.get (tag).data;
-  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
+  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), (unsigned) -1}))
   {
     hb_blob_destroy (blob);
     return false;

+ 59 - 13
thirdparty/harfbuzz/src/hb-face.cc

@@ -90,10 +90,6 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
 {
   HB_OBJECT_HEADER_STATIC,
 
-  nullptr, /* reference_table_func */
-  nullptr, /* user_data */
-  nullptr, /* destroy */
-
   0,    /* index */
   1000, /* upem */
   0,    /* num_glyphs */
@@ -110,8 +106,9 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
  *
  * Variant of hb_face_create(), built for those cases where it is more
  * convenient to provide data for individual tables instead of the whole font
- * data. With the caveat that hb_face_get_table_tags() does not currently work
- * with faces created this way.
+ * data. With the caveat that hb_face_get_table_tags() would not work
+ * with faces created this way. You can address that by calling the
+ * hb_face_set_get_table_tags_func() function and setting the appropriate callback.
  *
  * Creates a new face object from the specified @user_data and @reference_table_func,
  * with the @destroy callback.
@@ -194,6 +191,22 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
   return blob;
 }
 
+static unsigned
+_hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED,
+				  unsigned int start_offset,
+				  unsigned int *table_count,
+				  hb_tag_t *table_tags,
+				  void *user_data)
+{
+  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
+  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+  return ot_face.get_table_tags (start_offset, table_count, table_tags);
+}
+
+
 /**
  * hb_face_create:
  * @blob: #hb_blob_t to work upon
@@ -240,6 +253,10 @@ hb_face_create (hb_blob_t    *blob,
   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
 				    closure,
 				    _hb_face_for_data_closure_destroy);
+  hb_face_set_get_table_tags_func (face,
+				   _hb_face_for_data_get_table_tags,
+				   closure,
+				   nullptr);
 
   face->index = index;
 
@@ -306,6 +323,9 @@ hb_face_destroy (hb_face_t *face)
   face->data.fini ();
   face->table.fini ();
 
+  if (face->get_table_tags_destroy)
+    face->get_table_tags_destroy (face->get_table_tags_user_data);
+
   if (face->destroy)
     face->destroy (face->user_data);
 
@@ -547,6 +567,37 @@ hb_face_get_glyph_count (const hb_face_t *face)
   return face->get_num_glyphs ();
 }
 
+/**
+ * hb_face_set_get_table_tags_func:
+ * @face: A face object
+ * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function
+ * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore
+ * @destroy: (nullable): A callback to call when @func is not needed anymore
+ *
+ * Sets the table-tag-fetching function for the specified face object.
+ *
+ * Since: 10.0.0
+ */
+HB_EXTERN void
+hb_face_set_get_table_tags_func (hb_face_t *face,
+				 hb_get_table_tags_func_t func,
+				 void                    *user_data,
+				 hb_destroy_func_t        destroy)
+{
+  if (hb_object_is_immutable (face))
+  {
+    if (destroy)
+      destroy (user_data);
+  }
+
+  if (face->get_table_tags_destroy)
+    face->get_table_tags_destroy (face->get_table_tags_user_data);
+
+  face->get_table_tags_func = func;
+  face->get_table_tags_user_data = user_data;
+  face->get_table_tags_destroy = destroy;
+}
+
 /**
  * hb_face_get_table_tags:
  * @face: A face object
@@ -568,19 +619,14 @@ hb_face_get_table_tags (const hb_face_t *face,
 			unsigned int *table_count, /* IN/OUT */
 			hb_tag_t     *table_tags /* OUT */)
 {
-  if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
+  if (!face->get_table_tags_func)
   {
     if (table_count)
       *table_count = 0;
     return 0;
   }
 
-  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
-
-  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
-  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
-
-  return ot_face.get_table_tags (start_offset, table_count, table_tags);
+  return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data);
 }
 
 

+ 28 - 0
thirdparty/harfbuzz/src/hb-face.h

@@ -135,6 +135,34 @@ hb_face_set_glyph_count (hb_face_t    *face,
 HB_EXTERN unsigned int
 hb_face_get_glyph_count (const hb_face_t *face);
 
+
+/**
+ * hb_get_table_tags_func_t:
+ * @face: A face object
+ * @start_offset: The index of first table tag to retrieve
+ * @table_count: (inout): Input = the maximum number of table tags to return;
+ *                Output = the actual number of table tags returned (may be zero)
+ * @table_tags: (out) (array length=table_count): The array of table tags found
+ * @user_data: User data pointer passed by the caller
+ *
+ * Callback function for hb_face_get_table_tags().
+ *
+ * Return value: Total number of tables, or zero if it is not possible to list
+ *
+ * Since: 10.0.0
+ */
+typedef unsigned int (*hb_get_table_tags_func_t) (const hb_face_t *face,
+						  unsigned int  start_offset,
+						  unsigned int *table_count, /* IN/OUT */
+						  hb_tag_t     *table_tags /* OUT */,
+						  void         *user_data);
+
+HB_EXTERN void
+hb_face_set_get_table_tags_func (hb_face_t *face,
+				 hb_get_table_tags_func_t func,
+				 void                    *user_data,
+				 hb_destroy_func_t        destroy);
+
 HB_EXTERN unsigned int
 hb_face_get_table_tags (const hb_face_t *face,
 			unsigned int  start_offset,

+ 7 - 3
thirdparty/harfbuzz/src/hb-face.hh

@@ -48,13 +48,17 @@ struct hb_face_t
 {
   hb_object_header_t header;
 
+  unsigned int index;			/* Face index in a collection, zero-based. */
+  mutable hb_atomic_int_t upem;		/* Units-per-EM. */
+  mutable hb_atomic_int_t num_glyphs;	/* Number of glyphs. */
+
   hb_reference_table_func_t  reference_table_func;
   void                      *user_data;
   hb_destroy_func_t          destroy;
 
-  unsigned int index;			/* Face index in a collection, zero-based. */
-  mutable hb_atomic_int_t upem;		/* Units-per-EM. */
-  mutable hb_atomic_int_t num_glyphs;	/* Number of glyphs. */
+  hb_get_table_tags_func_t   get_table_tags_func;
+  void                      *get_table_tags_user_data;
+  hb_destroy_func_t          get_table_tags_destroy;
 
   hb_shaper_object_dataset_t<hb_face_t> data;/* Various shaper data. */
   hb_ot_face_t table;			/* All the face's tables. */

+ 0 - 119
thirdparty/harfbuzz/src/hb-features.h

@@ -1,119 +0,0 @@
-/*
- * Copyright © 2022 Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#ifndef HB_FEATURES_H
-#define HB_FEATURES_H
-
-HB_BEGIN_DECLS
-
-/**
- * SECTION: hb-features
- * @title: hb-features
- * @short_description: Feature detection
- * @include: hb-features.h
- *
- * Macros for detecting optional HarfBuzz features at build time.
- **/
-
-/**
- * HB_HAS_CAIRO:
- *
- * Defined if Harfbuzz has been built with cairo support.
- */
-#
-
-/**
- * HB_HAS_CORETEXT:
- *
- * Defined if Harfbuzz has been built with CoreText support.
- */
-#undef HB_HAS_CORETEXT
-
-/**
- * HB_HAS_DIRECTWRITE:
- *
- * Defined if Harfbuzz has been built with DirectWrite support.
- */
-#undef HB_HAS_DIRECTWRITE
-
-/**
- * HB_HAS_FREETYPE:
- *
- * Defined if Harfbuzz has been built with Freetype support.
- */
-#define HB_HAS_FREETYPE 1
-
-/**
- * HB_HAS_GDI:
- *
- * Defined if Harfbuzz has been built with GDI support.
- */
-#undef HB_HAS_GDI
-
-/**
- * HB_HAS_GLIB:
- *
- * Defined if Harfbuzz has been built with GLib support.
- */
-#define HB_HAS_GLIB 1
-
-/**
- * HB_HAS_GOBJECT:
- *
- * Defined if Harfbuzz has been built with GObject support.
- */
-#undef HB_HAS_GOBJECT
-
-/**
- * HB_HAS_GRAPHITE:
- *
- * Defined if Harfbuzz has been built with Graphite support.
- */
-#undef HB_HAS_GRAPHITE
-
-/**
- * HB_HAS_ICU:
- *
- * Defined if Harfbuzz has been built with ICU support.
- */
-#undef HB_HAS_ICU
-
-/**
- * HB_HAS_UNISCRIBE:
- *
- * Defined if Harfbuzz has been built with Uniscribe support.
- */
-#undef HB_HAS_UNISCRIBE
-
-/**
- * HB_HAS_WASM:
- *
- * Defined if Harfbuzz has been built with WebAssembly support.
- */
-#undef HB_HAS_WASM
-
-
-HB_END_DECLS
-
-#endif /* HB_FEATURES_H */

+ 1 - 1
thirdparty/harfbuzz/src/hb-ft-colr.hh

@@ -108,7 +108,7 @@ struct hb_ft_paint_context_t
   hb_map_t current_glyphs;
   hb_map_t current_layers;
   int depth_left = HB_MAX_NESTING_LEVEL;
-  int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
+  int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
 };
 
 static unsigned

+ 40 - 0
thirdparty/harfbuzz/src/hb-ft.cc

@@ -1104,6 +1104,45 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
 			 buffer, hb_free);
 }
 
+static unsigned
+_hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED,
+		       unsigned int start_offset,
+		       unsigned int *table_count,
+		       hb_tag_t *table_tags,
+		       void *user_data)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+
+  FT_ULong population = 0;
+  FT_Sfnt_Table_Info (ft_face,
+		      0, // table_index; ignored
+		      nullptr,
+                      &population);
+
+  if (!table_count)
+    return population;
+  else
+    *table_count = 0;
+
+  if (unlikely (start_offset >= population))
+    return population;
+
+  unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population);
+  if (unlikely (end_offset < start_offset))
+    return population;
+
+  *table_count = end_offset - start_offset;
+  for (unsigned i = start_offset; i < end_offset; i++)
+  {
+    FT_ULong tag = 0, length;
+    FT_Sfnt_Table_Info (ft_face, i, &tag, &length);
+    table_tags[i - start_offset] = tag;
+  }
+
+  return population;
+}
+
+
 /**
  * hb_ft_face_create:
  * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
@@ -1145,6 +1184,7 @@ hb_ft_face_create (FT_Face           ft_face,
     hb_blob_destroy (blob);
   } else {
     face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
+    hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr);
   }
 
   hb_face_set_index (face, ft_face->face_index);

+ 284 - 0
thirdparty/harfbuzz/src/hb-geometry.hh

@@ -0,0 +1,284 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+#ifndef HB_GEOMETRY_HH
+#define HB_GEOMETRY_HH
+
+#include "hb.hh"
+
+
+struct hb_extents_t
+{
+  hb_extents_t () {}
+  hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
+    xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
+
+  bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
+  bool is_void () const { return xmin > xmax; }
+
+  void union_ (const hb_extents_t &o)
+  {
+    xmin = hb_min (xmin, o.xmin);
+    ymin = hb_min (ymin, o.ymin);
+    xmax = hb_max (xmax, o.xmax);
+    ymax = hb_max (ymax, o.ymax);
+  }
+
+  void intersect (const hb_extents_t &o)
+  {
+    xmin = hb_max (xmin, o.xmin);
+    ymin = hb_max (ymin, o.ymin);
+    xmax = hb_min (xmax, o.xmax);
+    ymax = hb_min (ymax, o.ymax);
+  }
+
+  void
+  add_point (float x, float y)
+  {
+    if (unlikely (is_void ()))
+    {
+      xmin = xmax = x;
+      ymin = ymax = y;
+    }
+    else
+    {
+      xmin = hb_min (xmin, x);
+      ymin = hb_min (ymin, y);
+      xmax = hb_max (xmax, x);
+      ymax = hb_max (ymax, y);
+    }
+  }
+
+  float xmin = 0.f;
+  float ymin = 0.f;
+  float xmax = -1.f;
+  float ymax = -1.f;
+};
+
+struct hb_transform_t
+{
+  hb_transform_t () {}
+  hb_transform_t (float xx, float yx,
+		  float xy, float yy,
+		  float x0, float y0) :
+    xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
+
+  void multiply (const hb_transform_t &o)
+  {
+    /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
+    hb_transform_t r;
+
+    r.xx = o.xx * xx + o.yx * xy;
+    r.yx = o.xx * yx + o.yx * yy;
+
+    r.xy = o.xy * xx + o.yy * xy;
+    r.yy = o.xy * yx + o.yy * yy;
+
+    r.x0 = o.x0 * xx + o.y0 * xy + x0;
+    r.y0 = o.x0 * yx + o.y0 * yy + y0;
+
+    *this = r;
+  }
+
+  void transform_distance (float &dx, float &dy) const
+  {
+    float new_x = xx * dx + xy * dy;
+    float new_y = yx * dx + yy * dy;
+    dx = new_x;
+    dy = new_y;
+  }
+
+  void transform_point (float &x, float &y) const
+  {
+    transform_distance (x, y);
+    x += x0;
+    y += y0;
+  }
+
+  void transform_extents (hb_extents_t &extents) const
+  {
+    float quad_x[4], quad_y[4];
+
+    quad_x[0] = extents.xmin;
+    quad_y[0] = extents.ymin;
+    quad_x[1] = extents.xmin;
+    quad_y[1] = extents.ymax;
+    quad_x[2] = extents.xmax;
+    quad_y[2] = extents.ymin;
+    quad_x[3] = extents.xmax;
+    quad_y[3] = extents.ymax;
+
+    extents = hb_extents_t {};
+    for (unsigned i = 0; i < 4; i++)
+    {
+      transform_point (quad_x[i], quad_y[i]);
+      extents.add_point (quad_x[i], quad_y[i]);
+    }
+  }
+
+  void transform (const hb_transform_t &o) { multiply (o); }
+
+  void translate (float x, float y)
+  {
+    if (x == 0.f && y == 0.f)
+      return;
+
+    x0 += xx * x + xy * y;
+    y0 += yx * x + yy * y;
+  }
+
+  void scale (float scaleX, float scaleY)
+  {
+    if (scaleX == 1.f && scaleY == 1.f)
+      return;
+
+    xx *= scaleX;
+    yx *= scaleX;
+    xy *= scaleY;
+    yy *= scaleY;
+  }
+
+  void rotate (float rotation)
+  {
+    if (rotation == 0.f)
+      return;
+
+    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
+    rotation = rotation * HB_PI;
+    float c;
+    float s;
+#ifdef HAVE_SINCOSF
+    sincosf (rotation, &s, &c);
+#else
+    c = cosf (rotation);
+    s = sinf (rotation);
+#endif
+    auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f};
+    transform (other);
+  }
+
+  void skew (float skewX, float skewY)
+  {
+    if (skewX == 0.f && skewY == 0.f)
+      return;
+
+    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
+    skewX = skewX * HB_PI;
+    skewY = skewY * HB_PI;
+    auto other = hb_transform_t{1.f,
+				skewY ? tanf (skewY) : 0.f,
+				skewX ? tanf (skewX) : 0.f,
+				1.f,
+				0.f, 0.f};
+    transform (other);
+  }
+
+  float xx = 1.f;
+  float yx = 0.f;
+  float xy = 0.f;
+  float yy = 1.f;
+  float x0 = 0.f;
+  float y0 = 0.f;
+};
+
+struct hb_bounds_t
+{
+  enum status_t {
+    UNBOUNDED,
+    BOUNDED,
+    EMPTY,
+  };
+
+  hb_bounds_t (status_t status) : status (status) {}
+  hb_bounds_t (const hb_extents_t &extents) :
+    status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
+
+  void union_ (const hb_bounds_t &o)
+  {
+    if (o.status == UNBOUNDED)
+      status = UNBOUNDED;
+    else if (o.status == BOUNDED)
+    {
+      if (status == EMPTY)
+	*this = o;
+      else if (status == BOUNDED)
+        extents.union_ (o.extents);
+    }
+  }
+
+  void intersect (const hb_bounds_t &o)
+  {
+    if (o.status == EMPTY)
+      status = EMPTY;
+    else if (o.status == BOUNDED)
+    {
+      if (status == UNBOUNDED)
+	*this = o;
+      else if (status == BOUNDED)
+      {
+        extents.intersect (o.extents);
+	if (extents.is_empty ())
+	  status = EMPTY;
+      }
+    }
+  }
+
+  status_t status;
+  hb_extents_t extents;
+};
+
+struct hb_transform_decomposed_t
+{
+  float translateX = 0;
+  float translateY = 0;
+  float rotation = 0;  // in degrees, counter-clockwise
+  float scaleX = 1;
+  float scaleY = 1;
+  float skewX = 0;  // in degrees, counter-clockwise
+  float skewY = 0;  // in degrees, counter-clockwise
+  float tCenterX = 0;
+  float tCenterY = 0;
+
+  operator bool () const
+  {
+    return translateX || translateY ||
+	   rotation ||
+	   scaleX != 1 || scaleY != 1 ||
+	   skewX || skewY ||
+	   tCenterX || tCenterY;
+  }
+
+  hb_transform_t to_transform () const
+  {
+    hb_transform_t t;
+    t.translate (translateX + tCenterX, translateY + tCenterY);
+    t.rotate (rotation);
+    t.scale (scaleX, scaleY);
+    t.skew (-skewX, skewY);
+    t.translate (-tCenterX, -tCenterY);
+    return t;
+  }
+};
+
+
+#endif /* HB_GEOMETRY_HH */

+ 10 - 0
thirdparty/harfbuzz/src/hb-iter.hh

@@ -324,6 +324,16 @@ struct hb_is_sink_of
 	(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
 
 
+struct
+{
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
+
+  unsigned operator () (unsigned _) const { return _; }
+}
+HB_FUNCOBJ (hb_len_of);
+
 /* Range-based 'for' for iterables. */
 
 template <typename Iterable,

+ 8 - 9
thirdparty/harfbuzz/src/hb-limits.hh

@@ -88,25 +88,24 @@
 #define HB_MAX_LOOKUP_VISIT_COUNT 35000
 #endif
 
-
-#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
-#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
+#ifndef HB_MAX_GRAPH_EDGE_COUNT
+#define HB_MAX_GRAPH_EDGE_COUNT 2048
 #endif
 
-#ifndef HB_GLYF_MAX_POINTS
-#define HB_GLYF_MAX_POINTS 20000
+#ifndef HB_VAR_COMPOSITE_MAX_AXES
+#define HB_VAR_COMPOSITE_MAX_AXES 4096
 #endif
 
-#ifndef HB_GLYF_MAX_EDGE_COUNT
-#define HB_GLYF_MAX_EDGE_COUNT 1024
+#ifndef HB_GLYF_MAX_POINTS
+#define HB_GLYF_MAX_POINTS 200000
 #endif
 
 #ifndef HB_CFF_MAX_OPS
 #define HB_CFF_MAX_OPS 10000
 #endif
 
-#ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 2048
+#ifndef HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH
+#define HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH 64
 #endif
 
 

+ 3 - 3
thirdparty/harfbuzz/src/hb-open-file.hh

@@ -250,7 +250,7 @@ struct TTCHeader
   {
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
-    case 1: return u.version1.get_face_count ();
+    case 1: hb_barrier (); return u.version1.get_face_count ();
     default:return 0;
     }
   }
@@ -258,7 +258,7 @@ struct TTCHeader
   {
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
-    case 1: return u.version1.get_face (i);
+    case 1: hb_barrier (); return u.version1.get_face (i);
     default:return Null (OpenTypeFontFace);
     }
   }
@@ -270,7 +270,7 @@ struct TTCHeader
     hb_barrier ();
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
-    case 1: return_trace (u.version1.sanitize (c));
+    case 1: hb_barrier (); return_trace (u.version1.sanitize (c));
     default:return_trace (true);
     }
   }

+ 729 - 12
thirdparty/harfbuzz/src/hb-open-type.hh

@@ -132,6 +132,89 @@ struct HBUINT15 : HBUINT16
   DEFINE_SIZE_STATIC (2);
 };
 
+/* 32-bit unsigned integer with variable encoding. */
+struct HBUINT32VAR
+{
+  unsigned get_size () const
+  {
+    unsigned b0 = v[0];
+    if (b0 < 0x80)
+      return 1;
+    else if (b0 < 0xC0)
+      return 2;
+    else if (b0 < 0xE0)
+      return 3;
+    else if (b0 < 0xF0)
+      return 4;
+    else
+      return 5;
+  }
+
+  static unsigned get_size (uint32_t v)
+  {
+    if (v < 0x80)
+      return 1;
+    else if (v < 0x4000)
+      return 2;
+    else if (v < 0x200000)
+      return 3;
+    else if (v < 0x10000000)
+      return 4;
+    else
+      return 5;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_range (v, 1) &&
+		  hb_barrier () &&
+		  c->check_range (v, get_size ()));
+  }
+
+  operator uint32_t () const
+  {
+    unsigned b0 = v[0];
+    if (b0 < 0x80)
+      return b0;
+    else if (b0 < 0xC0)
+      return ((b0 & 0x3F) << 8) | v[1];
+    else if (b0 < 0xE0)
+      return ((b0 & 0x1F) << 16) | (v[1] << 8) | v[2];
+    else if (b0 < 0xF0)
+      return ((b0 & 0x0F) << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
+    else
+      return (v[1] << 24) | (v[2] << 16) | (v[3] << 8) | v[4];
+  }
+
+  static bool serialize (hb_serialize_context_t *c, uint32_t v)
+  {
+    unsigned len = get_size (v);
+
+    unsigned char *buf = c->allocate_size<unsigned char> (len, false);
+    if (unlikely (!buf))
+      return false;
+
+    unsigned char *p = buf + len;
+    for (unsigned i = 0; i < len; i++)
+    {
+      *--p = v & 0xFF;
+      v >>= 8;
+    }
+
+    if (len > 1)
+      buf[0] |= ((1 << (len - 1)) - 1) << (9 - len);
+
+    return true;
+  }
+
+  protected:
+  unsigned char v[5];
+
+  public:
+  DEFINE_SIZE_MIN (1);
+};
+
 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
 typedef HBINT16 FWORD;
 
@@ -149,6 +232,7 @@ struct HBFixed : Type
 
   operator signed () const = delete;
   operator unsigned () const = delete;
+  explicit operator float () const { return to_float (); }
   typename Type::type to_int () const { return Type::v; }
   void set_int (typename Type::type i ) { Type::v = i; }
   float to_float (float offset = 0) const  { return ((int32_t) Type::v + offset) / shift; }
@@ -570,7 +654,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, Base
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
     if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return this+*p;
   }
   Type& operator [] (int i_)
@@ -578,7 +662,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, Base
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
     if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return this+*p;
   }
 
@@ -629,14 +713,14 @@ struct ArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Null (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Crap (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i];
   }
 
@@ -756,6 +840,7 @@ template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
 /* Array of Offset's */
+template <typename Type> using Array8OfOffset24To = ArrayOf<OffsetTo<Type, HBUINT24>, HBUINT8>;
 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
@@ -768,14 +853,14 @@ struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Null (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return this+this->arrayZ[i];
   }
   const Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Crap (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return this+this->arrayZ[i];
   }
 
@@ -813,14 +898,14 @@ struct HeadlessArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Null (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i-1];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Crap (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i-1];
   }
   unsigned int get_size () const
@@ -907,14 +992,14 @@ struct ArrayOfM1
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Null (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Crap (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return arrayZ[i];
   }
   unsigned int get_size () const
@@ -1099,14 +1184,14 @@ struct VarSizedBinSearchArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Null (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Crap (Type);
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   unsigned int get_length () const
@@ -1163,6 +1248,638 @@ struct VarSizedBinSearchArrayOf
 };
 
 
+/* CFF INDEX */
+
+template <typename COUNT>
+struct CFFIndex
+{
+  unsigned int offset_array_size () const
+  { return offSize * (count + 1); }
+
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  bool serialize (hb_serialize_context_t *c,
+		  const Iterable &iterable,
+		  const unsigned *p_data_size = nullptr,
+                  unsigned min_off_size = 0)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned data_size;
+    if (p_data_size)
+      data_size = *p_data_size;
+    else
+      total_size (iterable, &data_size);
+
+    auto it = hb_iter (iterable);
+    if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
+    unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
+    if (unlikely (!ret)) return_trace (false);
+    for (const auto &_ : +it)
+    {
+      unsigned len = _.length;
+      if (!len)
+	continue;
+      if (len <= 1)
+      {
+	*ret++ = *_.arrayZ;
+	continue;
+      }
+      hb_memcpy (ret, _.arrayZ, len);
+      ret += len;
+    }
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+	    hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_header (hb_serialize_context_t *c,
+			 Iterator it,
+			 unsigned data_size,
+                         unsigned min_off_size = 0)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
+    off_size = hb_max(min_off_size, off_size);
+
+    /* serialize CFFIndex header */
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    this->count = hb_len (it);
+    if (!this->count) return_trace (true);
+    if (unlikely (!c->extend (this->offSize))) return_trace (false);
+    this->offSize = off_size;
+    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
+      return_trace (false);
+
+    /* serialize indices */
+    unsigned int offset = 1;
+    if (HB_OPTIMIZE_SIZE_VAL)
+    {
+      unsigned int i = 0;
+      for (const auto &_ : +it)
+      {
+	set_offset_at (i++, offset);
+	offset += hb_len_of (_);
+      }
+      set_offset_at (i, offset);
+    }
+    else
+      switch (off_size)
+      {
+	case 1:
+	{
+	  HBUINT8 *p = (HBUINT8 *) offsets;
+	  for (const auto &_ : +it)
+	  {
+	    *p++ = offset;
+	    offset += hb_len_of (_);
+	  }
+	  *p = offset;
+	}
+	break;
+	case 2:
+	{
+	  HBUINT16 *p = (HBUINT16 *) offsets;
+	  for (const auto &_ : +it)
+	  {
+	    *p++ = offset;
+	    offset += hb_len_of (_);
+	  }
+	  *p = offset;
+	}
+	break;
+	case 3:
+	{
+	  HBUINT24 *p = (HBUINT24 *) offsets;
+	  for (const auto &_ : +it)
+	  {
+	    *p++ = offset;
+	    offset += hb_len_of (_);
+	  }
+	  *p = offset;
+	}
+	break;
+	case 4:
+	{
+	  HBUINT32 *p = (HBUINT32 *) offsets;
+	  for (const auto &_ : +it)
+	  {
+	    *p++ = offset;
+	    offset += hb_len_of (_);
+	  }
+	  *p = offset;
+	}
+	break;
+	default:
+	break;
+      }
+
+    assert (offset == data_size + 1);
+    return_trace (true);
+  }
+
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
+  {
+    auto it = + hb_iter (iterable);
+    if (!it)
+    {
+      if (data_size) *data_size = 0;
+      return min_size;
+    }
+
+    unsigned total = 0;
+    for (const auto &_ : +it)
+      total += hb_len_of (_);
+
+    if (data_size) *data_size = total;
+
+    unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+    off_size = hb_max(min_off_size, off_size);
+
+    return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
+  }
+
+  void set_offset_at (unsigned int index, unsigned int offset)
+  {
+    assert (index <= count);
+
+    unsigned int size = offSize;
+    const HBUINT8 *p = offsets;
+    switch (size)
+    {
+      case 1: ((HBUINT8  *) p)[index] = offset; break;
+      case 2: ((HBUINT16 *) p)[index] = offset; break;
+      case 3: ((HBUINT24 *) p)[index] = offset; break;
+      case 4: ((HBUINT32 *) p)[index] = offset; break;
+      default: return;
+    }
+  }
+
+  private:
+  unsigned int offset_at (unsigned int index) const
+  {
+    assert (index <= count);
+
+    unsigned int size = offSize;
+    const HBUINT8 *p = offsets;
+    switch (size)
+    {
+      case 1: return ((HBUINT8  *) p)[index];
+      case 2: return ((HBUINT16 *) p)[index];
+      case 3: return ((HBUINT24 *) p)[index];
+      case 4: return ((HBUINT32 *) p)[index];
+      default: return 0;
+    }
+  }
+
+  const unsigned char *data_base () const
+  { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
+  public:
+
+  hb_ubytes_t operator [] (unsigned int index) const
+  {
+    if (unlikely (index >= count)) return hb_ubytes_t ();
+    hb_barrier ();
+    unsigned offset0 = offset_at (index);
+    unsigned offset1 = offset_at (index + 1);
+    if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
+      return hb_ubytes_t ();
+    return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
+  }
+
+  unsigned int get_size () const
+  {
+    if (count)
+      return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
+    return min_size;  /* empty CFFIndex contains count only */
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  hb_barrier () &&
+			  (count == 0 || /* empty INDEX */
+			   (count < count + 1u &&
+			    c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
+			    c->check_array (offsets, offSize, count + 1u) &&
+			    c->check_range (data_base (), offset_at (count))))));
+  }
+
+  public:
+  COUNT		count;		/* Number of object data. Note there are (count+1) offsets */
+  private:
+  HBUINT8	offSize;	/* The byte size of each offset in the offsets array. */
+  HBUINT8	offsets[HB_VAR_ARRAY];
+				/* The array of (count + 1) offsets into objects array (1-base). */
+  /* HBUINT8 data[HB_VAR_ARRAY];	Object data */
+  public:
+  DEFINE_SIZE_MIN (COUNT::static_size);
+};
+typedef CFFIndex<HBUINT16> CFF1Index;
+typedef CFFIndex<HBUINT32> CFF2Index;
+
+
+/* TupleValues */
+struct TupleValues
+{
+  enum packed_value_flag_t
+  {
+    VALUES_ARE_ZEROS     = 0x80,
+    VALUES_ARE_BYTES     = 0x00,
+    VALUES_ARE_WORDS     = 0x40,
+    VALUES_ARE_LONGS     = 0xC0,
+    VALUES_SIZE_MASK     = 0xC0,
+    VALUE_RUN_COUNT_MASK = 0x3F
+  };
+
+  static unsigned compile (hb_array_t<const int> values, /* IN */
+			   hb_array_t<unsigned char> encoded_bytes /* OUT */)
+  {
+    unsigned num_values = values.length;
+    unsigned encoded_len = 0;
+    unsigned i = 0;
+    while (i < num_values)
+    {
+      int val = values.arrayZ[i];
+      if (val == 0)
+        encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values);
+      else if (val >= -128 && val <= 127)
+        encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values);
+      else if (val >= -32768 && val <= 32767)
+        encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values);
+      else
+        encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values);
+    }
+    return encoded_len;
+  }
+
+  static unsigned encode_value_run_as_zeroes (unsigned& i,
+					      hb_array_t<unsigned char> encoded_bytes,
+					      hb_array_t<const int> values)
+  {
+    unsigned num_values = values.length;
+    unsigned run_length = 0;
+    auto it = encoded_bytes.iter ();
+    unsigned encoded_len = 0;
+    while (i < num_values && values.arrayZ[i] == 0)
+    {
+      i++;
+      run_length++;
+    }
+
+    while (run_length >= 64)
+    {
+      *it++ = char (VALUES_ARE_ZEROS | 63);
+      run_length -= 64;
+      encoded_len++;
+    }
+
+    if (run_length)
+    {
+      *it++ = char (VALUES_ARE_ZEROS | (run_length - 1));
+      encoded_len++;
+    }
+    return encoded_len;
+  }
+
+  static unsigned encode_value_run_as_bytes (unsigned &i,
+					     hb_array_t<unsigned char> encoded_bytes,
+					     hb_array_t<const int> values)
+  {
+    unsigned start = i;
+    unsigned num_values = values.length;
+    while (i < num_values)
+    {
+      int val = values.arrayZ[i];
+      if (val > 127 || val < -128)
+        break;
+
+      /* from fonttools: if there're 2 or more zeros in a sequence,
+       * it is better to start a new run to save bytes. */
+      if (val == 0 && i + 1 < num_values && values.arrayZ[i+1] == 0)
+        break;
+
+      i++;
+    }
+    unsigned run_length = i - start;
+
+    unsigned encoded_len = 0;
+    auto it = encoded_bytes.iter ();
+
+    while (run_length >= 64)
+    {
+      *it++ = (VALUES_ARE_BYTES | 63);
+      encoded_len++;
+
+      for (unsigned j = 0; j < 64; j++)
+      {
+        *it++ = static_cast<char> (values.arrayZ[start + j]);
+        encoded_len++;
+      }
+
+      start += 64;
+      run_length -= 64;
+    }
+
+    if (run_length)
+    {
+      *it++ = (VALUES_ARE_BYTES | (run_length - 1));
+      encoded_len++;
+
+      while (start < i)
+      {
+        *it++ = static_cast<char> (values.arrayZ[start++]);
+        encoded_len++;
+      }
+    }
+
+    return encoded_len;
+  }
+
+  static unsigned encode_value_run_as_words (unsigned &i,
+					     hb_array_t<unsigned char> encoded_bytes,
+					     hb_array_t<const int> values)
+  {
+    unsigned start = i;
+    unsigned num_values = values.length;
+    while (i < num_values)
+    {
+      int val = values.arrayZ[i];
+
+      /* start a new run for a single zero value*/
+      if (val == 0) break;
+
+      /* from fonttools: continue word-encoded run if there's only one
+       * single value in the range [-128, 127] because it is more compact.
+       * Only start a new run when there're 2 continuous such values. */
+      if (val >= -128 && val <= 127 &&
+          i + 1 < num_values &&
+          values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127)
+        break;
+
+      i++;
+    }
+
+    unsigned run_length = i - start;
+    auto it = encoded_bytes.iter ();
+    unsigned encoded_len = 0;
+    while (run_length >= 64)
+    {
+      *it++ = (VALUES_ARE_WORDS | 63);
+      encoded_len++;
+
+      for (unsigned j = 0; j < 64; j++)
+      {
+        int16_t value_val = values.arrayZ[start + j];
+        *it++ = static_cast<char> (value_val >> 8);
+        *it++ = static_cast<char> (value_val & 0xFF);
+
+        encoded_len += 2;
+      }
+
+      start += 64;
+      run_length -= 64;
+    }
+
+    if (run_length)
+    {
+      *it++ = (VALUES_ARE_WORDS | (run_length - 1));
+      encoded_len++;
+      while (start < i)
+      {
+        int16_t value_val = values.arrayZ[start++];
+        *it++ = static_cast<char> (value_val >> 8);
+        *it++ = static_cast<char> (value_val & 0xFF);
+
+        encoded_len += 2;
+      }
+    }
+    return encoded_len;
+  }
+
+  static unsigned encode_value_run_as_longs (unsigned &i,
+					     hb_array_t<unsigned char> encoded_bytes,
+					     hb_array_t<const int> values)
+  {
+    unsigned start = i;
+    unsigned num_values = values.length;
+    while (i < num_values)
+    {
+      int val = values.arrayZ[i];
+
+      if (val >= -32768 && val <= 32767)
+        break;
+
+      i++;
+    }
+
+    unsigned run_length = i - start;
+    auto it = encoded_bytes.iter ();
+    unsigned encoded_len = 0;
+    while (run_length >= 64)
+    {
+      *it++ = (VALUES_ARE_LONGS | 63);
+      encoded_len++;
+
+      for (unsigned j = 0; j < 64; j++)
+      {
+        int32_t value_val = values.arrayZ[start + j];
+        *it++ = static_cast<char> (value_val >> 24);
+        *it++ = static_cast<char> (value_val >> 16);
+        *it++ = static_cast<char> (value_val >> 8);
+        *it++ = static_cast<char> (value_val & 0xFF);
+
+        encoded_len += 4;
+      }
+
+      start += 64;
+      run_length -= 64;
+    }
+
+    if (run_length)
+    {
+      *it++ = (VALUES_ARE_LONGS | (run_length - 1));
+      encoded_len++;
+      while (start < i)
+      {
+        int32_t value_val = values.arrayZ[start++];
+        *it++ = static_cast<char> (value_val >> 24);
+        *it++ = static_cast<char> (value_val >> 16);
+        *it++ = static_cast<char> (value_val >> 8);
+        *it++ = static_cast<char> (value_val & 0xFF);
+
+        encoded_len += 4;
+      }
+    }
+    return encoded_len;
+  }
+
+  template <typename T>
+  static bool decompile (const HBUINT8 *&p /* IN/OUT */,
+			 hb_vector_t<T> &values /* IN/OUT */,
+			 const HBUINT8 *end,
+			 bool consume_all = false)
+  {
+    unsigned i = 0;
+    unsigned count = consume_all ? UINT_MAX : values.length;
+    if (consume_all)
+      values.alloc ((end - p) / 2);
+    while (i < count)
+    {
+      if (unlikely (p + 1 > end)) return consume_all;
+      unsigned control = *p++;
+      unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
+      if (consume_all)
+      {
+        if (unlikely (!values.resize (values.length + run_count, false)))
+	  return false;
+      }
+      unsigned stop = i + run_count;
+      if (unlikely (stop > count)) return false;
+      if ((control & VALUES_SIZE_MASK) == VALUES_ARE_ZEROS)
+      {
+        for (; i < stop; i++)
+          values.arrayZ[i] = 0;
+      }
+      else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_WORDS)
+      {
+        if (unlikely (p + run_count * HBINT16::static_size > end)) return false;
+        for (; i < stop; i++)
+        {
+          values.arrayZ[i] = * (const HBINT16 *) p;
+          p += HBINT16::static_size;
+        }
+      }
+      else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_LONGS)
+      {
+        if (unlikely (p + run_count * HBINT32::static_size > end)) return false;
+        for (; i < stop; i++)
+        {
+          values.arrayZ[i] = * (const HBINT32 *) p;
+          p += HBINT32::static_size;
+        }
+      }
+      else if ((control & VALUES_SIZE_MASK) ==  VALUES_ARE_BYTES)
+      {
+        if (unlikely (p + run_count > end)) return false;
+        for (; i < stop; i++)
+        {
+          values.arrayZ[i] = * (const HBINT8 *) p++;
+        }
+      }
+    }
+    return true;
+  }
+
+  struct iter_t : hb_iter_with_fallback_t<iter_t, int>
+  {
+    iter_t (const unsigned char *p_, unsigned len_)
+	    : p (p_), end (p_ + len_)
+    { if (ensure_run ()) read_value (); }
+
+    private:
+    const unsigned char *p;
+    const unsigned char * const end;
+    int current_value = 0;
+    signed run_count = 0;
+    unsigned width = 0;
+
+    bool ensure_run ()
+    {
+      if (likely (run_count > 0)) return true;
+
+      if (unlikely (p >= end))
+      {
+        run_count = 0;
+        current_value = 0;
+	return false;
+      }
+
+      unsigned control = *p++;
+      run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
+      width = control & VALUES_SIZE_MASK;
+      switch (width)
+      {
+        case VALUES_ARE_ZEROS: width = 0; break;
+	case VALUES_ARE_BYTES: width = HBINT8::static_size;  break;
+	case VALUES_ARE_WORDS: width = HBINT16::static_size; break;
+	case VALUES_ARE_LONGS: width = HBINT32::static_size; break;
+	default: assert (false);
+      }
+
+      if (unlikely (p + run_count * width > end))
+      {
+	run_count = 0;
+	current_value = 0;
+	return false;
+      }
+
+      return true;
+    }
+    void read_value ()
+    {
+      switch (width)
+      {
+        case 0: current_value = 0; break;
+	case 1: current_value = * (const HBINT8  *) p; break;
+	case 2: current_value = * (const HBINT16 *) p; break;
+	case 4: current_value = * (const HBINT32 *) p; break;
+      }
+      p += width;
+    }
+
+    public:
+
+    typedef int __item_t__;
+    __item_t__ __item__ () const
+    { return current_value; }
+
+    bool __more__ () const { return run_count || p < end; }
+    void __next__ ()
+    {
+      run_count--;
+      if (unlikely (!ensure_run ()))
+	return;
+      read_value ();
+    }
+    void __forward__ (unsigned n)
+    {
+      if (unlikely (!ensure_run ()))
+	return;
+      while (n)
+      {
+	unsigned i = hb_min (n, (unsigned) run_count);
+	run_count -= i;
+	n -= i;
+	p += (i - 1) * width;
+	if (unlikely (!ensure_run ()))
+	  return;
+	read_value ();
+      }
+    }
+    bool operator != (const iter_t& o) const
+    { return p != o.p || run_count != o.run_count; }
+    iter_t __end__ () const
+    {
+      iter_t it (end, 0);
+      return it;
+    }
+  };
+};
+
+struct TupleList : CFF2Index
+{
+  TupleValues::iter_t operator [] (unsigned i) const
+  {
+    auto bytes = CFF2Index::operator [] (i);
+    return TupleValues::iter_t (bytes.arrayZ, bytes.length);
+  }
+};
+
+
 } /* namespace OT */
 
 

+ 8 - 249
thirdparty/harfbuzz/src/hb-ot-cff-common.hh

@@ -68,247 +68,6 @@ using str_buff_t = hb_vector_t<unsigned char>;
 using str_buff_vec_t = hb_vector_t<str_buff_t>;
 using glyph_to_sid_map_t = hb_vector_t<code_pair_t>;
 
-struct length_f_t
-{
-  template <typename Iterable,
-	    hb_requires (hb_is_iterable (Iterable))>
-  unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
-
-  unsigned operator () (unsigned _) const { return _; }
-}
-HB_FUNCOBJ (length_f);
-
-/* CFF INDEX */
-template <typename COUNT>
-struct CFFIndex
-{
-  unsigned int offset_array_size () const
-  { return offSize * (count + 1); }
-
-  template <typename Iterable,
-	    hb_requires (hb_is_iterable (Iterable))>
-  bool serialize (hb_serialize_context_t *c,
-		  const Iterable &iterable,
-		  const unsigned *p_data_size = nullptr,
-                  unsigned min_off_size = 0)
-  {
-    TRACE_SERIALIZE (this);
-    unsigned data_size;
-    if (p_data_size)
-      data_size = *p_data_size;
-    else
-      total_size (iterable, &data_size);
-
-    auto it = hb_iter (iterable);
-    if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
-    unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
-    if (unlikely (!ret)) return_trace (false);
-    for (const auto &_ : +it)
-    {
-      unsigned len = _.length;
-      if (!len)
-	continue;
-      if (len <= 1)
-      {
-	*ret++ = *_.arrayZ;
-	continue;
-      }
-      hb_memcpy (ret, _.arrayZ, len);
-      ret += len;
-    }
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_iterator (Iterator))>
-  bool serialize_header (hb_serialize_context_t *c,
-			 Iterator it,
-			 unsigned data_size,
-                         unsigned min_off_size = 0)
-  {
-    TRACE_SERIALIZE (this);
-
-    unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
-    off_size = hb_max(min_off_size, off_size);
-
-    /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    this->count = hb_len (it);
-    if (!this->count) return_trace (true);
-    if (unlikely (!c->extend (this->offSize))) return_trace (false);
-    this->offSize = off_size;
-    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
-      return_trace (false);
-
-    /* serialize indices */
-    unsigned int offset = 1;
-    if (HB_OPTIMIZE_SIZE_VAL)
-    {
-      unsigned int i = 0;
-      for (const auto &_ : +it)
-      {
-	set_offset_at (i++, offset);
-	offset += length_f (_);
-      }
-      set_offset_at (i, offset);
-    }
-    else
-      switch (off_size)
-      {
-	case 1:
-	{
-	  HBUINT8 *p = (HBUINT8 *) offsets;
-	  for (const auto &_ : +it)
-	  {
-	    *p++ = offset;
-	    offset += length_f (_);
-	  }
-	  *p = offset;
-	}
-	break;
-	case 2:
-	{
-	  HBUINT16 *p = (HBUINT16 *) offsets;
-	  for (const auto &_ : +it)
-	  {
-	    *p++ = offset;
-	    offset += length_f (_);
-	  }
-	  *p = offset;
-	}
-	break;
-	case 3:
-	{
-	  HBUINT24 *p = (HBUINT24 *) offsets;
-	  for (const auto &_ : +it)
-	  {
-	    *p++ = offset;
-	    offset += length_f (_);
-	  }
-	  *p = offset;
-	}
-	break;
-	case 4:
-	{
-	  HBUINT32 *p = (HBUINT32 *) offsets;
-	  for (const auto &_ : +it)
-	  {
-	    *p++ = offset;
-	    offset += length_f (_);
-	  }
-	  *p = offset;
-	}
-	break;
-	default:
-	break;
-      }
-
-    assert (offset == data_size + 1);
-    return_trace (true);
-  }
-
-  template <typename Iterable,
-	    hb_requires (hb_is_iterable (Iterable))>
-  static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
-  {
-    auto it = + hb_iter (iterable);
-    if (!it)
-    {
-      if (data_size) *data_size = 0;
-      return min_size;
-    }
-
-    unsigned total = 0;
-    for (const auto &_ : +it)
-      total += length_f (_);
-
-    if (data_size) *data_size = total;
-
-    unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
-    off_size = hb_max(min_off_size, off_size);
-
-    return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
-  }
-
-  void set_offset_at (unsigned int index, unsigned int offset)
-  {
-    assert (index <= count);
-
-    unsigned int size = offSize;
-    const HBUINT8 *p = offsets;
-    switch (size)
-    {
-      case 1: ((HBUINT8  *) p)[index] = offset; break;
-      case 2: ((HBUINT16 *) p)[index] = offset; break;
-      case 3: ((HBUINT24 *) p)[index] = offset; break;
-      case 4: ((HBUINT32 *) p)[index] = offset; break;
-      default: return;
-    }
-  }
-
-  private:
-  unsigned int offset_at (unsigned int index) const
-  {
-    assert (index <= count);
-
-    unsigned int size = offSize;
-    const HBUINT8 *p = offsets;
-    switch (size)
-    {
-      case 1: return ((HBUINT8  *) p)[index];
-      case 2: return ((HBUINT16 *) p)[index];
-      case 3: return ((HBUINT24 *) p)[index];
-      case 4: return ((HBUINT32 *) p)[index];
-      default: return 0;
-    }
-  }
-
-  const unsigned char *data_base () const
-  { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
-  public:
-
-  hb_ubytes_t operator [] (unsigned int index) const
-  {
-    if (unlikely (index >= count)) return hb_ubytes_t ();
-    _hb_compiler_memory_r_barrier ();
-    unsigned offset0 = offset_at (index);
-    unsigned offset1 = offset_at (index + 1);
-    if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
-      return hb_ubytes_t ();
-    return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
-  }
-
-  unsigned int get_size () const
-  {
-    if (count)
-      return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
-    return min_size;  /* empty CFFIndex contains count only */
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-			  hb_barrier () &&
-			  (count == 0 || /* empty INDEX */
-			   (count < count + 1u &&
-			    hb_barrier () &&
-			    c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
-			    c->check_array (offsets, offSize, count + 1u) &&
-			    c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
-  }
-
-  public:
-  COUNT		count;		/* Number of object data. Note there are (count+1) offsets */
-  private:
-  HBUINT8	offSize;	/* The byte size of each offset in the offsets array. */
-  HBUINT8	offsets[HB_VAR_ARRAY];
-				/* The array of (count + 1) offsets into objects array (1-base). */
-  /* HBUINT8 data[HB_VAR_ARRAY];	Object data */
-  public:
-  DEFINE_SIZE_MIN (COUNT::static_size);
-};
-
 /* Top Dict, Font Dict, Private Dict */
 struct Dict : UnsizedByteStr
 {
@@ -549,8 +308,8 @@ struct FDSelect
   {
     switch (format)
     {
-    case 0: return format.static_size + u.format0.get_size (num_glyphs);
-    case 3: return format.static_size + u.format3.get_size ();
+    case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: hb_barrier (); return format.static_size + u.format3.get_size ();
     default:return 0;
     }
   }
@@ -561,8 +320,8 @@ struct FDSelect
 
     switch (format)
     {
-    case 0: return u.format0.get_fd (glyph);
-    case 3: return u.format3.get_fd (glyph);
+    case 0: hb_barrier (); return u.format0.get_fd (glyph);
+    case 3: hb_barrier (); return u.format3.get_fd (glyph);
     default:return 0;
     }
   }
@@ -573,8 +332,8 @@ struct FDSelect
 
     switch (format)
     {
-    case 0: return u.format0.get_fd_range (glyph);
-    case 3: return u.format3.get_fd_range (glyph);
+    case 0: hb_barrier (); return u.format0.get_fd_range (glyph);
+    case 3: hb_barrier (); return u.format3.get_fd_range (glyph);
     default:return {0, 1};
     }
   }
@@ -588,8 +347,8 @@ struct FDSelect
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, fdcount));
-    case 3: return_trace (u.format3.sanitize (c, fdcount));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount));
+    case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount));
     default:return_trace (false);
     }
   }

+ 25 - 26
thirdparty/harfbuzz/src/hb-ot-cff1-table.hh

@@ -51,9 +51,6 @@ namespace CFF {
 enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
 enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
 
-typedef CFFIndex<HBUINT16>  CFF1Index;
-
-typedef CFFIndex<HBUINT16> CFF1Index;
 typedef CFF1Index          CFF1CharStrings;
 typedef Subrs<HBUINT16>    CFF1Subrs;
 
@@ -242,8 +239,8 @@ struct Encoding
     unsigned int size = min_size;
     switch (table_format ())
     {
-    case 0: size += u.format0.get_size (); break;
-    case 1: size += u.format1.get_size (); break;
+    case 0: hb_barrier (); size += u.format0.get_size (); break;
+    case 1: hb_barrier (); size += u.format1.get_size (); break;
     }
     if (has_supplement ())
       size += suppEncData ().get_size ();
@@ -254,8 +251,8 @@ struct Encoding
   {
     switch (table_format ())
     {
-    case 0: return u.format0.get_code (glyph);
-    case 1: return u.format1.get_code (glyph);
+    case 0: hb_barrier (); return u.format0.get_code (glyph);
+    case 1: hb_barrier (); return u.format1.get_code (glyph);
     default:return 0;
     }
   }
@@ -279,8 +276,8 @@ struct Encoding
 
     switch (table_format ())
     {
-    case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break;
-    case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break;
+    case 0: hb_barrier (); if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break;
+    case 1: hb_barrier (); if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break;
     default:return_trace (false);
     }
     return_trace (likely (!has_supplement () || suppEncData ().sanitize (c)));
@@ -291,8 +288,8 @@ struct Encoding
   {
     switch (table_format ())
     {
-    case 0: return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
-    case 1: return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
+    case 0: hb_barrier (); return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
+    case 1: hb_barrier (); return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
     default:return Null (CFF1SuppEncData);
     }
   }
@@ -570,9 +567,9 @@ struct Charset
   {
     switch (format)
     {
-    case 0: return min_size + u.format0.get_size (num_glyphs);
-    case 1: return min_size + u.format1.get_size (num_glyphs);
-    case 2: return min_size + u.format2.get_size (num_glyphs);
+    case 0: hb_barrier (); return min_size + u.format0.get_size (num_glyphs);
+    case 1: hb_barrier (); return min_size + u.format1.get_size (num_glyphs);
+    case 2: hb_barrier (); return min_size + u.format2.get_size (num_glyphs);
     default:return 0;
     }
   }
@@ -582,9 +579,9 @@ struct Charset
   {
     switch (format)
     {
-    case 0: return u.format0.get_sid (glyph, num_glyphs);
-    case 1: return u.format1.get_sid (glyph, num_glyphs, cache);
-    case 2: return u.format2.get_sid (glyph, num_glyphs, cache);
+    case 0: hb_barrier (); return u.format0.get_sid (glyph, num_glyphs);
+    case 1: hb_barrier (); return u.format1.get_sid (glyph, num_glyphs, cache);
+    case 2: hb_barrier (); return u.format2.get_sid (glyph, num_glyphs, cache);
     default:return 0;
     }
   }
@@ -593,9 +590,9 @@ struct Charset
   {
     switch (format)
     {
-    case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return;
-    case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return;
-    case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    case 0: hb_barrier (); u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    case 1: hb_barrier (); u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return;
+    case 2: hb_barrier (); u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return;
     default:return;
     }
   }
@@ -604,9 +601,9 @@ struct Charset
   {
     switch (format)
     {
-    case 0: return u.format0.get_glyph (sid, num_glyphs);
-    case 1: return u.format1.get_glyph (sid, num_glyphs);
-    case 2: return u.format2.get_glyph (sid, num_glyphs);
+    case 0: hb_barrier (); return u.format0.get_glyph (sid, num_glyphs);
+    case 1: hb_barrier (); return u.format1.get_glyph (sid, num_glyphs);
+    case 2: hb_barrier (); return u.format2.get_glyph (sid, num_glyphs);
     default:return 0;
     }
   }
@@ -620,9 +617,9 @@ struct Charset
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
-    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
-    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 1: hb_barrier (); return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+    case 2: hb_barrier (); return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
     default:return_trace (false);
     }
   }
@@ -1179,6 +1176,7 @@ struct cff1
 	  if (unlikely (!font_interp.interpret (*font)))   goto fail;
 	  PRIVDICTVAL *priv = &privateDicts[i];
 	  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
+	  if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	  num_interp_env_t env2 (privDictStr);
 	  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
 	  priv->init ();
@@ -1193,6 +1191,7 @@ struct cff1
 	PRIVDICTVAL *priv = &privateDicts[0];
 
 	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
+	if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	num_interp_env_t env (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
 	priv->init ();

+ 6 - 1
thirdparty/harfbuzz/src/hb-ot-cff2-table.cc

@@ -202,6 +202,11 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int
 struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {};
 
 bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
+{
+  return get_path_at (font, glyph, draw_session, hb_array (font->coords, font->num_coords));
+}
+
+bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
@@ -212,7 +217,7 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
 
   unsigned int fd = fdSelect->get_fd (glyph);
   const hb_ubytes_t str = (*charStrings)[glyph];
-  cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
+  cff2_cs_interp_env_t<number_t> env (str, *this, fd, coords.arrayZ, coords.length);
   cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env);
   cff2_path_param_t param (font, draw_session);
   if (unlikely (!interp.interpret (param))) return false;

+ 11 - 11
thirdparty/harfbuzz/src/hb-ot-cff2-table.hh

@@ -40,8 +40,6 @@ namespace CFF {
  */
 #define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
 
-typedef CFFIndex<HBUINT32>  CFF2Index;
-
 typedef CFF2Index         CFF2CharStrings;
 typedef Subrs<HBUINT32>   CFF2Subrs;
 
@@ -64,9 +62,9 @@ struct CFF2FDSelect
   {
     switch (format)
     {
-    case 0: return format.static_size + u.format0.get_size (num_glyphs);
-    case 3: return format.static_size + u.format3.get_size ();
-    case 4: return format.static_size + u.format4.get_size ();
+    case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: hb_barrier (); return format.static_size + u.format3.get_size ();
+    case 4: hb_barrier (); return format.static_size + u.format4.get_size ();
     default:return 0;
     }
   }
@@ -78,9 +76,9 @@ struct CFF2FDSelect
 
     switch (format)
     {
-    case 0: return u.format0.get_fd (glyph);
-    case 3: return u.format3.get_fd (glyph);
-    case 4: return u.format4.get_fd (glyph);
+    case 0: hb_barrier (); return u.format0.get_fd (glyph);
+    case 3: hb_barrier (); return u.format3.get_fd (glyph);
+    case 4: hb_barrier (); return u.format4.get_fd (glyph);
     default:return 0;
     }
   }
@@ -94,9 +92,9 @@ struct CFF2FDSelect
 
     switch (format)
     {
-    case 0: return_trace (u.format0.sanitize (c, fdcount));
-    case 3: return_trace (u.format3.sanitize (c, fdcount));
-    case 4: return_trace (u.format4.sanitize (c, fdcount));
+    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount));
+    case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount));
+    case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount));
     default:return_trace (false);
     }
   }
@@ -460,6 +458,7 @@ struct cff2
 	if (unlikely (!font_interp.interpret (*font))) goto fail;
 
 	const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
+	if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	cff2_priv_dict_interp_env_t env2 (privDictStr);
 	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
 	privateDicts[i].init ();
@@ -521,6 +520,7 @@ struct cff2
 				  hb_glyph_extents_t *extents) const;
     HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
     HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
+    HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const;
   };
 
   struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>

+ 172 - 54
thirdparty/harfbuzz/src/hb-ot-cmap-table.hh

@@ -43,27 +43,145 @@ namespace OT {
 
 static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
 {
-  uint16_t mapping[] = {
-    0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
-    0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
-    0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
-    0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
-    0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
-    0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
-    0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
-    0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
-    0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
-    0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
-    0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
-    0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
-    0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
-    0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
-    0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
-    0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+  static const struct unicode_to_macroman_t
+  {
+    uint16_t unicode;
+    uint8_t macroman;
+  }
+  mapping[] =
+  {
+    { 0x00A0, 0xCA },
+    { 0x00A1, 0xC1 },
+    { 0x00A2, 0xA2 },
+    { 0x00A3, 0xA3 },
+    { 0x00A5, 0xB4 },
+    { 0x00A7, 0xA4 },
+    { 0x00A8, 0xAC },
+    { 0x00A9, 0xA9 },
+    { 0x00AA, 0xBB },
+    { 0x00AB, 0xC7 },
+    { 0x00AC, 0xC2 },
+    { 0x00AE, 0xA8 },
+    { 0x00AF, 0xF8 },
+    { 0x00B0, 0xA1 },
+    { 0x00B1, 0xB1 },
+    { 0x00B4, 0xAB },
+    { 0x00B5, 0xB5 },
+    { 0x00B6, 0xA6 },
+    { 0x00B7, 0xE1 },
+    { 0x00B8, 0xFC },
+    { 0x00BA, 0xBC },
+    { 0x00BB, 0xC8 },
+    { 0x00BF, 0xC0 },
+    { 0x00C0, 0xCB },
+    { 0x00C1, 0xE7 },
+    { 0x00C2, 0xE5 },
+    { 0x00C3, 0xCC },
+    { 0x00C4, 0x80 },
+    { 0x00C5, 0x81 },
+    { 0x00C6, 0xAE },
+    { 0x00C7, 0x82 },
+    { 0x00C8, 0xE9 },
+    { 0x00C9, 0x83 },
+    { 0x00CA, 0xE6 },
+    { 0x00CB, 0xE8 },
+    { 0x00CC, 0xED },
+    { 0x00CD, 0xEA },
+    { 0x00CE, 0xEB },
+    { 0x00CF, 0xEC },
+    { 0x00D1, 0x84 },
+    { 0x00D2, 0xF1 },
+    { 0x00D3, 0xEE },
+    { 0x00D4, 0xEF },
+    { 0x00D5, 0xCD },
+    { 0x00D6, 0x85 },
+    { 0x00D8, 0xAF },
+    { 0x00D9, 0xF4 },
+    { 0x00DA, 0xF2 },
+    { 0x00DB, 0xF3 },
+    { 0x00DC, 0x86 },
+    { 0x00DF, 0xA7 },
+    { 0x00E0, 0x88 },
+    { 0x00E1, 0x87 },
+    { 0x00E2, 0x89 },
+    { 0x00E3, 0x8B },
+    { 0x00E4, 0x8A },
+    { 0x00E5, 0x8C },
+    { 0x00E6, 0xBE },
+    { 0x00E7, 0x8D },
+    { 0x00E8, 0x8F },
+    { 0x00E9, 0x8E },
+    { 0x00EA, 0x90 },
+    { 0x00EB, 0x91 },
+    { 0x00EC, 0x93 },
+    { 0x00ED, 0x92 },
+    { 0x00EE, 0x94 },
+    { 0x00EF, 0x95 },
+    { 0x00F1, 0x96 },
+    { 0x00F2, 0x98 },
+    { 0x00F3, 0x97 },
+    { 0x00F4, 0x99 },
+    { 0x00F5, 0x9B },
+    { 0x00F6, 0x9A },
+    { 0x00F7, 0xD6 },
+    { 0x00F8, 0xBF },
+    { 0x00F9, 0x9D },
+    { 0x00FA, 0x9C },
+    { 0x00FB, 0x9E },
+    { 0x00FC, 0x9F },
+    { 0x00FF, 0xD8 },
+    { 0x0131, 0xF5 },
+    { 0x0152, 0xCE },
+    { 0x0153, 0xCF },
+    { 0x0178, 0xD9 },
+    { 0x0192, 0xC4 },
+    { 0x02C6, 0xF6 },
+    { 0x02C7, 0xFF },
+    { 0x02D8, 0xF9 },
+    { 0x02D9, 0xFA },
+    { 0x02DA, 0xFB },
+    { 0x02DB, 0xFE },
+    { 0x02DC, 0xF7 },
+    { 0x02DD, 0xFD },
+    { 0x03A9, 0xBD },
+    { 0x03C0, 0xB9 },
+    { 0x2013, 0xD0 },
+    { 0x2014, 0xD1 },
+    { 0x2018, 0xD4 },
+    { 0x2019, 0xD5 },
+    { 0x201A, 0xE2 },
+    { 0x201C, 0xD2 },
+    { 0x201D, 0xD3 },
+    { 0x201E, 0xE3 },
+    { 0x2020, 0xA0 },
+    { 0x2021, 0xE0 },
+    { 0x2022, 0xA5 },
+    { 0x2026, 0xC9 },
+    { 0x2030, 0xE4 },
+    { 0x2039, 0xDC },
+    { 0x203A, 0xDD },
+    { 0x2044, 0xDA },
+    { 0x20AC, 0xDB },
+    { 0x2122, 0xAA },
+    { 0x2202, 0xB6 },
+    { 0x2206, 0xC6 },
+    { 0x220F, 0xB8 },
+    { 0x2211, 0xB7 },
+    { 0x221A, 0xC3 },
+    { 0x221E, 0xB0 },
+    { 0x222B, 0xBA },
+    { 0x2248, 0xC5 },
+    { 0x2260, 0xAD },
+    { 0x2264, 0xB2 },
+    { 0x2265, 0xB3 },
+    { 0x25CA, 0xD7 },
+    { 0xF8FF, 0xF0 },
+    { 0xFB01, 0xDE },
+    { 0xFB02, 0xDF },
   };
-  uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
-			    _hb_cmp_operator<uint16_t, uint16_t>);
-  return c ? (c - mapping) + 0x7F : 0;
+  auto *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
+			_hb_cmp_operator<uint16_t, uint16_t>);
+  return c ? c->macroman : 0;
 }
 
 struct CmapSubtableFormat0
@@ -1379,12 +1497,12 @@ struct CmapSubtable
 		  hb_codepoint_t *glyph) const
   {
     switch (u.format) {
-    case  0: return u.format0 .get_glyph (codepoint, glyph);
-    case  4: return u.format4 .get_glyph (codepoint, glyph);
-    case  6: return u.format6 .get_glyph (codepoint, glyph);
-    case 10: return u.format10.get_glyph (codepoint, glyph);
-    case 12: return u.format12.get_glyph (codepoint, glyph);
-    case 13: return u.format13.get_glyph (codepoint, glyph);
+    case  0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph);
+    case  4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph);
+    case  6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph);
+    case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph);
+    case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph);
+    case 13: hb_barrier (); return u.format13.get_glyph (codepoint, glyph);
     case 14:
     default: return false;
     }
@@ -1392,12 +1510,12 @@ struct CmapSubtable
   void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
   {
     switch (u.format) {
-    case  0: u.format0 .collect_unicodes (out); return;
-    case  4: u.format4 .collect_unicodes (out); return;
-    case  6: u.format6 .collect_unicodes (out); return;
-    case 10: u.format10.collect_unicodes (out); return;
-    case 12: u.format12.collect_unicodes (out, num_glyphs); return;
-    case 13: u.format13.collect_unicodes (out, num_glyphs); return;
+    case  0: hb_barrier (); u.format0 .collect_unicodes (out); return;
+    case  4: hb_barrier (); u.format4 .collect_unicodes (out); return;
+    case  6: hb_barrier (); u.format6 .collect_unicodes (out); return;
+    case 10: hb_barrier (); u.format10.collect_unicodes (out); return;
+    case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return;
+    case 13: hb_barrier (); u.format13.collect_unicodes (out, num_glyphs); return;
     case 14:
     default: return;
     }
@@ -1408,12 +1526,12 @@ struct CmapSubtable
 			unsigned num_glyphs = UINT_MAX) const
   {
     switch (u.format) {
-    case  0: u.format0 .collect_mapping (unicodes, mapping); return;
-    case  4: u.format4 .collect_mapping (unicodes, mapping); return;
-    case  6: u.format6 .collect_mapping (unicodes, mapping); return;
-    case 10: u.format10.collect_mapping (unicodes, mapping); return;
-    case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
-    case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case  0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return;
+    case  4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return;
+    case  6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return;
+    case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return;
+    case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case 13: hb_barrier (); u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
     case 14:
     default: return;
     }
@@ -1422,12 +1540,12 @@ struct CmapSubtable
   unsigned get_language () const
   {
     switch (u.format) {
-    case  0: return u.format0 .get_language ();
-    case  4: return u.format4 .get_language ();
-    case  6: return u.format6 .get_language ();
-    case 10: return u.format10.get_language ();
-    case 12: return u.format12.get_language ();
-    case 13: return u.format13.get_language ();
+    case  0: hb_barrier (); return u.format0 .get_language ();
+    case  4: hb_barrier (); return u.format4 .get_language ();
+    case  6: hb_barrier (); return u.format6 .get_language ();
+    case 10: hb_barrier (); return u.format10.get_language ();
+    case 12: hb_barrier (); return u.format12.get_language ();
+    case 13: hb_barrier (); return u.format13.get_language ();
     case 14:
     default: return 0;
     }
@@ -1442,9 +1560,9 @@ struct CmapSubtable
 		  const void *base)
   {
     switch (format) {
-    case  4: return u.format4.serialize (c, it);
-    case 12: return u.format12.serialize (c, it);
-    case 14: return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
+    case  4: hb_barrier (); return u.format4.serialize (c, it);
+    case 12: hb_barrier (); return u.format12.serialize (c, it);
+    case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
     default: return;
     }
   }
@@ -1455,13 +1573,13 @@ struct CmapSubtable
     if (!u.format.sanitize (c)) return_trace (false);
     hb_barrier ();
     switch (u.format) {
-    case  0: return_trace (u.format0 .sanitize (c));
-    case  4: return_trace (u.format4 .sanitize (c));
-    case  6: return_trace (u.format6 .sanitize (c));
-    case 10: return_trace (u.format10.sanitize (c));
-    case 12: return_trace (u.format12.sanitize (c));
-    case 13: return_trace (u.format13.sanitize (c));
-    case 14: return_trace (u.format14.sanitize (c));
+    case  0: hb_barrier (); return_trace (u.format0 .sanitize (c));
+    case  4: hb_barrier (); return_trace (u.format4 .sanitize (c));
+    case  6: hb_barrier (); return_trace (u.format6 .sanitize (c));
+    case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
+    case 12: hb_barrier (); return_trace (u.format12.sanitize (c));
+    case 13: hb_barrier (); return_trace (u.format13.sanitize (c));
+    case 14: hb_barrier (); return_trace (u.format14.sanitize (c));
     default:return_trace (true);
     }
   }

+ 3 - 0
thirdparty/harfbuzz/src/hb-ot-face-table-list.hh

@@ -96,6 +96,9 @@ HB_OT_CORE_TABLE (OT, avar)
 HB_OT_CORE_TABLE (OT, cvar)
 HB_OT_ACCELERATOR (OT, gvar)
 HB_OT_CORE_TABLE (OT, MVAR)
+#ifndef HB_NO_VAR_COMPOSITES
+HB_OT_CORE_TABLE (OT, VARC)
+#endif
 #endif
 
 /* Legacy kern. */

+ 8 - 0
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -43,6 +43,7 @@
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-var-varc-table.hh"
 #include "hb-ot-vorg-table.hh"
 #include "OT/Color/CBDT/CBDT.hh"
 #include "OT/Color/COLR/COLR.hh"
@@ -523,6 +524,10 @@ hb_ot_draw_glyph (hb_font_t *font,
   { // Need draw_session to be destructed before emboldening.
     hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs,
 				    embolden ? &outline : draw_data, font->slant_xy);
+#ifndef HB_NO_VAR_COMPOSITES
+    if (!font->face->table.VARC->get_path (font, glyph, draw_session))
+#endif
+    // Keep the following in synch with VARC::get_path_at()
     if (!font->face->table.glyf->get_path (font, glyph, draw_session))
 #ifndef HB_NO_CFF
     if (!font->face->table.cff2->get_path (font, glyph, draw_session))
@@ -562,6 +567,9 @@ hb_ot_paint_glyph (hb_font_t *font,
   if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
   if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
 #endif
+#endif
+#ifndef HB_NO_VAR_COMPOSITES
+  if (font->face->table.VARC->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
 #endif
   if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
 #ifndef HB_NO_CFF

+ 1 - 0
thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh

@@ -30,6 +30,7 @@
 #include "hb-open-type.hh"
 #include "hb-ot-maxp-table.hh"
 #include "hb-ot-hhea-table.hh"
+#include "hb-ot-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
 #include "hb-ot-var-mvar-table.hh"
 #include "hb-ot-metrics.hh"

+ 9 - 9
thirdparty/harfbuzz/src/hb-ot-kern-table.hh

@@ -132,7 +132,7 @@ struct KernSubTable
   {
     switch (get_type ()) {
     /* This method hooks up to hb_font_t's get_h_kerning.  Only support Format0. */
-    case 0: return u.format0.get_kerning (left, right);
+    case 0: hb_barrier (); return u.format0.get_kerning (left, right);
     default:return 0;
     }
   }
@@ -311,9 +311,9 @@ struct kern
   bool has_state_machine () const
   {
     switch (get_type ()) {
-    case 0: return u.ot.has_state_machine ();
+    case 0: hb_barrier (); return u.ot.has_state_machine ();
 #ifndef HB_NO_AAT_SHAPE
-    case 1: return u.aat.has_state_machine ();
+    case 1: hb_barrier (); return u.aat.has_state_machine ();
 #endif
     default:return false;
     }
@@ -322,9 +322,9 @@ struct kern
   bool has_cross_stream () const
   {
     switch (get_type ()) {
-    case 0: return u.ot.has_cross_stream ();
+    case 0: hb_barrier (); return u.ot.has_cross_stream ();
 #ifndef HB_NO_AAT_SHAPE
-    case 1: return u.aat.has_cross_stream ();
+    case 1: hb_barrier (); return u.aat.has_cross_stream ();
 #endif
     default:return false;
     }
@@ -333,9 +333,9 @@ struct kern
   int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
   {
     switch (get_type ()) {
-    case 0: return u.ot.get_h_kerning (left, right);
+    case 0: hb_barrier (); return u.ot.get_h_kerning (left, right);
 #ifndef HB_NO_AAT_SHAPE
-    case 1: return u.aat.get_h_kerning (left, right);
+    case 1: hb_barrier (); return u.aat.get_h_kerning (left, right);
 #endif
     default:return 0;
     }
@@ -370,9 +370,9 @@ struct kern
   AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
   {
     switch (get_type ()) {
-    case 0: return u.ot.create_accelerator_data (num_glyphs);
+    case 0: hb_barrier (); return u.ot.create_accelerator_data (num_glyphs);
 #ifndef HB_NO_AAT_SHAPE
-    case 1: return u.aat.create_accelerator_data (num_glyphs);
+    case 1: hb_barrier (); return u.aat.create_accelerator_data (num_glyphs);
 #endif
     default:return AAT::kern_accelerator_data_t ();
     }

+ 10 - 10
thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh

@@ -172,9 +172,9 @@ struct BaseCoord
 			   hb_direction_t        direction) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coord (font, direction);
-    case 2: return u.format2.get_coord (font, direction);
-    case 3: return u.format3.get_coord (font, var_store, direction);
+    case 1: hb_barrier (); return u.format1.get_coord (font, direction);
+    case 2: hb_barrier (); return u.format2.get_coord (font, direction);
+    case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction);
     default:return 0;
     }
   }
@@ -182,7 +182,7 @@ struct BaseCoord
   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
   {
     switch (u.format) {
-    case 3: u.format3.collect_variation_indices (varidx_set);
+    case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set);
     default:return;
     }
   }
@@ -193,9 +193,9 @@ struct BaseCoord
     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -206,9 +206,9 @@ struct BaseCoord
     if (unlikely (!u.format.sanitize (c))) return_trace (false);
     hb_barrier ();
     switch (u.format) {
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 3: return_trace (u.format3.sanitize (c));
+    case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
+    case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
+    case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
     default:return_trace (false);
     }
   }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 750 - 62
thirdparty/harfbuzz/src/hb-ot-layout-common.hh


+ 51 - 36
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh

@@ -406,6 +406,7 @@ struct hb_ot_apply_context_t :
 
     void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
+    void set_ignore_hidden (bool ignore_hidden_) { ignore_hidden = ignore_hidden_; }
     void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     void set_mask (hb_mask_t mask_) { mask = mask_; }
     void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
@@ -451,9 +452,10 @@ struct hb_ot_apply_context_t :
       if (!c->check_glyph_property (&info, lookup_props))
 	return SKIP_YES;
 
-      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
+      if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
-		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
+		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
+		    (ignore_hidden || !_hb_glyph_info_is_hidden (&info))))
 	return SKIP_MAYBE;
 
       return SKIP_NO;
@@ -464,6 +466,7 @@ struct hb_ot_apply_context_t :
     hb_mask_t mask = -1;
     bool ignore_zwnj = false;
     bool ignore_zwj = false;
+    bool ignore_hidden = false;
     bool per_syllable = false;
     uint8_t syllable = 0;
     match_func_t match_func = nullptr;
@@ -486,6 +489,8 @@ struct hb_ot_apply_context_t :
       matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
       /* Ignore ZWJ if we are matching context, or asked to. */
       matcher.set_ignore_zwj  (context_match || c->auto_zwj);
+      /* Ignore hidden glyphs (like CGJ) during GPOS. */
+      matcher.set_ignore_hidden (c->table_index == 1);
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
       /* Per syllable matching is only for GSUB. */
       matcher.set_per_syllable (c->table_index == 0 && c->per_syllable);
@@ -2901,12 +2906,12 @@ struct Context
     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
-    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
-    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
 #endif
     default:return_trace (c->default_return_value ());
     }
@@ -3390,6 +3395,15 @@ struct ChainRuleSet
      *
      * Replicated from LigatureSet::apply(). */
 
+    /* If the input skippy has non-auto joiners behavior (as in Indic shapers),
+     * skip this fast path, as we don't distinguish between input & lookahead
+     * matching in the fast path.
+     *
+     * https://github.com/harfbuzz/harfbuzz/issues/4813
+     */
+    if (!c->auto_zwnj || !c->auto_zwj)
+      goto slow;
+
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
@@ -3429,10 +3443,10 @@ struct ChainRuleSet
     }
     matched = skippy_iter.next ();
     if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
-     {
+    {
       second = &c->buffer->info[skippy_iter.idx];
       unsafe_to2 = skippy_iter.idx + 1;
-     }
+    }
 
     auto match_input = lookup_context.funcs.match[1];
     auto match_lookahead = lookup_context.funcs.match[2];
@@ -4225,12 +4239,12 @@ struct ChainContext
     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
-    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
-    case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
+    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
 #endif
     default:return_trace (c->default_return_value ());
     }
@@ -4314,7 +4328,7 @@ struct Extension
   unsigned int get_type () const
   {
     switch (u.format) {
-    case 1: return u.format1.get_type ();
+    case 1: hb_barrier (); return u.format1.get_type ();
     default:return 0;
     }
   }
@@ -4322,7 +4336,7 @@ struct Extension
   const X& get_subtable () const
   {
     switch (u.format) {
-    case 1: return u.format1.template get_subtable<typename T::SubTable> ();
+    case 1: hb_barrier (); return u.format1.template get_subtable<typename T::SubTable> ();
     default:return Null (typename T::SubTable);
     }
   }
@@ -4334,7 +4348,7 @@ struct Extension
   typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
   {
     switch (u.format) {
-    case 1: return u.format1.subset (c);
+    case 1: hb_barrier (); return u.format1.subset (c);
     default: return c->default_return_value ();
     }
   }
@@ -4345,7 +4359,7 @@ struct Extension
     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     switch (u.format) {
-    case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
+    case 1: hb_barrier (); return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -4560,9 +4574,9 @@ struct GSUBGPOS
   unsigned int get_size () const
   {
     switch (u.version.major) {
-    case 1: return u.version1.get_size ();
+    case 1: hb_barrier (); return u.version1.get_size ();
 #ifndef HB_NO_BEYOND_64K
-    case 2: return u.version2.get_size ();
+    case 2: hb_barrier (); return u.version2.get_size ();
 #endif
     default: return u.version.static_size;
     }
@@ -4575,9 +4589,9 @@ struct GSUBGPOS
     if (unlikely (!u.version.sanitize (c))) return_trace (false);
     hb_barrier ();
     switch (u.version.major) {
-    case 1: return_trace (u.version1.sanitize<TLookup> (c));
+    case 1: hb_barrier (); return_trace (u.version1.sanitize<TLookup> (c));
 #ifndef HB_NO_BEYOND_64K
-    case 2: return_trace (u.version2.sanitize<TLookup> (c));
+    case 2: hb_barrier (); return_trace (u.version2.sanitize<TLookup> (c));
 #endif
     default: return_trace (true);
     }
@@ -4587,9 +4601,9 @@ struct GSUBGPOS
   bool subset (hb_subset_layout_context_t *c) const
   {
     switch (u.version.major) {
-    case 1: return u.version1.subset<TLookup> (c);
+    case 1: hb_barrier (); return u.version1.subset<TLookup> (c);
 #ifndef HB_NO_BEYOND_64K
-    case 2: return u.version2.subset<TLookup> (c);
+    case 2: hb_barrier (); return u.version2.subset<TLookup> (c);
 #endif
     default: return false;
     }
@@ -4598,9 +4612,9 @@ struct GSUBGPOS
   const ScriptList &get_script_list () const
   {
     switch (u.version.major) {
-    case 1: return this+u.version1.scriptList;
+    case 1: hb_barrier (); return this+u.version1.scriptList;
 #ifndef HB_NO_BEYOND_64K
-    case 2: return this+u.version2.scriptList;
+    case 2: hb_barrier (); return this+u.version2.scriptList;
 #endif
     default: return Null (ScriptList);
     }
@@ -4608,9 +4622,9 @@ struct GSUBGPOS
   const FeatureList &get_feature_list () const
   {
     switch (u.version.major) {
-    case 1: return this+u.version1.featureList;
+    case 1: hb_barrier (); return this+u.version1.featureList;
 #ifndef HB_NO_BEYOND_64K
-    case 2: return this+u.version2.featureList;
+    case 2: hb_barrier (); return this+u.version2.featureList;
 #endif
     default: return Null (FeatureList);
     }
@@ -4618,9 +4632,9 @@ struct GSUBGPOS
   unsigned int get_lookup_count () const
   {
     switch (u.version.major) {
-    case 1: return (this+u.version1.lookupList).len;
+    case 1: hb_barrier (); return (this+u.version1.lookupList).len;
 #ifndef HB_NO_BEYOND_64K
-    case 2: return (this+u.version2.lookupList).len;
+    case 2: hb_barrier (); return (this+u.version2.lookupList).len;
 #endif
     default: return 0;
     }
@@ -4628,9 +4642,9 @@ struct GSUBGPOS
   const Lookup& get_lookup (unsigned int i) const
   {
     switch (u.version.major) {
-    case 1: return (this+u.version1.lookupList)[i];
+    case 1: hb_barrier (); return (this+u.version1.lookupList)[i];
 #ifndef HB_NO_BEYOND_64K
-    case 2: return (this+u.version2.lookupList)[i];
+    case 2: hb_barrier (); return (this+u.version2.lookupList)[i];
 #endif
     default: return Null (Lookup);
     }
@@ -4638,9 +4652,9 @@ struct GSUBGPOS
   const FeatureVariations &get_feature_variations () const
   {
     switch (u.version.major) {
-    case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
+    case 1: hb_barrier (); return (u.version.to_int () >= 0x00010001u && hb_barrier () ? this+u.version1.featureVars : Null (FeatureVariations));
 #ifndef HB_NO_BEYOND_64K
-    case 2: return this+u.version2.featureVars;
+    case 2: hb_barrier (); return this+u.version2.featureVars;
 #endif
     default: return Null (FeatureVariations);
     }
@@ -4674,13 +4688,14 @@ struct GSUBGPOS
   { return get_feature_list ().find_index (tag, index); }
 
   bool find_variations_index (const int *coords, unsigned int num_coords,
-			      unsigned int *index) const
+			      unsigned int *index,
+			      ItemVarStoreInstancer *instancer) const
   {
 #ifdef HB_NO_VAR
     *index = FeatureVariations::NOT_FOUND_INDEX;
     return false;
 #endif
-    return get_feature_variations ().find_index (coords, num_coords, index);
+    return get_feature_variations ().find_index (coords, num_coords, index, instancer);
   }
   const Feature& get_feature_variation (unsigned int feature_index,
 					unsigned int variations_index) const

+ 5 - 1
thirdparty/harfbuzz/src/hb-ot-layout.cc

@@ -1443,8 +1443,12 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
 					    unsigned int *variations_index /* out */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::GDEF &gdef = *face->table.GDEF->table;
 
-  return g.find_variations_index (coords, num_coords, variations_index);
+  auto instancer = OT::ItemVarStoreInstancer(&gdef.get_var_store(), nullptr,
+					     hb_array (coords, num_coords));
+
+  return g.find_variations_index (coords, num_coords, variations_index, &instancer);
 }
 
 

+ 9 - 6
thirdparty/harfbuzz/src/hb-ot-layout.hh

@@ -173,12 +173,12 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
 
 /* Design:
  * unicode_props() is a two-byte number.  The low byte includes:
- * - General_Category: 5 bits.
+ * - Extended General_Category: 5 bits.
  * - A bit each for:
  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
  *   * Whether it's one of the four Mongolian Free Variation Selectors,
  *     CGJ, or other characters that are hidden but should not be ignored
- *     like most other Default_Ignorable()s do during matching.
+ *     like most other Default_Ignorable()s do during GSUB matching.
  *   * Whether it's a grapheme continuation.
  *
  * The high-byte has different meanings, switched by the Gen-Cat:
@@ -311,12 +311,15 @@ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
   return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
 	 !_hb_glyph_info_substituted (info);
 }
+static inline void
+_hb_glyph_info_clear_default_ignorable (hb_glyph_info_t *info)
+{
+  info->unicode_props() &= ~ UPROPS_MASK_IGNORABLE;
+}
 static inline bool
-_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
+_hb_glyph_info_is_hidden (const hb_glyph_info_t *info)
 {
-  return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
-	  == UPROPS_MASK_IGNORABLE) &&
-	 !_hb_glyph_info_substituted (info);
+  return info->unicode_props() & UPROPS_MASK_HIDDEN;
 }
 static inline void
 _hb_glyph_info_unhide (hb_glyph_info_t *info)

+ 15 - 6
thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh

@@ -84,9 +84,9 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
   old_gid_new_index_map.alloc (num_glyphs);
   glyph_name_to_new_index.alloc (num_glyphs);
 
-  for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
+  for (auto _ : c->plan->new_to_old_gid_list)
   {
-    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+    hb_codepoint_t old_gid = _.second;
     unsigned old_index = glyphNameIndex[old_gid];
 
     unsigned new_index;
@@ -125,13 +125,22 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
     old_gid_new_index_map.set (old_gid, new_index);
   }
 
+  if (old_gid_new_index_map.in_error())
+    return_trace (false);
+
   auto index_iter =
   + hb_range (num_glyphs)
-  | hb_map (reverse_glyph_map)
-  | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
+  | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
                             {
-                              unsigned new_index = old_gid_new_index_map.get (old_gid);
-                              return hb_pair_t<unsigned, unsigned> (old_gid, new_index);
+                              hb_codepoint_t *old_gid;
+                              /* use 0 for retain-gid holes, which refers to the name .notdef,
+                               * as the glyphNameIndex entry for that glyph ID."*/
+                              unsigned new_index = 0;
+                              if (reverse_glyph_map.has (new_gid, &old_gid)) {
+                                new_index = old_gid_new_index_map.get (*old_gid);
+                                return hb_pair_t<unsigned, unsigned> (*old_gid, new_index);
+                              }
+                              return hb_pair_t<unsigned, unsigned> (new_gid, new_index);
                             })
   ;
 

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-post-table.hh

@@ -301,7 +301,7 @@ struct post
     return_trace (c->check_struct (this) &&
 		  hb_barrier () &&
 		  (version.to_int () == 0x00010000 ||
-		   (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
+		   (version.to_int () == 0x00020000 && hb_barrier () && v2X.sanitize (c)) ||
 		   version.to_int () == 0x00030000));
   }
 

+ 13 - 23
thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc

@@ -74,23 +74,6 @@
  *     Indic shaper may want to disallow recomposing of two matras.
  */
 
-static bool
-decompose_unicode (const hb_ot_shape_normalize_context_t *c,
-		   hb_codepoint_t  ab,
-		   hb_codepoint_t *a,
-		   hb_codepoint_t *b)
-{
-  return (bool) c->unicode->decompose (ab, a, b);
-}
-
-static bool
-compose_unicode (const hb_ot_shape_normalize_context_t *c,
-		 hb_codepoint_t  a,
-		 hb_codepoint_t  b,
-		 hb_codepoint_t *ab)
-{
-  return (bool) c->unicode->compose (a, b, ab);
-}
 
 static inline void
 set_glyph (hb_glyph_info_t &info, hb_font_t *font)
@@ -170,7 +153,7 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
   hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph = 0;
 
-  if (shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
+  if (shortest && c->font->get_nominal_glyph (u, &glyph, buffer->not_found))
   {
     next_char (buffer, glyph);
     return;
@@ -182,7 +165,7 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
     return;
   }
 
-  if (!shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
+  if (!shortest && c->font->get_nominal_glyph (u, &glyph, buffer->not_found))
   {
     next_char (buffer, glyph);
     return;
@@ -237,6 +220,13 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
 	/* Just pass on the two characters separately, let GSUB do its magic. */
 	set_glyph (buffer->cur(), font);
 	(void) buffer->next_glyph ();
+
+        buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK;
+	_hb_glyph_info_set_general_category (&buffer->cur(),
+					     _HB_UNICODE_GENERAL_CATEGORY_VARIATION_SELECTOR);
+	if (buffer->not_found_variation_selector != HB_CODEPOINT_INVALID)
+	  _hb_glyph_info_clear_default_ignorable (&buffer->cur());
+
 	set_glyph (buffer->cur(), font);
 	(void) buffer->next_glyph ();
       }
@@ -307,15 +297,15 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
       mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
   }
 
-  const hb_ot_shape_normalize_context_t c = {
+  hb_ot_shape_normalize_context_t c = {
     plan,
     buffer,
     font,
     buffer->unicode,
-    buffer->not_found,
-    plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
-    plan->shaper->compose   ? plan->shaper->compose   : compose_unicode
+    plan->shaper->decompose ? plan->shaper->decompose : hb_ot_shape_normalize_context_t::decompose_unicode,
+    plan->shaper->compose   ? plan->shaper->compose   : hb_ot_shape_normalize_context_t::compose_unicode
   };
+  c.override_decompose_and_compose (plan->shaper->decompose, plan->shaper->compose);
 
   bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
   bool might_short_circuit = always_short_circuit ||

+ 33 - 1
thirdparty/harfbuzz/src/hb-ot-shape-normalize.hh

@@ -28,6 +28,7 @@
 #define HB_OT_SHAPE_NORMALIZE_HH
 
 #include "hb.hh"
+#include "hb-unicode.hh"
 
 
 /* buffer var allocations, used during the normalization process */
@@ -52,11 +53,42 @@ HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
 
 struct hb_ot_shape_normalize_context_t
 {
+  static bool
+  decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+		     hb_codepoint_t  ab,
+		     hb_codepoint_t *a,
+		     hb_codepoint_t *b)
+  {
+    return (bool) c->unicode->decompose (ab, a, b);
+  }
+
+  static bool
+  compose_unicode (const hb_ot_shape_normalize_context_t *c,
+		   hb_codepoint_t  a,
+		   hb_codepoint_t  b,
+		   hb_codepoint_t *ab)
+  {
+    return (bool) c->unicode->compose (a, b, ab);
+  }
+
+  void
+  override_decompose_and_compose (bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+						      hb_codepoint_t  ab,
+						      hb_codepoint_t *a,
+						      hb_codepoint_t *b),
+				  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+						   hb_codepoint_t  a,
+						   hb_codepoint_t  b,
+						   hb_codepoint_t *ab))
+  {
+    this->decompose = decompose ? decompose : decompose_unicode;
+    this->compose = compose ? compose : compose_unicode;
+  }
+
   const hb_ot_shape_plan_t *plan;
   hb_buffer_t *buffer;
   hb_font_t *font;
   hb_unicode_funcs_t *unicode;
-  const hb_codepoint_t not_found;
   bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
 		     hb_codepoint_t  ab,
 		     hb_codepoint_t *a,

+ 25 - 1
thirdparty/harfbuzz/src/hb-ot-shape.cc

@@ -85,7 +85,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *fac
 						, apply_morx (_hb_apply_morx (face, props))
 #endif
 {
-  shaper = hb_ot_shaper_categorize (this);
+  shaper = hb_ot_shaper_categorize (props.script, props.direction, map.chosen_script[0]);
 
   script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
   script_fallback_mark_positioning = shaper->fallback_position;
@@ -837,6 +837,29 @@ hb_ot_zero_width_default_ignorables (const hb_buffer_t *buffer)
       pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
 }
 
+static void
+hb_ot_deal_with_variation_selectors (hb_buffer_t *buffer)
+{
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK) ||
+	buffer->not_found_variation_selector == HB_CODEPOINT_INVALID)
+    return;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (_hb_glyph_info_get_general_category (&info[i]) ==
+	_HB_UNICODE_GENERAL_CATEGORY_VARIATION_SELECTOR)
+    {
+      info[i].codepoint = buffer->not_found_variation_selector;
+      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
+      _hb_glyph_info_set_general_category (&info[i], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
+    }
+  }
+}
+
 static void
 hb_ot_hide_default_ignorables (hb_buffer_t *buffer,
 			       hb_font_t   *font)
@@ -966,6 +989,7 @@ hb_ot_substitute_post (const hb_ot_shape_context_t *c)
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
 #endif
 
+  hb_ot_deal_with_variation_selectors (c->buffer);
   hb_ot_hide_default_ignorables (c->buffer, c->font);
 
   if (c->plan->shaper->postprocess_glyphs &&

+ 4 - 4
thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh

@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-15.1.0.txt
- * # Date: 2023-01-05
- * # Scripts-15.1.0.txt
- * # Date: 2023-07-28, 16:01:07 GMT
+ * # ArabicShaping-16.0.0.txt
+ * # Date: 2024-07-30
+ * # Scripts-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:40 GMT
  */
 
 #ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH

+ 15 - 8
thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh

@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-15.1.0.txt
- * # Date: 2023-01-05
- * # Blocks-15.1.0.txt
- * # Date: 2023-07-28, 15:47:20 GMT
+ * # ArabicShaping-16.0.0.txt
+ * # Date: 2024-07-30
+ * # Blocks-16.0.0.txt
+ * # Date: 2024-02-02
  * UnicodeData.txt does not have a header.
  */
 
@@ -136,7 +136,13 @@ static const uint8_t joining_table[] =
   /* 10D00 */ L,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 10D20 */ D,D,R,D,
 
-#define joining_offset_0x10f30u 1182
+#define joining_offset_0x10ec2u 1182
+
+  /* Arabic Extended-C */
+
+  /* 10EC0 */     R,D,D,
+
+#define joining_offset_0x10f30u 1185
 
   /* Sogdian */
 
@@ -155,14 +161,14 @@ static const uint8_t joining_table[] =
   /* 10FA0 */                                 D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
   /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
 
-#define joining_offset_0x110bdu 1338
+#define joining_offset_0x110bdu 1341
 
   /* Kaithi */
 
   /* 110A0 */                                                           U,X,X,
   /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
 
-#define joining_offset_0x1e900u 1355
+#define joining_offset_0x1e900u 1358
 
   /* Adlam */
 
@@ -170,7 +176,7 @@ static const uint8_t joining_table[] =
   /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1431; occupancy: 57% */
+}; /* Table items: 1434; occupancy: 57% */
 
 
 static unsigned int
@@ -198,6 +204,7 @@ joining_type (hb_codepoint_t u)
       if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10EC2u, 0x10EC4u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
       break;
 

+ 0 - 3
thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc

@@ -233,10 +233,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
    map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
    /* https://github.com/harfbuzz/harfbuzz/issues/1573 */
    if (!map->has_feature (HB_TAG('r','c','l','t')))
-   {
      map->add_gsub_pause (nullptr);
-     map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
-   }
 
    map->enable_feature (HB_TAG('l','i','g','a'), F_MANUAL_ZWJ);
    map->enable_feature (HB_TAG('c','l','i','g'), F_MANUAL_ZWJ);

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc

@@ -78,7 +78,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
   return found;
 #endif
 
-  if (!found && !c->plan->has_gpos_mark)
+  if (!found && (c->plan && !c->plan->has_gpos_mark))
   {
       /* Special-case Hebrew presentation forms that are excluded from
        * standard normalization, but wanted for old fonts. */

+ 19 - 9
thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc

@@ -6,12 +6,12 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-15.1.0.txt
- * # Date: 2023-01-05
- * # IndicPositionalCategory-15.1.0.txt
- * # Date: 2023-01-05
- * # Blocks-15.1.0.txt
- * # Date: 2023-07-28, 15:47:20 GMT
+ * # IndicSyllabicCategory-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:21 GMT
+ * # IndicPositionalCategory-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:21 GMT
+ * # Blocks-16.0.0.txt
+ * # Date: 2024-02-02
  */
 
 #include "hb.hh"
@@ -89,7 +89,7 @@ static_assert (OT_VPst == M_Cat(VPst), "");
 #define _OT_MW   OT_MW           /*   2 chars; MW */
 #define _OT_MY   OT_MY           /*   3 chars; MY */
 #define _OT_N    OT_N            /*  17 chars; N */
-#define _OT_GB   OT_PLACEHOLDER  /* 165 chars; PLACEHOLDER */
+#define _OT_GB   OT_PLACEHOLDER  /* 185 chars; PLACEHOLDER */
 #define _OT_PT   OT_PT           /*   8 chars; PT */
 #define _OT_R    OT_Ra           /*  14 chars; Ra */
 #define _OT_Rf   OT_Repha        /*   1 chars; Repha */
@@ -112,7 +112,7 @@ static_assert (OT_VPst == M_Cat(VPst), "");
 #define _POS_A   POS_AFTER_MAIN  /*   3 chars; AFTER_MAIN */
 #define _POS_AP  POS_AFTER_POST  /*  50 chars; AFTER_POST */
 #define _POS_AS  POS_AFTER_SUB   /*  51 chars; AFTER_SUB */
-#define _POS_C   POS_BASE_C      /* 833 chars; BASE_C */
+#define _POS_C   POS_BASE_C      /* 853 chars; BASE_C */
 #define _POS_BS  POS_BEFORE_SUB  /*  25 chars; BEFORE_SUB */
 #define _POS_B   POS_BELOW_C     /*  13 chars; BELOW_C */
 #define _POS_X   POS_END         /*  71 chars; END */
@@ -458,7 +458,16 @@ static const uint16_t indic_table[] = {
 
   /* 11338 */  _(X,X),  _(X,X),  _(X,X),  _(N,X),  _(N,X),  _(X,X),  _(X,X),  _(X,X),
 
-}; /* Table items: 1728; occupancy: 71% */
+#define indic_offset_0x116d0u 1728
+
+
+  /* Myanmar Extended-C */
+
+  /* 116D0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 116D8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C),
+  /* 116E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C),  _(X,X),  _(X,X),  _(X,X),  _(X,X),
+
+}; /* Table items: 1752; occupancy: 71% */
 
 uint16_t
 hb_indic_get_categories (hb_codepoint_t u)
@@ -498,6 +507,7 @@ hb_indic_get_categories (hb_codepoint_t u)
     case 0x11u:
       if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x11307u)) return indic_table[u - 0x11300u + indic_offset_0x11300u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11338u, 0x1133Fu)) return indic_table[u - 0x11338u + indic_offset_0x11338u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x116D0u, 0x116E7u)) return indic_table[u - 0x116D0u + indic_offset_0x116d0u];
       break;
 
     default:

+ 285 - 258
thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh

@@ -6,18 +6,18 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-15.1.0.txt
- * # Date: 2023-01-05
- * # IndicPositionalCategory-15.1.0.txt
- * # Date: 2023-01-05
- * # ArabicShaping-15.1.0.txt
- * # Date: 2023-01-05
- * # DerivedCoreProperties-15.1.0.txt
- * # Date: 2023-08-07, 15:21:24 GMT
- * # Blocks-15.1.0.txt
- * # Date: 2023-07-28, 15:47:20 GMT
- * # Scripts-15.1.0.txt
- * # Date: 2023-07-28, 16:01:07 GMT
+ * # IndicSyllabicCategory-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:21 GMT
+ * # IndicPositionalCategory-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:21 GMT
+ * # ArabicShaping-16.0.0.txt
+ * # Date: 2024-07-30
+ * # DerivedCoreProperties-16.0.0.txt
+ * # Date: 2024-05-31, 18:09:32 GMT
+ * # Blocks-16.0.0.txt
+ * # Date: 2024-02-02
+ * # Scripts-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:40 GMT
  * # Override values For Indic_Syllabic_Category
  * # Not derivable
  * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -27,6 +27,7 @@
  * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
  * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
  * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
+ * # Updated for Unicode 16.0 by Andrew Glass 2024-09-11
  * # Override values For Indic_Positional_Category
  * # Not derivable
  * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -38,6 +39,7 @@
  * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
  * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
  * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
+ * # Updated for Unicode 16.0 by Andrew Glass 2024-09-11
  * UnicodeData.txt does not have a header.
  */
 
@@ -99,16 +101,16 @@
 #ifndef HB_OPTIMIZE_SIZE
 
 static const uint8_t
-hb_use_u8[3187] =
+hb_use_u8[3343] =
 {
-     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
+     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   57,   58,   59,  195,  211,   62,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-     14,    0,    1,    2,    2,    2,    2,    3,    2,    2,    2,    2,    2,    4,    2,    2,
+     15,    0,    1,    2,    2,    2,    2,    3,    2,    2,    2,    2,    2,    4,    2,    2,
       5,    6,    2,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,    2,    2,   17,
      18,   19,   20,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   21,
      22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,    2,   33,    2,    2,    2,
@@ -121,24 +123,26 @@ hb_use_u8[3187] =
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   47,   48,    2,
      49,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   50,   51,    2,    2,    2,
-      2,    2,    2,    2,    2,   52,   53,    2,   54,    2,    2,   55,    2,    2,   56,   57,
-     58,   59,   60,   61,   62,   63,   64,   65,    2,   66,   67,    2,   68,   69,   70,   71,
-      2,   72,    2,   73,   74,   75,   76,    2,    2,   77,   78,   79,   80,    2,   81,   82,
-      2,   83,   83,   83,   83,   83,   83,   83,   83,   84,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,   52,   53,    2,   54,    2,    2,   55,   56,    2,   57,   58,
+     59,   60,   61,   62,   63,   64,   65,   66,   67,   68,   69,    2,   70,   71,   72,   73,
+      2,   74,    2,   75,   76,   77,   78,    2,    2,   79,   80,   81,   82,    2,   83,   84,
+      2,   85,   85,   85,   85,   85,   85,   85,   85,   86,   85,   85,   85,   85,   85,   85,
+     85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,   85,
+     85,   85,   85,   85,   85,   85,   85,   85,   87,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,   88,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   89,   90,    2,    2,    2,   91,    2,    2,    2,   92,
+     93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   94,   94,   94,   95,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,   85,   86,    2,    2,    2,    2,    2,    2,    2,   87,
-     88,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,   89,   89,   89,   90,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,   96,   97,    2,    2,    2,    2,    2,
+      2,    2,    2,   98,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,    2,    2,   91,   92,    2,    2,    2,    2,    2,
-      2,    2,    2,   93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,   94,    2,    2,   95,    2,    2,    2,   96,    2,    2,    2,    2,    2,
-      2,    2,    2,   97,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,   98,   98,   99,  100,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,
-     98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,   98,
-     98,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      2,    2,    2,   99,    2,    2,  100,    2,    2,    2,  101,    2,  102,    2,    2,    2,
+      2,    2,    2,  103,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,  104,  104,  105,  106,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,
+    104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,  104,
+    104,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
       0,    2,    2,    2,    2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    3,    4,
       0,    5,    0,    0,    0,    0,    0,    6,    0,    0,    7,    0,    0,    0,    0,    0,
       0,    0,    0,    0,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
@@ -167,7 +171,7 @@ hb_use_u8[3187] =
       0,    0,    0,   27,   31,    2,    9,    0,    0,   10,   29,   30,    2,    2,    2,    9,
       2,    2,    2,   30,    2,    2,    0,   17,   45,    0,    0,   35,   47,    0,    0,    0,
       9,   50,   51,    0,    0,    0,    0,    0,    0,   11,   29,    2,    2,    2,    2,    9,
-      2,    2,    2,    2,    2,    2,   52,   53,   23,   23,   19,   31,   48,   33,   48,   34,
+      2,    2,    2,    2,    2,    2,   52,   53,   23,   19,   20,   31,   48,   33,   48,   34,
      54,    0,    0,    0,   35,    0,    0,    0,   30,   12,   29,   30,    2,    2,    2,    2,
       2,    2,    2,    2,    9,    0,    2,    2,    2,    2,   30,    2,    2,    2,    2,   30,
       0,    2,    2,    2,    9,    0,   55,    0,   35,   23,   22,   31,   31,   18,   48,   48,
@@ -195,88 +199,95 @@ hb_use_u8[3187] =
       0,    2,    2,  100,  101,  102,  103,   61,   63,  104,   16,   45,   22,   59,   21,   80,
      48,   48,   76,   11,   11,   11,  105,   46,   40,   11,  106,   74,    2,    2,    2,    2,
       2,    2,    2,  107,   22,   20,   20,   22,   48,   48,   22,  108,    2,    2,    2,    9,
-      0,    0,    0,    0,    0,    0,  109,  110,  111,  111,  111,    0,    0,    0,    0,    0,
-      0,  106,   74,    2,    2,    2,    2,    2,    2,   60,   61,   59,   25,   22,  112,   61,
+      0,    0,    0,    0,    0,    0,  109,  110,  110,  110,  110,    0,    0,    0,    0,    0,
+      0,  106,   74,    2,    2,    2,    2,    2,    2,   60,   61,   59,   25,   22,  111,   61,
       2,    2,    2,    2,  107,   22,   23,   45,   45,  102,   14,    0,    0,    0,    0,    0,
-      0,    2,    2,   61,   18,   48,   23,  113,  102,  102,  102,  114,  115,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    0,   30,    2,   11,   46,  116,  116,  116,   11,  116,
-    116,   15,  116,  116,  116,   26,    0,   40,    0,    0,    0,  117,   51,   11,    5,    0,
-      0,    0,    0,    0,    0,    0,  118,    0,    0,    0,    0,    0,    0,    0,    6,  119,
-    120,   42,   42,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  120,  120,
-    121,  120,  120,  120,  120,  120,  120,  120,  120,    0,    0,  122,    0,    0,    0,    0,
-      0,    0,    7,  122,    0,    0,    0,    0,    0,   46,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,  123,  123,    0,    0,
+      0,    2,    2,   61,   18,   48,   23,  112,  102,  102,  102,  113,  114,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,   30,    2,   11,   46,  115,  115,  115,   11,  115,
+    115,   15,  115,  115,  115,   26,    0,   40,    0,    0,    0,  116,   51,   11,    5,    0,
+      0,    0,    0,    0,    0,    0,  117,    0,    0,    0,    0,    0,    0,    0,    6,  118,
+    119,   42,   42,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  119,  119,
+    120,  119,  119,  119,  119,  119,  119,  119,  119,    0,    0,  121,    0,    0,    0,    0,
+      0,    0,    7,  121,    0,    0,    0,    0,    0,   46,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,  122,  122,    0,    0,
       0,    2,    2,    2,    2,    0,    0,    0,   30,    0,    0,    0,    0,    0,    0,    0,
-    124,    0,  123,  123,    0,    0,    0,    0,    0,    2,   53,    2,  108,    2,   10,    2,
+    123,    0,  122,  122,    0,    0,    0,    0,    0,    2,   53,    2,  108,    2,   10,    2,
       2,    2,   65,   19,   16,    0,    0,   31,    0,    2,    2,    0,    0,    0,    0,    0,
-      0,   29,    2,    2,    2,    2,    2,    2,    2,    2,    2,  125,   23,   23,   23,   23,
-     23,   23,   23,  126,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11,   11,
-     11,   11,    2,    0,    0,    0,    0,    0,   52,    2,    2,    2,   22,   22,  127,  116,
-      0,    2,    2,    2,  128,   20,   59,   20,  113,  102,  129,    0,    0,    0,    0,    0,
-      0,   11,  130,    2,    2,    2,    2,    2,    2,    2,  131,   23,   22,   20,   48,  132,
-    133,  134,    0,    0,    0,    0,    0,    0,    0,    2,    2,   52,   30,    2,    2,    2,
-      2,    2,    2,    2,    2,   10,   22,   59,   99,   76,  135,  136,  137,    0,    0,    0,
-      0,    2,  138,    2,    2,    2,    2,  139,    0,   30,    2,   42,    5,    0,   79,   15,
-      2,   53,   22,  140,   52,   53,    2,    2,  105,   10,    9,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,  141,   21,   25,    0,    0,  142,  143,    0,    0,    0,
-      0,    2,   65,   45,   23,   80,   47,  144,    0,   81,   81,   81,   81,   81,   81,   81,
-     81,    0,    0,    0,    0,    0,    0,    0,    6,  120,  120,  120,  120,  121,    0,    0,
+      0,   29,    2,    2,    2,    2,    2,    2,    2,    2,    2,  124,   23,   23,   23,   23,
+     23,   23,   23,  125,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11,   11,
+     11,   11,    2,    0,    0,    0,    0,    0,   52,    2,    2,    2,   22,   22,  126,  115,
+      0,    2,    2,    2,  127,   20,   59,   20,  112,  102,  128,    0,    0,    0,    0,    0,
+      0,   11,  129,    2,    2,    2,    2,    2,    2,    2,  130,   23,   22,   20,   48,  131,
+    132,  133,    0,    0,    0,    0,    0,    0,    0,    2,    2,   52,   30,    2,    2,    2,
+      2,    2,    2,    2,    2,   10,   22,   59,   99,   76,  134,  135,  136,    0,    0,    0,
+      0,    2,  137,    2,    2,    2,    2,  138,    0,   30,    2,   42,    5,    0,   79,   15,
+      2,   53,   22,  139,   52,   53,    2,    2,  105,   10,    9,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,  140,   21,   25,    0,    0,  141,  142,    0,    0,    0,
+      0,    2,   65,   45,   23,   80,   47,  143,    0,   81,   81,   81,   81,   81,   81,   81,
+     81,    0,    0,    0,    0,    0,    0,    0,    6,  119,  119,  119,  119,  120,    0,    0,
       0,    2,    2,    2,    2,    2,    9,    2,    2,    2,    9,    2,   30,    2,    2,    2,
-      2,    2,   30,    2,    2,    2,   30,    9,    0,  128,   20,   27,   31,    0,    0,  145,
-    146,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,    2,    0,   14,   37,    0,
-    147,    2,    2,   13,   37,    0,   30,    2,    2,    2,    0,    0,    0,    0,    0,    0,
+      2,    2,   30,    2,    2,    2,   30,    9,    0,  127,   20,   27,   31,    0,    0,  144,
+    145,    2,    2,   30,    2,   30,    2,    2,    2,    2,    2,    2,    0,   14,   37,    0,
+    146,    2,    2,   13,   37,    0,   30,    2,    2,    2,    0,    0,    0,    0,    0,    0,
       0,    0,    0,    0,    0,   30,    2,    2,    9,    2,    2,   11,   41,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,   27,   38,    0,    2,    2,    2,  116,  116,  116,  116,
-    116,  148,    2,    9,    0,    0,    0,    0,    0,    2,   14,   14,    0,    0,    0,    0,
+      0,    2,    2,    2,    0,   27,   22,   22,   30,    2,    2,    2,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   27,   38,    0,    2,    2,    2,  115,  115,  115,  115,
+    115,  147,    2,    9,    0,    0,    0,    0,    0,    2,   14,   14,    0,    0,    0,    0,
       0,    9,    2,    2,    9,    2,    2,    2,    2,   30,    2,    9,    0,   30,    2,    0,
-      0,  149,  150,  151,    2,    2,    2,    2,    2,    2,    2,    2,    2,   22,   22,   20,
-     20,   20,   22,   22,  134,    0,    0,    0,    0,    0,  152,  152,  152,  152,  152,  152,
-    152,  152,  152,  152,    2,    2,    2,    2,    2,   53,   52,   53,    0,    0,    0,    0,
-    153,   11,   74,    2,    2,    2,    2,    2,    2,   18,   19,   21,   16,   24,   37,    0,
+      0,  148,  149,  150,    2,    2,    2,    2,    2,    2,    2,    2,    2,   22,   22,   20,
+     20,   20,   22,   22,  133,    0,    0,    0,    0,    0,  151,  151,  151,  151,  151,  151,
+    151,  151,  151,  151,    2,    2,    2,    2,    2,   53,   52,   53,    0,    0,    0,    0,
+    152,   11,   74,    2,    2,    2,    2,    2,    2,   18,   19,   21,   16,   24,   37,    0,
       0,    0,   31,    0,    0,    0,    0,    0,    0,   11,   49,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,  128,   20,   22,  154,   22,   21,  155,  156,    2,    2,    2,    2,
-      2,    0,    0,   65,  157,    0,    0,    0,    0,    2,   13,    0,    0,    0,    0,    0,
-      0,    2,   65,   25,   20,   20,   20,   22,   22,  108,  158,    0,    0,   56,  159,   31,
-    160,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   23,
-     19,   22,   22,  161,   44,    0,    0,    0,   49,  128,    0,    0,    0,    0,    0,    0,
+      2,    2,    2,    2,  127,   20,   22,  153,   22,   21,  154,  155,    2,    2,    2,    2,
+      2,    0,    0,   65,  156,    0,    0,    0,    0,    2,   13,    0,    0,    0,    0,    0,
+      0,    2,   65,   25,   20,   20,   20,   22,   22,  108,  157,    0,    0,   56,  158,   31,
+    159,   30,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   23,
+     19,   22,   22,  160,   44,    0,    0,    0,   49,  127,    0,    0,    0,    0,    0,    0,
       0,    2,    2,    2,    9,    9,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
-     30,    2,    2,    2,    2,    2,    2,    2,   10,   18,   19,   21,   22,  162,   31,    0,
+     30,    2,    2,    2,    2,    2,    2,    2,   10,   18,   19,   21,   22,  161,   31,    0,
       0,   11,   11,   30,    2,    2,    2,    9,   30,    9,    2,   30,    2,    2,   58,   17,
      23,   16,   23,   47,   32,   33,   32,   34,    0,    0,    0,    0,   35,    0,    0,    0,
       2,    2,   23,    0,   11,   11,   11,   46,    0,   11,   11,   46,    0,    0,    0,    0,
-      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  126,   15,   17,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    0,    0,  163,  164,    0,    0,    0,    0,    0,    0,
-      0,   18,   19,   20,   20,   66,   99,   25,  160,   11,  165,    9,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,    2,   65,   25,   20,   20,    0,   48,   48,   11,
-    166,   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   20,
-      0,   23,   19,   20,   20,   21,   16,   82,  166,   38,    0,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,   10,  167,   25,   20,   22,   22,  165,    9,    0,    0,
-      0,    2,    2,    2,    2,    2,    9,   43,  136,   23,   22,   20,   76,   21,   22,    0,
-      0,    2,    2,    2,    9,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   18,
-     19,   20,   21,   22,  105,  166,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
-      2,    2,    2,   30,    9,    2,    2,    2,    2,   23,   23,   18,   32,   33,   12,  168,
-    169,  170,  171,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
-      2,   65,   25,   20,   20,    0,   22,   23,   29,  108,    0,   33,    0,    0,    0,    0,
-      0,   52,   20,   22,   22,   22,  140,    2,    2,    2,  172,  173,   11,   15,  174,   72,
-    175,    0,    0,    1,  147,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
-      2,    2,    2,  158,  158,  158,  176,  176,  176,  176,  176,  176,   15,  177,    0,   30,
-      0,   22,   20,   20,   31,   22,   22,   11,  166,    0,   61,   61,   61,   61,   61,   61,
-     61,   66,   21,   82,   46,    0,    0,    0,    0,    2,    2,    2,    9,    2,   30,    2,
-      2,   52,   22,   22,   31,    0,   38,   22,   27,   11,  159,  178,  174,    0,    0,    0,
-      0,    2,    2,    2,   30,    9,    2,    2,    2,    2,    2,    2,    2,    2,   23,   23,
-     47,   22,   35,   82,   68,    0,    0,    0,    0,    2,  179,   66,   47,    0,    0,    0,
-      0,   11,  180,    2,    2,    2,    2,    2,    2,    2,    2,   23,   22,   20,   31,    0,
-     48,   16,  143,    0,    0,    0,    0,    0,    0,  181,  181,  181,  181,  181,  181,  181,
-    181,  182,  182,  182,  183,  184,  182,  181,  181,  185,  181,  181,  186,  187,  187,  187,
-    187,  187,  187,  187,    0,    0,    0,    0,    0,   11,   11,   11,   46,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    9,    0,   58,  188,   20,   20,   20,   20,   20,   20,
-     20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,    0,    0,    0,
-     40,  116,   26,    0,    0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,
-      0,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   58,
-     37,    0,    6,  120,  120,  120,  121,    0,    0,   11,   11,   11,   49,    2,    2,    2,
-      0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
-     46,    2,    2,    2,    2,    2,    2,   11,   11,    2,    2,    2,    2,    2,    2,   22,
-     22,    2,    2,   44,   44,   44,   92,    0,    0,    O,    O,    O,   GB,    B,    B,    O,
+      0,    2,    2,    2,    2,    2,   30,    0,    9,    2,    2,    2,   30,   45,   59,   20,
+     20,   31,   33,   32,   32,   25,  162,   29,  163,  164,   37,    0,    0,    0,    0,    0,
+      0,   12,   26,    0,    0,    0,    0,    0,    0,    2,    2,   65,   25,   20,   20,   20,
+     22,   23,  125,   15,   17,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,    0,
+    165,  166,    0,    0,    0,    0,    0,    0,    0,   18,   19,   20,   20,   66,   99,   25,
+    159,   11,  167,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+     65,   25,   20,   20,    0,   48,   48,   11,  168,   37,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    2,    2,   20,    0,   23,   19,   20,   20,   21,   16,   82,
+    168,   38,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   10,  169,
+     25,   20,   22,   22,  167,    9,    0,    0,    0,    2,    2,    2,    2,    2,    9,   43,
+    135,   23,   22,   20,   76,   21,   22,    0,    0,    2,    2,    2,    9,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,   18,   19,   20,   21,   22,  105,  168,   37,    0,
+      0,    2,    2,    2,    9,   30,    0,    2,    2,    2,    2,   30,    9,    2,    2,    2,
+      2,   23,   23,   18,   32,   33,   12,  170,  164,  171,  172,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    0,    2,    2,    2,   65,   25,   20,   20,    0,   22,   23,
+     29,  108,    0,   33,    0,    0,    0,    0,    0,   52,   20,   22,   22,   22,  139,    2,
+      2,    2,  173,  174,   11,   15,  175,   61,  176,    0,    0,    1,  146,    0,    0,    0,
+      0,   52,   20,   22,   16,   19,   20,    2,    2,    2,    2,  157,  157,  157,  177,  177,
+    177,  177,  177,  177,   15,  178,    0,   30,    0,   22,   20,   20,   31,   22,   22,   11,
+    168,    0,   61,   61,   61,   61,   61,   61,   61,   66,   21,   82,   46,    0,    0,    0,
+      0,    2,    2,    2,    9,    2,   30,    2,    2,   52,   22,   22,   31,    0,   38,   22,
+     27,   11,  158,  179,  180,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
+      2,    2,    2,    2,    2,    2,   23,   23,   47,   22,   35,   82,   68,    0,    0,    0,
+      0,    2,  181,   66,   47,    0,    0,    0,    0,   11,  182,    2,    2,    2,    2,    2,
+      2,    2,    2,   23,   22,   20,   31,    0,   48,   16,  142,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,  155,    0,    0,  183,  183,  183,  183,  183,  183,  183,
+    183,  184,  184,  184,  185,  186,  184,  183,  183,  187,  183,  183,  188,  189,  189,  189,
+    189,  189,  189,  189,    0,    0,    0,    0,    0,  183,  183,  183,  183,  183,  190,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   22,   22,   22,   22,   22,   22,  191,  192,
+    193,   11,   11,   11,   46,    0,    0,    0,    0,   29,   74,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   65,   47,    0,    2,    2,    2,    2,    2,    9,    0,
+     58,  194,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,    0,    0,    0,   40,  115,   26,    0,    0,    0,    0,    0,
+      0,    0,    0,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+     30,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  119,  119,  119,  120,    0,
+      0,   11,   11,   11,   49,    2,    2,    2,    0,    2,    2,    2,    2,    2,    0,    0,
+      2,    2,    2,    2,    2,    2,    2,    2,   46,    2,    2,    2,    2,    2,    2,   11,
+     11,    2,    2,    2,    2,    2,    2,   22,   22,    2,    2,    2,    2,    2,    2,    2,
+     20,    2,    2,   44,   44,   44,   92,    0,    0,    O,    O,    O,   GB,    B,    B,    O,
      SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,
   VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst,
    VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O,
@@ -290,20 +301,20 @@ hb_use_u8[3187] =
   FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,
   CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv,
    VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv,
-   VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,
-  CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,
-     SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,
-  CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv,
-   FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,
-     IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,
-     IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,
-      B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst,   IS,    R, MPst,    R, MPst,
-  CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,   GB,
-   VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,    G,    G,   HM,   HM,
-     HM,    O, VBlw,
+   VPst,    H,    B,    O,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,
+  VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,
+      H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv,
+   MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,
+      B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,
+      B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,
+      O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,VMPst,    O,VMAbv,
+  CMBlw,   IS,    R,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst, MPst,
+      R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,   CS,  SUB,  SUB,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,
+     IS,    R, MBlw,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,   SB,   SE,    J,   HR,
+      G,    G,   HM,   HM,   HM,    G,    O, MPre, MPre, MPst,VMAbv, MBlw, VBlw,    O, VBlw,
 };
 static const uint16_t
-hb_use_u16[808] =
+hb_use_u16[856] =
 {
     0,  0,  1,  2,  0,  3,  0,  3,  0,  0,  4,  5,  0,  6,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,
@@ -332,28 +343,31 @@ hb_use_u16[808] =
     0,  0,  0,  0,  0,  0,  0,164,  0,  0,  0,  0,  0,  0,  0,165,
     0,  0,  0,  0,  0,  0,  0,166,166,167, 34,168,  0,  0,  0,  0,
   169,170, 10,171, 95,  0,  0,  0,  0,  0,  0,  0, 70, 10,172,  0,
-   10,173,174,  0,  0,  0,  0,  0, 10, 10,175,  2,  0,  0,  0,  0,
-   10, 10,176,173,  0,  0,  0,  0,  0,  0,  0, 10,177,178,  0, 10,
-  179,  0,  0,180,181,  0,  0,  0,182, 10, 10,183,184,185,186,187,
-  188, 10, 10,189,190,  0,  0,  0,191, 10,192,193,194, 10, 10,195,
-  188, 10, 10,196,197,106,198,103, 10, 34,199,200,201,  0,  0,  0,
-  202,203, 95, 10, 10,204,205,  2,206, 21, 22,207,208,209,210,211,
-   10, 10, 10,212,213,214,215,  0,198, 10, 10,216,217,  2,  0,  0,
-   10, 10,218,219,220,221,  0,  0, 10, 10, 10,222,223,  2,  0,  0,
-   10, 10,224,225,  2,  0,  0,  0, 10,226,227,104,228,  0,  0,  0,
-   10, 10,229,230,  0,  0,  0,  0,231,232, 10,233,234,  2,  0,  0,
-    0,  0,235, 10, 10,236,237,  0,238, 10, 10,239,240,241, 10, 10,
-  242,243,  0,  0,  0,  0,  0,  0, 22, 10,218,244,  8, 10, 71, 19,
-   10,245, 74,246,  0,  0,  0,  0,247, 10, 10,248,249,  2,250, 10,
-  251,252,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,253,
-  254, 49, 10,255,256,  2,  0,  0,257,257,257,257,257,257,257,257,
-  257,257,257,258,259,260,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-   10, 10, 10,261,  0,  0,  0,  0, 10, 10, 10, 10,262,263,264,264,
-  265,266,  0,  0,  0,  0,267,  0, 10, 10, 10, 10, 10, 10, 10, 10,
-   10, 10, 10, 10, 10,268,  0,  0, 10, 10, 10, 10, 10, 10,106, 71,
-   95,269,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,270,
-   10, 10, 71,271,272,  0,  0,  0,  0, 10,273,  0, 10, 10,274,  2,
-    0,  0,  0,  0,  0, 10,275,  2, 10, 10, 10, 10,276,  2,  0,  0,
+   10,173,174,  0,  0,  0,  0,  0, 10, 10,175,  2,  9, 10,176, 10,
+  177,  0,  0,  0,  0,  0,  0,  0, 10, 10,178,173,  0,  0,  0,  0,
+    0,  0,  0, 10,179,180,  0, 10,181,  0,  0,182,183,  0,  0,  0,
+  184, 10, 10,185,186,187,188,189,190, 10, 10,191,192,  0,  0,  0,
+  193, 10,194,195,196, 10, 10,197,190, 10, 10,198,199,106,200,103,
+   10, 34,201,202,203,  0,  0,  0,204,205, 95, 10, 10,206,207,  2,
+  208, 21, 22,209,210,211,212,213,214, 10, 10,215,216,217,218,  0,
+   10, 10, 10,219,220,221,222,  0,200, 10, 10,223,224,  2,  0,  0,
+   10, 10,225,226,227,228,  0,  0, 10, 10, 10,229,230,  2,  0,  0,
+   10, 10,231,232,  2, 10,141,  0, 10,233,234,104,235,  0,  0,  0,
+   10, 10,236,237,  0,  0,  0,  0,238,239, 10,240,241,  2,  0,  0,
+    0,  0,242, 10, 10,243,244,  0,245, 10, 10,246,247,248, 10, 10,
+  249,250,  0,  0,  0,  0,  0,  0, 22, 10,225,251,  8, 10, 71, 19,
+   10,252, 74,253,  0,  0,  0,  0,254, 10, 10,255,256,  2,257, 10,
+  258,259,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,260,
+  261, 49, 10,262,263,264,  0,  0,265,265,265,265,265,265,265,265,
+  265,265,265,266,267,268,265,265,265,265,265,265,265,265,265,269,
+   10,270,271,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+   10, 10, 10,272,  0,  0,  0,  0,  0,  0,  0,  0,273, 10,274,  2,
+   10, 10, 10, 10,275,276,277,277,278,279,  0,  0,  0,  0,280,  0,
+   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,177,  0,281,
+   10, 10, 10, 10, 10, 10,106, 71, 95,282,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,283, 10, 10, 71,284,285,  0,  0,  0,
+    0, 10,286,  0, 10, 10,287,  2,  0,  0,  0,  0,  0, 10,288,  2,
+    0,  0,  0,  0,  0, 10,289,106, 10, 10, 10, 10,290,  2,  0,  0,
   130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163,
   163,163,163,163,163,163,163,130,
 };
@@ -366,23 +380,23 @@ hb_use_b4 (const uint8_t* a, unsigned i)
 static inline uint_fast8_t
 hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[2809+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+  return u<921600u?hb_use_u8[2953+(((hb_use_u8[625+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
 }
 
 
 #else
 
 static const uint8_t
-hb_use_u8[3483] =
+hb_use_u8[3655] =
 {
-     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
+     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   57,   58,   59,  195,  211,   62,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-     14,    0,    1,    1,    2,    1,    1,    3,    4,    5,    6,    7,    8,    9,   10,    1,
+     15,    0,    1,    1,    2,    1,    1,    3,    4,    5,    6,    7,    8,    9,   10,    1,
      11,   12,    1,    1,    1,    1,    1,    1,   13,   14,   15,   16,   17,   18,   19,    1,
       1,   20,    1,    1,    1,    1,   21,    1,   22,    1,    1,    1,    1,    1,   23,   24,
       1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -390,14 +404,15 @@ hb_use_u8[3483] =
       1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   29,
      30,    1,    1,    1,    1,    1,   31,    1,    1,    1,    1,   32,   33,    1,   34,   35,
      36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,    1,   48,   49,   50,
-     51,   52,   52,   52,   52,   53,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   54,   55,    1,    1,    1,
-     56,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   57,   58,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   59,    1,    1,
-      1,    1,   60,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,   61,   62,    1,   63,    1,    1,    1,    1,   64,    1,    1,    1,    1,    1,
-      1,   65,   66,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
-     65,    0,    1,    2,    2,    0,    3,    4,    0,    0,    0,    0,    0,    0,    0,    0,
+     51,   52,   52,   52,   52,   53,   52,   52,   52,   52,   52,   52,   52,   52,   52,   52,
+     52,   52,   52,   52,   54,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,   55,    1,    1,    1,    1,    1,    1,    1,    1,   56,   57,    1,   58,    1,
+     59,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   60,   61,    1,    1,
+      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   62,    1,    1,
+      1,    1,   63,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+      1,    1,   64,   65,    1,   66,   67,    1,    1,    1,   68,    1,    1,    1,    1,    1,
+      1,   69,   70,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+     69,    0,    1,    2,    2,    0,    3,    4,    0,    0,    0,    0,    0,    0,    0,    0,
       0,    0,    0,    5,    0,    0,    0,    0,    0,    0,    0,    6,    0,    0,    0,    0,
       0,    0,    0,    0,    0,    0,    0,    7,    8,    0,    0,    9,    0,    0,    0,    0,
       0,   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,   22,   23,   24,
@@ -414,23 +429,25 @@ hb_use_u8[3483] =
     122,    0,    0,    0,    0,    0,    0,   56,  123,  124,    0,    0,    0,    0,    0,    0,
     125,    0,    0,    0,    0,    0,    0,    0,  126,    0,    0,    0,  127,  128,  129,    0,
       0,  130,  131,  132,    0,    0,    0,   51,  133,    0,    0,    0,    0,  134,  135,    0,
-      0,   56,  136,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   56,  137,    0,
-      0,    0,  101,  138,  101,  139,  140,  141,    0,  142,  143,  144,  145,  146,  147,  148,
-      0,  149,  150,  151,  152,  146,  153,  154,  155,  156,  157,  158,    0,  159,  160,  161,
-    162,  163,  164,  165,  166,    0,    0,    0,    0,   56,  167,  168,  169,  170,  171,  172,
-      0,    0,    0,    0,    0,   56,  173,  174,    0,   56,  175,  176,    0,   56,  177,   67,
-      0,  178,  179,  180,    0,    0,    0,    0,    0,   56,  181,    0,    0,    0,    0,    0,
-      0,  182,  183,  184,    0,    0,  185,  186,  187,  188,  189,  190,   56,  191,    0,    0,
-      0,  192,  193,  194,  195,  196,  197,    0,    0,  198,  199,  200,  201,  202,   67,    0,
-      0,    0,    0,    0,    0,    0,    0,    0,  203,  204,  205,  206,    0,    0,    0,    0,
-      0,  207,  207,  207,  207,  207,  207,  207,  207,  207,  208,  209,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,    0,   67,    0,   56,  210,    0,    0,    0,    0,    0,
-      0,   56,   56,  211,  212,  213,    0,    0,  214,   56,   56,   56,   56,   56,   56,   56,
-     56,   56,   56,   56,   56,   56,   56,  215,    0,   56,   56,   56,  216,  217,    0,    0,
-      0,    0,    0,    0,  218,    0,    0,    0,    0,   56,  219,  220,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,  101,  221,   56,  222,    0,    0,    0,    0,    0,    0,  101,
-    223,   56,   56,  224,    0,    0,    0,    0,    0,  225,  225,  225,  225,  225,  225,  225,
-    225,  226,  226,  226,  226,  226,  226,  226,  227,    0,    0,    0,    0,    0,    0,    0,
+      0,   56,  136,    7,  137,  138,    0,    0,    0,    0,    0,    0,    0,   56,  139,    0,
+      0,    0,  101,  140,  101,  141,  142,  143,    0,  144,  145,  146,  147,  148,  149,  150,
+      0,  151,  152,  153,  154,  148,  155,  156,  157,  158,  159,  160,    0,  161,  162,  163,
+    164,  165,  166,  167,  168,  169,  170,  171,  172,   56,  173,  174,  175,  176,  177,  178,
+      0,    0,    0,    0,    0,   56,  179,  180,    0,   56,  181,  182,    0,   56,  183,  184,
+    185,  186,  187,  188,    0,    0,    0,    0,    0,   56,  189,    0,    0,    0,    0,    0,
+      0,  190,  191,  192,    0,    0,  193,  194,  195,  196,  197,  198,   56,  199,    0,    0,
+      0,  200,  201,  202,  203,  204,  205,    0,    0,  206,  207,  208,  209,  210,   67,    0,
+      0,    0,    0,    0,    0,    0,    0,    0,  211,  212,  213,  214,    0,    0,    0,    0,
+      0,  215,  215,  215,  215,  215,  215,  215,  215,  215,  216,  217,  215,  215,  215,  215,
+    215,  215,  215,  215,  215,  215,  215,  215,  218,  219,  220,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,   67,    0,   56,  221,    0,    0,    0,    0,    0,
+      0,    0,    0,  222,  223,    0,    0,    0,    0,   56,   56,  224,  225,  226,    0,    0,
+    227,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,   56,  228,
+    229,   56,   56,   56,  230,  231,    0,    0,    0,    0,    0,    0,  232,    0,    0,    0,
+      0,   56,  233,  234,    0,    0,    0,    0,    0,    0,    0,    0,    0,  101,  235,   56,
+    236,    0,    0,    0,    0,    0,    0,  101,  237,    0,    0,    0,    0,    0,    0,  101,
+    238,   56,   56,  239,    0,    0,    0,    0,    0,  240,  240,  240,  240,  240,  240,  240,
+    240,  241,  241,  241,  241,  241,  241,  241,  242,    0,    0,    0,    0,    0,    0,    0,
       0,    0,    0,    0,    0,    0,    0,    1,    0,    2,    2,    2,    2,    2,    0,    0,
       0,    0,    0,    0,    0,    0,    3,    4,    0,    5,    0,    0,    0,    0,    0,    6,
       0,    0,    7,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,    0,
@@ -460,7 +477,7 @@ hb_use_u8[3483] =
       0,   10,   29,   30,    2,    2,    2,    9,    2,    2,    2,   30,    2,    2,    0,   17,
      45,    0,    0,   35,   47,    0,    0,    0,    9,   50,   51,    0,    0,    0,    0,    0,
       0,   11,   29,    2,    2,    2,    2,    9,    2,    2,    2,    2,    2,    2,   52,   53,
-     23,   23,   19,   31,   48,   33,   48,   34,   54,    0,    0,    0,   35,    0,    0,    0,
+     23,   19,   20,   31,   48,   33,   48,   34,   54,    0,    0,    0,   35,    0,    0,    0,
      30,   12,   29,   30,    2,    2,    2,    2,    2,    2,    2,    2,    9,    0,    2,    2,
       2,    2,   30,    2,    2,    2,    2,   30,    0,    2,    2,    2,    9,    0,   55,    0,
      35,   23,   22,   31,   31,   18,   48,   48,   25,    0,   23,    0,    0,    0,    0,    0,
@@ -488,87 +505,94 @@ hb_use_u8[3483] =
      63,  104,   16,   45,   22,   59,   21,   80,   48,   48,   76,   11,   11,   11,  105,   46,
      40,   11,  106,   74,    2,    2,    2,    2,    2,    2,    2,  107,   22,   20,   20,   22,
      48,   48,   22,  108,    2,    2,    2,    9,    0,    0,    0,    0,    0,    0,  109,  110,
-    111,  111,  111,    0,    0,    0,    0,    0,    0,  106,   74,    2,    2,    2,    2,    2,
-      2,   60,   61,   59,   25,   22,  112,   61,    2,    2,    2,    2,  107,   22,   23,   45,
-     45,  102,   14,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  113,
-    102,  102,  102,  114,  115,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
-      2,   11,   46,  116,  116,  116,   11,  116,  116,   15,  116,  116,  116,   26,    0,   40,
-      0,    0,    0,  117,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  118,    0,
-      0,    0,    0,    0,    0,    0,    6,  119,  120,   42,   42,    5,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    0,  120,  120,  121,  120,  120,  120,  120,  120,  120,  120,
-    120,    0,    0,  122,    0,    0,    0,    0,    0,    0,    7,  122,    0,    0,    0,    0,
+    110,  110,  110,    0,    0,    0,    0,    0,    0,  106,   74,    2,    2,    2,    2,    2,
+      2,   60,   61,   59,   25,   22,  111,   61,    2,    2,    2,    2,  107,   22,   23,   45,
+     45,  102,   14,    0,    0,    0,    0,    0,    0,    2,    2,   61,   18,   48,   23,  112,
+    102,  102,  102,  113,  114,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   30,
+      2,   11,   46,  115,  115,  115,   11,  115,  115,   15,  115,  115,  115,   26,    0,   40,
+      0,    0,    0,  116,   51,   11,    5,    0,    0,    0,    0,    0,    0,    0,  117,    0,
+      0,    0,    0,    0,    0,    0,    6,  118,  119,   42,   42,    5,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,  119,  119,  120,  119,  119,  119,  119,  119,  119,  119,
+    119,    0,    0,  121,    0,    0,    0,    0,    0,    0,    7,  121,    0,    0,    0,    0,
       0,   46,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    9,
-      0,    0,    0,    0,  123,  123,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
-     30,    0,    0,    0,    0,    0,    0,    0,  124,    0,  123,  123,    0,    0,    0,    0,
+      0,    0,    0,    0,  122,  122,    0,    0,    0,    2,    2,    2,    2,    0,    0,    0,
+     30,    0,    0,    0,    0,    0,    0,    0,  123,    0,  122,  122,    0,    0,    0,    0,
       0,    2,   53,    2,  108,    2,   10,    2,    2,    2,   65,   19,   16,    0,    0,   31,
       0,    2,    2,    0,    0,    0,    0,    0,    0,   29,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,  125,   23,   23,   23,   23,   23,   23,   23,  126,    0,    0,    0,    0,
+      2,    2,    2,  124,   23,   23,   23,   23,   23,   23,   23,  125,    0,    0,    0,    0,
       0,   11,   11,   11,   11,   11,   11,   11,   11,   11,    2,    0,    0,    0,    0,    0,
-     52,    2,    2,    2,   22,   22,  127,  116,    0,    2,    2,    2,  128,   20,   59,   20,
-    113,  102,  129,    0,    0,    0,    0,    0,    0,   11,  130,    2,    2,    2,    2,    2,
-      2,    2,  131,   23,   22,   20,   48,  132,  133,  134,    0,    0,    0,    0,    0,    0,
+     52,    2,    2,    2,   22,   22,  126,  115,    0,    2,    2,    2,  127,   20,   59,   20,
+    112,  102,  128,    0,    0,    0,    0,    0,    0,   11,  129,    2,    2,    2,    2,    2,
+      2,    2,  130,   23,   22,   20,   48,  131,  132,  133,    0,    0,    0,    0,    0,    0,
       0,    2,    2,   52,   30,    2,    2,    2,    2,    2,    2,    2,    2,   10,   22,   59,
-     99,   76,  135,  136,  137,    0,    0,    0,    0,    2,  138,    2,    2,    2,    2,  139,
-      0,   30,    2,   42,    5,    0,   79,   15,    2,   53,   22,  140,   52,   53,    2,    2,
-    105,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  141,   21,
-     25,    0,    0,  142,  143,    0,    0,    0,    0,    2,   65,   45,   23,   80,   47,  144,
+     99,   76,  134,  135,  136,    0,    0,    0,    0,    2,  137,    2,    2,    2,    2,  138,
+      0,   30,    2,   42,    5,    0,   79,   15,    2,   53,   22,  139,   52,   53,    2,    2,
+    105,   10,    9,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  140,   21,
+     25,    0,    0,  141,  142,    0,    0,    0,    0,    2,   65,   45,   23,   80,   47,  143,
       0,   81,   81,   81,   81,   81,   81,   81,   81,    0,    0,    0,    0,    0,    0,    0,
-      6,  120,  120,  120,  120,  121,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
+      6,  119,  119,  119,  119,  120,    0,    0,    0,    2,    2,    2,    2,    2,    9,    2,
       2,    2,    9,    2,   30,    2,    2,    2,    2,    2,   30,    2,    2,    2,   30,    9,
-      0,  128,   20,   27,   31,    0,    0,  145,  146,    2,    2,   30,    2,   30,    2,    2,
-      2,    2,    2,    2,    0,   14,   37,    0,  147,    2,    2,   13,   37,    0,   30,    2,
+      0,  127,   20,   27,   31,    0,    0,  144,  145,    2,    2,   30,    2,   30,    2,    2,
+      2,    2,    2,    2,    0,   14,   37,    0,  146,    2,    2,   13,   37,    0,   30,    2,
       2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,
-      9,    2,    2,   11,   41,    0,    0,    0,    0,    2,    2,    2,    2,    2,   27,   38,
-      0,    2,    2,    2,  116,  116,  116,  116,  116,  148,    2,    9,    0,    0,    0,    0,
+      9,    2,    2,   11,   41,    0,    0,    0,    0,    2,    2,    2,    0,   27,   22,   22,
+     30,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   27,   38,
+      0,    2,    2,    2,  115,  115,  115,  115,  115,  147,    2,    9,    0,    0,    0,    0,
       0,    2,   14,   14,    0,    0,    0,    0,    0,    9,    2,    2,    9,    2,    2,    2,
-      2,   30,    2,    9,    0,   30,    2,    0,    0,  149,  150,  151,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  134,    0,    0,    0,
-      0,    0,  152,  152,  152,  152,  152,  152,  152,  152,  152,  152,    2,    2,    2,    2,
-      2,   53,   52,   53,    0,    0,    0,    0,  153,   11,   74,    2,    2,    2,    2,    2,
+      2,   30,    2,    9,    0,   30,    2,    0,    0,  148,  149,  150,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,   22,   22,   20,   20,   20,   22,   22,  133,    0,    0,    0,
+      0,    0,  151,  151,  151,  151,  151,  151,  151,  151,  151,  151,    2,    2,    2,    2,
+      2,   53,   52,   53,    0,    0,    0,    0,  152,   11,   74,    2,    2,    2,    2,    2,
       2,   18,   19,   21,   16,   24,   37,    0,    0,    0,   31,    0,    0,    0,    0,    0,
-      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  128,   20,   22,  154,
-     22,   21,  155,  156,    2,    2,    2,    2,    2,    0,    0,   65,  157,    0,    0,    0,
+      0,   11,   49,    2,    2,    2,    2,    2,    2,    2,    2,    2,  127,   20,   22,  153,
+     22,   21,  154,  155,    2,    2,    2,    2,    2,    0,    0,   65,  156,    0,    0,    0,
       0,    2,   13,    0,    0,    0,    0,    0,    0,    2,   65,   25,   20,   20,   20,   22,
-     22,  108,  158,    0,    0,   56,  159,   31,  160,   30,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,   23,   19,   22,   22,  161,   44,    0,    0,    0,
-     49,  128,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
+     22,  108,  157,    0,    0,   56,  158,   31,  159,   30,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   23,   19,   22,   22,  160,   44,    0,    0,    0,
+     49,  127,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    9,    9,    2,    2,
      30,    2,    2,    2,    2,    2,    2,    2,   30,    2,    2,    2,    2,    2,    2,    2,
-     10,   18,   19,   21,   22,  162,   31,    0,    0,   11,   11,   30,    2,    2,    2,    9,
+     10,   18,   19,   21,   22,  161,   31,    0,    0,   11,   11,   30,    2,    2,    2,    9,
      30,    9,    2,   30,    2,    2,   58,   17,   23,   16,   23,   47,   32,   33,   32,   34,
       0,    0,    0,    0,   35,    0,    0,    0,    2,    2,   23,    0,   11,   11,   11,   46,
-      0,   11,   11,   46,    0,    0,    0,    0,    0,    2,    2,   65,   25,   20,   20,   20,
-     22,   23,  126,   15,   17,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,    0,
-    163,  164,    0,    0,    0,    0,    0,    0,    0,   18,   19,   20,   20,   66,   99,   25,
-    160,   11,  165,    9,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
-     65,   25,   20,   20,    0,   48,   48,   11,  166,   37,    0,    0,    0,    0,    0,    0,
-      0,    0,    0,    0,    0,    2,    2,   20,    0,   23,   19,   20,   20,   21,   16,   82,
-    166,   38,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   10,  167,
-     25,   20,   22,   22,  165,    9,    0,    0,    0,    2,    2,    2,    2,    2,    9,   43,
-    136,   23,   22,   20,   76,   21,   22,    0,    0,    2,    2,    2,    9,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,   18,   19,   20,   21,   22,  105,  166,   37,    0,
-      0,    2,    2,    2,    9,   30,    0,    2,    2,    2,    2,   30,    9,    2,    2,    2,
-      2,   23,   23,   18,   32,   33,   12,  168,  169,  170,  171,    0,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    0,    2,    2,    2,   65,   25,   20,   20,    0,   22,   23,
-     29,  108,    0,   33,    0,    0,    0,    0,    0,   52,   20,   22,   22,   22,  140,    2,
-      2,    2,  172,  173,   11,   15,  174,   72,  175,    0,    0,    1,  147,    0,    0,    0,
-      0,   52,   20,   22,   16,   19,   20,    2,    2,    2,    2,  158,  158,  158,  176,  176,
-    176,  176,  176,  176,   15,  177,    0,   30,    0,   22,   20,   20,   31,   22,   22,   11,
-    166,    0,   61,   61,   61,   61,   61,   61,   61,   66,   21,   82,   46,    0,    0,    0,
-      0,    2,    2,    2,    9,    2,   30,    2,    2,   52,   22,   22,   31,    0,   38,   22,
-     27,   11,  159,  178,  174,    0,    0,    0,    0,    2,    2,    2,   30,    9,    2,    2,
-      2,    2,    2,    2,    2,    2,   23,   23,   47,   22,   35,   82,   68,    0,    0,    0,
-      0,    2,  179,   66,   47,    0,    0,    0,    0,   11,  180,    2,    2,    2,    2,    2,
-      2,    2,    2,   23,   22,   20,   31,    0,   48,   16,  143,    0,    0,    0,    0,    0,
-      0,  181,  181,  181,  181,  181,  181,  181,  181,  182,  182,  182,  183,  184,  182,  181,
-    181,  185,  181,  181,  186,  187,  187,  187,  187,  187,  187,  187,    0,    0,    0,    0,
-      0,   11,   11,   11,   46,    0,    0,    0,    0,    2,    2,    2,    2,    2,    9,    0,
-     58,  188,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
-     20,   20,   20,   20,   20,    0,    0,    0,   40,  116,   26,    0,    0,    0,    0,    0,
-      0,    0,    0,    9,    0,    0,    0,    0,    0,    2,    2,    2,    0,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    0,   58,   37,    0,    6,  120,  120,  120,  121,    0,
-      0,   11,   11,   11,   49,    2,    2,    2,    0,    2,    2,    2,    2,    2,    0,    0,
-      2,    2,    2,    2,    2,    2,    2,    2,   46,    2,    2,    2,    2,    2,    2,   11,
-     11,    2,    2,    2,    2,    2,    2,   22,   22,    2,    2,   44,   44,   44,   92,    0,
+      0,   11,   11,   46,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,   30,    0,
+      9,    2,    2,    2,   30,   45,   59,   20,   20,   31,   33,   32,   32,   25,  162,   29,
+    163,  164,   37,    0,    0,    0,    0,    0,    0,   12,   26,    0,    0,    0,    0,    0,
+      0,    2,    2,   65,   25,   20,   20,   20,   22,   23,  125,   15,   17,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,    0,  165,  166,    0,    0,    0,    0,    0,    0,
+      0,   18,   19,   20,   20,   66,   99,   25,  159,   11,  167,    9,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   65,   25,   20,   20,    0,   48,   48,   11,
+    168,   37,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   20,
+      0,   23,   19,   20,   20,   21,   16,   82,  168,   38,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,   10,  169,   25,   20,   22,   22,  167,    9,    0,    0,
+      0,    2,    2,    2,    2,    2,    9,   43,  135,   23,   22,   20,   76,   21,   22,    0,
+      0,    2,    2,    2,    9,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   18,
+     19,   20,   21,   22,  105,  168,   37,    0,    0,    2,    2,    2,    9,   30,    0,    2,
+      2,    2,    2,   30,    9,    2,    2,    2,    2,   23,   23,   18,   32,   33,   12,  170,
+    164,  171,  172,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
+      2,   65,   25,   20,   20,    0,   22,   23,   29,  108,    0,   33,    0,    0,    0,    0,
+      0,   52,   20,   22,   22,   22,  139,    2,    2,    2,  173,  174,   11,   15,  175,   61,
+    176,    0,    0,    1,  146,    0,    0,    0,    0,   52,   20,   22,   16,   19,   20,    2,
+      2,    2,    2,  157,  157,  157,  177,  177,  177,  177,  177,  177,   15,  178,    0,   30,
+      0,   22,   20,   20,   31,   22,   22,   11,  168,    0,   61,   61,   61,   61,   61,   61,
+     61,   66,   21,   82,   46,    0,    0,    0,    0,    2,    2,    2,    9,    2,   30,    2,
+      2,   52,   22,   22,   31,    0,   38,   22,   27,   11,  158,  179,  180,    0,    0,    0,
+      0,    2,    2,    2,   30,    9,    2,    2,    2,    2,    2,    2,    2,    2,   23,   23,
+     47,   22,   35,   82,   68,    0,    0,    0,    0,    2,  181,   66,   47,    0,    0,    0,
+      0,   11,  182,    2,    2,    2,    2,    2,    2,    2,    2,   23,   22,   20,   31,    0,
+     48,   16,  142,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  155,    0,
+      0,  183,  183,  183,  183,  183,  183,  183,  183,  184,  184,  184,  185,  186,  184,  183,
+    183,  187,  183,  183,  188,  189,  189,  189,  189,  189,  189,  189,    0,    0,    0,    0,
+      0,  183,  183,  183,  183,  183,  190,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+     22,   22,   22,   22,   22,   22,  191,  192,  193,   11,   11,   11,   46,    0,    0,    0,
+      0,   29,   74,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   65,   47,
+      0,    2,    2,    2,    2,    2,    9,    0,   58,  194,   20,   20,   20,   20,   20,   20,
+     20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,    0,    0,    0,
+     40,  115,   26,    0,    0,    0,    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    0,   30,    2,    2,    2,    2,    2,    0,   58,
+     37,    0,    6,  119,  119,  119,  120,    0,    0,   11,   11,   11,   49,    2,    2,    2,
+      0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
+     46,    2,    2,    2,    2,    2,    2,   11,   11,    2,    2,    2,    2,    2,    2,   22,
+     22,    2,    2,    2,    2,    2,    2,    2,   20,    2,    2,   44,   44,   44,   92,    0,
       0,    O,    O,    O,   GB,    B,    B,    O,   SB,    O,   SE,   GB,    O,    O,   WJ,FMPst,
   FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,
   VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst,
@@ -582,20 +606,21 @@ hb_use_u8[3483] =
   VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,
   FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst,
    FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,
-    SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,
-  SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,
-    CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,
-  VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw,
-   MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,
-      O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,
-      B,    N,    N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw,
-   VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst,
-   VAbv,VMAbv, VPst,   IS,    R, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,
-     GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,   GB, VAbv,    R,VMPst,    G,    G,    J,    J,    J,
-     SB,   SE,    J,   HR,    G,    G,   HM,   HM,   HM,    O, VBlw,
+    SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMAbv,SMAbv, VPst,
+     IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,
+     WJ,   WJ,    O,FMPst,    O,   SB,   SE,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B,
+   VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre,
+   MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst,
+   VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,
+      N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,CMBlw, VAbv, VPre,
+  VMAbv,VMAbv,    H, VAbv,CMBlw,VMPst,    O,VMAbv,CMBlw,   IS,    R,FMAbv,    B,   CS,   CS,    H,
+  CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,   CS,
+    SUB,  SUB,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,    R, MBlw,   GB, VAbv,    R,VMPst,    G,
+      G,    J,    J,    J,   SB,   SE,    J,   HR,    G,    G,   HM,   HM,   HM,    G,    O, MPre,
+   MPre, MPst,VMAbv, MBlw, VBlw,    O, VBlw,
 };
 static const uint16_t
-hb_use_u16[456] =
+hb_use_u16[486] =
 {
     0,  0,  1,  2,  0,  3,  4,  5,  0,  6,  7,  0,  8,  0,  9, 10,
    11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23,
@@ -614,18 +639,20 @@ hb_use_u16[456] =
   148,149,150, 10, 10,151,152,  2,153, 99,154,155,156,  2, 10,157,
    10,158,159,  0,160,161,162,  2,163,  0,  0,164,  0,165,  0,166,
   166,167, 34,168,169,170, 10,171, 95,  0,172,  0, 10,173,174,  0,
-  175,  2,176,173,177,178,179,  0,  0,180,181,  0,182, 10, 10,183,
-  184,185,186,187,188, 10, 10,189,190,  0,191, 10,192,193,194, 10,
-   10,195, 10,196,197,106,198,103, 10, 34,199,200,201,  0,202,203,
-   95, 10, 10,204,205,  2,206, 21, 22,207,208,209,210,211, 10,212,
-  213,214,215,  0,198, 10, 10,216,217,  2,218,219,220,221, 10,222,
-  223,  2,224,225, 10,226,227,104,228,  0,229,230,231,232, 10,233,
-  234,  2,235, 10, 10,236,237,  0,238, 10, 10,239,240,241,242,243,
-   22, 10,218,244,  8, 10, 71, 19, 10,245, 74,246,247, 10, 10,248,
-  249,  2,250, 10,251,252, 10,253,254, 49, 10,255,256,  2,257,257,
-  257,258,259,260, 10,261,262,263,264,264,265,266,267,  0, 10,268,
-  106, 71, 95,269,  0,270, 71,271,272,  0,273,  0,274,  2,275,  2,
-  276,  2,130,130,163,163,163,130,
+  175,  2,176, 10,177,  0,178,173,179,180,181,  0,  0,182,183,  0,
+  184, 10, 10,185,186,187,188,189,190, 10, 10,191,192,  0,193, 10,
+  194,195,196, 10, 10,197, 10,198,199,106,200,103, 10, 34,201,202,
+  203,  0,204,205, 95, 10, 10,206,207,  2,208, 21, 22,209,210,211,
+  212,213,214, 10, 10,215,216,217,218,  0, 10,219,220,221,222,  0,
+  200, 10, 10,223,224,  2,225,226,227,228, 10,229,230,  2,231,232,
+    2, 10,141,  0, 10,233,234,104,235,  0,236,237,238,239, 10,240,
+  241,  2,242, 10, 10,243,244,  0,245, 10, 10,246,247,248,249,250,
+   22, 10,225,251,  8, 10, 71, 19, 10,252, 74,253,254, 10, 10,255,
+  256,  2,257, 10,258,259, 10,260,261, 49, 10,262,263,264,265,265,
+  265,266,267,268,265,269, 10,270,271,  2, 10,272,273, 10,274,  2,
+  275,276,277,277,278,279,280,  0, 10,177,  0,281,106, 71, 95,282,
+    0,283, 71,284,285,  0,286,  0,287,  2,288,  2,289,106,290,  2,
+  130,130,163,163,163,130,
 };
 
 static inline unsigned
@@ -636,7 +663,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
 static inline uint_fast8_t
 hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[3105+(((hb_use_u8[889+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+  return u<921600u?hb_use_u8[3265+(((hb_use_u8[937+(((hb_use_u16[((hb_use_u8[369+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
 }
 
 #endif

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc

@@ -10,8 +10,8 @@
  * # Date: 2015-03-12, 21:17:00 GMT [AG]
  * # Date: 2019-11-08, 23:22:00 GMT [AG]
  *
- * # Scripts-15.1.0.txt
- * # Date: 2023-07-28, 16:01:07 GMT
+ * # Scripts-16.0.0.txt
+ * # Date: 2024-04-30, 21:48:40 GMT
  */
 
 #include "hb.hh"

+ 23 - 13
thirdparty/harfbuzz/src/hb-ot-shaper.hh

@@ -174,9 +174,11 @@ HB_OT_SHAPERS_IMPLEMENT_SHAPERS
 
 
 static inline const hb_ot_shaper_t *
-hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
+hb_ot_shaper_categorize (hb_script_t script,
+			 hb_direction_t direction,
+			 hb_tag_t gsub_script)
 {
-  switch ((hb_tag_t) planner->props.script)
+  switch ((hb_tag_t) script)
   {
     default:
       return &_hb_ot_shaper_default;
@@ -192,9 +194,8 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
        * This is because we do fallback shaping for Arabic script (and not others).
        * But note that Arabic shaping is applicable only to horizontal layout; for
        * vertical text, just use the generic shaper instead. */
-      if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
-	   planner->props.script == HB_SCRIPT_ARABIC) &&
-	  HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
+      if ((gsub_script != HB_OT_TAG_DEFAULT_SCRIPT || script == HB_SCRIPT_ARABIC) &&
+	  HB_DIRECTION_IS_HORIZONTAL (direction))
 	return &_hb_ot_shaper_arabic;
       else
 	return &_hb_ot_shaper_default;
@@ -235,10 +236,10 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
        * Otherwise, use the specific shaper.
        *
        * If it's indy3 tag, send to USE. */
-      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
-	  planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
+      if (gsub_script == HB_TAG ('D','F','L','T') ||
+	  gsub_script == HB_TAG ('l','a','t','n'))
 	return &_hb_ot_shaper_default;
-      else if ((planner->map.chosen_script[0] & 0x000000FF) == '3')
+      else if ((gsub_script & 0x000000FF) == '3')
 	return &_hb_ot_shaper_use;
       else
 	return &_hb_ot_shaper_indic;
@@ -254,9 +255,9 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
        * If designer designed for 'mymr' tag, also send to default
        * shaper.  That's tag used from before Myanmar shaping spec
        * was developed.  The shaping spec uses 'mym2' tag. */
-      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
-	  planner->map.chosen_script[0] == HB_TAG ('l','a','t','n') ||
-	  planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
+      if (gsub_script == HB_TAG ('D','F','L','T') ||
+	  gsub_script == HB_TAG ('l','a','t','n') ||
+	  gsub_script == HB_TAG ('m','y','m','r'))
 	return &_hb_ot_shaper_default;
       else
 	return &_hb_ot_shaper_myanmar;
@@ -386,13 +387,22 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
     case HB_SCRIPT_KAWI:
     case HB_SCRIPT_NAG_MUNDARI:
 
+    /* Unicode-16.0 additions */
+    case HB_SCRIPT_GARAY:
+    case HB_SCRIPT_GURUNG_KHEMA:
+    case HB_SCRIPT_KIRAT_RAI:
+    case HB_SCRIPT_OL_ONAL:
+    case HB_SCRIPT_SUNUWAR:
+    case HB_SCRIPT_TODHRI:
+    case HB_SCRIPT_TULU_TIGALARI:
+
       /* If the designer designed the font for the 'DFLT' script,
        * (or we ended up arbitrarily pick 'latn'), use the default shaper.
        * Otherwise, use the specific shaper.
        * Note that for some simple scripts, there may not be *any*
        * GSUB/GPOS needed, so there may be no scripts found! */
-      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
-	  planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
+      if (gsub_script == HB_TAG ('D','F','L','T') ||
+	  gsub_script == HB_TAG ('l','a','t','n'))
 	return &_hb_ot_shaper_default;
       else
 	return &_hb_ot_shaper_use;

+ 23 - 23
thirdparty/harfbuzz/src/hb-ot-stat-table.hh

@@ -354,10 +354,10 @@ struct AxisValue
   {
     switch (u.format)
     {
-    case 1: return u.format1.get_value ();
-    case 2: return u.format2.get_value ();
-    case 3: return u.format3.get_value ();
-    case 4: return u.format4.get_axis_record (axis_index).get_value ();
+    case 1: hb_barrier (); return u.format1.get_value ();
+    case 2: hb_barrier (); return u.format2.get_value ();
+    case 3: hb_barrier (); return u.format3.get_value ();
+    case 4: hb_barrier (); return u.format4.get_axis_record (axis_index).get_value ();
     default:return 0.f;
     }
   }
@@ -366,9 +366,9 @@ struct AxisValue
   {
     switch (u.format)
     {
-    case 1: return u.format1.get_axis_index ();
-    case 2: return u.format2.get_axis_index ();
-    case 3: return u.format3.get_axis_index ();
+    case 1: hb_barrier (); return u.format1.get_axis_index ();
+    case 2: hb_barrier (); return u.format2.get_axis_index ();
+    case 3: hb_barrier (); return u.format3.get_axis_index ();
     /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
     default:return -1;
     }
@@ -378,10 +378,10 @@ struct AxisValue
   {
     switch (u.format)
     {
-    case 1: return u.format1.get_value_name_id ();
-    case 2: return u.format2.get_value_name_id ();
-    case 3: return u.format3.get_value_name_id ();
-    case 4: return u.format4.get_value_name_id ();
+    case 1: hb_barrier (); return u.format1.get_value_name_id ();
+    case 2: hb_barrier (); return u.format2.get_value_name_id ();
+    case 3: hb_barrier (); return u.format3.get_value_name_id ();
+    case 4: hb_barrier (); return u.format4.get_value_name_id ();
     default:return HB_OT_NAME_ID_INVALID;
     }
   }
@@ -392,10 +392,10 @@ struct AxisValue
     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
-    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -405,10 +405,10 @@ struct AxisValue
   {
     switch (u.format)
     {
-    case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
-    case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
-    case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
-    case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
+    case 1: hb_barrier (); return u.format1.keep_axis_value (axis_records, user_axes_location);
+    case 2: hb_barrier (); return u.format2.keep_axis_value (axis_records, user_axes_location);
+    case 3: hb_barrier (); return u.format3.keep_axis_value (axis_records, user_axes_location);
+    case 4: hb_barrier (); return u.format4.keep_axis_value (axis_records, user_axes_location);
     default:return false;
     }
   }
@@ -422,10 +422,10 @@ struct AxisValue
 
     switch (u.format)
     {
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 3: return_trace (u.format3.sanitize (c));
-    case 4: return_trace (u.format4.sanitize (c));
+    case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
+    case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
+    case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
+    case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
     default:return_trace (true);
     }
   }

+ 56 - 10
thirdparty/harfbuzz/src/hb-ot-tag-table.hh

@@ -6,8 +6,8 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2023-09-30 01:21 AM" />
- * File-Date: 2024-03-07
+ * <meta name="updated_at" content="2024-05-31 05:41 PM" />
+ * File-Date: 2024-05-16
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
@@ -26,7 +26,7 @@ static const LangTag ot_languages2[] = {
   {HB_TAG('a','y',' ',' '),	HB_TAG('A','Y','M',' ')},	/* Aymara [macrolanguage] */
   {HB_TAG('a','z',' ',' '),	HB_TAG('A','Z','E',' ')},	/* Azerbaijani [macrolanguage] */
   {HB_TAG('b','a',' ',' '),	HB_TAG('B','S','H',' ')},	/* Bashkir */
-  {HB_TAG('b','e',' ',' '),	HB_TAG('B','E','L',' ')},	/* Belarusian -> Belarussian */
+  {HB_TAG('b','e',' ',' '),	HB_TAG('B','E','L',' ')},	/* Belarusian */
   {HB_TAG('b','g',' ',' '),	HB_TAG('B','G','R',' ')},	/* Bulgarian */
   {HB_TAG('b','i',' ',' '),	HB_TAG('B','I','S',' ')},	/* Bislama */
   {HB_TAG('b','i',' ',' '),	HB_TAG('C','P','P',' ')},	/* Bislama -> Creoles */
@@ -64,6 +64,7 @@ static const LangTag ot_languages2[] = {
   {HB_TAG('f','r',' ',' '),	HB_TAG('F','R','A',' ')},	/* French */
   {HB_TAG('f','y',' ',' '),	HB_TAG('F','R','I',' ')},	/* Western Frisian -> Frisian */
   {HB_TAG('g','a',' ',' '),	HB_TAG('I','R','I',' ')},	/* Irish */
+  {HB_TAG('g','a',' ',' '),	HB_TAG('I','R','T',' ')},	/* Irish -> Irish Traditional */
   {HB_TAG('g','d',' ',' '),	HB_TAG('G','A','E',' ')},	/* Scottish Gaelic */
   {HB_TAG('g','l',' ',' '),	HB_TAG('G','A','L',' ')},	/* Galician */
   {HB_TAG('g','n',' ',' '),	HB_TAG('G','U','A',' ')},	/* Guarani [macrolanguage] */
@@ -132,7 +133,7 @@ static const LangTag ot_languages2[] = {
   {HB_TAG('m','l',' ',' '),	HB_TAG('M','A','L',' ')},	/* Malayalam -> Malayalam Traditional */
   {HB_TAG('m','l',' ',' '),	HB_TAG('M','L','R',' ')},	/* Malayalam -> Malayalam Reformed */
   {HB_TAG('m','n',' ',' '),	HB_TAG('M','N','G',' ')},	/* Mongolian [macrolanguage] */
-  {HB_TAG('m','o',' ',' '),	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) -> Romanian (Moldova) */
+  {HB_TAG('m','o',' ',' '),	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) */
   {HB_TAG('m','o',' ',' '),	HB_TAG('R','O','M',' ')},	/* Moldavian (retired code) -> Romanian */
   {HB_TAG('m','r',' ',' '),	HB_TAG('M','A','R',' ')},	/* Marathi */
   {HB_TAG('m','s',' ',' '),	HB_TAG('M','L','Y',' ')},	/* Malay [macrolanguage] */
@@ -223,6 +224,7 @@ static const LangTag ot_languages2[] = {
 static const LangTag ot_languages3[] = {
   {HB_TAG('a','a','e',' '),	HB_TAG('S','Q','I',' ')},	/* Arbëreshë Albanian -> Albanian */
   {HB_TAG('a','a','o',' '),	HB_TAG('A','R','A',' ')},	/* Algerian Saharan Arabic -> Arabic */
+/*{HB_TAG('a','a','q',' '),	HB_TAG('A','A','Q',' ')},*/	/* Eastern Abnaki -> Eastern Abenaki */
   {HB_TAG('a','a','t',' '),	HB_TAG('S','Q','I',' ')},	/* Arvanitika Albanian -> Albanian */
   {HB_TAG('a','b','a',' '),	HB_TAG_NONE	       },	/* Abé != Abaza */
   {HB_TAG('a','b','h',' '),	HB_TAG('A','R','A',' ')},	/* Tajiki Arabic -> Arabic */
@@ -238,6 +240,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('a','c','r',' '),	HB_TAG('M','Y','N',' ')},	/* Achi -> Mayan */
   {HB_TAG('a','c','w',' '),	HB_TAG('A','R','A',' ')},	/* Hijazi Arabic -> Arabic */
   {HB_TAG('a','c','x',' '),	HB_TAG('A','R','A',' ')},	/* Omani Arabic -> Arabic */
+  {HB_TAG('a','c','y',' '),	HB_TAG('A','C','Y',' ')},	/* Cypriot Arabic */
   {HB_TAG('a','c','y',' '),	HB_TAG('A','R','A',' ')},	/* Cypriot Arabic -> Arabic */
   {HB_TAG('a','d','a',' '),	HB_TAG('D','N','G',' ')},	/* Adangme -> Dangme */
   {HB_TAG('a','d','f',' '),	HB_TAG('A','R','A',' ')},	/* Dhofari Arabic -> Arabic */
@@ -288,6 +291,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('a','s','t',' '),	HB_TAG('A','S','T',' ')},*/	/* Asturian */
 /*{HB_TAG('a','t','h',' '),	HB_TAG('A','T','H',' ')},*/	/* Athapascan [collection] -> Athapaskan */
   {HB_TAG('a','t','j',' '),	HB_TAG('R','C','R',' ')},	/* Atikamekw -> R-Cree */
+/*{HB_TAG('a','t','s',' '),	HB_TAG('A','T','S',' ')},*/	/* Gros Ventre (Atsina) */
   {HB_TAG('a','t','v',' '),	HB_TAG('A','L','T',' ')},	/* Northern Altai -> Altai */
   {HB_TAG('a','u','j',' '),	HB_TAG('B','B','R',' ')},	/* Awjilah -> Berber */
   {HB_TAG('a','u','z',' '),	HB_TAG('A','R','A',' ')},	/* Uzbeki Arabic -> Arabic */
@@ -326,6 +330,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('b','c','l',' '),	HB_TAG('B','I','K',' ')},	/* Central Bikol -> Bikol */
   {HB_TAG('b','c','q',' '),	HB_TAG('B','C','H',' ')},	/* Bench */
   {HB_TAG('b','c','r',' '),	HB_TAG('A','T','H',' ')},	/* Babine -> Athapaskan */
+/*{HB_TAG('b','d','c',' '),	HB_TAG('B','D','C',' ')},*/	/* Emberá-Baudó */
 /*{HB_TAG('b','d','y',' '),	HB_TAG('B','D','Y',' ')},*/	/* Bandjalang */
   {HB_TAG('b','e','a',' '),	HB_TAG('A','T','H',' ')},	/* Beaver -> Athapaskan */
   {HB_TAG('b','e','b',' '),	HB_TAG('B','T','I',' ')},	/* Bebele -> Beti */
@@ -421,6 +426,8 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('c','a','f',' '),	HB_TAG('A','T','H',' ')},	/* Southern Carrier -> Athapaskan */
   {HB_TAG('c','a','k',' '),	HB_TAG('C','A','K',' ')},	/* Kaqchikel */
   {HB_TAG('c','a','k',' '),	HB_TAG('M','Y','N',' ')},	/* Kaqchikel -> Mayan */
+/*{HB_TAG('c','a','y',' '),	HB_TAG('C','A','Y',' ')},*/	/* Cayuga */
+/*{HB_TAG('c','b','g',' '),	HB_TAG('C','B','G',' ')},*/	/* Chimila */
   {HB_TAG('c','b','k',' '),	HB_TAG('C','B','K',' ')},	/* Chavacano -> Zamboanga Chavacano */
   {HB_TAG('c','b','k',' '),	HB_TAG('C','P','P',' ')},	/* Chavacano -> Creoles */
   {HB_TAG('c','b','l',' '),	HB_TAG('Q','I','N',' ')},	/* Bualkhaw Chin -> Chin */
@@ -467,6 +474,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('c','l','j',' '),	HB_TAG('Q','I','N',' ')},	/* Laitu Chin -> Chin */
   {HB_TAG('c','l','s',' '),	HB_TAG('S','A','N',' ')},	/* Classical Sanskrit -> Sanskrit */
   {HB_TAG('c','l','t',' '),	HB_TAG('Q','I','N',' ')},	/* Lautu Chin -> Chin */
+/*{HB_TAG('c','m','i',' '),	HB_TAG('C','M','I',' ')},*/	/* Emberá-Chamí */
   {HB_TAG('c','m','n',' '),	HB_TAG('Z','H','S',' ')},	/* Mandarin Chinese -> Chinese, Simplified */
   {HB_TAG('c','m','r',' '),	HB_TAG('Q','I','N',' ')},	/* Mro-Khimi Chin -> Chin */
   {HB_TAG('c','n','b',' '),	HB_TAG('Q','I','N',' ')},	/* Chinbon Chin -> Chin */
@@ -480,6 +488,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('c','n','w',' '),	HB_TAG('Q','I','N',' ')},	/* Ngawn Chin -> Chin */
   {HB_TAG('c','o','a',' '),	HB_TAG('M','L','Y',' ')},	/* Cocos Islands Malay -> Malay */
   {HB_TAG('c','o','b',' '),	HB_TAG('M','Y','N',' ')},	/* Chicomuceltec -> Mayan */
+/*{HB_TAG('c','o','o',' '),	HB_TAG('C','O','O',' ')},*/	/* Comox */
 /*{HB_TAG('c','o','p',' '),	HB_TAG('C','O','P',' ')},*/	/* Coptic */
   {HB_TAG('c','o','q',' '),	HB_TAG('A','T','H',' ')},	/* Coquille -> Athapaskan */
   {HB_TAG('c','p','a',' '),	HB_TAG('C','C','H','N')},	/* Palantla Chinantec -> Chinantec */
@@ -529,6 +538,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('c','t','g',' '),	HB_TAG('C','T','G',' ')},*/	/* Chittagonian */
   {HB_TAG('c','t','h',' '),	HB_TAG('Q','I','N',' ')},	/* Thaiphum Chin -> Chin */
   {HB_TAG('c','t','l',' '),	HB_TAG('C','C','H','N')},	/* Tlacoatzintepec Chinantec -> Chinantec */
+/*{HB_TAG('c','t','o',' '),	HB_TAG('C','T','O',' ')},*/	/* Emberá-Catío */
   {HB_TAG('c','t','s',' '),	HB_TAG('B','I','K',' ')},	/* Northern Catanduanes Bikol -> Bikol */
 /*{HB_TAG('c','t','t',' '),	HB_TAG('C','T','T',' ')},*/	/* Wayanad Chetti */
   {HB_TAG('c','t','u',' '),	HB_TAG('M','Y','N',' ')},	/* Chol -> Mayan */
@@ -552,7 +562,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('d','e','p',' '),	HB_TAG('C','P','P',' ')},	/* Pidgin Delaware -> Creoles */
   {HB_TAG('d','g','o',' '),	HB_TAG('D','G','O',' ')},	/* Dogri (individual language) */
   {HB_TAG('d','g','o',' '),	HB_TAG('D','G','R',' ')},	/* Dogri (macrolanguage) */
-  {HB_TAG('d','g','r',' '),	HB_TAG('A','T','H',' ')},	/* Dogrib -> Athapaskan */
+  {HB_TAG('d','g','r',' '),	HB_TAG('A','T','H',' ')},	/* Tlicho -> Athapaskan */
   {HB_TAG('d','h','d',' '),	HB_TAG('M','A','W',' ')},	/* Dhundari -> Marwari */
 /*{HB_TAG('d','h','g',' '),	HB_TAG('D','H','G',' ')},*/	/* Dhangu */
   {HB_TAG('d','h','v',' '),	HB_TAG_NONE	       },	/* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */
@@ -591,6 +601,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('e','k','y',' '),	HB_TAG('K','R','N',' ')},	/* Eastern Kayah -> Karen */
   {HB_TAG('e','m','k',' '),	HB_TAG('E','M','K',' ')},	/* Eastern Maninkakan */
   {HB_TAG('e','m','k',' '),	HB_TAG('M','N','K',' ')},	/* Eastern Maninkakan -> Maninka */
+/*{HB_TAG('e','m','p',' '),	HB_TAG('E','M','P',' ')},*/	/* Northern Emberá */
   {HB_TAG('e','m','y',' '),	HB_TAG('M','Y','N',' ')},	/* Epigraphic Mayan -> Mayan */
   {HB_TAG('e','n','b',' '),	HB_TAG('K','A','L',' ')},	/* Markweeta -> Kalenjin */
   {HB_TAG('e','n','f',' '),	HB_TAG('F','N','E',' ')},	/* Forest Enets */
@@ -655,6 +666,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('g','e','z',' '),	HB_TAG('G','E','Z',' ')},*/	/* Geez */
   {HB_TAG('g','g','o',' '),	HB_TAG('G','O','N',' ')},	/* Southern Gondi (retired code) -> Gondi */
   {HB_TAG('g','h','a',' '),	HB_TAG('B','B','R',' ')},	/* Ghadamès -> Berber */
+  {HB_TAG('g','h','c',' '),	HB_TAG('I','R','T',' ')},	/* Hiberno-Scottish Gaelic -> Irish Traditional */
   {HB_TAG('g','h','k',' '),	HB_TAG('K','R','N',' ')},	/* Geko Karen -> Karen */
   {HB_TAG('g','h','o',' '),	HB_TAG('B','B','R',' ')},	/* Ghomara -> Berber */
   {HB_TAG('g','i','b',' '),	HB_TAG('C','P','P',' ')},	/* Gibanawa -> Creoles */
@@ -744,6 +756,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('h','s','n',' '),	HB_TAG('Z','H','S',' ')},	/* Xiang Chinese -> Chinese, Simplified */
   {HB_TAG('h','u','j',' '),	HB_TAG('H','M','N',' ')},	/* Northern Guiyang Hmong -> Hmong */
   {HB_TAG('h','u','p',' '),	HB_TAG('A','T','H',' ')},	/* Hupa -> Athapaskan */
+/*{HB_TAG('h','u','r',' '),	HB_TAG('H','U','R',' ')},*/	/* Halkomelem */
   {HB_TAG('h','u','s',' '),	HB_TAG('M','Y','N',' ')},	/* Huastec -> Mayan */
   {HB_TAG('h','w','c',' '),	HB_TAG('C','P','P',' ')},	/* Hawai'i Creole English -> Creoles */
   {HB_TAG('h','y','w',' '),	HB_TAG('H','Y','E',' ')},	/* Western Armenian -> Armenian */
@@ -781,6 +794,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('j','b','n',' '),	HB_TAG('B','B','R',' ')},	/* Nafusi -> Berber */
 /*{HB_TAG('j','b','o',' '),	HB_TAG('J','B','O',' ')},*/	/* Lojban */
 /*{HB_TAG('j','c','t',' '),	HB_TAG('J','C','T',' ')},*/	/* Krymchak */
+/*{HB_TAG('j','d','t',' '),	HB_TAG('J','D','T',' ')},*/	/* Judeo-Tat */
   {HB_TAG('j','g','o',' '),	HB_TAG('B','M','L',' ')},	/* Ngomba -> Bamileke */
   {HB_TAG('j','i','i',' '),	HB_TAG_NONE	       },	/* Jiiddu != Yiddish */
   {HB_TAG('j','k','m',' '),	HB_TAG('K','R','N',' ')},	/* Mobwa Karen -> Karen */
@@ -795,6 +809,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('k','a','m',' '),	HB_TAG('K','M','B',' ')},	/* Kamba (Kenya) */
   {HB_TAG('k','a','r',' '),	HB_TAG('K','R','N',' ')},	/* Karen [collection] */
 /*{HB_TAG('k','a','w',' '),	HB_TAG('K','A','W',' ')},*/	/* Kawi (Old Javanese) */
+/*{HB_TAG('k','b','c',' '),	HB_TAG('K','B','C',' ')},*/	/* Kadiwéu */
   {HB_TAG('k','b','d',' '),	HB_TAG('K','A','B',' ')},	/* Kabardian */
   {HB_TAG('k','b','y',' '),	HB_TAG('K','N','R',' ')},	/* Manga Kanuri -> Kanuri */
   {HB_TAG('k','c','a',' '),	HB_TAG('K','H','K',' ')},	/* Khanty -> Khanty-Kazim */
@@ -830,6 +845,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('k','j','b',' '),	HB_TAG('M','Y','N',' ')},	/* Q'anjob'al -> Mayan */
 /*{HB_TAG('k','j','d',' '),	HB_TAG('K','J','D',' ')},*/	/* Southern Kiwai */
   {HB_TAG('k','j','h',' '),	HB_TAG('K','H','A',' ')},	/* Khakas -> Khakass */
+/*{HB_TAG('k','j','j',' '),	HB_TAG('K','J','J',' ')},*/	/* Khinalugh -> Khinalug */
   {HB_TAG('k','j','p',' '),	HB_TAG('K','J','P',' ')},	/* Pwo Eastern Karen -> Eastern Pwo Karen */
   {HB_TAG('k','j','p',' '),	HB_TAG('K','R','N',' ')},	/* Pwo Eastern Karen -> Karen */
   {HB_TAG('k','j','t',' '),	HB_TAG('K','R','N',' ')},	/* Phrae Pwo Karen -> Karen */
@@ -931,6 +947,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('l','i','j',' '),	HB_TAG('L','I','J',' ')},*/	/* Ligurian */
   {HB_TAG('l','i','r',' '),	HB_TAG('C','P','P',' ')},	/* Liberian English -> Creoles */
 /*{HB_TAG('l','i','s',' '),	HB_TAG('L','I','S',' ')},*/	/* Lisu */
+/*{HB_TAG('l','i','v',' '),	HB_TAG('L','I','V',' ')},*/	/* Liv */
   {HB_TAG('l','i','w',' '),	HB_TAG('M','L','Y',' ')},	/* Col -> Malay */
   {HB_TAG('l','i','y',' '),	HB_TAG('B','A','D','0')},	/* Banda-Bambari -> Banda */
 /*{HB_TAG('l','j','p',' '),	HB_TAG('L','J','P',' ')},*/	/* Lampung Api -> Lampung */
@@ -996,12 +1013,14 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('m','e','n',' '),	HB_TAG('M','D','E',' ')},	/* Mende (Sierra Leone) */
   {HB_TAG('m','e','o',' '),	HB_TAG('M','L','Y',' ')},	/* Kedah Malay -> Malay */
 /*{HB_TAG('m','e','r',' '),	HB_TAG('M','E','R',' ')},*/	/* Meru */
+/*{HB_TAG('m','e','v',' '),	HB_TAG('M','E','V',' ')},*/	/* Mano */
   {HB_TAG('m','f','a',' '),	HB_TAG('M','F','A',' ')},	/* Pattani Malay */
   {HB_TAG('m','f','a',' '),	HB_TAG('M','L','Y',' ')},	/* Pattani Malay -> Malay */
   {HB_TAG('m','f','b',' '),	HB_TAG('M','L','Y',' ')},	/* Bangka -> Malay */
   {HB_TAG('m','f','e',' '),	HB_TAG('M','F','E',' ')},	/* Morisyen */
   {HB_TAG('m','f','e',' '),	HB_TAG('C','P','P',' ')},	/* Morisyen -> Creoles */
   {HB_TAG('m','f','p',' '),	HB_TAG('C','P','P',' ')},	/* Makassar Malay -> Creoles */
+  {HB_TAG('m','g','a',' '),	HB_TAG('S','G','A',' ')},	/* Middle Irish (900-1200) -> Old Irish */
   {HB_TAG('m','h','c',' '),	HB_TAG('M','Y','N',' ')},	/* Mocho -> Mayan */
   {HB_TAG('m','h','r',' '),	HB_TAG('L','M','A',' ')},	/* Eastern Mari -> Low Mari */
   {HB_TAG('m','h','v',' '),	HB_TAG('A','R','K',' ')},	/* Arakanese (retired code) -> Rakhine */
@@ -1154,6 +1173,8 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('o','k','i',' '),	HB_TAG('K','A','L',' ')},	/* Okiek -> Kalenjin */
   {HB_TAG('o','k','m',' '),	HB_TAG('K','O','H',' ')},	/* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
   {HB_TAG('o','k','r',' '),	HB_TAG('I','J','O',' ')},	/* Kirike -> Ijo */
+/*{HB_TAG('o','n','e',' '),	HB_TAG('O','N','E',' ')},*/	/* Oneida */
+/*{HB_TAG('o','n','o',' '),	HB_TAG('O','N','O',' ')},*/	/* Onondaga */
   {HB_TAG('o','n','x',' '),	HB_TAG('C','P','P',' ')},	/* Onin Based Pidgin -> Creoles */
   {HB_TAG('o','o','r',' '),	HB_TAG('C','P','P',' ')},	/* Oorlams -> Creoles */
   {HB_TAG('o','r','c',' '),	HB_TAG('O','R','O',' ')},	/* Orma -> Oromo */
@@ -1194,7 +1215,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('p','i','s',' '),	HB_TAG('C','P','P',' ')},	/* Pijin -> Creoles */
   {HB_TAG('p','k','h',' '),	HB_TAG('Q','I','N',' ')},	/* Pankhu -> Chin */
   {HB_TAG('p','k','o',' '),	HB_TAG('K','A','L',' ')},	/* Pökoot -> Kalenjin */
-  {HB_TAG('p','l','g',' '),	HB_TAG_NONE	       },	/* Pilagá != Palaung */
+  {HB_TAG('p','l','g',' '),	HB_TAG('P','L','G','0')},	/* Pilagá */
   {HB_TAG('p','l','k',' '),	HB_TAG_NONE	       },	/* Kohistani Shina != Polish */
   {HB_TAG('p','l','l',' '),	HB_TAG('P','L','G',' ')},	/* Shwe Palaung -> Palaung */
   {HB_TAG('p','l','n',' '),	HB_TAG('C','P','P',' ')},	/* Palenquero -> Creoles */
@@ -1354,6 +1375,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('s','d','h',' '),	HB_TAG('K','U','R',' ')},	/* Southern Kurdish -> Kurdish */
   {HB_TAG('s','d','n',' '),	HB_TAG('S','R','D',' ')},	/* Gallurese Sardinian -> Sardinian */
   {HB_TAG('s','d','s',' '),	HB_TAG('B','B','R',' ')},	/* Sened -> Berber */
+/*{HB_TAG('s','e','e',' '),	HB_TAG('S','E','E',' ')},*/	/* Seneca */
   {HB_TAG('s','e','h',' '),	HB_TAG('S','N','A',' ')},	/* Sena */
   {HB_TAG('s','e','k',' '),	HB_TAG('A','T','H',' ')},	/* Sekani -> Athapaskan */
 /*{HB_TAG('s','e','l',' '),	HB_TAG('S','E','L',' ')},*/	/* Selkup */
@@ -1375,6 +1397,7 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('s','i','d',' '),	HB_TAG('S','I','D',' ')},*/	/* Sidamo */
   {HB_TAG('s','i','g',' '),	HB_TAG_NONE	       },	/* Paasaal != Silte Gurage */
   {HB_TAG('s','i','z',' '),	HB_TAG('B','B','R',' ')},	/* Siwi -> Berber */
+/*{HB_TAG('s','j','a',' '),	HB_TAG('S','J','A',' ')},*/	/* Epena */
   {HB_TAG('s','j','d',' '),	HB_TAG('K','S','M',' ')},	/* Kildin Sami */
   {HB_TAG('s','j','o',' '),	HB_TAG('S','I','B',' ')},	/* Xibe -> Sibe */
   {HB_TAG('s','j','s',' '),	HB_TAG('B','B','R',' ')},	/* Senhaja De Srair -> Berber */
@@ -1411,6 +1434,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('s','s','m',' '),	HB_TAG_NONE	       },	/* Semnam != Southern Sami */
   {HB_TAG('s','t','a',' '),	HB_TAG('C','P','P',' ')},	/* Settla -> Creoles */
 /*{HB_TAG('s','t','q',' '),	HB_TAG('S','T','Q',' ')},*/	/* Saterfriesisch -> Saterland Frisian */
+/*{HB_TAG('s','t','r',' '),	HB_TAG('S','T','R',' ')},*/	/* Straits Salish */
   {HB_TAG('s','t','v',' '),	HB_TAG('S','I','G',' ')},	/* Silt'e -> Silte Gurage */
 /*{HB_TAG('s','u','k',' '),	HB_TAG('S','U','K',' ')},*/	/* Sukuma */
   {HB_TAG('s','u','q',' '),	HB_TAG('S','U','R',' ')},	/* Suri */
@@ -1432,6 +1456,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('t','a','a',' '),	HB_TAG('A','T','H',' ')},	/* Lower Tanana -> Athapaskan */
 /*{HB_TAG('t','a','b',' '),	HB_TAG('T','A','B',' ')},*/	/* Tabassaran -> Tabasaran */
   {HB_TAG('t','a','j',' '),	HB_TAG_NONE	       },	/* Eastern Tamang != Tajiki */
+  {HB_TAG('t','a','q',' '),	HB_TAG('T','A','Q',' ')},	/* Tamasheq */
   {HB_TAG('t','a','q',' '),	HB_TAG('T','M','H',' ')},	/* Tamasheq -> Tamashek */
   {HB_TAG('t','a','q',' '),	HB_TAG('B','B','R',' ')},	/* Tamasheq -> Berber */
   {HB_TAG('t','a','s',' '),	HB_TAG('C','P','P',' ')},	/* Tay Boi -> Creoles */
@@ -1443,6 +1468,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('t','c','s',' '),	HB_TAG('C','P','P',' ')},	/* Torres Strait Creole -> Creoles */
   {HB_TAG('t','c','y',' '),	HB_TAG('T','U','L',' ')},	/* Tulu */
   {HB_TAG('t','c','z',' '),	HB_TAG('Q','I','N',' ')},	/* Thado Chin -> Chin */
+/*{HB_TAG('t','d','c',' '),	HB_TAG('T','D','C',' ')},*/	/* Emberá-Tadó */
 /*{HB_TAG('t','d','d',' '),	HB_TAG('T','D','D',' ')},*/	/* Tai Nüa -> Dehong Dai */
   {HB_TAG('t','d','x',' '),	HB_TAG('M','L','G',' ')},	/* Tandroy-Mahafaly Malagasy -> Malagasy */
   {HB_TAG('t','e','c',' '),	HB_TAG('K','A','L',' ')},	/* Terik -> Kalenjin */
@@ -1456,9 +1482,12 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('t','g','r',' '),	HB_TAG_NONE	       },	/* Tareng != Tigre */
   {HB_TAG('t','g','x',' '),	HB_TAG('A','T','H',' ')},	/* Tagish -> Athapaskan */
   {HB_TAG('t','g','y',' '),	HB_TAG_NONE	       },	/* Togoyo != Tigrinya */
+/*{HB_TAG('t','h','p',' '),	HB_TAG('T','H','P',' ')},*/	/* Thompson */
   {HB_TAG('t','h','t',' '),	HB_TAG('A','T','H',' ')},	/* Tahltan -> Athapaskan */
+  {HB_TAG('t','h','v',' '),	HB_TAG('T','H','V',' ')},	/* Tahaggart Tamahaq */
   {HB_TAG('t','h','v',' '),	HB_TAG('T','M','H',' ')},	/* Tahaggart Tamahaq -> Tamashek */
   {HB_TAG('t','h','v',' '),	HB_TAG('B','B','R',' ')},	/* Tahaggart Tamahaq -> Berber */
+  {HB_TAG('t','h','z',' '),	HB_TAG('T','H','Z',' ')},	/* Tayart Tamajeq */
   {HB_TAG('t','h','z',' '),	HB_TAG('T','M','H',' ')},	/* Tayart Tamajeq -> Tamashek */
   {HB_TAG('t','h','z',' '),	HB_TAG('B','B','R',' ')},	/* Tayart Tamajeq -> Berber */
   {HB_TAG('t','i','a',' '),	HB_TAG('B','B','R',' ')},	/* Tidikelt Tamazight -> Berber */
@@ -1469,6 +1498,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('t','k','g',' '),	HB_TAG('M','L','G',' ')},	/* Tesaka Malagasy -> Malagasy */
   {HB_TAG('t','k','m',' '),	HB_TAG_NONE	       },	/* Takelma != Turkmen */
 /*{HB_TAG('t','l','i',' '),	HB_TAG('T','L','I',' ')},*/	/* Tlingit */
+/*{HB_TAG('t','l','y',' '),	HB_TAG('T','L','Y',' ')},*/	/* Talysh */
   {HB_TAG('t','m','g',' '),	HB_TAG('C','P','P',' ')},	/* Ternateño -> Creoles */
   {HB_TAG('t','m','h',' '),	HB_TAG('T','M','H',' ')},	/* Tamashek [macrolanguage] */
   {HB_TAG('t','m','h',' '),	HB_TAG('B','B','R',' ')},	/* Tamashek [macrolanguage] -> Berber */
@@ -1494,11 +1524,13 @@ static const LangTag ot_languages3[] = {
 /*{HB_TAG('t','s','j',' '),	HB_TAG('T','S','J',' ')},*/	/* Tshangla */
   {HB_TAG('t','t','c',' '),	HB_TAG('M','Y','N',' ')},	/* Tektiteko -> Mayan */
   {HB_TAG('t','t','m',' '),	HB_TAG('A','T','H',' ')},	/* Northern Tutchone -> Athapaskan */
+  {HB_TAG('t','t','q',' '),	HB_TAG('T','T','Q',' ')},	/* Tawallammat Tamajaq */
   {HB_TAG('t','t','q',' '),	HB_TAG('T','M','H',' ')},	/* Tawallammat Tamajaq -> Tamashek */
   {HB_TAG('t','t','q',' '),	HB_TAG('B','B','R',' ')},	/* Tawallammat Tamajaq -> Berber */
   {HB_TAG('t','u','a',' '),	HB_TAG_NONE	       },	/* Wiarumus != Turoyo Aramaic */
   {HB_TAG('t','u','l',' '),	HB_TAG_NONE	       },	/* Tula != Tulu */
 /*{HB_TAG('t','u','m',' '),	HB_TAG('T','U','M',' ')},*/	/* Tumbuka */
+/*{HB_TAG('t','u','s',' '),	HB_TAG('T','U','S',' ')},*/	/* Tuscarora */
   {HB_TAG('t','u','u',' '),	HB_TAG('A','T','H',' ')},	/* Tututni -> Athapaskan */
   {HB_TAG('t','u','v',' '),	HB_TAG_NONE	       },	/* Turkana != Tuvin */
   {HB_TAG('t','u','y',' '),	HB_TAG('K','A','L',' ')},	/* Tugen -> Kalenjin */
@@ -1515,6 +1547,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('t','z','o',' '),	HB_TAG('T','Z','O',' ')},	/* Tzotzil */
   {HB_TAG('t','z','o',' '),	HB_TAG('M','Y','N',' ')},	/* Tzotzil -> Mayan */
   {HB_TAG('u','b','l',' '),	HB_TAG('B','I','K',' ')},	/* Buhi'non Bikol -> Bikol */
+/*{HB_TAG('u','d','i',' '),	HB_TAG('U','D','I',' ')},*/	/* Udi */
 /*{HB_TAG('u','d','m',' '),	HB_TAG('U','D','M',' ')},*/	/* Udmurt */
   {HB_TAG('u','k','i',' '),	HB_TAG('K','U','I',' ')},	/* Kui (India) */
   {HB_TAG('u','l','n',' '),	HB_TAG('C','P','P',' ')},	/* Unserdeutsch -> Creoles */
@@ -1533,14 +1566,17 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('v','k','t',' '),	HB_TAG('M','L','Y',' ')},	/* Tenggarong Kutai Malay -> Malay */
   {HB_TAG('v','l','s',' '),	HB_TAG('F','L','E',' ')},	/* Vlaams -> Dutch (Flemish) */
   {HB_TAG('v','m','w',' '),	HB_TAG('M','A','K',' ')},	/* Makhuwa */
-/*{HB_TAG('v','r','o',' '),	HB_TAG('V','R','O',' ')},*/	/* Võro */
+  {HB_TAG('v','r','o',' '),	HB_TAG('V','R','O',' ')},	/* Võro */
+  {HB_TAG('v','r','o',' '),	HB_TAG('E','T','I',' ')},	/* Võro -> Estonian */
   {HB_TAG('v','s','n',' '),	HB_TAG('S','A','N',' ')},	/* Vedic Sanskrit -> Sanskrit */
   {HB_TAG('w','a','g',' '),	HB_TAG_NONE	       },	/* Wa'ema != Wagdi */
 /*{HB_TAG('w','a','r',' '),	HB_TAG('W','A','R',' ')},*/	/* Waray (Philippines) -> Waray-Waray */
+/*{HB_TAG('w','b','l',' '),	HB_TAG('W','B','L',' ')},*/	/* Wakhi */
   {HB_TAG('w','b','m',' '),	HB_TAG('W','A',' ',' ')},	/* Wa */
   {HB_TAG('w','b','r',' '),	HB_TAG('W','A','G',' ')},	/* Wagdi */
   {HB_TAG('w','b','r',' '),	HB_TAG('R','A','J',' ')},	/* Wagdi -> Rajasthani */
 /*{HB_TAG('w','c','i',' '),	HB_TAG('W','C','I',' ')},*/	/* Waci Gbe */
+/*{HB_TAG('w','d','t',' '),	HB_TAG('W','D','T',' ')},*/	/* Wendat */
   {HB_TAG('w','e','a',' '),	HB_TAG('K','R','N',' ')},	/* Wewaw -> Karen */
   {HB_TAG('w','e','s',' '),	HB_TAG('C','P','P',' ')},	/* Cameroon Pidgin -> Creoles */
   {HB_TAG('w','e','u',' '),	HB_TAG('Q','I','N',' ')},	/* Rawngtu Chin -> Chin */
@@ -1552,6 +1588,9 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('w','s','g',' '),	HB_TAG('G','O','N',' ')},	/* Adilabad Gondi -> Gondi */
 /*{HB_TAG('w','t','m',' '),	HB_TAG('W','T','M',' ')},*/	/* Mewati */
   {HB_TAG('w','u','u',' '),	HB_TAG('Z','H','S',' ')},	/* Wu Chinese -> Chinese, Simplified */
+  {HB_TAG('w','y','a',' '),	HB_TAG('W','D','T',' ')},	/* Wyandot (retired code) -> Wendat */
+  {HB_TAG('w','y','a',' '),	HB_TAG('W','Y','N',' ')},	/* Wyandot (retired code) */
+/*{HB_TAG('w','y','n',' '),	HB_TAG('W','Y','N',' ')},*/	/* Wyandot */
   {HB_TAG('x','a','l',' '),	HB_TAG('K','L','M',' ')},	/* Kalmyk */
   {HB_TAG('x','a','l',' '),	HB_TAG('T','O','D',' ')},	/* Kalmyk -> Todo */
   {HB_TAG('x','a','n',' '),	HB_TAG('S','E','K',' ')},	/* Xamtanga -> Sekota */
@@ -1593,6 +1632,7 @@ static const LangTag ot_languages3[] = {
   {HB_TAG('y','o','s',' '),	HB_TAG('Q','I','N',' ')},	/* Yos (retired code) -> Chin */
   {HB_TAG('y','u','a',' '),	HB_TAG('M','Y','N',' ')},	/* Yucateco -> Mayan */
   {HB_TAG('y','u','e',' '),	HB_TAG('Z','H','H',' ')},	/* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
+/*{HB_TAG('y','u','f',' '),	HB_TAG('Y','U','F',' ')},*/	/* Havasupai-Walapai-Yavapai */
 /*{HB_TAG('y','w','q',' '),	HB_TAG('Y','W','Q',' ')},*/	/* Wuding-Luquan Yi */
   {HB_TAG('z','c','h',' '),	HB_TAG('Z','H','A',' ')},	/* Central Hongshuihe Zhuang -> Zhuang */
   {HB_TAG('z','d','j',' '),	HB_TAG('C','M','R',' ')},	/* Ngazidja Comorian -> Comorian */
@@ -2645,7 +2685,7 @@ out:
       /* Romanian; Moldova */
       unsigned int i;
       hb_tag_t possible_tags[] = {
-	HB_TAG('M','O','L',' '),  /* Romanian (Moldova) */
+	HB_TAG('M','O','L',' '),  /* Moldavian */
 	HB_TAG('R','O','M',' '),  /* Romanian */
       };
       for (i = 0; i < 2 && i < *count; i++)
@@ -2872,7 +2912,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
   case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
     return hb_language_from_string ("und-fonipa", -1);  /* Undetermined; International Phonetic Alphabet */
   case HB_TAG('I','R','T',' '):  /* Irish Traditional */
-    return hb_language_from_string ("ga-Latg", -1);  /* Irish; Latin (Gaelic variant) */
+    return hb_language_from_string ("ghc", -1);  /* Hiberno-Scottish Gaelic */
   case HB_TAG('J','I','I',' '):  /* Yiddish */
     return hb_language_from_string ("yi", -1);  /* Yiddish [macrolanguage] */
   case HB_TAG('K','A','L',' '):  /* Kalenjin */
@@ -2899,7 +2939,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
     return hb_language_from_string ("ms", -1);  /* Malay [macrolanguage] */
   case HB_TAG('M','N','K',' '):  /* Maninka */
     return hb_language_from_string ("man", -1);  /* Mandingo [macrolanguage] */
-  case HB_TAG('M','O','L',' '):  /* Romanian (Moldova) */
+  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 */
@@ -2927,6 +2967,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
     return hb_language_from_string ("ro", -1);  /* Romanian */
   case HB_TAG('R','O','Y',' '):  /* Romany */
     return hb_language_from_string ("rom", -1);  /* Romany [macrolanguage] */
+  case HB_TAG('S','G','A',' '):  /* Old Irish */
+    return hb_language_from_string ("sga", -1);  /* Old Irish (to 900) */
   case HB_TAG('S','R','B',' '):  /* Serbian */
     return hb_language_from_string ("sr", -1);  /* Serbian */
   case HB_TAG('S','X','T',' '):  /* Sutu */
@@ -2943,6 +2985,10 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
     return hb_language_from_string ("tmh", -1);  /* Tamashek [macrolanguage] */
   case HB_TAG('T','O','D',' '):  /* Todo */
     return hb_language_from_string ("xwo", -1);  /* Written Oirat */
+  case HB_TAG('W','D','T',' '):  /* Wendat */
+    return hb_language_from_string ("wdt", -1);  /* Wendat */
+  case HB_TAG('W','Y','N',' '):  /* Wyandot */
+    return hb_language_from_string ("wyn", -1);  /* Wyandot */
   case HB_TAG('Z','H','H',' '):  /* Chinese, Traditional, Hong Kong SAR */
     return hb_language_from_string ("zh-HK", -1);  /* Chinese [macrolanguage]; Hong Kong */
   case HB_TAG('Z','H','S',' '):  /* Chinese, Simplified */

+ 41 - 441
thirdparty/harfbuzz/src/hb-ot-var-common.hh

@@ -33,213 +33,6 @@
 
 namespace OT {
 
-template <typename MapCountT>
-struct DeltaSetIndexMapFormat01
-{
-  friend struct DeltaSetIndexMap;
-
-  unsigned get_size () const
-  { return min_size + mapCount * get_width (); }
-
-  private:
-  DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (c->embed (this));
-  }
-
-  template <typename T>
-  bool serialize (hb_serialize_context_t *c, const T &plan)
-  {
-    unsigned int width = plan.get_width ();
-    unsigned int inner_bit_count = plan.get_inner_bit_count ();
-    const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
-
-    TRACE_SERIALIZE (this);
-    if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
-      return_trace (false);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-
-    entryFormat = ((width-1)<<4)|(inner_bit_count-1);
-    mapCount = output_map.length;
-    HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
-    if (unlikely (!p)) return_trace (false);
-    for (unsigned int i = 0; i < output_map.length; i++)
-    {
-      unsigned int v = output_map.arrayZ[i];
-      if (v)
-      {
-	unsigned int outer = v >> 16;
-	unsigned int inner = v & 0xFFFF;
-	unsigned int u = (outer << inner_bit_count) | inner;
-	for (unsigned int w = width; w > 0;)
-	{
-	  p[--w] = u;
-	  u >>= 8;
-	}
-      }
-      p += width;
-    }
-    return_trace (true);
-  }
-
-  uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
-  {
-    /* If count is zero, pass value unchanged.  This takes
-     * care of direct mapping for advance map. */
-    if (!mapCount)
-      return v;
-
-    if (v >= mapCount)
-      v = mapCount - 1;
-
-    unsigned int u = 0;
-    { /* Fetch it. */
-      unsigned int w = get_width ();
-      const HBUINT8 *p = mapDataZ.arrayZ + w * v;
-      for (; w; w--)
-        u = (u << 8) + *p++;
-    }
-
-    { /* Repack it. */
-      unsigned int n = get_inner_bit_count ();
-      unsigned int outer = u >> n;
-      unsigned int inner = u & ((1 << n) - 1);
-      u = (outer<<16) | inner;
-    }
-
-    return u;
-  }
-
-  unsigned get_map_count () const       { return mapCount; }
-  unsigned get_width () const           { return ((entryFormat >> 4) & 3) + 1; }
-  unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
-
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  hb_barrier () &&
-                  c->check_range (mapDataZ.arrayZ,
-                                  mapCount,
-                                  get_width ()));
-  }
-
-  protected:
-  HBUINT8       format;         /* Format identifier--format = 0 */
-  HBUINT8       entryFormat;    /* A packed field that describes the compressed
-                                 * representation of delta-set indices. */
-  MapCountT     mapCount;       /* The number of mapping entries. */
-  UnsizedArrayOf<HBUINT8>
-                mapDataZ;       /* The delta-set index mapping data. */
-
-  public:
-  DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
-};
-
-struct DeltaSetIndexMap
-{
-  template <typename T>
-  bool serialize (hb_serialize_context_t *c, const T &plan)
-  {
-    TRACE_SERIALIZE (this);
-    unsigned length = plan.get_output_map ().length;
-    u.format = length <= 0xFFFF ? 0 : 1;
-    switch (u.format) {
-    case 0: return_trace (u.format0.serialize (c, plan));
-    case 1: return_trace (u.format1.serialize (c, plan));
-    default:return_trace (false);
-    }
-  }
-
-  uint32_t map (unsigned v) const
-  {
-    switch (u.format) {
-    case 0: return (u.format0.map (v));
-    case 1: return (u.format1.map (v));
-    default:return v;
-    }
-  }
-
-  unsigned get_map_count () const
-  {
-    switch (u.format) {
-    case 0: return u.format0.get_map_count ();
-    case 1: return u.format1.get_map_count ();
-    default:return 0;
-    }
-  }
-
-  unsigned get_width () const
-  {
-    switch (u.format) {
-    case 0: return u.format0.get_width ();
-    case 1: return u.format1.get_width ();
-    default:return 0;
-    }
-  }
-
-  unsigned get_inner_bit_count () const
-  {
-    switch (u.format) {
-    case 0: return u.format0.get_inner_bit_count ();
-    case 1: return u.format1.get_inner_bit_count ();
-    default:return 0;
-    }
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return_trace (false);
-    hb_barrier ();
-    switch (u.format) {
-    case 0: return_trace (u.format0.sanitize (c));
-    case 1: return_trace (u.format1.sanitize (c));
-    default:return_trace (true);
-    }
-  }
-
-  DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
-  {
-    TRACE_SERIALIZE (this);
-    switch (u.format) {
-    case 0: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format0.copy (c)));
-    case 1: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format1.copy (c)));
-    default:return_trace (nullptr);
-    }
-  }
-
-  protected:
-  union {
-  HBUINT8                            format;         /* Format identifier */
-  DeltaSetIndexMapFormat01<HBUINT16> format0;
-  DeltaSetIndexMapFormat01<HBUINT32> format1;
-  } u;
-  public:
-  DEFINE_SIZE_UNION (1, format);
-};
-
-
-struct ItemVarStoreInstancer
-{
-  ItemVarStoreInstancer (const ItemVariationStore *varStore,
-		     const DeltaSetIndexMap *varIdxMap,
-		     hb_array_t<int> coords) :
-    varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
-
-  operator bool () const { return varStore && bool (coords); }
-
-  /* according to the spec, if colr table has varStore but does not have
-   * varIdxMap, then an implicit identity mapping is used */
-  float operator() (uint32_t varIdx, unsigned short offset = 0) const
-  { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
-
-  const ItemVariationStore *varStore;
-  const DeltaSetIndexMap *varIdxMap;
-  hb_array_t<int> coords;
-};
 
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
 struct TupleVariationHeader
@@ -305,9 +98,9 @@ struct TupleVariationHeader
     return true;
   }
 
-  double calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
-                          const hb_array_t<const F2DOT14> shared_tuples,
-			  const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
+  double calculate_scalar (hb_array_t<const int> coords, unsigned int coord_count,
+			   const hb_array_t<const F2DOT14> shared_tuples,
+			   const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
   {
     const F2DOT14 *peak_tuple;
 
@@ -428,13 +221,6 @@ struct TupleVariationHeader
   DEFINE_SIZE_MIN (4);
 };
 
-enum packed_delta_flag_t
-{
-  DELTAS_ARE_ZERO      = 0x80,
-  DELTAS_ARE_WORDS     = 0x40,
-  DELTA_RUN_COUNT_MASK = 0x3F
-};
-
 struct tuple_delta_t
 {
   static constexpr bool realloc_move = true;  // Watch out when adding new members!
@@ -452,8 +238,8 @@ struct tuple_delta_t
   /* compiled data: header and deltas
    * compiled point data is saved in a hashmap within tuple_variations_t cause
    * some point sets might be reused by different tuple variations */
-  hb_vector_t<char> compiled_tuple_header;
-  hb_vector_t<char> compiled_deltas;
+  hb_vector_t<unsigned char> compiled_tuple_header;
+  hb_vector_t<unsigned char> compiled_deltas;
 
   /* compiled peak coords, empty for non-gvar tuples */
   hb_vector_t<char> compiled_peak_coords;
@@ -728,10 +514,10 @@ struct tuple_delta_t
   bool compile_deltas ()
   { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
 
-  bool compile_deltas (const hb_vector_t<bool> &point_indices,
-                       const hb_vector_t<double> &x_deltas,
-                       const hb_vector_t<double> &y_deltas,
-                       hb_vector_t<char> &compiled_deltas /* OUT */)
+  static bool compile_deltas (const hb_vector_t<bool> &point_indices,
+			      const hb_vector_t<double> &x_deltas,
+			      const hb_vector_t<double> &y_deltas,
+			      hb_vector_t<unsigned char> &compiled_deltas /* OUT */)
   {
     hb_vector_t<int> rounded_deltas;
     if (unlikely (!rounded_deltas.alloc (point_indices.length)))
@@ -745,15 +531,14 @@ struct tuple_delta_t
     }
 
     if (!rounded_deltas) return true;
-    /* allocate enough memories 3 * num_deltas */
-    unsigned alloc_len = 3 * rounded_deltas.length;
+    /* allocate enough memories 5 * num_deltas */
+    unsigned alloc_len = 5 * rounded_deltas.length;
     if (y_deltas)
       alloc_len *= 2;
 
     if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
 
-    unsigned i = 0;
-    unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
+    unsigned encoded_len = compile_deltas (compiled_deltas, rounded_deltas);
 
     if (y_deltas)
     {
@@ -770,174 +555,15 @@ struct tuple_delta_t
       }
 
       if (j != rounded_deltas.length) return false;
-      /* reset i because we reuse rounded_deltas for y_deltas */
-      i = 0;
-      encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
+      encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
     }
     return compiled_deltas.resize (encoded_len);
   }
 
-  unsigned encode_delta_run (unsigned& i,
-                             hb_array_t<char> encoded_bytes,
-                             const hb_vector_t<int>& deltas) const
-  {
-    unsigned num_deltas = deltas.length;
-    unsigned encoded_len = 0;
-    while (i < num_deltas)
-    {
-      int val = deltas.arrayZ[i];
-      if (val == 0)
-        encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
-      else if (val >= -128 && val <= 127)
-        encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas);
-      else
-        encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas);
-    }
-    return encoded_len;
-  }
-
-  unsigned encode_delta_run_as_zeroes (unsigned& i,
-                                       hb_array_t<char> encoded_bytes,
-                                       const hb_vector_t<int>& deltas) const
-  {
-    unsigned num_deltas = deltas.length;
-    unsigned run_length = 0;
-    auto it = encoded_bytes.iter ();
-    unsigned encoded_len = 0;
-    while (i < num_deltas && deltas.arrayZ[i] == 0)
-    {
-      i++;
-      run_length++;
-    }
-
-    while (run_length >= 64)
-    {
-      *it++ = char (DELTAS_ARE_ZERO | 63);
-      run_length -= 64;
-      encoded_len++;
-    }
-
-    if (run_length)
-    {
-      *it++ = char (DELTAS_ARE_ZERO | (run_length - 1));
-      encoded_len++;
-    }
-    return encoded_len;
-  }
-
-  unsigned encode_delta_run_as_bytes (unsigned &i,
-                                      hb_array_t<char> encoded_bytes,
-                                      const hb_vector_t<int>& deltas) const
-  {
-    unsigned start = i;
-    unsigned num_deltas = deltas.length;
-    while (i < num_deltas)
-    {
-      int val = deltas.arrayZ[i];
-      if (val > 127 || val < -128)
-        break;
-
-      /* from fonttools: if there're 2 or more zeros in a sequence,
-       * it is better to start a new run to save bytes. */
-      if (val == 0 && i + 1 < num_deltas && deltas.arrayZ[i+1] == 0)
-        break;
-
-      i++;
-    }
-    unsigned run_length = i - start;
-
-    unsigned encoded_len = 0;
-    auto it = encoded_bytes.iter ();
-
-    while (run_length >= 64)
-    {
-      *it++ = 63;
-      encoded_len++;
-
-      for (unsigned j = 0; j < 64; j++)
-      {
-        *it++ = static_cast<char> (deltas.arrayZ[start + j]);
-        encoded_len++;
-      }
-
-      start += 64;
-      run_length -= 64;
-    }
-
-    if (run_length)
-    {
-      *it++ = run_length - 1;
-      encoded_len++;
-
-      while (start < i)
-      {
-        *it++ = static_cast<char> (deltas.arrayZ[start++]);
-        encoded_len++;
-      }
-    }
-
-    return encoded_len;
-  }
-
-  unsigned encode_delta_run_as_words (unsigned &i,
-                                      hb_array_t<char> encoded_bytes,
-                                      const hb_vector_t<int>& deltas) const
+  static unsigned compile_deltas (hb_array_t<unsigned char> encoded_bytes,
+				  hb_array_t<const int> deltas)
   {
-    unsigned start = i;
-    unsigned num_deltas = deltas.length;
-    while (i < num_deltas)
-    {
-      int val = deltas.arrayZ[i];
-
-      /* start a new run for a single zero value*/
-      if (val == 0) break;
-
-      /* from fonttools: continue word-encoded run if there's only one
-       * single value in the range [-128, 127] because it is more compact.
-       * Only start a new run when there're 2 continuous such values. */
-      if (val >= -128 && val <= 127 &&
-          i + 1 < num_deltas &&
-          deltas.arrayZ[i+1] >= -128 && deltas.arrayZ[i+1] <= 127)
-        break;
-
-      i++;
-    }
-
-    unsigned run_length = i - start;
-    auto it = encoded_bytes.iter ();
-    unsigned encoded_len = 0;
-    while (run_length >= 64)
-    {
-      *it++ = (DELTAS_ARE_WORDS | 63);
-      encoded_len++;
-
-      for (unsigned j = 0; j < 64; j++)
-      {
-        int16_t delta_val = deltas.arrayZ[start + j];
-        *it++ = static_cast<char> (delta_val >> 8);
-        *it++ = static_cast<char> (delta_val & 0xFF);
-
-        encoded_len += 2;
-      }
-
-      start += 64;
-      run_length -= 64;
-    }
-
-    if (run_length)
-    {
-      *it++ = (DELTAS_ARE_WORDS | (run_length - 1));
-      encoded_len++;
-      while (start < i)
-      {
-        int16_t delta_val = deltas.arrayZ[start++];
-        *it++ = static_cast<char> (delta_val >> 8);
-        *it++ = static_cast<char> (delta_val & 0xFF);
-
-        encoded_len += 2;
-      }
-    }
-    return encoded_len;
+    return TupleValues::compile (deltas, encoded_bytes);
   }
 
   bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
@@ -1079,20 +705,20 @@ struct tuple_delta_t
         opt_indices.arrayZ[i] = false;
     }
 
-    hb_vector_t<char> opt_point_data;
+    hb_vector_t<unsigned char> opt_point_data;
     if (!compile_point_set (opt_indices, opt_point_data))
       return false;
-    hb_vector_t<char> opt_deltas_data;
+    hb_vector_t<unsigned char> opt_deltas_data;
     if (!compile_deltas (opt_indices,
                          is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
                          is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
                          opt_deltas_data))
       return false;
 
-    hb_vector_t<char> point_data;
+    hb_vector_t<unsigned char> point_data;
     if (!compile_point_set (indices, point_data))
       return false;
-    hb_vector_t<char> deltas_data;
+    hb_vector_t<unsigned char> deltas_data;
     if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
       return false;
 
@@ -1114,7 +740,7 @@ struct tuple_delta_t
   }
 
   static bool compile_point_set (const hb_vector_t<bool> &point_indices,
-                                 hb_vector_t<char>& compiled_points /* OUT */)
+                                 hb_vector_t<unsigned char>& compiled_points /* OUT */)
   {
     unsigned num_points = 0;
     for (bool i : point_indices)
@@ -1316,7 +942,7 @@ struct TupleVariationData
         bool has_private_points = iterator.current_tuple->has_private_points ();
         const HBUINT8 *end = p + length;
         if (has_private_points &&
-            !TupleVariationData::unpack_points (p, private_indices, end))
+            !TupleVariationData::decompile_points (p, private_indices, end))
           return false;
 
         const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
@@ -1326,14 +952,14 @@ struct TupleVariationData
         hb_vector_t<int> deltas_x;
 
         if (unlikely (!deltas_x.resize (num_deltas, false) ||
-                      !TupleVariationData::unpack_deltas (p, deltas_x, end)))
+                      !TupleVariationData::decompile_deltas (p, deltas_x, end)))
           return false;
 
         hb_vector_t<int> deltas_y;
         if (is_gvar)
         {
           if (unlikely (!deltas_y.resize (num_deltas, false) ||
-                        !TupleVariationData::unpack_deltas (p, deltas_y, end)))
+                        !TupleVariationData::decompile_deltas (p, deltas_y, end)))
             return false;
         }
 
@@ -1508,7 +1134,7 @@ struct TupleVariationData
           continue;
         }
 
-        hb_vector_t<char> compiled_point_data;
+        hb_vector_t<unsigned char> compiled_point_data;
         if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
           return false;
 
@@ -1700,7 +1326,7 @@ struct TupleVariationData
       {
         const HBUINT8 *base = &(table_base+var_data->data);
         const HBUINT8 *p = base;
-        if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
+        if (!decompile_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
         data_offset = p - base;
       }
       return true;
@@ -1750,9 +1376,9 @@ struct TupleVariationData
 
   bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
 
-  static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
-                             hb_vector_t<unsigned int> &points /* OUT */,
-                             const HBUINT8 *end)
+  static bool decompile_points (const HBUINT8 *&p /* IN/OUT */,
+				hb_vector_t<unsigned int> &points /* OUT */,
+				const HBUINT8 *end)
   {
     enum packed_point_flag_t
     {
@@ -1802,43 +1428,13 @@ struct TupleVariationData
     return true;
   }
 
-  static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
-                             hb_vector_t<int> &deltas /* IN/OUT */,
-                             const HBUINT8 *end)
+  template <typename T>
+  static bool decompile_deltas (const HBUINT8 *&p /* IN/OUT */,
+				hb_vector_t<T> &deltas /* IN/OUT */,
+				const HBUINT8 *end,
+				bool consume_all = false)
   {
-    unsigned i = 0;
-    unsigned count = deltas.length;
-    while (i < count)
-    {
-      if (unlikely (p + 1 > end)) return false;
-      unsigned control = *p++;
-      unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
-      unsigned stop = i + run_count;
-      if (unlikely (stop > count)) return false;
-      if (control & DELTAS_ARE_ZERO)
-      {
-        for (; i < stop; i++)
-          deltas.arrayZ[i] = 0;
-      }
-      else if (control & DELTAS_ARE_WORDS)
-      {
-        if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
-        for (; i < stop; i++)
-        {
-          deltas.arrayZ[i] = * (const HBINT16 *) p;
-          p += HBUINT16::static_size;
-        }
-      }
-      else
-      {
-        if (unlikely (p + run_count > end)) return false;
-        for (; i < stop; i++)
-        {
-          deltas.arrayZ[i] = * (const HBINT8 *) p++;
-        }
-      }
-    }
-    return true;
+    return TupleValues::decompile (p, deltas, end, consume_all);
   }
 
   bool has_data () const { return tupleVarCount; }
@@ -2067,7 +1663,9 @@ struct item_variations_t
       }
     }
 
-    if (!all_regions || !all_unique_regions) return false;
+    /* regions are empty means no variation data, return true */
+    if (!all_regions || !all_unique_regions) return true;
+
     if (!region_list.alloc (all_regions.get_population ()))
       return false;
 
@@ -2132,7 +1730,8 @@ struct item_variations_t
 
   bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
   {
-    if (!region_list) return false;
+    /* return true if no variation data */
+    if (!region_list) return true;
     unsigned num_cols = region_list.length;
     /* pre-alloc a 2D vector for all sub_table's VarData rows */
     unsigned total_rows = 0;
@@ -2382,6 +1981,7 @@ struct item_variations_t
   }
 };
 
+
 } /* namespace OT */
 
 

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-var-cvar-table.hh

@@ -107,14 +107,14 @@ struct cvar
 
       bool has_private_points = iterator.current_tuple->has_private_points ();
       if (has_private_points &&
-          !TupleVariationData::unpack_points (p, private_indices, end))
+          !TupleVariationData::decompile_points (p, private_indices, end))
         return false;
       const hb_vector_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
 
       bool apply_to_all = (indices.length == 0);
       unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
       if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
-      if (unlikely (!TupleVariationData::unpack_deltas (p, unpacked_deltas, end))) return false;
+      if (unlikely (!TupleVariationData::decompile_deltas (p, unpacked_deltas, end))) return false;
 
       for (unsigned int i = 0; i < num_deltas; i++)
       {

+ 13 - 7
thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh

@@ -359,7 +359,10 @@ struct gvar
     out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
 
     unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
-    bool long_offset = glyph_var_data_size & ~0xFFFFu || force_long_offsets;
+    /* According to the spec: If the short format (Offset16) is used for offsets,
+     * the value stored is the offset divided by 2, so the maximum data size should
+     * be 2 * 0xFFFFu, which is 0x1FFFEu */
+    bool long_offset = glyph_var_data_size > 0x1FFFEu || force_long_offsets;
     out->flags = long_offset ? 1 : 0;
 
     HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
@@ -440,7 +443,10 @@ struct gvar
       subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
     }
 
-    bool long_offset = (subset_data_size & ~0xFFFFu);
+    /* According to the spec: If the short format (Offset16) is used for offsets,
+     * the value stored is the offset divided by 2, so the maximum data size should
+     * be 2 * 0xFFFFu, which is 0x1FFFEu */
+    bool long_offset = subset_data_size > 0x1FFFEu;
 #ifdef HB_EXPERIMENTAL_API
     long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
 #endif
@@ -540,7 +546,7 @@ struct gvar
   unsigned get_offset (unsigned glyph_count, unsigned i) const
   {
     if (unlikely (i > glyph_count)) return 0;
-    _hb_compiler_memory_r_barrier ();
+    hb_barrier ();
     return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
   }
 
@@ -618,7 +624,7 @@ struct gvar
 
     public:
     bool apply_deltas_to_points (hb_codepoint_t glyph,
-				 hb_array_t<int> coords,
+				 hb_array_t<const int> coords,
 				 const hb_array_t<contour_point_t> points,
 				 bool phantom_only = false) const
     {
@@ -673,16 +679,16 @@ struct gvar
 
 	bool has_private_points = iterator.current_tuple->has_private_points ();
 	if (has_private_points &&
-	    !GlyphVariationData::unpack_points (p, private_indices, end))
+	    !GlyphVariationData::decompile_points (p, private_indices, end))
 	  return false;
 	const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
 
 	bool apply_to_all = (indices.length == 0);
 	unsigned int num_deltas = apply_to_all ? points.length : indices.length;
 	if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
-	if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
+	if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end))) return false;
 	if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
-	if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
+	if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end))) return false;
 
 	if (!apply_to_all)
 	{

+ 32 - 0
thirdparty/harfbuzz/src/hb-ot-var-varc-table.hh

@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2024  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_VAR_VARC_TABLE_HH
+#define HB_OT_VAR_VARC_TABLE_HH
+
+#include "OT/Var/VARC/VARC.hh"
+
+#endif /* HB_OT_VAR_VARC_TABLE_HH */

+ 5 - 163
thirdparty/harfbuzz/src/hb-paint-extents.hh

@@ -28,169 +28,8 @@
 #include "hb.hh"
 #include "hb-paint.h"
 
+#include "hb-geometry.hh"
 
-typedef struct hb_extents_t
-{
-  hb_extents_t () {}
-  hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
-    xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
-
-  bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
-  bool is_void () const { return xmin > xmax; }
-
-  void union_ (const hb_extents_t &o)
-  {
-    xmin = hb_min (xmin, o.xmin);
-    ymin = hb_min (ymin, o.ymin);
-    xmax = hb_max (xmax, o.xmax);
-    ymax = hb_max (ymax, o.ymax);
-  }
-
-  void intersect (const hb_extents_t &o)
-  {
-    xmin = hb_max (xmin, o.xmin);
-    ymin = hb_max (ymin, o.ymin);
-    xmax = hb_min (xmax, o.xmax);
-    ymax = hb_min (ymax, o.ymax);
-  }
-
-  void
-  add_point (float x, float y)
-  {
-    if (unlikely (is_void ()))
-    {
-      xmin = xmax = x;
-      ymin = ymax = y;
-    }
-    else
-    {
-      xmin = hb_min (xmin, x);
-      ymin = hb_min (ymin, y);
-      xmax = hb_max (xmax, x);
-      ymax = hb_max (ymax, y);
-    }
-  }
-
-  float xmin = 0.f;
-  float ymin = 0.f;
-  float xmax = -1.f;
-  float ymax = -1.f;
-} hb_extents_t;
-
-typedef struct hb_transform_t
-{
-  hb_transform_t () {}
-  hb_transform_t (float xx, float yx,
-		  float xy, float yy,
-		  float x0, float y0) :
-    xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
-
-  void multiply (const hb_transform_t &o)
-  {
-    /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
-    hb_transform_t r;
-
-    r.xx = o.xx * xx + o.yx * xy;
-    r.yx = o.xx * yx + o.yx * yy;
-
-    r.xy = o.xy * xx + o.yy * xy;
-    r.yy = o.xy * yx + o.yy * yy;
-
-    r.x0 = o.x0 * xx + o.y0 * xy + x0;
-    r.y0 = o.x0 * yx + o.y0 * yy + y0;
-
-    *this = r;
-  }
-
-  void transform_distance (float &dx, float &dy) const
-  {
-    float new_x = xx * dx + xy * dy;
-    float new_y = yx * dx + yy * dy;
-    dx = new_x;
-    dy = new_y;
-  }
-
-  void transform_point (float &x, float &y) const
-  {
-    transform_distance (x, y);
-    x += x0;
-    y += y0;
-  }
-
-  void transform_extents (hb_extents_t &extents) const
-  {
-    float quad_x[4], quad_y[4];
-
-    quad_x[0] = extents.xmin;
-    quad_y[0] = extents.ymin;
-    quad_x[1] = extents.xmin;
-    quad_y[1] = extents.ymax;
-    quad_x[2] = extents.xmax;
-    quad_y[2] = extents.ymin;
-    quad_x[3] = extents.xmax;
-    quad_y[3] = extents.ymax;
-
-    extents = hb_extents_t {};
-    for (unsigned i = 0; i < 4; i++)
-    {
-      transform_point (quad_x[i], quad_y[i]);
-      extents.add_point (quad_x[i], quad_y[i]);
-    }
-  }
-
-  float xx = 1.f;
-  float yx = 0.f;
-  float xy = 0.f;
-  float yy = 1.f;
-  float x0 = 0.f;
-  float y0 = 0.f;
-} hb_transform_t;
-
-typedef struct hb_bounds_t
-{
-  enum status_t {
-    UNBOUNDED,
-    BOUNDED,
-    EMPTY,
-  };
-
-  hb_bounds_t (status_t status) : status (status) {}
-  hb_bounds_t (const hb_extents_t &extents) :
-    status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
-
-  void union_ (const hb_bounds_t &o)
-  {
-    if (o.status == UNBOUNDED)
-      status = UNBOUNDED;
-    else if (o.status == BOUNDED)
-    {
-      if (status == EMPTY)
-	*this = o;
-      else if (status == BOUNDED)
-        extents.union_ (o.extents);
-    }
-  }
-
-  void intersect (const hb_bounds_t &o)
-  {
-    if (o.status == EMPTY)
-      status = EMPTY;
-    else if (o.status == BOUNDED)
-    {
-      if (status == UNBOUNDED)
-	*this = o;
-      else if (status == BOUNDED)
-      {
-        extents.intersect (o.extents);
-	if (extents.is_empty ())
-	  status = EMPTY;
-      }
-    }
-  }
-
-  status_t status;
-  hb_extents_t extents;
-} hb_bounds_t;
 
 typedef struct  hb_paint_extents_context_t hb_paint_extents_context_t;
 
@@ -231,7 +70,10 @@ struct hb_paint_extents_context_t
     const hb_transform_t &t = transforms.tail ();
     t.transform_extents (extents);
 
-    clips.push (hb_bounds_t {extents});
+    auto bounds = hb_bounds_t {extents};
+    bounds.intersect (clips.tail ());
+
+    clips.push (bounds);
   }
 
   void pop_clip ()

+ 2 - 2
thirdparty/harfbuzz/src/hb-style.cc

@@ -61,8 +61,8 @@ _hb_ratio_to_angle (float r)
  * @style_tag: a style tag.
  *
  * Searches variation axes of a #hb_font_t object for a specific axis first,
- * if not set, then tries to get default style values from different
- * tables of the font.
+ * if not set, first tries to get default style values in `STAT` table
+ * then tries to polyfill from different tables of the font.
  *
  * Returns: Corresponding axis or default value to a style tag.
  *

+ 0 - 3
thirdparty/harfbuzz/src/hb-subset-cff2.cc

@@ -666,9 +666,6 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
 bool
 OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
 {
-  if (c->plan->normalized_coords && !c->plan->all_axes_pinned)
-    fprintf (stdout, "warning: CFF partial instancing is not supported.\n");
-
   cff2_subset_plan cff2_plan;
 
   if (unlikely (!cff2_plan.create (*this, c->plan))) return false;

+ 2 - 1
thirdparty/harfbuzz/src/hb-subset-input.cc

@@ -412,6 +412,7 @@ hb_subset_input_keep_everything (hb_subset_input_t *input)
   hb_subset_input_set_flags (input,
 			     HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
 			     HB_SUBSET_FLAGS_GLYPH_NAMES |
+			     HB_SUBSET_FLAGS_NAME_LEGACY |
 			     HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES |
                              HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED);
 }
@@ -730,7 +731,7 @@ hb_subset_input_override_name_table (hb_subset_input_t  *input,
         src = hb_utf8_t::next (src, src_end, &unicode, replacement);
         if (unicode >= 0x0080u)
         {
-          printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");
+          printf ("Non-ascii character detected, ignored...This API supports ascii characters only for mac platform\n");
           return false;
         }
       }

+ 1 - 1
thirdparty/harfbuzz/src/hb-subset-instancer-solver.cc

@@ -376,7 +376,7 @@ double renormalizeValue (double v, const Triple &triple,
   assert (lower <= def && def <= upper);
 
   if (!extrapolate)
-      v = hb_max (hb_min (v, upper), lower);
+    v = hb_clamp (v, lower, upper);
 
   if (v == def)
     return 0.0;

+ 71 - 65
thirdparty/harfbuzz/src/hb-subset-plan.cc

@@ -491,7 +491,7 @@ _collect_base_variation_indices (hb_subset_plan_t* plan)
   base->collect_variation_indices (plan, varidx_set);
   const OT::ItemVariationStore &var_store = base->get_var_store ();
   unsigned subtable_count = var_store.get_sub_table_count ();
-  
+
 
   _remap_variation_indices (var_store, varidx_set,
                             plan->normalized_coords,
@@ -515,6 +515,7 @@ _cmap_closure (hb_face_t	   *face,
   cmap.table->closure_glyphs (unicodes, glyphset);
 }
 
+#ifndef HB_NO_VAR
 static void
 _remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
                                        const hb_set_t &delta_set_idxes,
@@ -531,7 +532,7 @@ _remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
     unsigned var_idx = index_map.map (delta_set_idx);
     unsigned new_varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
     int delta = 0;
-    
+
     if (var_idx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
     {
       hb_pair_t<unsigned, int> *new_varidx_delta;
@@ -547,6 +548,7 @@ _remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
   }
   variation_idx_delta_map = std::move (delta_set_idx_delta_map);
 }
+#endif
 
 static void _colr_closure (hb_subset_plan_t* plan,
                            hb_set_t *glyphs_colred)
@@ -570,6 +572,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
   _remap_indexes (&layer_indices, &plan->colrv1_layers);
   _remap_palette_indexes (&palette_indices, &plan->colr_palettes);
 
+#ifndef HB_NO_VAR
   if (!colr.has_var_store () || !variation_indices) return;
 
   const OT::ItemVariationStore &var_store = colr.get_var_store ();
@@ -600,6 +603,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
                                              plan->colrv1_variation_idx_delta_map,
                                              plan->colrv1_new_deltaset_idx_varidx_map);
   }
+#endif
 }
 
 static inline void
@@ -638,6 +642,36 @@ _remove_invalid_gids (hb_set_t *glyphs,
   glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID);
 }
 
+template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, typename G, hb_requires (hb_is_iterator (I))>
+static void
+_fill_unicode_and_glyph_map(hb_subset_plan_t *plan,
+                            I unicode_iterator,
+                            F unicode_to_gid_for_iterator,
+                            G unicode_to_gid_general)
+{
+  for (hb_codepoint_t cp : unicode_iterator)
+  {
+    hb_codepoint_t gid = unicode_to_gid_for_iterator(cp);
+    if (!GID_ALWAYS_EXISTS && gid == HB_MAP_VALUE_INVALID)
+    {
+      DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+      continue;
+    }
+
+    plan->codepoint_to_glyph->set (cp, gid);
+    plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+  }
+}
+
+template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, hb_requires (hb_is_iterator (I))>
+static void
+_fill_unicode_and_glyph_map(hb_subset_plan_t *plan,
+                            I unicode_iterator,
+                            F unicode_to_gid_for_iterator)
+{
+  _fill_unicode_and_glyph_map(plan, unicode_iterator, unicode_to_gid_for_iterator, unicode_to_gid_for_iterator);
+}
+
 static void
 _populate_unicodes_to_retain (const hb_set_t *unicodes,
                               const hb_set_t *glyphs,
@@ -657,35 +691,21 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
     // not excessively large (eg. an inverted set).
     plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
     if (!unicode_to_gid) {
-      for (hb_codepoint_t cp : *unicodes)
-      {
+      _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
         hb_codepoint_t gid;
-        if (!cmap.get_nominal_glyph (cp, &gid))
-        {
-          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-          continue;
+        if (!cmap.get_nominal_glyph (cp, &gid)) {
+          return HB_MAP_VALUE_INVALID;
         }
-
-        plan->codepoint_to_glyph->set (cp, gid);
-        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
-      }
+        return gid;
+      });
     } else {
       // Use in memory unicode to gid map it's faster then looking up from
       // the map. This code is mostly duplicated from above to avoid doing
       // conditionals on the presence of the unicode_to_gid map each
       // iteration.
-      for (hb_codepoint_t cp : *unicodes)
-      {
-        hb_codepoint_t gid = unicode_to_gid->get (cp);
-        if (gid == HB_MAP_VALUE_INVALID)
-        {
-          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-          continue;
-        }
-
-        plan->codepoint_to_glyph->set (cp, gid);
-        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
-      }
+      _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
+        return unicode_to_gid->get (cp);
+      });
     }
   }
   else
@@ -715,29 +735,29 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
       plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
 
       auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
+
       for (hb_codepoint_t gid : *glyphs)
       {
         auto unicodes = gid_to_unicodes.get (gid);
-
-	for (hb_codepoint_t cp : unicodes)
-	{
-	  plan->codepoint_to_glyph->set (cp, gid);
-	  plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
-	}
+        _fill_unicode_and_glyph_map<true>(plan, unicodes, [&] (hb_codepoint_t cp) {
+          return gid;
+        },
+        [&] (hb_codepoint_t cp) {
+          return unicode_glyphid_map->get(cp);
+        });
       }
-      for (hb_codepoint_t cp : *unicodes)
-      {
-	/* Don't double-add entry. */
+
+      _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
+          /* Don't double-add entry. */
 	if (plan->codepoint_to_glyph->has (cp))
-	  continue;
+          return HB_MAP_VALUE_INVALID;
 
-        hb_codepoint_t *gid;
-        if (!unicode_glyphid_map->has(cp, &gid))
-          continue;
+        return unicode_glyphid_map->get(cp);
+      },
+      [&] (hb_codepoint_t cp) {
+          return unicode_glyphid_map->get(cp);
+      });
 
-	plan->codepoint_to_glyph->set (cp, *gid);
-	plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
-      }
       plan->unicode_to_new_gid_list.qsort ();
     }
     else
@@ -746,15 +766,15 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
       hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
       for (; cmap_unicodes->next_range (&first, &last); )
       {
-        for (unsigned cp = first; cp <= last; cp++)
-	{
-	  hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+        _fill_unicode_and_glyph_map(plan, hb_range(first, last + 1), [&] (hb_codepoint_t cp) {
+          hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
 	  if (!unicodes->has (cp) && !glyphs->has (gid))
-	    continue;
-
-	  plan->codepoint_to_glyph->set (cp, gid);
-	  plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
-	}
+	    return HB_MAP_VALUE_INVALID;
+          return gid;
+        },
+        [&] (hb_codepoint_t cp) {
+          return unicode_glyphid_map->get(cp);
+        });
       }
     }
 
@@ -779,10 +799,6 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
   }
 }
 
-#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
-#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64
-#endif
-
 static unsigned
 _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
 			    hb_codepoint_t gid,
@@ -808,18 +824,6 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
 				  operation_count,
 				  depth);
 
-#ifndef HB_NO_VAR_COMPOSITES
-  for (auto &item : glyph.get_var_composite_iterator ())
-   {
-    operation_count =
-      _glyf_add_gid_and_children (glyf,
-				  item.get_gid (),
-				  gids_to_retain,
-				  operation_count,
-				  depth);
-   }
-#endif
-
   return operation_count;
 }
 
@@ -916,13 +920,15 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
 
   plan->_glyphset_colred = cur_glyphset;
 
+  // XXX TODO VARC closure / subset
+
   _nameid_closure (plan, drop_tables);
   /* Populate a full set of glyphs to retain by adding all referenced
    * composite glyphs. */
   if (glyf.has_data ())
     for (hb_codepoint_t gid : cur_glyphset)
       _glyf_add_gid_and_children (glyf, gid, &plan->_glyphset,
-				  cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH);
+				  cur_glyphset.get_population () * HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH);
   else
     plan->_glyphset.union_ (cur_glyphset);
 #ifndef HB_NO_SUBSET_CFF

+ 8 - 2
thirdparty/harfbuzz/src/hb-subset.cc

@@ -594,14 +594,20 @@ static void _attach_accelerator_data (hb_subset_plan_t* plan,
  * @input: input to use for the subsetting.
  *
  * Subsets a font according to provided input. Returns nullptr
- * if the subset operation fails.
+ * if the subset operation fails or the face has no glyphs.
  *
  * Since: 2.9.0
  **/
 hb_face_t *
 hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
 {
-  if (unlikely (!input || !source)) return hb_face_get_empty ();
+  if (unlikely (!input || !source)) return nullptr;
+
+  if (unlikely (!source->get_num_glyphs ()))
+  {
+    DEBUG_MSG (SUBSET, nullptr, "No glyphs in source font.");
+    return nullptr;
+  }
 
   hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input);
   if (unlikely (!plan)) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 499 - 523
thirdparty/harfbuzz/src/hb-ucd-table.hh


+ 4 - 4
thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh

@@ -7,13 +7,13 @@
  * on file with this header:
  *
  * # emoji-data.txt
- * # Date: 2023-02-01, 02:22:54 GMT
- * # © 2023 Unicode®, Inc.
+ * # Date: 2024-05-01, 21:25:24 GMT
+ * # © 2024 Unicode®, Inc.
  * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
- * # For terms of use, see https://www.unicode.org/terms_of_use.html
+ * # For terms of use and license, see https://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Used with Emoji Version 15.1 and subsequent minor revisions (if any)
+ * # Used with Emoji Version 16.0 and subsequent minor revisions (if any)
  * #
  * # For documentation and usage, see https://www.unicode.org/reports/tr51
  */

+ 3 - 0
thirdparty/harfbuzz/src/hb-unicode.hh

@@ -34,6 +34,9 @@
 #include "hb.hh"
 
 
+// Hack. See: https://github.com/harfbuzz/harfbuzz/pull/4529#discussion_r1769638033
+#define _HB_UNICODE_GENERAL_CATEGORY_VARIATION_SELECTOR ((hb_unicode_general_category_t) 30)
+
 extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
 
 /*

+ 4 - 4
thirdparty/harfbuzz/src/hb-version.h

@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
  *
  * The major component of the library version available at compile-time.
  */
-#define HB_VERSION_MAJOR 8
+#define HB_VERSION_MAJOR 10
 /**
  * HB_VERSION_MINOR:
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 5
+#define HB_VERSION_MINOR 0
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 1
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "8.5.0"
+#define HB_VERSION_STRING "10.0.1"
 
 /**
  * HB_VERSION_ATLEAST:

+ 1 - 0
thirdparty/harfbuzz/src/hb.hh

@@ -84,6 +84,7 @@
 #pragma GCC diagnostic error   "-Wredundant-decls"
 #pragma GCC diagnostic error   "-Wreorder"
 #pragma GCC diagnostic error   "-Wsign-compare"
+#pragma GCC diagnostic error   "-Wstrict-flex-arrays"
 #pragma GCC diagnostic error   "-Wstrict-prototypes"
 #pragma GCC diagnostic error   "-Wstring-conversion"
 #pragma GCC diagnostic error   "-Wswitch-enum"

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است