Sfoglia il codice sorgente

Merge pull request #105480 from bruvzg/hb111

Update HarfBuzz to 11.2.1
Rémi Verschelde 2 mesi fa
parent
commit
15c3656626
100 ha cambiato i file con 6245 aggiunte e 4140 eliminazioni
  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. 6 6
      thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh
  5. 131 27
      thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
  6. 6 5
      thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh
  7. 8 7
      thirdparty/harfbuzz/src/OT/Color/svg/svg.hh
  8. 1 1
      thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
  9. 1 1
      thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
  10. 12 12
      thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
  11. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
  12. 4 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
  13. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
  14. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
  15. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
  16. 2 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
  17. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
  18. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh
  19. 60 47
      thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc
  20. 103 57
      thirdparty/harfbuzz/src/OT/Var/VARC/VARC.hh
  21. 16 5
      thirdparty/harfbuzz/src/OT/glyf/glyf.hh
  22. 135 9
      thirdparty/harfbuzz/src/hb-aat-layout-common.hh
  23. 45 17
      thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
  24. 18 66
      thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
  25. 44 3
      thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
  26. 35 24
      thirdparty/harfbuzz/src/hb-aat-layout.cc
  27. 5 3
      thirdparty/harfbuzz/src/hb-aat-layout.hh
  28. 5 0
      thirdparty/harfbuzz/src/hb-aat-map.cc
  29. 31 47
      thirdparty/harfbuzz/src/hb-atomic.hh
  30. 2 2
      thirdparty/harfbuzz/src/hb-bit-set.hh
  31. 195 0
      thirdparty/harfbuzz/src/hb-bit-vector.hh
  32. 266 336
      thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
  33. 371 472
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh
  34. 58 134
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh
  35. 11 11
      thirdparty/harfbuzz/src/hb-buffer-serialize.cc
  36. 17 18
      thirdparty/harfbuzz/src/hb-buffer-verify.cc
  37. 14 2
      thirdparty/harfbuzz/src/hb-buffer.cc
  38. 62 3
      thirdparty/harfbuzz/src/hb-buffer.h
  39. 5 0
      thirdparty/harfbuzz/src/hb-buffer.hh
  40. 25 12
      thirdparty/harfbuzz/src/hb-cache.hh
  41. 4 9
      thirdparty/harfbuzz/src/hb-cairo-utils.cc
  42. 15 9
      thirdparty/harfbuzz/src/hb-cairo.cc
  43. 52 14
      thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
  44. 60 3
      thirdparty/harfbuzz/src/hb-common.cc
  45. 12 431
      thirdparty/harfbuzz/src/hb-common.h
  46. 1 1
      thirdparty/harfbuzz/src/hb-config.hh
  47. 55 52
      thirdparty/harfbuzz/src/hb-coretext-font.cc
  48. 12 463
      thirdparty/harfbuzz/src/hb-coretext-shape.cc
  49. 580 0
      thirdparty/harfbuzz/src/hb-coretext.cc
  50. 4 0
      thirdparty/harfbuzz/src/hb-coretext.h
  51. 53 0
      thirdparty/harfbuzz/src/hb-coretext.hh
  52. 3 3
      thirdparty/harfbuzz/src/hb-debug.hh
  53. 80 2
      thirdparty/harfbuzz/src/hb-deprecated.h
  54. 392 0
      thirdparty/harfbuzz/src/hb-directwrite-font.cc
  55. 656 0
      thirdparty/harfbuzz/src/hb-directwrite-shape.cc
  56. 155 737
      thirdparty/harfbuzz/src/hb-directwrite.cc
  57. 20 3
      thirdparty/harfbuzz/src/hb-directwrite.h
  58. 223 0
      thirdparty/harfbuzz/src/hb-directwrite.hh
  59. 93 0
      thirdparty/harfbuzz/src/hb-draw.cc
  60. 1 1
      thirdparty/harfbuzz/src/hb-draw.h
  61. 25 35
      thirdparty/harfbuzz/src/hb-draw.hh
  62. 220 8
      thirdparty/harfbuzz/src/hb-face.cc
  63. 15 1
      thirdparty/harfbuzz/src/hb-face.h
  64. 3 3
      thirdparty/harfbuzz/src/hb-face.hh
  65. 487 124
      thirdparty/harfbuzz/src/hb-font.cc
  66. 61 36
      thirdparty/harfbuzz/src/hb-font.h
  67. 293 72
      thirdparty/harfbuzz/src/hb-font.hh
  68. 56 0
      thirdparty/harfbuzz/src/hb-fontations.h
  69. 59 46
      thirdparty/harfbuzz/src/hb-ft-colr.hh
  70. 183 165
      thirdparty/harfbuzz/src/hb-ft.cc
  71. 4 0
      thirdparty/harfbuzz/src/hb-ft.h
  72. 29 1
      thirdparty/harfbuzz/src/hb-geometry.hh
  73. 1 1
      thirdparty/harfbuzz/src/hb-graphite2.cc
  74. 1 1
      thirdparty/harfbuzz/src/hb-machinery.hh
  75. 6 0
      thirdparty/harfbuzz/src/hb-mutex.hh
  76. 3 3
      thirdparty/harfbuzz/src/hb-object.hh
  77. 12 2
      thirdparty/harfbuzz/src/hb-open-type.hh
  78. 6 4
      thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
  79. 9 1
      thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
  80. 16 2
      thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
  81. 52 31
      thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
  82. 4 4
      thirdparty/harfbuzz/src/hb-ot-color.cc
  83. 1 1
      thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
  84. 1 0
      thirdparty/harfbuzz/src/hb-ot-face.cc
  85. 155 240
      thirdparty/harfbuzz/src/hb-ot-font.cc
  86. 7 1
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  87. 2 0
      thirdparty/harfbuzz/src/hb-ot-kern-table.hh
  88. 1 1
      thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
  89. 31 24
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  90. 218 245
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  91. 12 5
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  92. 16 1
      thirdparty/harfbuzz/src/hb-ot-layout.hh
  93. 18 0
      thirdparty/harfbuzz/src/hb-ot-math-table.hh
  94. 14 0
      thirdparty/harfbuzz/src/hb-ot-math.cc
  95. 1 1
      thirdparty/harfbuzz/src/hb-ot-post-table.hh
  96. 8 1
      thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc
  97. 34 10
      thirdparty/harfbuzz/src/hb-ot-shape.cc
  98. 4 0
      thirdparty/harfbuzz/src/hb-ot-shape.hh
  99. 1 1
      thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
  100. 2 4
      thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc

+ 1 - 0
modules/text_server_adv/SCsub

@@ -83,6 +83,7 @@ if env["builtin_harfbuzz"]:
         "src/hb-ot-tag.cc",
         "src/hb-ot-var.cc",
         "src/hb-outline.cc",
+        "src/hb-paint-bounded.cc",
         "src/hb-paint-extents.cc",
         "src/hb-paint.cc",
         "src/hb-set.cc",

+ 1 - 0
modules/text_server_adv/gdextension_build/SConstruct

@@ -347,6 +347,7 @@ thirdparty_harfbuzz_sources = [
     "src/hb-ot-tag.cc",
     "src/hb-ot-var.cc",
     "src/hb-outline.cc",
+    "src/hb-paint-bounded.cc",
     "src/hb-paint-extents.cc",
     "src/hb-paint.cc",
     "src/hb-set.cc",

+ 1 - 1
thirdparty/README.md

@@ -436,7 +436,7 @@ Patches:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 10.4.0 (3ef8709829a5884517ad91a97b32b9435b2f20d1, 2025)
+- Version: 11.2.1 (33a3f8de60dcad7535f14f07d6710144548853ac, 2025)
 - License: MIT
 
 Files extracted from upstream source:

+ 6 - 6
thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh

@@ -949,25 +949,25 @@ struct CBDT
 
       hb_glyph_extents_t extents;
       hb_glyph_extents_t pixel_extents;
-      hb_blob_t *blob = reference_png (font, glyph);
-
-      if (unlikely (blob == hb_blob_get_empty ()))
+      if (unlikely (!font->get_glyph_extents (glyph, &extents, false)))
         return false;
 
-      if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
         return false;
 
-      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+      hb_blob_t *blob = reference_png (font, glyph);
+      if (unlikely (hb_blob_is_immutable (blob)))
         return false;
 
       bool ret = funcs->image (data,
 			       blob,
 			       pixel_extents.width, -pixel_extents.height,
 			       HB_PAINT_IMAGE_FORMAT_PNG,
-			       font->slant_xy,
+			       0.f,
 			       &extents);
 
       hb_blob_destroy (blob);
+
       return ret;
     }
 

+ 131 - 27
thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh

@@ -33,6 +33,7 @@
 #include "../../../hb-open-type.hh"
 #include "../../../hb-ot-var-common.hh"
 #include "../../../hb-paint.hh"
+#include "../../../hb-paint-bounded.hh"
 #include "../../../hb-paint-extents.hh"
 
 #include "../CPAL/CPAL.hh"
@@ -47,6 +48,12 @@ namespace OT {
 struct hb_paint_context_t;
 }
 
+struct hb_colr_scratch_t
+{
+  hb_paint_bounded_context_t paint_bounded;
+  hb_paint_extents_context_t paint_extents;
+};
+
 namespace OT {
 
 struct COLR;
@@ -90,12 +97,27 @@ public:
     font (font_),
     palette (
 #ifndef HB_NO_COLOR
-	     font->face->table.CPAL->get_palette_colors (palette_)
+	     // https://github.com/harfbuzz/harfbuzz/issues/5116
+	     font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0)
 #endif
     ),
     foreground (foreground_),
     instancer (instancer_)
-  { }
+  {
+    if (font->is_synthetic ())
+    {
+      font = hb_font_create_sub_font (font);
+      hb_font_set_synthetic_bold (font, 0, 0, true);
+      hb_font_set_synthetic_slant (font, 0);
+    }
+    else
+      hb_font_reference (font);
+  }
+
+  ~hb_paint_context_t ()
+  {
+    hb_font_destroy (font);
+  }
 
   hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
   {
@@ -932,9 +954,9 @@ struct PaintGlyph
   void paint_glyph (hb_paint_context_t *c) const
   {
     TRACE_PAINT (this);
-    c->funcs->push_inverse_root_transform (c->data, c->font);
+    c->funcs->push_inverse_font_transform (c->data, c->font);
     c->funcs->push_clip_glyph (c->data, gid, c->font);
-    c->funcs->push_root_transform (c->data, c->font);
+    c->funcs->push_font_transform (c->data, c->font);
     c->recurse (this+paint);
     c->funcs->pop_transform (c->data);
     c->funcs->pop_clip (c->data);
@@ -1511,10 +1533,12 @@ struct PaintComposite
   void paint_glyph (hb_paint_context_t *c) const
   {
     TRACE_PAINT (this);
+    c->funcs->push_group (c->data);
     c->recurse (this+backdrop);
     c->funcs->push_group (c->data);
     c->recurse (this+src);
     c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
+    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
   }
 
   HBUINT8		format; /* format = 32 */
@@ -1612,7 +1636,7 @@ struct ClipBox
   void closurev1 (hb_colrv1_closure_context_t* c) const
   {
     switch (u.format) {
-    case 2: u.format2.closurev1 (c);
+    case 2: u.format2.closurev1 (c); return;
     default:return;
     }
   }
@@ -2079,6 +2103,8 @@ struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
+  bool has_data () const { return has_v0_data () || version; }
+
   bool has_v0_data () const { return numBaseGlyphs; }
   bool has_v1_data () const
   {
@@ -2112,7 +2138,53 @@ struct COLR
   {
     accelerator_t (hb_face_t *face)
     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
-    ~accelerator_t () { this->colr.destroy (); }
+
+    ~accelerator_t ()
+    {
+      auto *scratch = cached_scratch.get_relaxed ();
+      if (scratch)
+      {
+	scratch->~hb_colr_scratch_t ();
+	hb_free (scratch);
+      }
+
+      colr.destroy ();
+    }
+
+
+    bool has_data () const { return colr->has_data (); }
+
+#ifndef HB_NO_PAINT
+    bool
+    get_extents (hb_font_t *font,
+		 hb_codepoint_t glyph,
+		 hb_glyph_extents_t *extents) const
+    {
+      if (unlikely (!has_data ())) return false;
+
+      hb_colr_scratch_t *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = colr->get_extents (font, glyph, extents, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+
+    bool paint_glyph (hb_font_t *font,
+		      hb_codepoint_t glyph,
+		      hb_paint_funcs_t *funcs, void *data,
+		      unsigned int palette_index,
+		      hb_color_t foreground,
+		      bool clip = true) const
+    {
+      if (unlikely (!has_data ())) return false;
+
+      hb_colr_scratch_t *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+#endif
 
     bool is_valid () { return colr.get_blob ()->length; }
 
@@ -2148,7 +2220,33 @@ struct COLR
     { return colr->get_delta_set_index_map_ptr (); }
 
     private:
+
+    hb_colr_scratch_t *acquire_scratch () const
+    {
+      hb_colr_scratch_t *scratch = cached_scratch.get_acquire ();
+
+      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
+      {
+	scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t));
+	if (unlikely (!scratch))
+	  return nullptr;
+      }
+
+      return scratch;
+    }
+    void release_scratch (hb_colr_scratch_t *scratch) const
+    {
+      if (!cached_scratch.cmpexch (nullptr, scratch))
+      {
+	scratch->~hb_colr_scratch_t ();
+	hb_free (scratch);
+      }
+    }
+
+    public:
     hb_blob_ptr_t<COLR> colr;
+    private:
+    mutable hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
   };
 
   void closure_glyphs (hb_codepoint_t glyph,
@@ -2520,7 +2618,10 @@ struct COLR
 
 #ifndef HB_NO_PAINT
   bool
-  get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+  get_extents (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_glyph_extents_t *extents,
+	       hb_colr_scratch_t &scratch) const
   {
 
     ItemVarStoreInstancer instancer (get_var_store_ptr (),
@@ -2534,10 +2635,10 @@ struct COLR
     }
 
     auto *extents_funcs = hb_paint_extents_get_funcs ();
-    hb_paint_extents_context_t extents_data;
-    bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
+    scratch.paint_extents.clear ();
+    bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch);
 
-    hb_extents_t e = extents_data.get_extents ();
+    auto e = scratch.paint_extents.get_extents ();
     if (e.is_void ())
     {
       extents->x_bearing = 0;
@@ -2583,7 +2684,12 @@ struct COLR
 
 #ifndef HB_NO_PAINT
   bool
-  paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
+  paint_glyph (hb_font_t *font,
+	       hb_codepoint_t glyph,
+	       hb_paint_funcs_t *funcs, void *data,
+	       unsigned int palette_index, hb_color_t foreground,
+	       bool clip,
+	       hb_colr_scratch_t &scratch) const
   {
     ItemVarStoreInstancer instancer (get_var_store_ptr (),
 				     get_delta_set_index_map_ptr (),
@@ -2617,26 +2723,26 @@ struct COLR
 	  }
 	  else
 	  {
-	    auto *extents_funcs = hb_paint_extents_get_funcs ();
-	    hb_paint_extents_context_t extents_data;
+	    clip = false;
+	    is_bounded = false;
+	  }
+
+	  if (!is_bounded)
+	  {
+	    auto *bounded_funcs = hb_paint_bounded_get_funcs ();
+	    scratch.paint_bounded.clear ();
 
 	    paint_glyph (font, glyph,
-			 extents_funcs, &extents_data,
+			 bounded_funcs, &scratch.paint_bounded,
 			 palette_index, foreground,
-			 false);
-
-	    hb_extents_t extents = extents_data.get_extents ();
-	    is_bounded = extents_data.is_bounded ();
+			 false,
+			 scratch);
 
-	    c.funcs->push_clip_rectangle (c.data,
-					  extents.xmin,
-					  extents.ymin,
-					  extents.xmax,
-					  extents.ymax);
+	    is_bounded = scratch.paint_bounded.is_bounded ();
 	  }
 	}
 
-	c.funcs->push_root_transform (c.data, font);
+	c.funcs->push_font_transform (c.data, font);
 
 	if (is_bounded)
 	  c.recurse (*paint);
@@ -2714,9 +2820,7 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
       return;
 
     const Paint &paint = paint_offset_lists.get_paint (i);
-    c->funcs->push_group (c->data);
     c->recurse (paint);
-    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
   }
 }
 
@@ -2728,7 +2832,7 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
   if (unlikely (!node.visit (gid)))
     return;
 
-  c->funcs->push_inverse_root_transform (c->data, c->font);
+  c->funcs->push_inverse_font_transform (c->data, c->font);
   if (c->funcs->color_glyph (c->data, gid, c->font))
   {
     c->funcs->pop_transform (c->data);

+ 6 - 5
thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh

@@ -237,27 +237,28 @@ struct sbix
 
       int x_offset = 0, y_offset = 0;
       unsigned int strike_ppem = 0;
-      hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
       hb_glyph_extents_t extents;
       hb_glyph_extents_t pixel_extents;
 
-      if (blob == hb_blob_get_empty ())
+      if (!font->get_glyph_extents (glyph, &extents, false))
         return false;
 
-      if (!hb_font_get_glyph_extents (font, glyph, &extents))
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
         return false;
 
-      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+      hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
+      if (hb_blob_is_immutable (blob))
         return false;
 
       bool ret = funcs->image (data,
 			       blob,
 			       pixel_extents.width, -pixel_extents.height,
 			       HB_PAINT_IMAGE_FORMAT_PNG,
-			       font->slant_xy,
+			       0.f,
 			       &extents);
 
       hb_blob_destroy (blob);
+
       return ret;
     }
 

+ 8 - 7
thirdparty/harfbuzz/src/OT/Color/svg/svg.hh

@@ -104,15 +104,16 @@ struct SVG
       if (blob == hb_blob_get_empty ())
         return false;
 
-      funcs->image (data,
-		    blob,
-		    0, 0,
-		    HB_PAINT_IMAGE_FORMAT_SVG,
-		    font->slant_xy,
-		    nullptr);
+      bool ret = funcs->image (data,
+			       blob,
+			       0, 0,
+			       HB_PAINT_IMAGE_FORMAT_SVG,
+			       0.f,
+			       nullptr);
 
       hb_blob_destroy (blob);
-      return true;
+
+      return ret;
     }
 
     private:

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh

@@ -77,7 +77,7 @@ struct CoverageFormat1_3
 
   bool intersects (const hb_set_t *glyphs) const
   {
-    if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
+    if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len))
     {
       for (auto g : *glyphs)
         if (get_coverage (g) != NOT_COVERED)

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh

@@ -120,7 +120,7 @@ struct CoverageFormat2_4
 
   bool intersects (const hb_set_t *glyphs) const
   {
-    if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
+    if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
     {
       for (auto g : *glyphs)
         if (get_coverage (g) != NOT_COVERED)

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

@@ -205,20 +205,19 @@ struct CaretValueFormat3
 
     unsigned varidx = (this+deviceTable).get_variation_index ();
     hb_pair_t<unsigned, int> *new_varidx_delta;
-    if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
-      return_trace (false);
+    if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
+      uint32_t new_varidx = hb_first (*new_varidx_delta);
+      int delta = hb_second (*new_varidx_delta);
+      if (delta != 0)
+      {
+        if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+          return_trace (false);
+      }
 
-    uint32_t new_varidx = hb_first (*new_varidx_delta);
-    int delta = hb_second (*new_varidx_delta);
-    if (delta != 0)
-    {
-      if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
-        return_trace (false);
+      if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+        return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
     }
 
-    if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
-      return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
-
     if (!c->serializer->embed (deviceTable))
       return_trace (false);
 
@@ -1015,7 +1014,8 @@ struct GDEF
     hb_blob_ptr_t<GDEF> table;
 #ifndef HB_NO_GDEF_CACHE
     hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
-    mutable hb_cache_t<21, 3, 8> glyph_props_cache;
+    mutable hb_cache_t<21, 3> glyph_props_cache;
+    static_assert (sizeof (glyph_props_cache) == 512, "");
 #endif
   };
 

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

@@ -130,7 +130,7 @@ struct CursivePosFormat1
 	unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
     hb_barrier ();
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_from;
     if (unlikely (!skippy_iter.prev (&unsafe_from)))

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

@@ -152,8 +152,11 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
     for (unsigned i = 0; i < len; i++)
       propagate_attachment_offsets (pos, len, i, direction);
 
-  if (unlikely (font->slant))
+  if (unlikely (font->slant_xy) &&
+      HB_DIRECTION_IS_HORIZONTAL (direction))
   {
+    /* Slanting shaping results is only supported for horizontal text,
+     * as it gets weird otherwise. */
     for (unsigned i = 0; i < len; i++)
       if (unlikely (pos[i].y_offset))
         pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);

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

@@ -119,7 +119,7 @@ struct MarkBasePosFormat1_2
     /* Now we search backwards for a non-mark glyph.
      * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
 
     if (c->last_base_until > buffer->idx)

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

@@ -101,7 +101,7 @@ struct MarkLigPosFormat1_2
 
     /* Now we search backwards for a non-mark glyph */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
 
     if (c->last_base_until > buffer->idx)

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

@@ -100,7 +100,7 @@ struct MarkMarkPosFormat1_2
     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
     unsigned unsafe_from;

+ 2 - 2
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh

@@ -54,7 +54,7 @@ struct PairPosFormat1_3
   {
     auto &cov = this+coverage;
 
-    if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
+    if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len))
     {
       for (hb_codepoint_t g : glyphs->iter())
       {
@@ -148,7 +148,7 @@ struct PairPosFormat1_3
 #endif
     if (index == NOT_COVERED) return_trace (false);
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
     if (unlikely (!skippy_iter.next (&unsafe_to)))

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

@@ -179,7 +179,7 @@ struct PairPosFormat2_4 : ValueBase
 #endif
     if (index == NOT_COVERED) return_trace (false);
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset_fast (buffer->idx);
     unsigned unsafe_to;
     if (unlikely (!skippy_iter.next (&unsafe_to)))

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh

@@ -96,7 +96,7 @@ struct LigatureSet
      *
      * This is replicated in ChainRuleSet and RuleSet. */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);

+ 60 - 47
thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc

@@ -126,24 +126,18 @@ hb_transforming_pen_get_funcs ()
   return static_transforming_pen_funcs.get_unconst ();
 }
 
-
 hb_ubytes_t
-VarComponent::get_path_at (hb_font_t *font,
+VarComponent::get_path_at (const hb_varc_context_t &c,
 			   hb_codepoint_t parent_gid,
-			   hb_draw_session_t &draw_session,
 			   hb_array_t<const int> coords,
 			   hb_transform_t total_transform,
 			   hb_ubytes_t total_record,
-			   hb_decycler_t *decycler,
-			   signed *edges_left,
-			   signed depth_left,
-			   hb_glyf_scratch_t &scratch,
 			   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->table;
+  auto &VARC = *c.font->face->table.VARC->table;
   auto &varStore = &VARC+VARC.varStore;
 
 #define READ_UINT32VAR(name) \
@@ -193,9 +187,9 @@ VarComponent::get_path_at (hb_font_t *font,
 
   // Axis values
 
-  auto &axisIndices = scratch.axisIndices;
+  auto &axisIndices = c.scratch.axisIndices;
   axisIndices.clear ();
-  auto &axisValues = scratch.axisValues;
+  auto &axisValues = c.scratch.axisValues;
   axisValues.clear ();
   if (flags & (unsigned) flags_t::HAVE_AXES)
   {
@@ -222,7 +216,7 @@ VarComponent::get_path_at (hb_font_t *font,
    * 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);
+    component_coords = hb_array<int> (c.font->coords, c.font->num_coords);
 
   // Transform
 
@@ -316,14 +310,18 @@ VarComponent::get_path_at (hb_font_t *font,
       transform.scaleY = transform.scaleX;
 
     total_transform.transform (transform.to_transform ());
-    total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
-			   font->y_mult ? 1.f / font->y_multf : 0.f);
+    total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,
+			   c.font->y_mult ? 1.f / c.font->y_multf : 0.f);
+
+    bool same_coords = component_coords.length == coords.length &&
+		       component_coords.arrayZ == coords.arrayZ;
 
-    VARC.get_path_at (font, gid,
-		      draw_session, component_coords, total_transform,
+    c.depth_left--;
+    VARC.get_path_at (c, gid,
+		      component_coords, total_transform,
 		      parent_gid,
-		      decycler, edges_left, depth_left - 1,
-		      scratch);
+		      same_coords ? cache : nullptr);
+    c.depth_left++;
   }
 
 #undef PROCESS_TRANSFORM_COMPONENTS
@@ -333,16 +331,12 @@ VarComponent::get_path_at (hb_font_t *font,
 }
 
 bool
-VARC::get_path_at (hb_font_t *font,
+VARC::get_path_at (const hb_varc_context_t &c,
 		   hb_codepoint_t glyph,
-		   hb_draw_session_t &draw_session,
 		   hb_array_t<const int> coords,
 		   hb_transform_t transform,
 		   hb_codepoint_t parent_glyph,
-		   hb_decycler_t *decycler,
-		   signed *edges_left,
-		   signed depth_left,
-		   hb_glyf_scratch_t &scratch) const
+		   VarRegionList::cache_t *parent_cache) const
 {
   // Don't recurse on the same glyph.
   unsigned idx = glyph == parent_glyph ?
@@ -350,50 +344,69 @@ VARC::get_path_at (hb_font_t *font,
 		 (this+coverage).get_coverage (glyph);
   if (idx == NOT_COVERED)
   {
-    // 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,
-					   draw_session.funcs,
-					   draw_session.draw_data,
-					   &draw_session.st};
-    hb_draw_session_t transformer_session {transformer_funcs, &context};
-    hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
-
-    if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords, scratch))
+    if (c.draw_session)
+    {
+      // 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,
+					     c.draw_session->funcs,
+					     c.draw_session->draw_data,
+					     &c.draw_session->st};
+      hb_draw_session_t transformer_session {transformer_funcs, &context};
+      hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;
+
+      if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true;
 #ifndef HB_NO_CFF
-    if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
-    if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations
+      if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true;
+      if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations
 #endif
       return false;
+    }
+    else if (c.extents)
+    {
+      hb_glyph_extents_t glyph_extents;
+      if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))
+#ifndef HB_NO_CFF
+      if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))
+      if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations
+#endif
+	return false;
+
+      hb_extents_t comp_extents (glyph_extents);
+      transform.transform_extents (comp_extents);
+      c.extents->union_ (comp_extents);
+    }
     return true;
   }
 
-  if (depth_left <= 0)
+  if (c.depth_left <= 0)
     return true;
 
-  if (*edges_left <= 0)
+  if (c.edges_left <= 0)
     return true;
-  (*edges_left)--;
+  (c.edges_left)--;
 
-  hb_decycler_node_t node (*decycler);
+  hb_decycler_node_t node (c.decycler);
   if (unlikely (!node.visit (glyph)))
     return true;
 
   hb_ubytes_t record = (this+glyphRecords)[idx];
 
-  float static_cache[sizeof (void *) * 16];
-  VarRegionList::cache_t *cache = (this+varStore).create_cache (hb_array (static_cache));
+  VarRegionList::cache_t static_cache[sizeof (void *) * 16];
+  VarRegionList::cache_t *cache = parent_cache ?
+				  parent_cache :
+				  (this+varStore).create_cache (hb_array (static_cache));
 
-  transform.scale (font->x_multf, font->y_multf);
+  transform.scale (c.font->x_multf, c.font->y_multf);
 
-  VarCompositeGlyph::get_path_at (font, glyph,
-				  draw_session, coords, transform,
+  VarCompositeGlyph::get_path_at (c,
+				  glyph,
+				  coords, transform,
 				  record,
-				  decycler, edges_left, depth_left,
-				  scratch,
 				  cache);
 
-  (this+varStore).destroy_cache (cache, hb_array (static_cache));
+  if (cache != parent_cache)
+    (this+varStore).destroy_cache (cache, hb_array (static_cache));
 
   return true;
 }

+ 103 - 57
thirdparty/harfbuzz/src/OT/Var/VARC/VARC.hh

@@ -21,6 +21,24 @@ namespace OT {
 
 #ifndef HB_NO_VAR_COMPOSITES
 
+struct hb_varc_scratch_t
+{
+  hb_vector_t<unsigned> axisIndices;
+  hb_vector_t<float> axisValues;
+  hb_glyf_scratch_t glyf_scratch;
+};
+
+struct hb_varc_context_t
+{
+  hb_font_t *font;
+  hb_draw_session_t *draw_session;
+  hb_extents_t *extents;
+  mutable hb_decycler_t decycler;
+  mutable signed edges_left;
+  mutable signed depth_left;
+  hb_varc_scratch_t &scratch;
+};
+
 struct VarComponent
 {
   enum class flags_t : uint32_t
@@ -44,41 +62,32 @@ struct VarComponent
   };
 
   HB_INTERNAL hb_ubytes_t
-  get_path_at (hb_font_t *font,
+  get_path_at (const hb_varc_context_t &c,
 	       hb_codepoint_t parent_gid,
-	       hb_draw_session_t &draw_session,
 	       hb_array_t<const int> coords,
 	       hb_transform_t transform,
 	       hb_ubytes_t record,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch,
 	       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,
+  get_path_at (const hb_varc_context_t &c,
+	       hb_codepoint_t gid,
 	       hb_array_t<const int> coords,
 	       hb_transform_t transform,
 	       hb_ubytes_t record,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch,
-	       VarRegionList::cache_t *cache = nullptr)
+	       VarRegionList::cache_t *cache)
   {
     while (record)
     {
       const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
-      record = comp.get_path_at (font, glyph,
-				 draw_session, coords, transform,
+      record = comp.get_path_at (c,
+				 gid,
+				 coords, transform,
 				 record,
-				 decycler, edges_left, depth_left, scratch, cache);
+				 cache);
     }
   }
 };
@@ -92,36 +101,47 @@ struct VARC
   static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
 
   HB_INTERNAL bool
-  get_path_at (hb_font_t *font,
-	       hb_codepoint_t glyph,
-	       hb_draw_session_t &draw_session,
+  get_path_at (const hb_varc_context_t &c,
+	       hb_codepoint_t gid,
 	       hb_array_t<const int> coords,
-	       hb_transform_t transform,
-	       hb_codepoint_t parent_glyph,
-	       hb_decycler_t *decycler,
-	       signed *edges_left,
-	       signed depth_left,
-	       hb_glyf_scratch_t &scratch) const;
+	       hb_transform_t transform = HB_TRANSFORM_IDENTITY,
+	       hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
+	       VarRegionList::cache_t *parent_cache = nullptr) const;
 
   bool
   get_path (hb_font_t *font,
 	    hb_codepoint_t gid,
 	    hb_draw_session_t &draw_session,
-	    hb_glyf_scratch_t &scratch) const
+	    hb_varc_scratch_t &scratch) const
   {
-    hb_decycler_t decycler;
-    signed edges = HB_MAX_GRAPH_EDGE_COUNT;
-
-    return get_path_at (font,
-			gid,
-			draw_session,
-			hb_array (font->coords, font->num_coords),
-			HB_TRANSFORM_IDENTITY,
-			HB_CODEPOINT_INVALID,
-			&decycler,
-			&edges,
-			HB_MAX_NESTING_LEVEL,
-			scratch);
+    hb_varc_context_t c {font,
+			 &draw_session,
+			 nullptr,
+			 hb_decycler_t {},
+			 HB_MAX_GRAPH_EDGE_COUNT,
+			 HB_MAX_NESTING_LEVEL,
+			 scratch};
+
+    return get_path_at (c, gid,
+			hb_array (font->coords, font->num_coords));
+  }
+
+  bool
+  get_extents (hb_font_t *font,
+	       hb_codepoint_t gid,
+	       hb_extents_t *extents,
+	       hb_varc_scratch_t &scratch) const
+  {
+    hb_varc_context_t c {font,
+			 nullptr,
+			 extents,
+			 hb_decycler_t {},
+			 HB_MAX_GRAPH_EDGE_COUNT,
+			 HB_MAX_NESTING_LEVEL,
+			 scratch};
+
+    return get_path_at (c, gid,
+			hb_array (font->coords, font->num_coords));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -150,7 +170,7 @@ struct VARC
       auto *scratch = cached_scratch.get_relaxed ();
       if (scratch)
       {
-	scratch->~hb_glyf_scratch_t ();
+	scratch->~hb_varc_scratch_t ();
 	hb_free (scratch);
       }
 
@@ -162,34 +182,60 @@ struct VARC
     {
       if (!table->has_data ()) return false;
 
-      hb_glyf_scratch_t *scratch;
+      auto *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = table->get_path (font, gid, draw_session, *scratch);
+      release_scratch (scratch);
+      return ret;
+    }
+
+    bool
+    get_extents (hb_font_t *font,
+		 hb_codepoint_t gid,
+		 hb_glyph_extents_t *extents) const
+    {
+      if (!table->has_data ()) return false;
+
+      hb_extents_t f_extents;
+
+      auto *scratch = acquire_scratch ();
+      if (unlikely (!scratch)) return true;
+      bool ret = table->get_extents (font, gid, &f_extents, *scratch);
+      release_scratch (scratch);
+
+      if (ret)
+	*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
+
+      return ret;
+    }
+
+    private:
 
-      // Borrow the cached strach buffer.
+    hb_varc_scratch_t *acquire_scratch () const
+    {
+      hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
+
+      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
       {
-	scratch = cached_scratch.get_acquire ();
-	if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
-	{
-	  scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
-	  if (unlikely (!scratch))
-	    return true;
-	}
+	scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
+	if (unlikely (!scratch))
+	  return nullptr;
       }
 
-      bool ret = table->get_path (font, gid, draw_session, *scratch);
-
-      // Put it back.
+      return scratch;
+    }
+    void release_scratch (hb_varc_scratch_t *scratch) const
+    {
       if (!cached_scratch.cmpexch (nullptr, scratch))
       {
-        scratch->~hb_glyf_scratch_t ();
+	scratch->~hb_varc_scratch_t ();
 	hb_free (scratch);
       }
-
-      return ret;
     }
 
     private:
     hb_blob_ptr_t<VARC> table;
-    hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
+    mutable hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
   };
 
   bool has_data () const { return version.major != 0; }

+ 16 - 5
thirdparty/harfbuzz/src/OT/glyf/glyf.hh

@@ -429,16 +429,27 @@ struct glyf_accelerator_t
   }
 
   public:
-  bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+
+  bool get_extents (hb_font_t *font,
+		    hb_codepoint_t gid,
+		    hb_glyph_extents_t *extents) const
+  { return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); }
+
+  bool get_extents_at (hb_font_t *font,
+		       hb_codepoint_t gid,
+		       hb_glyph_extents_t *extents,
+		       hb_array_t<const int> coords) const
   {
     if (unlikely (gid >= num_glyphs)) return false;
 
 #ifndef HB_NO_VAR
-    if (font->num_coords)
+    if (coords)
     {
       hb_glyf_scratch_t scratch;
-      return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true),
-			 hb_array (font->coords, font->num_coords),
+      return get_points (font,
+			 gid,
+			 points_aggregator_t (font, extents, nullptr, true),
+			 coords,
 			 scratch);
     }
 #endif
@@ -532,7 +543,7 @@ struct glyf_accelerator_t
   unsigned int num_glyphs;
   hb_blob_ptr_t<loca> loca_table;
   hb_blob_ptr_t<glyf> glyf_table;
-  hb_atomic_ptr_t<hb_glyf_scratch_t> cached_scratch;
+  mutable hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
 };
 
 

+ 135 - 9
thirdparty/harfbuzz/src/hb-aat-layout-common.hh

@@ -29,6 +29,8 @@
 
 #include "hb-aat-layout.hh"
 #include "hb-aat-map.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-layout-gdef-table.hh"
 #include "hb-open-type.hh"
 #include "hb-cache.hh"
 #include "hb-bit-set.hh"
@@ -48,6 +50,61 @@ struct ankr;
 using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
 static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
 
+struct hb_aat_scratch_t
+{
+  hb_aat_scratch_t () = default;
+  hb_aat_scratch_t (const hb_aat_scratch_t &) = delete;
+
+  hb_aat_scratch_t (hb_aat_scratch_t &&o)
+  {
+    buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
+    o.buffer_glyph_set.set_relaxed (nullptr);
+  }
+  hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o)
+  {
+    buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
+    o.buffer_glyph_set.set_relaxed (nullptr);
+    return *this;
+  }
+  ~hb_aat_scratch_t ()
+  {
+    auto *s = buffer_glyph_set.get_relaxed ();
+    if (unlikely (!s))
+      return;
+    s->fini ();
+    hb_free (s);
+  }
+
+  hb_bit_set_t *create_buffer_glyph_set () const
+  {
+    hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
+    if (s && buffer_glyph_set.cmpexch (s, nullptr))
+      return s;
+
+    s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
+    if (unlikely (!s))
+      return nullptr;
+    s->init ();
+
+    return s;
+  }
+  void destroy_buffer_glyph_set (hb_bit_set_t *s) const
+  {
+    if (unlikely (!s))
+      return;
+    if (buffer_glyph_set.cmpexch (nullptr, s))
+      return;
+    s->fini ();
+    hb_free (s);
+  }
+
+  mutable hb_atomic_t<hb_bit_set_t *> buffer_glyph_set;
+};
+
+enum { DELETED_GLYPH = 0xFFFF };
+
+#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0
+
 struct hb_aat_apply_context_t :
        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
 {
@@ -64,10 +121,11 @@ struct hb_aat_apply_context_t :
   hb_buffer_t *buffer;
   hb_sanitize_context_t sanitizer;
   const ankr *ankr_table;
-  const OT::GDEF *gdef_table;
+  const OT::GDEF &gdef;
+  bool has_glyph_classes;
   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
   bool using_buffer_glyph_set = false;
-  hb_bit_set_t buffer_glyph_set;
+  hb_bit_set_t *buffer_glyph_set = nullptr;
   const hb_bit_set_t *left_set = nullptr;
   const hb_bit_set_t *right_set = nullptr;
   const hb_bit_set_t *machine_glyph_set = nullptr;
@@ -90,15 +148,15 @@ struct hb_aat_apply_context_t :
 
   void setup_buffer_glyph_set ()
   {
-    using_buffer_glyph_set = buffer->len >= 4;
+    using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
 
-    if (using_buffer_glyph_set)
-      buffer->collect_codepoints (buffer_glyph_set);
+    if (likely (using_buffer_glyph_set))
+      buffer->collect_codepoints (*buffer_glyph_set);
   }
   bool buffer_intersects_machine () const
   {
-    if (using_buffer_glyph_set)
-      return buffer_glyph_set.intersects (*machine_glyph_set);
+    if (likely (using_buffer_glyph_set))
+      return buffer_glyph_set->intersects (*machine_glyph_set);
 
     // Faster for shorter buffers.
     for (unsigned i = 0; i < buffer->len; i++)
@@ -106,6 +164,69 @@ struct hb_aat_apply_context_t :
 	return true;
     return false;
   }
+
+  template <typename T>
+  HB_NODISCARD bool output_glyphs (unsigned int count,
+				   const T *glyphs)
+  {
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add_array (glyphs, count);
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs[i] == DELETED_GLYPH)
+      {
+        buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
+	_hb_glyph_info_set_aat_deleted (&buffer->cur());
+      }
+      else
+      {
+#ifndef HB_NO_OT_LAYOUT
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->cur(),
+					  gdef.get_glyph_props (glyphs[i]));
+#endif
+      }
+      if (unlikely (!buffer->output_glyph (glyphs[i]))) return false;
+    }
+    return true;
+  }
+
+  HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph)
+  {
+    if (glyph == DELETED_GLYPH)
+    {
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
+      _hb_glyph_info_set_aat_deleted (&buffer->cur());
+    }
+
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add (glyph);
+#ifndef HB_NO_OT_LAYOUT
+    if (has_glyph_classes)
+      _hb_glyph_info_set_glyph_props (&buffer->cur(),
+				      gdef.get_glyph_props (glyph));
+#endif
+    return buffer->replace_glyph (glyph);
+  }
+
+  HB_NODISCARD bool delete_glyph ()
+  {
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
+    _hb_glyph_info_set_aat_deleted (&buffer->cur());
+    return buffer->replace_glyph (DELETED_GLYPH);
+  }
+
+  void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph)
+  {
+    buffer->info[i].codepoint = glyph;
+    if (likely (using_buffer_glyph_set))
+      buffer_glyph_set->add (glyph);
+#ifndef HB_NO_OT_LAYOUT
+    if (has_glyph_classes)
+      _hb_glyph_info_set_glyph_props (&buffer->info[i],
+				      gdef.get_glyph_props (glyph));
+#endif
+  }
 };
 
 
@@ -113,8 +234,6 @@ struct hb_aat_apply_context_t :
  * Lookup Table
  */
 
-enum { DELETED_GLYPH = 0xFFFF };
-
 template <typename T> struct Lookup;
 
 template <typename T>
@@ -179,6 +298,7 @@ struct LookupSegmentSingle
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
   {
+    if (first == DELETED_GLYPH) return;
     if (!filter (value)) return;
     glyphs.add_range (first, last);
   }
@@ -268,6 +388,7 @@ struct LookupSegmentArray
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
   {
+    if (first == DELETED_GLYPH) return;
     const auto &values = base+valuesZ;
     for (hb_codepoint_t i = first; i <= last; i++)
       if (filter (values[i - first]))
@@ -368,6 +489,7 @@ struct LookupSingle
   template <typename set_t, typename filter_t>
   void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
   {
+    if (glyph == DELETED_GLYPH) return;
     if (!filter (value)) return;
     glyphs.add (glyph);
   }
@@ -746,6 +868,10 @@ struct StateTable
     }
 
     // And glyphs in those classes.
+
+    if (filter (CLASS_DELETED_GLYPH))
+      glyphs.add (DELETED_GLYPH);
+
     (this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
   }
 

+ 45 - 17
thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh

@@ -185,6 +185,9 @@ struct Format1Entry<true>
     DEFINE_SIZE_STATIC (2);
   };
 
+  static bool initiateAction (const Entry<EntryData> &entry)
+  { return entry.flags & Push; }
+
   static bool performAction (const Entry<EntryData> &entry)
   { return entry.data.kernActionIndex != 0xFFFF; }
 
@@ -325,8 +328,9 @@ struct KerxSubTableFormat1
 	    }
 	    else if (buffer->info[idx].mask & kern_mask)
 	    {
-	      o.x_advance += c->font->em_scale_x (v);
-	      o.x_offset += c->font->em_scale_x (v);
+	      auto scaled = c->font->em_scale_x (v);
+	      o.x_advance += scaled;
+	      o.x_offset += scaled;
 	    }
 	  }
 	  else
@@ -394,10 +398,8 @@ struct KerxSubTableFormat1
   template <typename set_t>
   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
   {
-    set_t set;
-    machine.collect_glyphs (set, num_glyphs);
-    left_set.union_ (set);
-    right_set.union_ (set);
+    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
+    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
   }
 
   protected:
@@ -671,10 +673,8 @@ struct KerxSubTableFormat4
   template <typename set_t>
   void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
   {
-    set_t set;
-    machine.collect_glyphs (set, num_glyphs);
-    left_set.union_ (set);
-    right_set.union_ (set);
+    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
+    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
   }
 
   protected:
@@ -921,7 +921,18 @@ struct KerxSubTable
  * The 'kerx' Table
  */
 
-using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
+struct kern_subtable_accelerator_data_t
+{
+  hb_bit_set_t left_set;
+  hb_bit_set_t right_set;
+  mutable hb_aat_class_cache_t class_cache;
+};
+
+struct kern_accelerator_data_t
+{
+  hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
+  hb_aat_scratch_t scratch;
+};
 
 template <typename T>
 struct KerxTable
@@ -985,6 +996,8 @@ struct KerxTable
   {
     c->buffer->unsafe_to_concat ();
 
+    c->setup_buffer_glyph_set ();
+
     typedef typename T::SubTable SubTable;
 
     bool ret = false;
@@ -996,12 +1009,25 @@ struct KerxTable
     {
       bool reverse;
 
+      auto &subtable_accel = accel_data.subtable_accels[i];
+
       if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
 	goto skip;
 
       if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
 	goto skip;
 
+      c->left_set = &subtable_accel.left_set;
+      c->right_set = &subtable_accel.right_set;
+      c->machine_glyph_set = &subtable_accel.left_set;
+      c->machine_class_cache = &subtable_accel.class_cache;
+
+      if (!c->buffer_intersects_machine ())
+      {
+	(void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
+	goto skip;
+      }
+
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
@@ -1028,9 +1054,6 @@ struct KerxTable
       if (reverse)
 	c->buffer->reverse ();
 
-      c->left_set = &accel_data[i].first;
-      c->right_set = &accel_data[i].second;
-
       {
 	/* See comment in sanitize() for conditional here. */
 	hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@@ -1106,9 +1129,13 @@ struct KerxTable
     unsigned int count = thiz()->tableCount;
     for (unsigned int i = 0; i < count; i++)
     {
-      hb_bit_set_t left_set, right_set;
-      st->collect_glyphs (left_set, right_set, num_glyphs);
-      accel_data.push (hb_pair (left_set, right_set));
+      auto &subtable_accel = *accel_data.subtable_accels.push ();
+      if (unlikely (accel_data.subtable_accels.in_error ()))
+	  return accel_data;
+
+      st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
+      subtable_accel.class_cache.clear ();
+
       st = &StructAfter<SubTable> (*st);
     }
 
@@ -1137,6 +1164,7 @@ struct KerxTable
 
     hb_blob_ptr_t<T> table;
     kern_accelerator_data_t accel_data;
+    hb_aat_scratch_t scratch;
   };
 };
 

+ 18 - 66
thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh

@@ -30,8 +30,6 @@
 #include "hb-open-type.hh"
 #include "hb-aat-layout-common.hh"
 #include "hb-ot-layout.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-layout-gdef-table.hh"
 #include "hb-aat-map.hh"
 
 /*
@@ -178,12 +176,6 @@ struct RearrangementSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -242,9 +234,7 @@ struct ContextualSubtable
 	ret (false),
 	c (c_),
 	table (table_),
-	gdef (*c->gdef_table),
 	mark_set (false),
-	has_glyph_classes (gdef.has_glyph_classes ()),
 	mark (0),
 	subs (table+table->substitutionTables) {}
 
@@ -281,12 +271,7 @@ struct ContextualSubtable
       if (replacement)
       {
 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
-	hb_codepoint_t glyph = *replacement;
-	buffer->info[mark].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (mark, *replacement);
 	ret = true;
       }
 
@@ -312,12 +297,7 @@ struct ContextualSubtable
       }
       if (replacement)
       {
-	hb_codepoint_t glyph = *replacement;
-	buffer->info[idx].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (idx, *replacement);
 	ret = true;
       }
 
@@ -333,9 +313,7 @@ struct ContextualSubtable
     hb_aat_apply_context_t *c;
     const ContextualSubtable *table;
     private:
-    const OT::GDEF &gdef;
     bool mark_set;
-    bool has_glyph_classes;
     unsigned int mark;
     const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
   };
@@ -348,12 +326,6 @@ struct ContextualSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -581,7 +553,7 @@ struct LigatureSubtable
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
-	    if (unlikely (!buffer->replace_glyph (lig))) return;
+	    if (unlikely (!c->replace_glyph (lig))) return;
 
 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
@@ -589,8 +561,7 @@ struct LigatureSubtable
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
 	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
-	      _hb_glyph_info_set_default_ignorable (&buffer->cur());
-	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
+	      if (!c->delete_glyph ()) return;
 	    }
 
 	    if (unlikely (!buffer->move_to (lig_end))) return;
@@ -624,12 +595,6 @@ struct LigatureSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -665,15 +630,6 @@ struct NoncontextualSubtable
   {
     TRACE_APPLY (this);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
-    const OT::GDEF &gdef (*c->gdef_table);
-    bool has_glyph_classes = gdef.has_glyph_classes ();
-
     bool ret = false;
     unsigned int num_glyphs = c->face->get_num_glyphs ();
 
@@ -703,12 +659,7 @@ struct NoncontextualSubtable
       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
-	hb_codepoint_t glyph = *replacement;
-	info[i].codepoint = glyph;
-	c->buffer_glyph_set.add (glyph);
-	if (has_glyph_classes)
-	  _hb_glyph_info_set_glyph_props (&info[i],
-					  gdef.get_glyph_props (*replacement));
+	c->replace_glyph_inplace (i, *replacement);
 	ret = true;
       }
     }
@@ -850,9 +801,7 @@ struct InsertionSubtable
 	if (buffer->idx < buffer->len && !before)
 	  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_glyph_set.add (glyphs[i]);
+	if (unlikely (!c->output_glyphs (count, glyphs))) return;
 	ret = true;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
@@ -881,7 +830,8 @@ struct InsertionSubtable
 	if (buffer->idx < buffer->len && !before)
 	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
+	if (unlikely (!c->output_glyphs (count, glyphs))) return;
+	ret = true;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
@@ -921,12 +871,6 @@ struct InsertionSubtable
 
     StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
 
-    if (!c->buffer_intersects_machine ())
-    {
-      (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
-      return_trace (false);
-    }
-
     driver.drive (&dc, c);
 
     return_trace (dc.ret);
@@ -1224,6 +1168,7 @@ struct Chain
       if (hb_none (hb_iter (c->range_flags) |
 		   hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
 	goto skip;
+
       c->subtable_flags = subtable_flags;
       c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
       c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
@@ -1233,6 +1178,12 @@ struct Chain
 	  bool (coverage & ChainSubtable<Types>::Vertical))
 	goto skip;
 
+      if (!c->buffer_intersects_machine ())
+      {
+	(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
+	goto skip;
+      }
+
       /* Buffer contents is always in logical direction.  Determine if
        * we need to reverse before applying this subtable.  We reverse
        * back after if we did reverse indeed.
@@ -1376,7 +1327,7 @@ struct mortmorx
 
       this->chain_count = table->get_chain_count ();
 
-      this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
+      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
       if (unlikely (!this->accels))
       {
 	this->chain_count = 0;
@@ -1423,7 +1374,8 @@ struct mortmorx
 
     hb_blob_ptr_t<T> table;
     unsigned int chain_count;
-    hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
+    hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
+    hb_aat_scratch_t scratch;
   };
 
 

+ 44 - 3
thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh

@@ -31,6 +31,7 @@
 #include "hb-aat-layout-common.hh"
 #include "hb-ot-layout.hh"
 #include "hb-open-type.hh"
+#include "hb-ot-stat-table.hh"
 
 /*
  * trak -- Tracking
@@ -115,7 +116,7 @@ struct TrackTableEntry
 
   protected:
   F16DOT16	track;		/* Track value for this record. */
-  NameID	trackNameID;	/* The 'name' table index for this track.
+  OT::NameID	trackNameID;	/* The 'name' table index for this track.
 				 * (a short word or phrase like "loose"
 				 * or "very tight") */
   NNOffset16To<UnsizedArrayOf<FWORD>>
@@ -142,9 +143,9 @@ struct TrackData
     unsigned j = count - 1;
 
     // Find the two entries that track is between.
-    while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
+    while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
       i++;
-    while (j > 0 && trackTable[j - 1].get_track_value () > track)
+    while (j > 0 && trackTable[j - 1].get_track_value () >= track)
       j--;
 
     // Exact match.
@@ -200,6 +201,46 @@ struct trak
     float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
     return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track));
   }
+  hb_position_t get_tracking (hb_font_t *font, hb_direction_t dir, float track = 0.f) const
+  {
+#ifndef HB_NO_STYLE
+    if (!font->face->table.STAT->has_data ())
+      return 0;
+    return HB_DIRECTION_IS_HORIZONTAL (dir) ?
+      get_h_tracking (font, track) :
+      get_v_tracking (font, track);
+#else
+    return 0;
+#endif
+  }
+
+  bool apply (hb_aat_apply_context_t *c, float track = 0.f) const
+  {
+    TRACE_APPLY (this);
+
+    float ptem = c->font->ptem;
+    if (unlikely (ptem <= 0.f))
+    {
+      /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
+      ptem = HB_CORETEXT_DEFAULT_FONT_SIZE;
+    }
+
+    hb_buffer_t *buffer = c->buffer;
+    if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+    {
+      hb_position_t advance_to_add = get_h_tracking (c->font, track);
+      foreach_grapheme (buffer, start, end)
+	buffer->pos[start].x_advance += advance_to_add;
+    }
+    else
+    {
+      hb_position_t advance_to_add = get_v_tracking (c->font, track);
+      foreach_grapheme (buffer, start, end)
+	buffer->pos[start].y_advance += advance_to_add;
+    }
+
+    return_trace (true);
+  }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {

+ 35 - 24
thirdparty/harfbuzz/src/hb-aat-layout.cc

@@ -34,7 +34,7 @@
 #include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-kerx-table.hh"
 #include "hb-aat-layout-morx-table.hh"
-#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-aat-layout-trak-table.hh"
 #include "hb-aat-ltag-table.hh"
 
 #include "hb-ot-layout-gsub-table.hh"
@@ -58,13 +58,14 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
 						       buffer (buffer_),
 						       sanitizer (),
 						       ankr_table (&Null (AAT::ankr)),
-						       gdef_table (
+						       gdef (
 #ifndef HB_NO_OT_LAYOUT
-							 face->table.GDEF->table
+							 *face->table.GDEF->table
 #else
-							 &Null (GDEF)
+							 Null (GDEF)
 #endif
 						       ),
+						       has_glyph_classes (gdef.has_glyph_classes ()),
 						       lookup_index (0)
 {
   sanitizer.init (blob);
@@ -203,7 +204,7 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 #endif
 
 
-#ifndef HB_NO_AAT
+#ifndef HB_NO_AAT_SHAPE
 
 /*
  * mort/morx/kerx/trak
@@ -287,11 +288,14 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  const hb_feature_t *features,
 			  unsigned num_features)
 {
-  hb_aat_map_builder_t builder (font->face, plan->props);
-  for (unsigned i = 0; i < num_features; i++)
-    builder.add_feature (features[i]);
   hb_aat_map_t map;
-  builder.compile (map);
+  if (num_features)
+  {
+    hb_aat_map_builder_t builder (font->face, plan->props);
+    for (unsigned i = 0; i < num_features; i++)
+      builder.add_feature (features[i]);
+    builder.compile (map);
+  }
 
   {
     auto &accel = *font->face->table.morx;
@@ -300,7 +304,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
     {
       AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
       if (!buffer->message (font, "start table morx")) return;
-      morx.apply (&c, map, accel);
+      c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
+      morx.apply (&c, num_features ? map : plan->aat_map, accel);
+      accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
+      c.buffer_glyph_set = nullptr;
       (void) buffer->message (font, "end table morx");
       return;
     }
@@ -313,34 +320,24 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
     {
       AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
       if (!buffer->message (font, "start table mort")) return;
-      mort.apply (&c, map, accel);
+      mort.apply (&c, num_features ? map : plan->aat_map, accel);
       (void) buffer->message (font, "end table mort");
       return;
     }
   }
 }
 
-void
-hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
-{
-  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 (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
-      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
-}
-
 static bool
 is_deleted_glyph (const hb_glyph_info_t *info)
 {
-  return info->codepoint == AAT::DELETED_GLYPH;
+  return _hb_glyph_info_is_aat_deleted (info);
 }
 
 void
 hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
 {
-  buffer->delete_glyphs_inplace (is_deleted_glyph);
+  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED)
+    buffer->delete_glyphs_inplace (is_deleted_glyph);
 }
 
 /**
@@ -371,8 +368,11 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
   if (!buffer->message (font, "start table kerx")) return;
+  c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
   c.set_ankr_table (font->face->table.ankr.get ());
   accel.apply (&c);
+  accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
+  c.buffer_glyph_set = nullptr;
   (void) buffer->message (font, "end table kerx");
 }
 
@@ -394,6 +394,17 @@ hb_aat_layout_has_tracking (hb_face_t *face)
   return face->table.trak->has_data ();
 }
 
+void
+hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
+		     hb_font_t *font,
+		     hb_buffer_t *buffer)
+{
+  const AAT::trak& trak = *font->face->table.trak;
+
+  AAT::hb_aat_apply_context_t c (plan, font, buffer);
+  trak.apply (&c);
+}
+
 /**
  * hb_aat_layout_get_feature_types:
  * @face: #hb_face_t to work upon

+ 5 - 3
thirdparty/harfbuzz/src/hb-aat-layout.hh

@@ -60,9 +60,6 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  const hb_feature_t *features,
 			  unsigned num_features);
 
-HB_INTERNAL void
-hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
-
 HB_INTERNAL void
 hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
 
@@ -71,5 +68,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
 			hb_font_t *font,
 			hb_buffer_t *buffer);
 
+HB_INTERNAL void
+hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
+		     hb_font_t *font,
+		     hb_buffer_t *buffer);
+
 
 #endif /* HB_AAT_LAYOUT_HH */

+ 5 - 0
thirdparty/harfbuzz/src/hb-aat-map.cc

@@ -85,6 +85,11 @@ void
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 {
   /* Compute active features per range, and compile each. */
+  if (!features.length)
+  {
+    hb_aat_layout_compile_map (this, &m);
+    return;
+  }
 
   /* Sort features by start/end events. */
   hb_vector_t<feature_event_t> feature_events;

+ 31 - 47
thirdparty/harfbuzz/src/hb-atomic.hh

@@ -80,15 +80,14 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 
 #include <atomic>
 
-#define _hb_memory_barrier()			std::atomic_thread_fence(std::memory_order_ack_rel)
 #define _hb_memory_r_barrier()			std::atomic_thread_fence(std::memory_order_acquire)
 #define _hb_memory_w_barrier()			std::atomic_thread_fence(std::memory_order_release)
 
-#define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
-#define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
-#define hb_atomic_int_impl_set(AI, V)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
-#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
+#define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
+#define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
+#define hb_atomic_int_impl_set(AI, V)		(reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
+#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
 
 #define hb_atomic_ptr_impl_set_relaxed(P, V)	(reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
@@ -149,68 +148,53 @@ static inline void _hb_compiler_memory_r_barrier () {}
 #define hb_atomic_ptr_impl_get_relaxed(P)	(*(P))
 #endif
 #ifndef hb_atomic_int_impl_set
-inline void hb_atomic_int_impl_set (int *AI, int v)	{ _hb_memory_w_barrier (); *AI = v; }
-inline void hb_atomic_int_impl_set (short *AI, short v)	{ _hb_memory_w_barrier (); *AI = v; }
+template <typename T>
+inline void hb_atomic_int_impl_set (T *AI, T v)	{ _hb_memory_w_barrier (); *AI = v; }
 #endif
 #ifndef hb_atomic_int_impl_get
-inline int hb_atomic_int_impl_get (const int *AI)	{ int v = *AI; _hb_memory_r_barrier (); return v; }
-inline short hb_atomic_int_impl_get (const short *AI)	{ short v = *AI; _hb_memory_r_barrier (); return v; }
+template <typename T>
+inline T hb_atomic_int_impl_get (const T *AI)	{ T v = *AI; _hb_memory_r_barrier (); return v; }
 #endif
 #ifndef hb_atomic_ptr_impl_get
 inline void *hb_atomic_ptr_impl_get (void ** const P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
 #endif
 
 
-struct hb_atomic_short_t
+template <typename T>
+struct hb_atomic_t
 {
-  hb_atomic_short_t () = default;
-  constexpr hb_atomic_short_t (short v) : v (v) {}
+  hb_atomic_t () = default;
+  constexpr hb_atomic_t (T v) : v (v) {}
 
-  hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
-  operator short () const { return get_relaxed (); }
+  hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
+  operator T () const { return get_relaxed (); }
 
-  void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
-  void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
-  short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
-  short get_acquire () const { return hb_atomic_int_impl_get (&v); }
-  short inc () { return hb_atomic_int_impl_add (&v,  1); }
-  short dec () { return hb_atomic_int_impl_add (&v, -1); }
+  void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
+  void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
+  T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
+  T get_acquire () const { return hb_atomic_int_impl_get (&v); }
+  T inc () { return hb_atomic_int_impl_add (&v,  1); }
+  T dec () { return hb_atomic_int_impl_add (&v, -1); }
 
-  short v = 0;
-};
-
-struct hb_atomic_int_t
-{
-  hb_atomic_int_t () = default;
-  constexpr hb_atomic_int_t (int v) : v (v) {}
+  int operator ++ (int) { return inc (); }
+  int operator -- (int) { return dec (); }
+  long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
 
-  hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
-  operator int () const { return get_relaxed (); }
-
-  void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
-  void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
-  int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
-  int get_acquire () const { return hb_atomic_int_impl_get (&v); }
-  int inc () { return hb_atomic_int_impl_add (&v,  1); }
-  int dec () { return hb_atomic_int_impl_add (&v, -1); }
-
-  int v = 0;
+  T v = 0;
 };
 
-template <typename P>
-struct hb_atomic_ptr_t
+template <typename T>
+struct hb_atomic_t<T*>
 {
-  typedef hb_remove_pointer<P> T;
-
-  hb_atomic_ptr_t () = default;
-  constexpr hb_atomic_ptr_t (T* v) : v (v) {}
-  hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
+  hb_atomic_t () = default;
+  constexpr hb_atomic_t (T* v) : v (v) {}
+  hb_atomic_t (const hb_atomic_t &other) = delete;
 
   void init (T* v_ = nullptr) { set_relaxed (v_); }
   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
   T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
   T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
-  bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
+  bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
 
   operator bool () const { return get_acquire () != nullptr; }
   T * operator -> () const                    { return get_acquire (); }

+ 2 - 2
thirdparty/harfbuzz/src/hb-bit-set.hh

@@ -77,7 +77,7 @@ struct hb_bit_set_t
 
   bool successful = true; /* Allocations successful */
   mutable unsigned int population = 0;
-  mutable hb_atomic_int_t last_page_lookup = 0;
+  mutable hb_atomic_t<unsigned> last_page_lookup = 0;
   hb_sorted_vector_t<page_map_t> page_map;
   hb_vector_t<page_t> pages;
 
@@ -88,7 +88,7 @@ struct hb_bit_set_t
   {
     if (unlikely (!successful)) return false;
 
-    if (pages.length < count && count <= 2)
+    if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
       exact_size = true; // Most sets are small and local
 
     if (unlikely (!pages.resize (count, clear, exact_size) ||

+ 195 - 0
thirdparty/harfbuzz/src/hb-bit-vector.hh

@@ -0,0 +1,195 @@
+/*
+ *  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BIT_VECTOR_HH
+#define HB_BIT_VECTOR_HH
+
+#include "hb.hh"
+
+#include "hb-atomic.hh"
+
+struct hb_min_max_t
+{
+  void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); }
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    min_v = hb_min (min_v, a);
+    max_v = hb_max (max_v, b);
+  }
+
+  template <typename set_t>
+  void union_ (const set_t &set)
+  {
+    hb_codepoint_t set_min = set.get_min ();
+    if (unlikely (set_min == HB_CODEPOINT_INVALID))
+      return;
+    hb_codepoint_t set_max = set.get_max ();
+    min_v = hb_min (min_v, set_min);
+    max_v = hb_max (max_v, set_max);
+  }
+
+  hb_codepoint_t get_min () const { return min_v; }
+  hb_codepoint_t get_max () const { return max_v; }
+
+  private:
+  hb_codepoint_t min_v = HB_CODEPOINT_INVALID;
+  hb_codepoint_t max_v = 0;
+};
+
+template <bool atomic = false>
+struct hb_bit_vector_t
+{
+  using int_t = uint64_t;
+  using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type;
+
+  hb_bit_vector_t () = delete;
+  hb_bit_vector_t (const hb_bit_vector_t &other) = delete;
+  hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete;
+
+  // Move
+  hb_bit_vector_t (hb_bit_vector_t &&other)
+		: min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts)
+  {
+    other.min_v = other.max_v = other.count = 0;
+    other.elts = nullptr;
+  }
+  hb_bit_vector_t &operator= (hb_bit_vector_t &&other)
+  {
+    hb_swap (min_v, other.min_v);
+    hb_swap (max_v, other.max_v);
+    hb_swap (count, other.count);
+    hb_swap (elts, other.elts);
+    return *this;
+  }
+
+  hb_bit_vector_t (unsigned min_v, unsigned max_v)
+    : min_v (min_v), max_v (max_v)
+  {
+    if (unlikely (min_v >= max_v))
+    {
+      min_v = max_v = count = 0;
+      return;
+    }
+
+    unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8);
+    elts = (elt_t *) hb_calloc (num, sizeof (int_t));
+    if (unlikely (!elts))
+    {
+      min_v = max_v = count = 0;
+      return;
+    }
+
+    count = max_v - min_v + 1;
+  }
+  ~hb_bit_vector_t ()
+  {
+    hb_free (elts);
+  }
+
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+  void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
+  bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
+  bool has (hb_codepoint_t g) const { return get (g); }
+  bool may_have (hb_codepoint_t g) const { return get (g); }
+
+  bool operator [] (hb_codepoint_t g) const { return get (g); }
+  bool operator () (hb_codepoint_t g) const { return get (g); }
+
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!count || a > b || a < min_v || b > max_v))
+      return;
+
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la |= (mask (b) << 1) - mask(a);
+    else
+    {
+      *la |= ~(mask (a) - 1llu);
+      la++;
+
+      hb_memset (la, 0xff, (char *) lb - (char *) la);
+
+      *lb |= ((mask (b) << 1) - 1llu);
+    }
+  }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!count || a > b || a < min_v || b > max_v))
+      return;
+
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la &= ~((mask (b) << 1llu) - mask(a));
+    else
+    {
+      *la &= mask (a) - 1;
+      la++;
+
+      hb_memset (la, 0, (char *) lb - (char *) la);
+
+      *lb &= ~((mask (b) << 1) - 1llu);
+    }
+  }
+  void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
+  { if (v) add_range (a, b); else del_range (a, b); }
+
+  template <typename set_t>
+  void union_ (const set_t &set)
+  {
+    for (hb_codepoint_t g : set)
+      add (g);
+  }
+
+  static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+
+  static constexpr elt_t zero = 0;
+
+  elt_t &elt (hb_codepoint_t g)
+  {
+    g -= min_v;
+    if (unlikely (g >= count))
+      return Crap(elt_t);
+    return elts[g / ELT_BITS];
+  }
+  const elt_t& elt (hb_codepoint_t g) const
+  {
+    g -= min_v;
+    if (unlikely (g >= count))
+      return Null(elt_t);
+    return elts[g / ELT_BITS];
+  }
+
+  static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
+
+  hb_codepoint_t min_v = 0, max_v = 0, count = 0;
+  elt_t *elts = nullptr;
+};
+
+
+#endif /* HB_BIT_VECTOR_HH */

+ 266 - 336
thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh

@@ -32,62 +32,68 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-json.hh"
+#line 33 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
-	0u, 0u, 9u, 123u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 
-	9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
-	9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 
-	34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 
-	9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 
-	9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
-	9u, 93u, 9u, 123u, 0u, 0u, 0
+	0u, 0u, 9u, 34u, 97u, 121u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
+	9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
+	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
+	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
+	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 
+	9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 
+	34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 
+	34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 98u, 98u, 9u, 123u, 9u, 123u, 9u, 123u, 
+	0
 };
 
 static const char _deserialize_json_key_spans[] = {
-	0, 115, 115, 26, 21, 2, 1, 50, 
-	49, 10, 117, 117, 117, 1, 50, 49, 
-	10, 117, 117, 1, 1, 50, 49, 117, 
-	117, 2, 1, 50, 49, 10, 117, 117, 
-	1, 50, 49, 10, 117, 117, 1, 1, 
-	50, 49, 117, 117, 1, 50, 49, 59, 
-	117, 59, 117, 117, 1, 50, 49, 117, 
-	85, 115, 0
+	0, 26, 25, 2, 1, 50, 49, 10, 
+	117, 117, 85, 117, 1, 50, 49, 10, 
+	117, 117, 1, 1, 50, 49, 117, 117, 
+	2, 1, 50, 49, 10, 117, 117, 1, 
+	50, 49, 10, 117, 117, 1, 1, 50, 
+	49, 117, 117, 1, 50, 49, 59, 117, 
+	59, 117, 117, 1, 50, 49, 10, 117, 
+	1, 50, 49, 117, 1, 115, 115, 115
 };
 
 static const short _deserialize_json_index_offsets[] = {
-	0, 0, 116, 232, 259, 281, 284, 286, 
-	337, 387, 398, 516, 634, 752, 754, 805, 
-	855, 866, 984, 1102, 1104, 1106, 1157, 1207, 
-	1325, 1443, 1446, 1448, 1499, 1549, 1560, 1678, 
-	1796, 1798, 1849, 1899, 1910, 2028, 2146, 2148, 
-	2150, 2201, 2251, 2369, 2487, 2489, 2540, 2590, 
-	2650, 2768, 2828, 2946, 3064, 3066, 3117, 3167, 
-	3285, 3371, 3487
+	0, 0, 27, 53, 56, 58, 109, 159, 
+	170, 288, 406, 492, 610, 612, 663, 713, 
+	724, 842, 960, 962, 964, 1015, 1065, 1183, 
+	1301, 1304, 1306, 1357, 1407, 1418, 1536, 1654, 
+	1656, 1707, 1757, 1768, 1886, 2004, 2006, 2008, 
+	2059, 2109, 2227, 2345, 2347, 2398, 2448, 2508, 
+	2626, 2686, 2804, 2922, 2924, 2975, 3025, 3036, 
+	3154, 3156, 3207, 3257, 3375, 3377, 3493, 3609
 };
 
 static const char _deserialize_json_indicies[] = {
 	0, 0, 0, 0, 0, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	0, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 2, 1, 3, 1, 4, 5, 
+	1, 6, 7, 8, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	9, 1, 8, 10, 10, 1, 11, 12, 
+	1, 13, 1, 13, 13, 13, 13, 13, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 13, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 14, 1, 14, 14, 
+	14, 14, 14, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 2, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 3, 1, 2, 2, 2, 
-	2, 2, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 2, 1, 1, 1, 
+	1, 1, 1, 1, 1, 14, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 15, 1, 1, 16, 17, 17, 
+	17, 17, 17, 17, 17, 17, 17, 1, 
+	18, 19, 19, 19, 19, 19, 19, 19, 
+	19, 19, 1, 20, 20, 20, 20, 20, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 20, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 21, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -95,48 +101,41 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 3, 
-	1, 4, 4, 4, 4, 4, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	4, 1, 5, 1, 6, 1, 7, 8, 
-	1, 9, 10, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 22, 
+	1, 23, 23, 23, 23, 23, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	11, 1, 12, 13, 1, 14, 1, 14, 
-	14, 14, 14, 14, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 14, 1, 
+	23, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 0, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	15, 1, 15, 15, 15, 15, 15, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 15, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 16, 1, 
-	1, 17, 18, 18, 18, 18, 18, 18, 
-	18, 18, 18, 1, 19, 20, 20, 20, 
-	20, 20, 20, 20, 20, 20, 1, 21, 
-	21, 21, 21, 21, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 21, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 22, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 24, 1, 24, 
+	24, 24, 24, 24, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 24, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 25, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 23, 1, 24, 24, 24, 
-	24, 24, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 25, 1, 20, 20, 20, 
+	20, 20, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 24, 1, 1, 1, 
+	1, 1, 1, 1, 20, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	4, 1, 1, 1, 1, 1, 1, 1, 
+	21, 1, 1, 1, 19, 19, 19, 19, 
+	19, 19, 19, 19, 19, 19, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -145,43 +144,42 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 22, 1, 26, 1, 26, 26, 26, 
+	26, 26, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 25, 1, 21, 21, 21, 21, 21, 
+	1, 1, 1, 1, 26, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 21, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 22, 1, 
-	1, 1, 20, 20, 20, 20, 20, 20, 
-	20, 20, 20, 20, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 27, 1, 
+	27, 27, 27, 27, 27, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 27, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 28, 1, 1, 29, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 1, 31, 32, 32, 32, 32, 32, 
+	32, 32, 32, 32, 1, 33, 33, 33, 
+	33, 33, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 33, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	34, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 23, 
-	1, 26, 1, 26, 26, 26, 26, 26, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 26, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 27, 1, 27, 27, 
-	27, 27, 27, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 27, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 1, 1, 29, 30, 30, 
-	30, 30, 30, 30, 30, 30, 30, 1, 
-	31, 32, 32, 32, 32, 32, 32, 32, 
-	32, 32, 1, 33, 33, 33, 33, 33, 
+	1, 35, 1, 33, 33, 33, 33, 33, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 33, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 34, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 32, 32, 32, 32, 32, 32, 
+	32, 32, 32, 32, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -190,39 +188,41 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 35, 
-	1, 33, 33, 33, 33, 33, 1, 1, 
+	1, 36, 1, 37, 1, 37, 37, 37, 
+	37, 37, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 37, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	33, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 34, 1, 1, 1, 
-	32, 32, 32, 32, 32, 32, 32, 32, 
-	32, 32, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 38, 1, 
+	38, 38, 38, 38, 38, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 38, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 39, 
+	40, 40, 40, 40, 40, 40, 40, 40, 
+	40, 1, 41, 41, 41, 41, 41, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 41, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 42, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 35, 1, 36, 
-	1, 37, 1, 37, 37, 37, 37, 37, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 37, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 38, 1, 38, 38, 
-	38, 38, 38, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 38, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 39, 40, 40, 
-	40, 40, 40, 40, 40, 40, 40, 1, 
+	1, 1, 1, 1, 1, 1, 43, 1, 
 	41, 41, 41, 41, 41, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 41, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 42, 1, 1, 1, 1, 
+	1, 1, 1, 42, 1, 1, 1, 44, 
+	44, 44, 44, 44, 44, 44, 44, 44, 
+	44, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -230,43 +230,43 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 43, 1, 45, 46, 
+	1, 47, 1, 47, 47, 47, 47, 47, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 43, 1, 41, 41, 
-	41, 41, 41, 1, 1, 1, 1, 1, 
+	1, 1, 47, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 41, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 42, 1, 1, 1, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 1, 
+	1, 1, 1, 1, 48, 1, 48, 48, 
+	48, 48, 48, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 48, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 49, 1, 1, 50, 51, 51, 
+	51, 51, 51, 51, 51, 51, 51, 1, 
+	52, 53, 53, 53, 53, 53, 53, 53, 
+	53, 53, 1, 54, 54, 54, 54, 54, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 54, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 55, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 43, 1, 45, 46, 1, 47, 
-	1, 47, 47, 47, 47, 47, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	47, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 48, 1, 48, 48, 48, 48, 
-	48, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 48, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	49, 1, 1, 50, 51, 51, 51, 51, 
-	51, 51, 51, 51, 51, 1, 52, 53, 
-	53, 53, 53, 53, 53, 53, 53, 53, 
+	1, 1, 1, 1, 1, 1, 1, 56, 
 	1, 54, 54, 54, 54, 54, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	54, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 55, 1, 1, 1, 
+	53, 53, 53, 53, 53, 53, 53, 53, 
+	53, 53, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -274,44 +274,42 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 56, 1, 57, 
+	1, 57, 57, 57, 57, 57, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 56, 1, 54, 
-	54, 54, 54, 54, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 54, 1, 
+	57, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 55, 1, 1, 1, 53, 53, 
-	53, 53, 53, 53, 53, 53, 53, 53, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 58, 1, 58, 58, 58, 58, 
+	58, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 58, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	59, 1, 1, 60, 61, 61, 61, 61, 
+	61, 61, 61, 61, 61, 1, 62, 63, 
+	63, 63, 63, 63, 63, 63, 63, 63, 
+	1, 64, 64, 64, 64, 64, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	64, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 65, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 56, 1, 57, 1, 57, 
-	57, 57, 57, 57, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 57, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	58, 1, 58, 58, 58, 58, 58, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 58, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 59, 1, 
-	1, 60, 61, 61, 61, 61, 61, 61, 
-	61, 61, 61, 1, 62, 63, 63, 63, 
-	63, 63, 63, 63, 63, 63, 1, 64, 
+	1, 1, 1, 1, 1, 66, 1, 64, 
 	64, 64, 64, 64, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 64, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 65, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 65, 1, 1, 1, 63, 63, 
+	63, 63, 63, 63, 63, 63, 63, 63, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -320,39 +318,41 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 66, 1, 64, 64, 64, 
-	64, 64, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 66, 1, 67, 1, 68, 
+	1, 68, 68, 68, 68, 68, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 64, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	65, 1, 1, 1, 63, 63, 63, 63, 
-	63, 63, 63, 63, 63, 63, 1, 1, 
+	68, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 69, 1, 69, 69, 69, 69, 
+	69, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 69, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 70, 71, 71, 71, 71, 
+	71, 71, 71, 71, 71, 1, 72, 72, 
+	72, 72, 72, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 72, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 73, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 66, 1, 67, 1, 68, 1, 68, 
-	68, 68, 68, 68, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 68, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	69, 1, 69, 69, 69, 69, 69, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 69, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 70, 71, 71, 71, 71, 71, 71, 
-	71, 71, 71, 1, 72, 72, 72, 72, 
+	1, 1, 74, 1, 72, 72, 72, 72, 
 	72, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 72, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 73, 
+	1, 1, 1, 75, 75, 75, 75, 75, 
+	75, 75, 75, 75, 75, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -361,71 +361,70 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	74, 1, 76, 1, 76, 76, 76, 76, 
+	76, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 76, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	74, 1, 72, 72, 72, 72, 72, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 77, 1, 77, 
+	77, 77, 77, 77, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 72, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 73, 1, 1, 
-	1, 75, 75, 75, 75, 75, 75, 75, 
-	75, 75, 75, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 77, 1, 
+	78, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 79, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	1, 82, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 83, 81, 84, 84, 84, 
+	84, 84, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 84, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	85, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 74, 1, 
-	76, 1, 76, 76, 76, 76, 76, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 76, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 77, 1, 77, 77, 77, 
-	77, 77, 1, 1, 1, 1, 1, 1, 
+	1, 86, 1, 81, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 77, 1, 78, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 79, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 1, 82, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 81, 81, 81, 81, 81, 81, 81, 
-	81, 83, 81, 84, 84, 84, 84, 84, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 84, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 85, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 81, 1, 87, 
+	87, 87, 87, 87, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 87, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 88, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 86, 
-	1, 81, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 81, 1, 87, 87, 87, 
+	1, 1, 1, 89, 1, 87, 87, 87, 
 	87, 87, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 87, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	88, 1, 1, 1, 1, 1, 1, 1, 
+	88, 1, 1, 1, 90, 90, 90, 90, 
+	90, 90, 90, 90, 90, 90, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -434,118 +433,151 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 89, 1, 91, 1, 91, 91, 91, 
+	91, 91, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 89, 1, 87, 87, 87, 87, 87, 
+	1, 1, 1, 1, 91, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 87, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 88, 1, 
-	1, 1, 90, 90, 90, 90, 90, 90, 
-	90, 90, 90, 90, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 92, 1, 
+	92, 92, 92, 92, 92, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 92, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 93, 1, 1, 94, 
+	95, 95, 95, 95, 95, 95, 95, 95, 
+	95, 1, 23, 96, 96, 96, 96, 96, 
+	96, 96, 96, 96, 1, 23, 23, 23, 
+	23, 23, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 23, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 1, 1, 96, 96, 96, 96, 
+	96, 96, 96, 96, 96, 96, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 89, 
-	1, 91, 1, 91, 91, 91, 91, 91, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 91, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 92, 1, 92, 92, 
-	92, 92, 92, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 92, 1, 1, 
+	1, 24, 1, 97, 1, 97, 97, 97, 
+	97, 97, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 93, 94, 94, 
-	94, 94, 94, 94, 94, 94, 94, 1, 
-	87, 87, 87, 87, 87, 1, 1, 1, 
+	1, 1, 1, 1, 97, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 87, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 88, 1, 1, 1, 95, 
-	95, 95, 95, 95, 95, 95, 95, 95, 
-	95, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 98, 1, 
+	98, 98, 98, 98, 98, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 98, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 99, 
+	100, 100, 100, 100, 100, 100, 100, 100, 
+	100, 1, 87, 87, 87, 87, 87, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 87, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 88, 1, 1, 
+	1, 101, 101, 101, 101, 101, 101, 101, 
+	101, 101, 101, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 89, 1, 
+	8, 1, 102, 102, 102, 102, 102, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 102, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 103, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 89, 1, 96, 96, 
-	96, 96, 96, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 96, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 97, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 104, 1, 103, 103, 
+	103, 103, 103, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 103, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 98, 1, 2, 2, 2, 2, 
-	2, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 2, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	104, 1, 25, 25, 25, 25, 25, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 25, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 3, 1, 
-	1, 0
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 104, 1, 0
 };
 
 static const char _deserialize_json_trans_targs[] = {
-	1, 0, 2, 3, 3, 4, 5, 19, 
-	25, 38, 44, 52, 6, 13, 7, 8, 
-	9, 10, 12, 10, 12, 11, 3, 56, 
-	11, 56, 14, 15, 16, 17, 18, 17, 
-	18, 11, 3, 56, 20, 21, 22, 23, 
-	24, 11, 3, 56, 24, 26, 32, 27, 
-	28, 29, 30, 31, 30, 31, 11, 3, 
-	56, 33, 34, 35, 36, 37, 36, 37, 
-	11, 3, 56, 39, 40, 41, 42, 43, 
-	11, 3, 56, 43, 45, 46, 47, 50, 
-	51, 47, 48, 49, 11, 3, 56, 11, 
-	3, 56, 51, 53, 54, 50, 55, 55, 
-	56, 57, 58
+	1, 0, 2, 3, 18, 24, 37, 43, 
+	51, 56, 60, 4, 12, 5, 6, 7, 
+	8, 11, 8, 11, 9, 1, 10, 9, 
+	10, 63, 13, 14, 15, 16, 17, 16, 
+	17, 9, 1, 10, 19, 20, 21, 22, 
+	23, 9, 1, 10, 23, 25, 31, 26, 
+	27, 28, 29, 30, 29, 30, 9, 1, 
+	10, 32, 33, 34, 35, 36, 35, 36, 
+	9, 1, 10, 38, 39, 40, 41, 42, 
+	9, 1, 10, 42, 44, 45, 46, 49, 
+	50, 46, 47, 48, 9, 1, 10, 9, 
+	1, 10, 50, 52, 53, 54, 9, 55, 
+	55, 57, 58, 49, 59, 59, 61, 62, 
+	1
 };
 
 static const char _deserialize_json_trans_actions[] = {
-	0, 0, 0, 1, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	2, 2, 2, 0, 0, 3, 3, 4, 
-	0, 5, 0, 0, 2, 2, 2, 0, 
-	0, 6, 6, 7, 0, 0, 0, 2, 
-	2, 8, 8, 9, 0, 0, 0, 0, 
-	0, 2, 2, 2, 0, 0, 10, 10, 
-	11, 0, 0, 2, 2, 2, 0, 0, 
-	12, 12, 13, 0, 0, 0, 2, 2, 
-	14, 14, 15, 0, 0, 0, 2, 16, 
-	16, 0, 17, 0, 18, 18, 19, 20, 
-	20, 21, 17, 0, 0, 22, 22, 23, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 1, 
+	1, 1, 0, 0, 2, 2, 2, 0, 
+	0, 3, 0, 0, 1, 1, 1, 0, 
+	0, 4, 4, 4, 0, 0, 0, 1, 
+	1, 5, 5, 5, 0, 0, 0, 0, 
+	0, 1, 1, 1, 0, 0, 6, 6, 
+	6, 0, 0, 1, 1, 1, 0, 0, 
+	7, 7, 7, 0, 0, 0, 1, 1, 
+	8, 8, 8, 0, 0, 0, 1, 9, 
+	9, 0, 10, 0, 11, 11, 11, 12, 
+	12, 12, 10, 0, 0, 1, 1, 1, 
+	0, 0, 0, 13, 13, 14, 0, 0, 
+	15
 };
 
-static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 56;
+static const int deserialize_json_start = 61;
+static const int deserialize_json_first_final = 61;
 static const int deserialize_json_error = 0;
 
-static const int deserialize_json_en_main = 1;
+static const int deserialize_json_en_main = 61;
 
 
-#line 111 "hb-buffer-deserialize-json.rl"
+#line 115 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
@@ -565,12 +597,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 569 "hb-buffer-deserialize-json.hh"
+#line 594 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
-#line 574 "hb-buffer-deserialize-json.hh"
+#line 597 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
 	int _trans;
@@ -595,14 +627,14 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_json_trans_actions[_trans] ) {
-	case 1:
+	case 15:
 #line 38 "hb-buffer-deserialize-json.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 	hb_memset (&pos , 0, sizeof (pos ));
 }
 	break;
-	case 5:
+	case 3:
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
@@ -612,21 +644,21 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 2:
+	case 1:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
 }
 	break;
-	case 17:
+	case 10:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 23:
+	case 14:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 18:
+	case 11:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
@@ -636,35 +668,35 @@ _resume:
 	  return false;
 }
 	break;
-	case 20:
+	case 12:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
-	case 8:
+	case 5:
 #line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
-	case 10:
+	case 6:
 #line 68 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 12:
+	case 7:
 #line 69 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 3:
+	case 2:
 #line 70 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 6:
+	case 4:
 #line 71 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
-	case 14:
+	case 8:
 #line 72 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
 	break;
-	case 16:
+	case 9:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -672,7 +704,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 22:
+	case 13:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -680,109 +712,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 19:
-#line 58 "hb-buffer-deserialize-json.rl"
-	{
-	/* TODO Unescape \" and \\ if found. */
-	if (!hb_font_glyph_from_string (font,
-					tok+1, p - tok - 2, /* Skip "" */
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 21:
-#line 66 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 9:
-#line 67 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 68 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 13:
-#line 69 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 4:
-#line 70 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 7:
-#line 71 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 15:
-#line 72 "hb-buffer-deserialize-json.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-json.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-#line 786 "hb-buffer-deserialize-json.hh"
+#line 689 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -794,12 +724,12 @@ _again:
 	_out: {}
 	}
 
-#line 132 "hb-buffer-deserialize-json.rl"
+#line 136 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;
 
-  return p == pe && *(p-1) != ']';
+  return p == pe;
 }
 
 #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

+ 371 - 472
thirdparty/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh

@@ -32,287 +32,344 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-text-glyphs.hh"
+#line 33 "hb-buffer-deserialize-text-glyphs.hh"
 static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
-	0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
-	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 0
+	0u, 0u, 35u, 124u, 48u, 57u, 60u, 124u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 
+	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 62u, 62u, 
+	93u, 124u, 45u, 57u, 48u, 57u, 35u, 124u, 45u, 57u, 48u, 57u, 35u, 124u, 35u, 124u, 
+	35u, 124u, 35u, 124u, 35u, 124u, 35u, 124u, 48u, 57u, 35u, 124u, 45u, 57u, 48u, 57u, 
+	44u, 44u, 45u, 57u, 48u, 57u, 35u, 124u, 35u, 124u, 44u, 57u, 35u, 124u, 43u, 124u, 
+	35u, 124u, 48u, 62u, 44u, 57u, 44u, 57u, 44u, 57u, 48u, 124u, 35u, 124u, 35u, 124u, 
+	35u, 124u, 0
 };
 
 static const char _deserialize_text_glyphs_key_spans[] = {
-	0, 10, 13, 10, 13, 10, 10, 13, 
-	10, 1, 13, 10, 14, 82, 116, 116, 
-	116, 116, 116, 116, 116, 116, 116, 116, 
-	116, 116, 116
+	0, 90, 10, 65, 13, 10, 1, 13, 
+	10, 1, 13, 10, 1, 13, 10, 1, 
+	32, 13, 10, 90, 13, 10, 90, 90, 
+	90, 90, 90, 90, 10, 90, 13, 10, 
+	1, 13, 10, 90, 90, 14, 90, 82, 
+	90, 15, 14, 14, 14, 77, 90, 90, 
+	90
 };
 
 static const short _deserialize_text_glyphs_index_offsets[] = {
-	0, 0, 11, 25, 36, 50, 61, 72, 
-	86, 97, 99, 113, 124, 139, 222, 339, 
-	456, 573, 690, 807, 924, 1041, 1158, 1275, 
-	1392, 1509, 1626
+	0, 0, 91, 102, 168, 182, 193, 195, 
+	209, 220, 222, 236, 247, 249, 263, 274, 
+	276, 309, 323, 334, 425, 439, 450, 541, 
+	632, 723, 814, 905, 996, 1007, 1098, 1112, 
+	1123, 1125, 1139, 1150, 1241, 1332, 1347, 1438, 
+	1521, 1612, 1628, 1643, 1658, 1673, 1751, 1842, 
+	1933
 };
 
 static const char _deserialize_text_glyphs_indicies[] = {
-	0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 1, 3, 1, 1, 4, 
-	5, 5, 5, 5, 5, 5, 5, 5, 
-	5, 1, 6, 7, 7, 7, 7, 7, 
-	7, 7, 7, 7, 1, 8, 1, 1, 
-	9, 10, 10, 10, 10, 10, 10, 10, 
-	10, 10, 1, 11, 12, 12, 12, 12, 
-	12, 12, 12, 12, 12, 1, 13, 14, 
-	14, 14, 14, 14, 14, 14, 14, 14, 
-	1, 15, 1, 1, 16, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 1, 18, 
+	1, 0, 0, 0, 0, 0, 0, 
+	0, 2, 3, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 4, 5, 0, 0, 6, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 7, 8, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 8, 0, 9, 10, 10, 10, 
+	10, 10, 10, 10, 10, 10, 3, 11, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	12, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 12, 
+	3, 13, 3, 3, 14, 15, 15, 15, 
+	15, 15, 15, 15, 15, 15, 3, 14, 
+	15, 15, 15, 15, 15, 15, 15, 15, 
+	15, 3, 16, 3, 17, 3, 3, 18, 
 	19, 19, 19, 19, 19, 19, 19, 19, 
-	19, 1, 20, 1, 21, 1, 1, 22, 
-	23, 23, 23, 23, 23, 23, 23, 23, 
-	23, 1, 24, 25, 25, 25, 25, 25, 
-	25, 25, 25, 25, 1, 20, 1, 1, 
-	1, 19, 19, 19, 19, 19, 19, 19, 
-	19, 19, 19, 1, 26, 26, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 26, 1, 
-	1, 26, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 26, 26, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 26, 1, 28, 
-	28, 28, 28, 28, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 28, 27, 
-	27, 29, 27, 27, 27, 27, 27, 27, 
-	27, 30, 1, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 31, 27, 27, 32, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 33, 1, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 27, 28, 27, 34, 34, 34, 34, 
-	34, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 34, 26, 26, 35, 26, 
-	26, 26, 26, 26, 26, 26, 36, 1, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	37, 26, 26, 38, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 39, 
-	1, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 40, 
-	26, 41, 41, 41, 41, 41, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	41, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 42, 1, 43, 43, 
-	43, 43, 43, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 43, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 44, 1, 41, 41, 41, 41, 41, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 41, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 42, 1, 
-	46, 46, 46, 46, 46, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 46, 
-	1, 1, 47, 1, 1, 1, 1, 1, 
-	1, 1, 1, 48, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 49, 1, 50, 50, 50, 
-	50, 50, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 50, 1, 1, 51, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	52, 1, 50, 50, 50, 50, 50, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 50, 1, 1, 51, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 12, 12, 12, 12, 12, 12, 12, 
-	12, 12, 12, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 52, 1, 46, 
-	46, 46, 46, 46, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 46, 1, 
-	1, 47, 1, 1, 1, 1, 1, 1, 
-	1, 1, 48, 1, 1, 1, 7, 7, 
-	7, 7, 7, 7, 7, 7, 7, 7, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 49, 1, 53, 53, 53, 53, 
-	53, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 53, 1, 1, 54, 1, 
-	1, 1, 1, 1, 1, 1, 55, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 56, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 57, 
-	1, 58, 58, 58, 58, 58, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	58, 1, 1, 59, 1, 1, 1, 1, 
-	1, 1, 1, 60, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 61, 1, 58, 58, 
-	58, 58, 58, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 58, 1, 1, 
-	59, 1, 1, 1, 1, 1, 1, 1, 
-	60, 1, 1, 1, 1, 25, 25, 25, 
-	25, 25, 25, 25, 25, 25, 25, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 61, 1, 53, 53, 53, 53, 53, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 53, 1, 1, 54, 1, 1, 
-	1, 1, 1, 1, 1, 55, 1, 1, 
-	1, 1, 62, 62, 62, 62, 62, 62, 
-	62, 62, 62, 62, 1, 1, 1, 1, 
-	1, 1, 56, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 57, 1, 
-	0
+	19, 3, 18, 19, 19, 19, 19, 19, 
+	19, 19, 19, 19, 3, 20, 3, 21, 
+	3, 3, 22, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 3, 22, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 3, 
+	24, 3, 25, 3, 3, 26, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 3, 
+	26, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 3, 28, 3, 29, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 29, 3, 30, 3, 
+	3, 31, 32, 32, 32, 32, 32, 32, 
+	32, 32, 32, 3, 33, 34, 34, 34, 
+	34, 34, 34, 34, 34, 34, 3, 35, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	36, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	37, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 38, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	38, 3, 39, 3, 3, 40, 41, 41, 
+	41, 41, 41, 41, 41, 41, 41, 3, 
+	42, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 3, 44, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 45, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 46, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 46, 3, 44, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 3, 3, 45, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	46, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 46, 
+	3, 35, 3, 3, 3, 3, 3, 3, 
+	3, 3, 36, 3, 3, 3, 34, 34, 
+	34, 34, 34, 34, 34, 34, 34, 34, 
+	3, 3, 37, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 38, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 38, 3, 1, 0, 0, 0, 
+	0, 0, 0, 0, 2, 3, 47, 0, 
+	0, 48, 49, 49, 49, 49, 49, 49, 
+	49, 49, 49, 0, 0, 4, 5, 0, 
+	0, 6, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 7, 8, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 8, 0, 1, 
+	0, 0, 0, 0, 0, 0, 0, 2, 
+	3, 0, 0, 0, 48, 49, 49, 49, 
+	49, 49, 49, 49, 49, 49, 0, 0, 
+	4, 5, 0, 0, 6, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	7, 8, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	8, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 2, 16, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 4, 5, 0, 0, 6, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 7, 8, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 8, 0, 50, 51, 51, 
+	51, 51, 51, 51, 51, 51, 51, 3, 
+	52, 3, 3, 3, 3, 3, 3, 3, 
+	53, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 54, 3, 3, 3, 55, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 56, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 56, 3, 57, 3, 3, 58, 59, 
+	59, 59, 59, 59, 59, 59, 59, 59, 
+	3, 60, 61, 61, 61, 61, 61, 61, 
+	61, 61, 61, 3, 62, 3, 63, 3, 
+	3, 64, 65, 65, 65, 65, 65, 65, 
+	65, 65, 65, 3, 66, 67, 67, 67, 
+	67, 67, 67, 67, 67, 67, 3, 68, 
+	3, 3, 3, 3, 3, 3, 3, 69, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	70, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 71, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	71, 3, 68, 3, 3, 3, 3, 3, 
+	3, 3, 69, 3, 3, 3, 3, 67, 
+	67, 67, 67, 67, 67, 67, 67, 67, 
+	67, 3, 3, 70, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 71, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 71, 3, 62, 3, 3, 
+	3, 61, 61, 61, 61, 61, 61, 61, 
+	61, 61, 61, 3, 52, 3, 3, 3, 
+	3, 3, 3, 3, 53, 3, 3, 3, 
+	3, 72, 72, 72, 72, 72, 72, 72, 
+	72, 72, 72, 3, 3, 54, 3, 3, 
+	3, 55, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 56, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 56, 3, 0, 
+	0, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 0, 3, 3, 0, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	0, 0, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	0, 3, 1, 0, 0, 0, 0, 0, 
+	0, 0, 2, 16, 0, 0, 0, 49, 
+	49, 49, 49, 49, 49, 49, 49, 49, 
+	49, 0, 0, 4, 5, 0, 0, 6, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 7, 8, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 8, 0, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 3, 
+	3, 3, 3, 28, 3, 24, 3, 3, 
+	3, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 3, 20, 3, 3, 3, 
+	19, 19, 19, 19, 19, 19, 19, 19, 
+	19, 19, 3, 16, 3, 3, 3, 15, 
+	15, 15, 15, 15, 15, 15, 15, 15, 
+	15, 3, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 3, 3, 11, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 12, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 3, 3, 3, 3, 12, 3, 
+	75, 74, 74, 74, 74, 74, 74, 74, 
+	76, 3, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 77, 78, 74, 74, 79, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	80, 81, 82, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 82, 74, 84, 83, 83, 83, 83, 
+	83, 83, 83, 85, 3, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 86, 87, 83, 83, 
+	88, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 89, 90, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 90, 83, 91, 74, 
+	74, 74, 74, 74, 74, 74, 92, 3, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 93, 
+	94, 74, 74, 95, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 81, 
+	96, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 96, 
+	74, 0
 };
 
 static const char _deserialize_text_glyphs_trans_targs[] = {
-	16, 0, 18, 3, 19, 22, 19, 22, 
-	5, 20, 21, 20, 21, 23, 26, 8, 
-	9, 12, 9, 12, 10, 11, 24, 25, 
-	24, 25, 15, 15, 14, 1, 2, 6, 
-	7, 13, 15, 1, 2, 6, 7, 13, 
-	14, 17, 14, 17, 14, 18, 17, 1, 
-	4, 14, 17, 1, 14, 17, 1, 2, 
-	7, 14, 17, 1, 2, 14, 26
+	1, 2, 17, 0, 25, 28, 30, 39, 
+	47, 3, 45, 4, 47, 5, 6, 44, 
+	7, 8, 9, 43, 10, 11, 12, 42, 
+	13, 14, 15, 41, 16, 47, 18, 19, 
+	24, 19, 24, 2, 20, 4, 47, 21, 
+	22, 23, 22, 23, 2, 4, 47, 26, 
+	27, 40, 29, 38, 2, 17, 4, 30, 
+	47, 31, 32, 37, 32, 37, 33, 34, 
+	35, 36, 35, 36, 2, 17, 4, 47, 
+	38, 45, 1, 2, 17, 25, 28, 30, 
+	48, 39, 47, 1, 2, 17, 25, 28, 
+	30, 39, 47, 2, 17, 25, 28, 30, 
+	47
 };
 
 static const char _deserialize_text_glyphs_trans_actions[] = {
-	1, 0, 1, 1, 1, 1, 0, 0, 
-	1, 1, 1, 0, 0, 1, 1, 1, 
-	1, 1, 0, 0, 2, 1, 1, 1, 
-	0, 0, 0, 4, 3, 5, 5, 5, 
-	5, 4, 6, 7, 7, 7, 7, 0, 
-	6, 8, 8, 0, 0, 0, 9, 10, 
-	10, 9, 11, 12, 11, 13, 14, 14, 
-	14, 13, 15, 16, 16, 15, 0
+	0, 1, 1, 0, 1, 1, 1, 0, 
+	1, 2, 2, 3, 3, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 2, 2, 
+	2, 0, 0, 4, 4, 4, 4, 2, 
+	2, 2, 0, 0, 5, 5, 5, 0, 
+	0, 0, 2, 2, 6, 6, 6, 6, 
+	6, 2, 2, 2, 0, 0, 7, 2, 
+	2, 2, 0, 0, 8, 8, 8, 8, 
+	0, 0, 9, 10, 10, 10, 10, 10, 
+	9, 9, 10, 12, 13, 13, 13, 13, 
+	13, 12, 13, 14, 14, 14, 14, 14, 
+	14
 };
 
 static const char _deserialize_text_glyphs_eof_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 3, 6, 
-	8, 0, 8, 9, 11, 11, 9, 13, 
-	15, 15, 13
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 11, 
+	0
 };
 
-static const int deserialize_text_glyphs_start = 14;
-static const int deserialize_text_glyphs_first_final = 14;
+static const int deserialize_text_glyphs_start = 46;
+static const int deserialize_text_glyphs_first_final = 46;
 static const int deserialize_text_glyphs_error = 0;
 
-static const int deserialize_text_glyphs_en_main = 14;
+static const int deserialize_text_glyphs_en_main = 46;
 
 
-#line 98 "hb-buffer-deserialize-text-glyphs.rl"
+#line 101 "hb-buffer-deserialize-text-glyphs.rl"
 
 
 static hb_bool_t
@@ -322,39 +379,22 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
 				    const char **end_ptr,
 				    hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   /* Ensure we have positions. */
   (void) hb_buffer_get_glyph_positions (buffer, nullptr);
 
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '['))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, ']');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 353 "hb-buffer-deserialize-text-glyphs.hh"
+#line 386 "hb-buffer-deserialize-text-glyphs.hh"
 	{
 	cs = deserialize_text_glyphs_start;
 	}
 
-#line 358 "hb-buffer-deserialize-text-glyphs.hh"
+#line 389 "hb-buffer-deserialize-text-glyphs.hh"
 	{
 	int _slen;
 	int _trans;
@@ -379,14 +419,14 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_text_glyphs_trans_actions[_trans] ) {
-	case 1:
-#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	case 2:
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
 }
 	break;
-	case 7:
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	case 1:
+#line 54 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	/* TODO Unescape delimiters. */
 	if (!hb_font_glyph_from_string (font,
@@ -395,162 +435,124 @@ _resume:
 	  return false;
 }
 	break;
-	case 14:
-#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+	case 6:
+#line 62 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
-	case 2:
-#line 64 "hb-buffer-deserialize-text-glyphs.rl"
+	case 7:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 16:
-#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+	case 8:
+#line 64 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 10:
-#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+	case 4:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 12:
-#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+	case 5:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
-	case 4:
+	case 3:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+	break;
+	case 9:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 	hb_memset (&pos , 0, sizeof (pos ));
 }
-#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
 }
 	break;
-	case 6:
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	case 10:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
 }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
+	tok = p;
 }
-	break;
-	case 13:
-#line 63 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+#line 54 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
 	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
 }
 	break;
-	case 15:
-#line 65 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+	case 12:
 #line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
+	buffer->add_info_and_pos (info, pos);
 	if (unlikely (!buffer->successful))
 	  return false;
-	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
-	break;
-	case 9:
-#line 66 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
 }
-	break;
-	case 11:
-#line 67 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
+	tok = p;
 }
 	break;
-	case 8:
-#line 68 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	case 14:
+#line 54 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
 	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
 }
-	break;
-	case 5:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 	hb_memset (&pos , 0, sizeof (pos ));
 }
-#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
 }
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	break;
+	case 13:
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
+	buffer->add_info_and_pos (info, pos);
+	if (unlikely (!buffer->successful))
 	  return false;
+	*end_ptr = p;
 }
-	break;
-	case 3:
 #line 38 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 	hb_memset (&pos , 0, sizeof (pos ));
 }
-#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+#line 50 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	tok = p;
 }
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+#line 54 "hb-buffer-deserialize-text-glyphs.rl"
 	{
 	/* TODO Unescape delimiters. */
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
-}
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
 }
 	break;
-#line 554 "hb-buffer-deserialize-text-glyphs.hh"
+#line 523 "hb-buffer-deserialize-text-glyphs.hh"
 	}
 
 _again:
@@ -562,127 +564,24 @@ _again:
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
-	case 6:
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 13:
-#line 63 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 15:
-#line 65 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 9:
-#line 66 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
 	case 11:
-#line 67 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 8:
-#line 68 "hb-buffer-deserialize-text-glyphs.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 3:
-#line 38 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	tok = p;
-}
-#line 55 "hb-buffer-deserialize-text-glyphs.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
 #line 43 "hb-buffer-deserialize-text-glyphs.rl"
 	{
-	buffer->add_info (info);
+	buffer->add_info_and_pos (info, pos);
 	if (unlikely (!buffer->successful))
 	  return false;
-	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
-#line 671 "hb-buffer-deserialize-text-glyphs.hh"
+#line 542 "hb-buffer-deserialize-text-glyphs.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 136 "hb-buffer-deserialize-text-glyphs.rl"
-
+#line 122 "hb-buffer-deserialize-text-glyphs.rl"
 
-  if (pe < orig_pe && *pe == ']')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
 
   *end_ptr = p;
 

+ 58 - 134
thirdparty/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh

@@ -34,135 +34,106 @@
 
 #line 36 "hb-buffer-deserialize-text-unicode.hh"
 static const unsigned char _deserialize_text_unicode_trans_keys[] = {
-	0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 0
+	0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 
+	85u, 117u, 85u, 117u, 0
 };
 
 static const char _deserialize_text_unicode_key_spans[] = {
-	0, 109, 60, 55, 10, 116, 116, 116, 
-	116
+	0, 60, 55, 77, 10, 63, 77, 58, 
+	33, 33
 };
 
 static const short _deserialize_text_unicode_index_offsets[] = {
-	0, 0, 110, 171, 227, 238, 355, 472, 
-	589
+	0, 0, 61, 117, 195, 206, 270, 348, 
+	407, 441
 };
 
 static const char _deserialize_text_unicode_indicies[] = {
-	0, 0, 0, 0, 0, 1, 1, 
+	0, 1, 1, 1, 1, 2, 2, 
+	2, 2, 2, 2, 2, 2, 2, 2, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	0, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 2, 2, 
+	2, 2, 2, 2, 2, 2, 2, 2, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 2, 
+	2, 2, 2, 2, 2, 1, 3, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	1, 1, 1, 4, 5, 1, 1, 3, 
+	3, 3, 3, 3, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 3, 
+	3, 3, 3, 3, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 5, 1, 6, 7, 7, 7, 
+	7, 7, 7, 7, 7, 7, 1, 8, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 3, 
-	1, 1, 1, 1, 4, 4, 4, 4, 
-	4, 4, 4, 4, 4, 4, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 4, 4, 4, 4, 
-	4, 4, 4, 4, 4, 4, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 4, 4, 4, 
-	4, 4, 4, 1, 5, 6, 6, 6, 
-	6, 6, 6, 6, 6, 6, 1, 7, 
-	7, 7, 7, 7, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 7, 1, 
+	1, 1, 1, 1, 1, 8, 1, 9, 
+	9, 9, 9, 9, 9, 9, 9, 9, 
+	9, 1, 1, 1, 1, 8, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 8, 8, 
-	8, 8, 8, 8, 8, 8, 8, 8, 
-	1, 1, 1, 9, 1, 1, 1, 8, 
-	8, 8, 8, 8, 8, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 8, 
-	8, 8, 8, 8, 8, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 10, 1, 11, 11, 11, 11, 
-	11, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 11, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 0, 
-	1, 12, 12, 12, 12, 12, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	12, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 8, 1, 10, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 11, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 13, 1, 12, 12, 
-	12, 12, 12, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 12, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 14, 14, 14, 
-	14, 14, 14, 14, 14, 14, 14, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 11, 1, 
+	11, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	11, 1, 12, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 13, 1, 0
+	1, 1, 12, 1, 0
 };
 
 static const char _deserialize_text_unicode_trans_targs[] = {
-	1, 0, 2, 3, 5, 7, 8, 6, 
-	5, 4, 1, 6, 6, 1, 8
+	2, 0, 3, 3, 4, 9, 5, 6, 
+	9, 6, 8, 1, 1
 };
 
 static const char _deserialize_text_unicode_trans_actions[] = {
-	0, 0, 1, 0, 2, 2, 2, 3, 
-	0, 4, 3, 0, 5, 5, 0
+	0, 0, 1, 0, 2, 2, 1, 1, 
+	3, 0, 0, 4, 6
 };
 
 static const char _deserialize_text_unicode_eof_actions[] = {
-	0, 0, 0, 0, 0, 3, 0, 5, 
-	5
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 5
 };
 
-static const int deserialize_text_unicode_start = 1;
-static const int deserialize_text_unicode_first_final = 5;
+static const int deserialize_text_unicode_start = 7;
+static const int deserialize_text_unicode_first_final = 7;
 static const int deserialize_text_unicode_error = 0;
 
-static const int deserialize_text_unicode_en_main = 1;
+static const int deserialize_text_unicode_en_main = 7;
 
 
-#line 79 "hb-buffer-deserialize-text-unicode.rl"
+#line 80 "hb-buffer-deserialize-text-unicode.rl"
 
 
 static hb_bool_t
@@ -172,37 +143,19 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
 				     const char **end_ptr,
 				     hb_font_t *font)
 {
-  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
-
-  while (p < pe && ISSPACE (*p))
-    p++;
-  if (p < pe && *p == (buffer->len ? '|' : '<'))
-    *end_ptr = ++p;
-
-  const char *end = strchr ((char *) p, '>');
-  if (end)
-    pe = eof = end;
-  else
-  {
-    end = strrchr ((char *) p, '|');
-    if (end)
-      pe = eof = end;
-    else
-      pe = eof = p;
-  }
-
+  const char *p = buf, *pe = buf + buf_len, *eof = pe;
 
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   const hb_glyph_position_t pos = {0};
   
-#line 201 "hb-buffer-deserialize-text-unicode.hh"
+#line 154 "hb-buffer-deserialize-text-unicode.hh"
 	{
 	cs = deserialize_text_unicode_start;
 	}
 
-#line 206 "hb-buffer-deserialize-text-unicode.hh"
+#line 159 "hb-buffer-deserialize-text-unicode.hh"
 	{
 	int _slen;
 	int _trans;
@@ -227,38 +180,27 @@ _resume:
 		goto _again;
 
 	switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
-	case 1:
+	case 4:
 #line 38 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	hb_memset (&info, 0, sizeof (info));
 }
 	break;
-	case 2:
+	case 1:
 #line 51 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	tok = p;
 }
 	break;
-	case 4:
+	case 2:
 #line 55 "hb-buffer-deserialize-text-unicode.rl"
 	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
 	break;
 	case 3:
-#line 55 "hb-buffer-deserialize-text-unicode.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 42 "hb-buffer-deserialize-text-unicode.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	if (buffer->have_positions)
-	  buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 5:
 #line 57 "hb-buffer-deserialize-text-unicode.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+	break;
+	case 6:
 #line 42 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	buffer->add_info (info);
@@ -267,9 +209,13 @@ _resume:
 	if (buffer->have_positions)
 	  buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+#line 38 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
 }
 	break;
-#line 273 "hb-buffer-deserialize-text-unicode.hh"
+#line 219 "hb-buffer-deserialize-text-unicode.hh"
 	}
 
 _again:
@@ -281,22 +227,7 @@ _again:
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_unicode_eof_actions[cs] ) {
-	case 3:
-#line 55 "hb-buffer-deserialize-text-unicode.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 42 "hb-buffer-deserialize-text-unicode.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	if (buffer->have_positions)
-	  buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
 	case 5:
-#line 57 "hb-buffer-deserialize-text-unicode.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 42 "hb-buffer-deserialize-text-unicode.rl"
 	{
 	buffer->add_info (info);
@@ -307,22 +238,15 @@ _again:
 	*end_ptr = p;
 }
 	break;
-#line 311 "hb-buffer-deserialize-text-unicode.hh"
+#line 242 "hb-buffer-deserialize-text-unicode.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 115 "hb-buffer-deserialize-text-unicode.rl"
-
+#line 98 "hb-buffer-deserialize-text-unicode.rl"
 
-  if (pe < orig_pe && *pe == '>')
-  {
-    pe++;
-    if (p == pe)
-      p++;
-  }
 
   *end_ptr = p;
 

+ 11 - 11
thirdparty/harfbuzz/src/hb-buffer-serialize.cc

@@ -169,11 +169,13 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
-      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
-                                extents.x_bearing, extents.y_bearing));
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
-                                extents.width, extents.height));
+      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
+      {
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+				  extents.x_bearing, extents.y_bearing));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+				  extents.width, extents.height));
+      }
     }
 
     *p++ = '}';
@@ -318,8 +320,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
-      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
     }
 
     if (i == end-1) {
@@ -737,8 +739,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  *
- * Return value: `true` if parse was successful, `false` if an error
- * occurred.
+ * Return value: `true` if the full string was parsed, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -810,8 +811,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  *
- * Return value: `true` if parse was successful, `false` if an error
- * occurred.
+ * Return value: `true` if the full string was parsed, `false` otherwise.
  *
  * Since: 2.7.3
  **/

+ 17 - 18
thirdparty/harfbuzz/src/hb-buffer-verify.cc

@@ -63,23 +63,24 @@ static bool
 buffer_verify_monotone (hb_buffer_t *buffer,
 			hb_font_t   *font)
 {
-  /* Check that clusters are monotone. */
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
-      buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
-    bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+    /* Cannot perform this check without monotone clusters. */
+    return true;
+  }
 
-    unsigned int num_glyphs;
-    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+  bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
 
-    for (unsigned int i = 1; i < num_glyphs; i++)
-      if (info[i-1].cluster != info[i].cluster &&
-	  (info[i-1].cluster < info[i].cluster) != is_forward)
-      {
-	buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
-	return false;
-      }
-  }
+  unsigned int num_glyphs;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+  for (unsigned int i = 1; i < num_glyphs; i++)
+    if (info[i-1].cluster != info[i].cluster &&
+	(info[i-1].cluster < info[i].cluster) != is_forward)
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
+      return false;
+    }
 
   return true;
 }
@@ -92,8 +93,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
 			       unsigned int        num_features,
 			       const char * const *shapers)
 {
-  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
     /* Cannot perform this check without monotone clusters. */
     return true;
@@ -207,8 +207,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
 				unsigned int        num_features,
 				const char * const *shapers)
 {
-  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
   {
     /* Cannot perform this check without monotone clusters. */
     return true;

+ 14 - 2
thirdparty/harfbuzz/src/hb-buffer.cc

@@ -370,6 +370,18 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
 
   len++;
 }
+void
+hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
+			       const hb_glyph_position_t &glyph_pos)
+{
+  if (unlikely (!ensure (len + 1))) return;
+
+  info[len] = glyph_info;
+  assert (have_positions);
+  pos[len] = glyph_pos;
+
+  len++;
+}
 
 
 void
@@ -518,7 +530,7 @@ void
 hb_buffer_t::merge_clusters_impl (unsigned int start,
 				  unsigned int end)
 {
-  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
   {
     unsafe_to_break (start, end);
     return;
@@ -551,7 +563,7 @@ void
 hb_buffer_t::merge_out_clusters (unsigned int start,
 				 unsigned int end)
 {
-  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
     return;
 
   if (unlikely (end - start < 2))

+ 62 - 3
thirdparty/harfbuzz/src/hb-buffer.h

@@ -422,18 +422,34 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
  * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
  * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
  *   equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
- * 
+ * @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order.
+ *
  * Data type for holding HarfBuzz's clustering behavior options. The cluster level
- * dictates one aspect of how HarfBuzz will treat non-base characters 
+ * dictates one aspect of how HarfBuzz will treat non-base characters
  * during shaping.
  *
  * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
  * characters are merged into the cluster of the base character that precedes them.
+ * There is also cluster merging every time the clusters will otherwise become non-monotone.
  *
  * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
  * assigned their own cluster values, which are not merged into preceding base
  * clusters. This allows HarfBuzz to perform additional operations like reorder
- * sequences of adjacent marks.
+ * sequences of adjacent marks. The output is still monotone, but the cluster
+ * values are more granular.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their
+ * own cluster values, which are not merged into preceding base clusters. Moreover,
+ * the cluster values are not merged into monotone order. This is the most granular
+ * cluster level, and it is useful for clients that need to know the exact cluster
+ * values of each character, but is harder to use for clients, since clusters
+ * might appear in any order.
+ *
+ * In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the
+ * cluster of the base character that precedes them. This is similar to the Unicode
+ * Grapheme Cluster algorithm, but it is not exactly the same. The output is
+ * not forced to be monotone. This is useful for clients that want to use HarfBuzz
+ * as a cheap implementation of the Unicode Grapheme Cluster algorithm.
  *
  * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
  * backward compatibility with older versions of HarfBuzz. New client programs that
@@ -446,9 +462,52 @@ typedef enum {
   HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES	= 0,
   HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS	= 1,
   HB_BUFFER_CLUSTER_LEVEL_CHARACTERS		= 2,
+  HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES		= 3,
   HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
 } hb_buffer_cluster_level_t;
 
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE:
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level groups cluster values into monotone order.
+ * Requires that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
+
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES:
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level groups cluster values by graphemes. Requires
+ * that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
+
+/**
+ * HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
+ * @level: #hb_buffer_cluster_level_t to test
+ *
+ * Tests whether a cluster level does not group cluster values by graphemes.
+ * Requires that the level be valid.
+ *
+ * Since: 11.0.0
+ */
+#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
+	((bool) ((1u << (unsigned) (level)) & \
+		 ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
+		  (1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
+
 HB_EXTERN void
 hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
 			     hb_buffer_cluster_level_t  cluster_level);

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

@@ -229,6 +229,8 @@ struct hb_buffer_t
   HB_INTERNAL void add (hb_codepoint_t  codepoint,
 			unsigned int    cluster);
   HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
+  HB_INTERNAL void add_info_and_pos (const hb_glyph_info_t &glyph_info,
+				     const hb_glyph_position_t &glyph_pos);
 
   void reverse_range (unsigned start, unsigned end)
   {
@@ -408,6 +410,9 @@ struct hb_buffer_t
 			 bool interior = false,
 			 bool from_out_buffer = false)
   {
+    if (unlikely (end != (unsigned) -1 && end - start > 255))
+      return;
+
     end = hb_min (end, len);
 
     if (interior && !from_out_buffer && end - start < 2)

+ 25 - 12
thirdparty/harfbuzz/src/hb-cache.hh

@@ -30,18 +30,31 @@
 #include "hb.hh"
 
 
-/* Implements a lockfree cache for int->int functions.
+/* Implements a lockfree and thread-safe cache for int->int functions,
+ * using (optionally) _relaxed_ atomic integer operations.
  *
- * The cache is a fixed-size array of 16-bit or 32-bit integers.
- * The key is split into two parts: the cache index and the rest.
+ * The cache is a fixed-size array of 16-bit or 32-bit integers,
+ * typically 256 elements.
  *
- * The cache index is used to index into the array.  The rest is used
- * to store the key and the value.
+ * The key is split into two parts: the cache index (high bits)
+ * and the rest (low bits).
+ *
+ * The cache index is used to index into the array.  The array
+ * member is a 16-bit or 32-bit integer that is used *both*
+ * to store the low bits of the key, and the value.
  *
  * The value is stored in the least significant bits of the integer.
- * The key is stored in the most significant bits of the integer.
- * The key is shifted by cache_bits to the left to make room for the
- * value.
+ * The low bits of the key are stored in the most significant bits
+ * of the integer.
+ *
+ * A cache hit is detected by comparing the low bits of the key
+ * with the high bits of the integer at the array position indexed
+ * by the high bits of the key. If they match, the value is extracted
+ * from the least significant bits of the integer and returned.
+ * Otherwise, a cache miss is reported.
+ *
+ * Cache operations (storage and retrieval) involve just a few
+ * arithmetic operations and a single memory access.
  */
 
 template <unsigned int key_bits=16,
@@ -52,11 +65,11 @@ struct hb_cache_t
 {
   using item_t = typename std::conditional<thread_safe,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
-								     hb_atomic_short_t,
-								     hb_atomic_int_t>::type,
+								     hb_atomic_t<unsigned short>,
+								     hb_atomic_t<unsigned int>>::type,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
-								     short,
-								     int>::type
+								     unsigned short,
+								     unsigned int>::type
 					  >::type;
 
   static_assert ((key_bits >= cache_bits), "");

+ 4 - 9
thirdparty/harfbuzz/src/hb-cairo-utils.cc

@@ -31,8 +31,6 @@
 
 #include "hb-cairo-utils.hh"
 
-#include <cairo.h>
-
 /* Some routines in this file were ported from BlackRenderer by Black Foundry.
  * Used by permission to relicense to HarfBuzz license.
  *
@@ -101,7 +99,7 @@ _hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
 			     unsigned width,
 			     unsigned height,
 			     hb_tag_t format,
-			     float slant,
+			     HB_UNUSED float slant_deprecated,
 			     hb_glyph_extents_t *extents)
 {
   cairo_t *cr = c->cr;
@@ -186,12 +184,6 @@ _hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
   cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
   cairo_pattern_set_matrix (pattern, &matrix);
 
-  /* Undo slant in the extents and apply it in the context. */
-  extents->width -= extents->height * slant;
-  extents->x_bearing -= extents->y_bearing * slant;
-  cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.};
-  cairo_transform (cr, &cairo_matrix);
-
   cairo_translate (cr, extents->x_bearing, extents->y_bearing);
   cairo_scale (cr, extents->width, extents->height);
   cairo_set_source (cr, pattern);
@@ -726,6 +718,9 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
     float span;
 
     span = angles[n_stops - 1] - angles[0];
+    if (!span)
+      goto done;
+
     k = 0;
     if (angles[0] >= 0)
     {

+ 15 - 9
thirdparty/harfbuzz/src/hb-cairo.cc

@@ -204,7 +204,9 @@ hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
 
   cairo_save (cr);
   cairo_new_path (cr);
+
   hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
+
   cairo_close_path (cr);
   cairo_clip (cr);
 }
@@ -572,9 +574,12 @@ hb_cairo_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
   hb_buffer_guess_segment_properties (buffer);
   hb_shape (font, buffer, nullptr, 0);
 
+  int x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+
   hb_cairo_glyphs_from_buffer (buffer,
 			       true,
-			       font->x_scale, font->y_scale,
+			       x_scale, y_scale,
 			       0., 0.,
 			       utf8, utf8_len,
 			       glyphs, (unsigned *) num_glyphs,
@@ -601,10 +606,11 @@ hb_cairo_render_glyph (cairo_scaled_font_t  *scaled_font,
 	       +1. / (x_scale ? x_scale : 1),
 	       -1. / (y_scale ? y_scale : 1));
 
-  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
-
-  cairo_fill (cr);
+  if (hb_font_draw_glyph_or_fail (font, glyph, hb_cairo_draw_get_funcs (), cr))
+    cairo_fill (cr);
 
+  // If draw fails, we still return SUCCESS, as we want empty drawing, not
+  // setting the cairo object into error.
   return CAIRO_STATUS_SUCCESS;
 }
 
@@ -639,8 +645,8 @@ hb_cairo_render_color_glyph (cairo_scaled_font_t  *scaled_font,
   c.cr = cr;
   c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
 
-  hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color);
-
+  if (!hb_font_paint_glyph_or_fail (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color))
+    return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
 
   return CAIRO_STATUS_SUCCESS;
 }
@@ -657,8 +663,7 @@ user_font_face_create (hb_face_t *face)
   cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);
   cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);
 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
-  if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face))
-    cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
+  cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
 #endif
 
   if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
@@ -689,7 +694,8 @@ hb_cairo_font_face_create_for_font (hb_font_t *font)
 {
   hb_font_make_immutable (font);
 
-  auto *cairo_face =  user_font_face_create (font->face);
+  auto *hb_face = hb_font_get_face (font);
+  auto *cairo_face =  user_font_face_create (hb_face);
 
   if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
 								       &hb_cairo_font_user_data_key,

+ 52 - 14
thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh

@@ -71,7 +71,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   template <typename ACC>
   cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
 			const int *coords_=nullptr, unsigned int num_coords_=0)
-    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
+    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
+      cached_scalars_vector (&acc.cached_scalars_vector)
   {
     coords = coords_;
     num_coords = num_coords_;
@@ -80,9 +81,39 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     set_ivs (acc.privateDicts[fd].ivs);
   }
 
-  void fini ()
+  ~cff2_cs_interp_env_t ()
   {
-    SUPER::fini ();
+    release_scalars_vector (scalars);
+  }
+
+  hb_vector_t<float> *acquire_scalars_vector () const
+  {
+    hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
+
+    if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
+    {
+      scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
+      if (unlikely (!scalars))
+	return nullptr;
+      scalars->init ();
+    }
+
+    return scalars;
+  }
+
+  void release_scalars_vector (hb_vector_t<float> *scalars) const
+  {
+    if (!scalars)
+      return;
+
+    scalars->clear ();
+
+    if (!cached_scalars_vector->cmpexch (nullptr, scalars))
+    {
+      scalars->fini ();
+      hb_free (scalars);
+    }
+    scalars = nullptr;
   }
 
   op_code_t fetch_op ()
@@ -111,14 +142,20 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   {
     if (!seen_blend)
     {
-      region_count = varStore->varStore.get_region_index_count (get_ivs ());
-      if (do_blend)
+      scalars = acquire_scalars_vector ();
+      if (unlikely (!scalars))
+	SUPER::set_error ();
+      else
       {
-	if (unlikely (!scalars.resize_exact (region_count)))
-	  SUPER::set_error ();
-	else
-	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
-						 &scalars[0], region_count);
+	region_count = varStore->varStore.get_region_index_count (get_ivs ());
+	if (do_blend)
+	{
+	  if (unlikely (!scalars->resize_exact (region_count)))
+	    SUPER::set_error ();
+	  else
+	    varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
+						   &(*scalars)[0], region_count);
+	}
       }
       seen_blend = true;
     }
@@ -149,11 +186,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     double v = 0;
     if (do_blend)
     {
-      if (likely (scalars.length == deltas.length))
+      if (likely (scalars && scalars->length == deltas.length))
       {
-        unsigned count = scalars.length;
+        unsigned count = scalars->length;
 	for (unsigned i = 0; i < count; i++)
-	  v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
+	  v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
       }
     }
     return v;
@@ -167,7 +204,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
   const	 CFF2ItemVariationStore *varStore;
   unsigned int  region_count;
   unsigned int  ivs;
-  hb_vector_t<float>  scalars;
+  hb_vector_t<float>  *scalars = nullptr;
+  hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
   bool	  do_blend;
   bool	  seen_vsindex_ = false;
   bool	  seen_blend = false;

+ 60 - 3
thirdparty/harfbuzz/src/hb-common.cc

@@ -42,7 +42,7 @@
 
 /* hb_options_t */
 
-hb_atomic_int_t _hb_options;
+hb_atomic_t<unsigned> _hb_options;
 
 void
 _hb_options_init ()
@@ -273,7 +273,7 @@ struct hb_language_item_t {
 
 /* Thread-safe lockfree language list */
 
-static hb_atomic_ptr_t <hb_language_item_t> langs;
+static hb_atomic_t<hb_language_item_t *> langs;
 
 static inline void
 free_langs ()
@@ -403,7 +403,7 @@ hb_language_to_string (hb_language_t language)
 hb_language_t
 hb_language_get_default ()
 {
-  static hb_atomic_ptr_t <hb_language_t> default_language;
+  static hb_atomic_t<hb_language_t> default_language;
 
   hb_language_t language = default_language;
   if (unlikely (language == HB_LANGUAGE_INVALID))
@@ -968,6 +968,9 @@ hb_feature_from_string (const char *str, int len,
  * understood by hb_feature_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
+ * Note that the feature value will be omitted if it is '1', but the
+ * string won't include any whitespace.
+ *
  * Since: 0.9.5
  **/
 void
@@ -1121,6 +1124,8 @@ get_C_locale ()
  * understood by hb_variation_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
+ * Note that the string won't include any whitespace.
+ *
  * Since: 1.4.2
  */
 void
@@ -1212,6 +1217,58 @@ uint8_t
   return hb_color_get_blue (color);
 }
 
+/**
+ * hb_malloc:
+ * @size: The size of the memory to allocate.
+ *
+ * Allocates @size bytes of memory, using the allocator set at
+ * compile-time. Typically just malloc().
+ *
+ * Return value: A pointer to the allocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
+
+/**
+ * hb_calloc:
+ * @nmemb: The number of elements to allocate.
+ * @size: The size of each element.
+ *
+ * Allocates @nmemb elements of @size bytes each, initialized to zero,
+ * using the allocator set at compile-time. Typically just calloc().
+ *
+ * Return value: A pointer to the allocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
+
+/**
+ * hb_realloc:
+ * @ptr: The pointer to the memory to reallocate.
+ * @size: The new size of the memory.
+ *
+ * Reallocates the memory pointed to by @ptr to @size bytes, using the
+ * allocator set at compile-time. Typically just realloc().
+ *
+ * Return value: A pointer to the reallocated memory.
+ *
+ * Since: 11.0.0
+ **/
+void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
+
+/**
+ * hb_free:
+ * @ptr: The pointer to the memory to free.
+ *
+ * Frees the memory pointed to by @ptr, using the allocator set at
+ * compile-time. Typically just free().
+ *
+ * Since: 11.0.0
+ **/
+void  hb_free(void *ptr) { hb_free_impl (ptr); }
+
 
 /* If there is no visibility control, then hb-static.cc will NOT
  * define anything.  Instead, we get it to define one set in here

+ 12 - 431
thirdparty/harfbuzz/src/hb-common.h

@@ -65,6 +65,7 @@ typedef unsigned __int64 uint64_t;
 #else
 #  include <inttypes.h>
 #endif
+#include <stddef.h>
 
 #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
 #define HB_DEPRECATED __attribute__((__deprecated__))
@@ -337,437 +338,7 @@ HB_EXTERN hb_bool_t
 hb_language_matches (hb_language_t language,
 		     hb_language_t specific);
 
-/**
- * hb_script_t:
- * @HB_SCRIPT_COMMON: `Zyyy`
- * @HB_SCRIPT_INHERITED: `Zinh`
- * @HB_SCRIPT_UNKNOWN: `Zzzz`
- * @HB_SCRIPT_ARABIC: `Arab`
- * @HB_SCRIPT_ARMENIAN: `Armn`
- * @HB_SCRIPT_BENGALI: `Beng`
- * @HB_SCRIPT_CYRILLIC: `Cyrl`
- * @HB_SCRIPT_DEVANAGARI: `Deva`
- * @HB_SCRIPT_GEORGIAN: `Geor`
- * @HB_SCRIPT_GREEK: `Grek`
- * @HB_SCRIPT_GUJARATI: `Gujr`
- * @HB_SCRIPT_GURMUKHI: `Guru`
- * @HB_SCRIPT_HANGUL: `Hang`
- * @HB_SCRIPT_HAN: `Hani`
- * @HB_SCRIPT_HEBREW: `Hebr`
- * @HB_SCRIPT_HIRAGANA: `Hira`
- * @HB_SCRIPT_KANNADA: `Knda`
- * @HB_SCRIPT_KATAKANA: `Kana`
- * @HB_SCRIPT_LAO: `Laoo`
- * @HB_SCRIPT_LATIN: `Latn`
- * @HB_SCRIPT_MALAYALAM: `Mlym`
- * @HB_SCRIPT_ORIYA: `Orya`
- * @HB_SCRIPT_TAMIL: `Taml`
- * @HB_SCRIPT_TELUGU: `Telu`
- * @HB_SCRIPT_THAI: `Thai`
- * @HB_SCRIPT_TIBETAN: `Tibt`
- * @HB_SCRIPT_BOPOMOFO: `Bopo`
- * @HB_SCRIPT_BRAILLE: `Brai`
- * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
- * @HB_SCRIPT_CHEROKEE: `Cher`
- * @HB_SCRIPT_ETHIOPIC: `Ethi`
- * @HB_SCRIPT_KHMER: `Khmr`
- * @HB_SCRIPT_MONGOLIAN: `Mong`
- * @HB_SCRIPT_MYANMAR: `Mymr`
- * @HB_SCRIPT_OGHAM: `Ogam`
- * @HB_SCRIPT_RUNIC: `Runr`
- * @HB_SCRIPT_SINHALA: `Sinh`
- * @HB_SCRIPT_SYRIAC: `Syrc`
- * @HB_SCRIPT_THAANA: `Thaa`
- * @HB_SCRIPT_YI: `Yiii`
- * @HB_SCRIPT_DESERET: `Dsrt`
- * @HB_SCRIPT_GOTHIC: `Goth`
- * @HB_SCRIPT_OLD_ITALIC: `Ital`
- * @HB_SCRIPT_BUHID: `Buhd`
- * @HB_SCRIPT_HANUNOO: `Hano`
- * @HB_SCRIPT_TAGALOG: `Tglg`
- * @HB_SCRIPT_TAGBANWA: `Tagb`
- * @HB_SCRIPT_CYPRIOT: `Cprt`
- * @HB_SCRIPT_LIMBU: `Limb`
- * @HB_SCRIPT_LINEAR_B: `Linb`
- * @HB_SCRIPT_OSMANYA: `Osma`
- * @HB_SCRIPT_SHAVIAN: `Shaw`
- * @HB_SCRIPT_TAI_LE: `Tale`
- * @HB_SCRIPT_UGARITIC: `Ugar`
- * @HB_SCRIPT_BUGINESE: `Bugi`
- * @HB_SCRIPT_COPTIC: `Copt`
- * @HB_SCRIPT_GLAGOLITIC: `Glag`
- * @HB_SCRIPT_KHAROSHTHI: `Khar`
- * @HB_SCRIPT_NEW_TAI_LUE: `Talu`
- * @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
- * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
- * @HB_SCRIPT_TIFINAGH: `Tfng`
- * @HB_SCRIPT_BALINESE: `Bali`
- * @HB_SCRIPT_CUNEIFORM: `Xsux`
- * @HB_SCRIPT_NKO: `Nkoo`
- * @HB_SCRIPT_PHAGS_PA: `Phag`
- * @HB_SCRIPT_PHOENICIAN: `Phnx`
- * @HB_SCRIPT_CARIAN: `Cari`
- * @HB_SCRIPT_CHAM: `Cham`
- * @HB_SCRIPT_KAYAH_LI: `Kali`
- * @HB_SCRIPT_LEPCHA: `Lepc`
- * @HB_SCRIPT_LYCIAN: `Lyci`
- * @HB_SCRIPT_LYDIAN: `Lydi`
- * @HB_SCRIPT_OL_CHIKI: `Olck`
- * @HB_SCRIPT_REJANG: `Rjng`
- * @HB_SCRIPT_SAURASHTRA: `Saur`
- * @HB_SCRIPT_SUNDANESE: `Sund`
- * @HB_SCRIPT_VAI: `Vaii`
- * @HB_SCRIPT_AVESTAN: `Avst`
- * @HB_SCRIPT_BAMUM: `Bamu`
- * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
- * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
- * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
- * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
- * @HB_SCRIPT_JAVANESE: `Java`
- * @HB_SCRIPT_KAITHI: `Kthi`
- * @HB_SCRIPT_LISU: `Lisu`
- * @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
- * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
- * @HB_SCRIPT_OLD_TURKIC: `Orkh`
- * @HB_SCRIPT_SAMARITAN: `Samr`
- * @HB_SCRIPT_TAI_THAM: `Lana`
- * @HB_SCRIPT_TAI_VIET: `Tavt`
- * @HB_SCRIPT_BATAK: `Batk`
- * @HB_SCRIPT_BRAHMI: `Brah`
- * @HB_SCRIPT_MANDAIC: `Mand`
- * @HB_SCRIPT_CHAKMA: `Cakm`
- * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
- * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
- * @HB_SCRIPT_MIAO: `Plrd`
- * @HB_SCRIPT_SHARADA: `Shrd`
- * @HB_SCRIPT_SORA_SOMPENG: `Sora`
- * @HB_SCRIPT_TAKRI: `Takr`
- * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
- * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
- * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
- * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
- * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
- * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
- * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
- * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
- * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
- * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
- * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
- * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
- * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
- * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
- * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
- * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
- * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
- * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
- * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
- * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
- * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
- * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
- * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
- * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
- * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
- * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
- * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
- * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
- * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
- * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
- * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
- * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
- * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
- * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
- * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
- * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
- * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
- * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
- * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
- * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
- * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
- * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
- * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
- * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
- * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
- * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
- * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
- * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
- * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
- * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
- * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
- * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
- * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
- * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
- * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
- * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
- * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
- * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
- * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
- * @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
- * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
- *
- * See also the Script (sc) property of the Unicode Character Database.
- *
- **/
-
-/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
-typedef enum
-{
-  HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'), /*1.1*/
-  HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'), /*1.1*/
-  HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'), /*5.0*/
-
-  HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'), /*1.1*/
-  HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'), /*1.1*/
-  HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'), /*1.1*/
-  HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'), /*1.1*/
-  HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'), /*1.1*/
-  HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'), /*1.1*/
-  HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'), /*1.1*/
-  HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'), /*1.1*/
-  HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'), /*1.1*/
-  HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'), /*1.1*/
-  HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'), /*1.1*/
-  HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'), /*1.1*/
-  HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'), /*1.1*/
-  HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'), /*1.1*/
-  HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'), /*1.1*/
-  HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'), /*1.1*/
-  HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'), /*1.1*/
-  HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'), /*1.1*/
-  HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'), /*1.1*/
-  HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'), /*1.1*/
-  HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'), /*1.1*/
-  HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'), /*1.1*/
-
-  HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'), /*2.0*/
-
-  HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'), /*3.0*/
-  HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'), /*3.0*/
-  HB_SCRIPT_CANADIAN_SYLLABICS		= HB_TAG ('C','a','n','s'), /*3.0*/
-  HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'), /*3.0*/
-  HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'), /*3.0*/
-  HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'), /*3.0*/
-  HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'), /*3.0*/
-  HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'), /*3.0*/
-  HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'), /*3.0*/
-  HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'), /*3.0*/
-  HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'), /*3.0*/
-  HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'), /*3.0*/
-  HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'), /*3.0*/
-  HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'), /*3.0*/
-
-  HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'), /*3.1*/
-  HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'), /*3.1*/
-  HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'), /*3.1*/
-
-  HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'), /*3.2*/
-  HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'), /*3.2*/
-  HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'), /*3.2*/
-  HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'), /*3.2*/
-
-  HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'), /*4.0*/
-  HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'), /*4.0*/
-  HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'), /*4.0*/
-  HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'), /*4.0*/
-  HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'), /*4.0*/
-  HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'), /*4.0*/
-  HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'), /*4.0*/
-
-  HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'), /*4.1*/
-  HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'), /*4.1*/
-  HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'), /*4.1*/
-  HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'), /*4.1*/
-  HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'), /*4.1*/
-  HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'), /*4.1*/
-  HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'), /*4.1*/
-  HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'), /*4.1*/
-
-  HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'), /*5.0*/
-  HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'), /*5.0*/
-  HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'), /*5.0*/
-  HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'), /*5.0*/
-  HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'), /*5.0*/
-
-  HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'), /*5.1*/
-  HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'), /*5.1*/
-  HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'), /*5.1*/
-  HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'), /*5.1*/
-  HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'), /*5.1*/
-  HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'), /*5.1*/
-  HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'), /*5.1*/
-  HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'), /*5.1*/
-  HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'), /*5.1*/
-  HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'), /*5.1*/
-  HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'), /*5.1*/
-
-  HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'), /*5.2*/
-  HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'), /*5.2*/
-  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'), /*5.2*/
-  HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'), /*5.2*/
-  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'), /*5.2*/
-  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'), /*5.2*/
-  HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'), /*5.2*/
-  HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'), /*5.2*/
-  HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'), /*5.2*/
-  HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'), /*5.2*/
-  HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'), /*5.2*/
-  HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'), /*5.2*/
-  HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'), /*5.2*/
-  HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'), /*5.2*/
-  HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'), /*5.2*/
-
-  HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'), /*6.0*/
-  HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'), /*6.0*/
-  HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'), /*6.0*/
-
-  HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'), /*6.1*/
-  HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'), /*6.1*/
-  HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'), /*6.1*/
-  HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'), /*6.1*/
-  HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'), /*6.1*/
-  HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'), /*6.1*/
-  HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'), /*6.1*/
-
-  /*
-   * Since: 0.9.30
-   */
-  HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'), /*7.0*/
-  HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'), /*7.0*/
-  HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'), /*7.0*/
-  HB_SCRIPT_ELBASAN			= HB_TAG ('E','l','b','a'), /*7.0*/
-  HB_SCRIPT_GRANTHA			= HB_TAG ('G','r','a','n'), /*7.0*/
-  HB_SCRIPT_KHOJKI			= HB_TAG ('K','h','o','j'), /*7.0*/
-  HB_SCRIPT_KHUDAWADI			= HB_TAG ('S','i','n','d'), /*7.0*/
-  HB_SCRIPT_LINEAR_A			= HB_TAG ('L','i','n','a'), /*7.0*/
-  HB_SCRIPT_MAHAJANI			= HB_TAG ('M','a','h','j'), /*7.0*/
-  HB_SCRIPT_MANICHAEAN			= HB_TAG ('M','a','n','i'), /*7.0*/
-  HB_SCRIPT_MENDE_KIKAKUI		= HB_TAG ('M','e','n','d'), /*7.0*/
-  HB_SCRIPT_MODI			= HB_TAG ('M','o','d','i'), /*7.0*/
-  HB_SCRIPT_MRO				= HB_TAG ('M','r','o','o'), /*7.0*/
-  HB_SCRIPT_NABATAEAN			= HB_TAG ('N','b','a','t'), /*7.0*/
-  HB_SCRIPT_OLD_NORTH_ARABIAN		= HB_TAG ('N','a','r','b'), /*7.0*/
-  HB_SCRIPT_OLD_PERMIC			= HB_TAG ('P','e','r','m'), /*7.0*/
-  HB_SCRIPT_PAHAWH_HMONG		= HB_TAG ('H','m','n','g'), /*7.0*/
-  HB_SCRIPT_PALMYRENE			= HB_TAG ('P','a','l','m'), /*7.0*/
-  HB_SCRIPT_PAU_CIN_HAU			= HB_TAG ('P','a','u','c'), /*7.0*/
-  HB_SCRIPT_PSALTER_PAHLAVI		= HB_TAG ('P','h','l','p'), /*7.0*/
-  HB_SCRIPT_SIDDHAM			= HB_TAG ('S','i','d','d'), /*7.0*/
-  HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'), /*7.0*/
-  HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'), /*7.0*/
-
-  HB_SCRIPT_AHOM			= HB_TAG ('A','h','o','m'), /*8.0*/
-  HB_SCRIPT_ANATOLIAN_HIEROGLYPHS	= HB_TAG ('H','l','u','w'), /*8.0*/
-  HB_SCRIPT_HATRAN			= HB_TAG ('H','a','t','r'), /*8.0*/
-  HB_SCRIPT_MULTANI			= HB_TAG ('M','u','l','t'), /*8.0*/
-  HB_SCRIPT_OLD_HUNGARIAN		= HB_TAG ('H','u','n','g'), /*8.0*/
-  HB_SCRIPT_SIGNWRITING			= HB_TAG ('S','g','n','w'), /*8.0*/
-
-  /*
-   * Since 1.3.0
-   */
-  HB_SCRIPT_ADLAM			= HB_TAG ('A','d','l','m'), /*9.0*/
-  HB_SCRIPT_BHAIKSUKI			= HB_TAG ('B','h','k','s'), /*9.0*/
-  HB_SCRIPT_MARCHEN			= HB_TAG ('M','a','r','c'), /*9.0*/
-  HB_SCRIPT_OSAGE			= HB_TAG ('O','s','g','e'), /*9.0*/
-  HB_SCRIPT_TANGUT			= HB_TAG ('T','a','n','g'), /*9.0*/
-  HB_SCRIPT_NEWA			= HB_TAG ('N','e','w','a'), /*9.0*/
-
-  /*
-   * Since 1.6.0
-   */
-  HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'), /*10.0*/
-  HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'), /*10.0*/
-  HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'), /*10.0*/
-  HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'), /*10.0*/
-
-  /*
-   * Since 1.8.0
-   */
-  HB_SCRIPT_DOGRA			= HB_TAG ('D','o','g','r'), /*11.0*/
-  HB_SCRIPT_GUNJALA_GONDI		= HB_TAG ('G','o','n','g'), /*11.0*/
-  HB_SCRIPT_HANIFI_ROHINGYA		= HB_TAG ('R','o','h','g'), /*11.0*/
-  HB_SCRIPT_MAKASAR			= HB_TAG ('M','a','k','a'), /*11.0*/
-  HB_SCRIPT_MEDEFAIDRIN			= HB_TAG ('M','e','d','f'), /*11.0*/
-  HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'), /*11.0*/
-  HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'), /*11.0*/
-
-  /*
-   * Since 2.4.0
-   */
-  HB_SCRIPT_ELYMAIC			= HB_TAG ('E','l','y','m'), /*12.0*/
-  HB_SCRIPT_NANDINAGARI			= HB_TAG ('N','a','n','d'), /*12.0*/
-  HB_SCRIPT_NYIAKENG_PUACHUE_HMONG	= HB_TAG ('H','m','n','p'), /*12.0*/
-  HB_SCRIPT_WANCHO			= HB_TAG ('W','c','h','o'), /*12.0*/
-
-  /*
-   * Since 2.6.7
-   */
-  HB_SCRIPT_CHORASMIAN			= HB_TAG ('C','h','r','s'), /*13.0*/
-  HB_SCRIPT_DIVES_AKURU			= HB_TAG ('D','i','a','k'), /*13.0*/
-  HB_SCRIPT_KHITAN_SMALL_SCRIPT		= HB_TAG ('K','i','t','s'), /*13.0*/
-  HB_SCRIPT_YEZIDI			= HB_TAG ('Y','e','z','i'), /*13.0*/
-
-  /*
-   * Since 3.0.0
-   */
-  HB_SCRIPT_CYPRO_MINOAN		= HB_TAG ('C','p','m','n'), /*14.0*/
-  HB_SCRIPT_OLD_UYGHUR			= HB_TAG ('O','u','g','r'), /*14.0*/
-  HB_SCRIPT_TANGSA			= HB_TAG ('T','n','s','a'), /*14.0*/
-  HB_SCRIPT_TOTO			= HB_TAG ('T','o','t','o'), /*14.0*/
-  HB_SCRIPT_VITHKUQI			= HB_TAG ('V','i','t','h'), /*14.0*/
-
-  /*
-   * Since 3.4.0
-   */
-  HB_SCRIPT_MATH			= HB_TAG ('Z','m','t','h'),
-
-  /*
-   * Since 5.2.0
-   */
-  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,
-
-  /*< private >*/
-
-  /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
-   * without risking undefined behavior.  We have two, for historical reasons.
-   * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
-   * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
-   *
-   * See this thread for technicalities:
-   *
-   *   https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
-   */
-  _HB_SCRIPT_MAX_VALUE				= HB_TAG_MAX_SIGNED, /*< skip >*/
-  _HB_SCRIPT_MAX_VALUE_SIGNED			= HB_TAG_MAX_SIGNED /*< skip >*/
-
-} hb_script_t;
-
+#include "hb-script-list.h"
 
 /* Script functions */
 
@@ -948,6 +519,16 @@ typedef struct hb_glyph_extents_t {
  */
 typedef struct hb_font_t hb_font_t;
 
+/* Not of much use to clients. */
+HB_EXTERN void*
+hb_malloc (size_t size);
+HB_EXTERN void*
+hb_calloc (size_t nmemb, size_t size);
+HB_EXTERN void*
+hb_realloc (void *ptr, size_t size);
+HB_EXTERN void
+hb_free (void *ptr);
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */

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

@@ -146,6 +146,7 @@
 
 #ifdef HB_NO_DRAW
 #define HB_NO_OUTLINE
+#define HB_NO_PAINT
 #endif
 
 #ifdef HB_NO_GETENV
@@ -191,7 +192,6 @@
 #ifdef HB_MINIMIZE_MEMORY_USAGE
 #define HB_NO_GDEF_CACHE
 #define HB_NO_OT_LAYOUT_LOOKUP_CACHE
-#define HB_NO_OT_FONT_ADVANCE_CACHE
 #define HB_NO_OT_FONT_CMAP_CACHE
 #endif
 

+ 55 - 52
thirdparty/harfbuzz/src/hb-coretext-font.cc

@@ -28,7 +28,8 @@
 
 #ifdef HAVE_CORETEXT
 
-#include "hb-coretext.h"
+#include "hb-coretext.hh"
+#include "hb-aat-layout-trak-table.hh"
 
 #include "hb-draw.hh"
 #include "hb-font.hh"
@@ -42,24 +43,17 @@
 #  define kCTFontOrientationVertical kCTFontVerticalOrientation
 #endif
 
-#define MAX_GLYPHS 64u
-
-static void
-_hb_coretext_font_destroy (void *font_data)
-{
-  CTFontRef ct_font = (CTFontRef) font_data;
-
-  CFRelease (ct_font);
-}
+#define MAX_GLYPHS 256u
 
 static hb_bool_t
-hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
-			       void *font_data,
+hb_coretext_get_nominal_glyph (hb_font_t *font,
+			       void *font_data HB_UNUSED,
 			       hb_codepoint_t unicode,
 			       hb_codepoint_t *glyph,
 			       void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   UniChar ch[2];
   CGGlyph cg_glyph[2];
   unsigned count = 0;
@@ -85,7 +79,7 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 }
 
 static unsigned int
-hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
+hb_coretext_get_nominal_glyphs (hb_font_t *font,
 				void *font_data,
 				unsigned int count,
 				const hb_codepoint_t *first_unicode,
@@ -94,6 +88,8 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 				unsigned int glyph_stride,
 				void *user_data HB_UNUSED)
 {
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   // If any non-BMP codepoint is requested, use the slow path.
   bool slow_path = false;
   auto *unicode = first_unicode;
@@ -119,8 +115,6 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
     return count;
   }
 
-  CTFontRef ct_font = (CTFontRef) font_data;
-
   UniChar ch[MAX_GLYPHS];
   CGGlyph cg_glyph[MAX_GLYPHS];
   for (unsigned i = 0; i < count; i += MAX_GLYPHS)
@@ -152,14 +146,14 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 }
 
 static hb_bool_t
-hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
-				 void *font_data,
+hb_coretext_get_variation_glyph (hb_font_t *font,
+				 void *font_data HB_UNUSED,
 				 hb_codepoint_t unicode,
 				 hb_codepoint_t variation_selector,
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   UniChar ch[4];
   CGGlyph cg_glyph[4];
@@ -194,12 +188,17 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
     if (cg_glyph[i])
       return false;
 
+  // Humm. CoreText falls back to the default glyph if the variation selector
+  // is not supported.  We cannot truly detect that case. So, in essence,
+  // we are always returning true here...
+
   *glyph = cg_glyph[0];
   return true;
 }
 
 static void
-hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
+hb_coretext_get_glyph_h_advances (hb_font_t* font,
+				  void* font_data HB_UNUSED,
 				  unsigned count,
 				  const hb_codepoint_t *first_glyph,
 				  unsigned glyph_stride,
@@ -207,10 +206,11 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
 				  unsigned advance_stride,
 				  void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+  hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f);
 
   CGGlyph cg_glyph[MAX_GLYPHS];
   CGSize advances[MAX_GLYPHS];
@@ -225,7 +225,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
     CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
     for (unsigned j = 0; j < c; j++)
     {
-      *first_advance = round (advances[j].width * x_mult);
+      *first_advance = round (advances[j].width * x_mult) - tracking;
       first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
     }
   }
@@ -233,7 +233,8 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
 
 #ifndef HB_NO_VERTICAL
 static void
-hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
+hb_coretext_get_glyph_v_advances (hb_font_t* font,
+				  void* font_data HB_UNUSED,
 				  unsigned count,
 				  const hb_codepoint_t *first_glyph,
 				  unsigned glyph_stride,
@@ -241,10 +242,11 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
 				  unsigned advance_stride,
 				  void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
+  hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f);
 
   CGGlyph cg_glyph[MAX_GLYPHS];
   CGSize advances[MAX_GLYPHS];
@@ -259,23 +261,21 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
     CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
     for (unsigned j = 0; j < c; j++)
     {
-      *first_advance = round (advances[j].width * y_mult);
+      *first_advance = round (advances[j].width * y_mult) - tracking;
       first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
     }
   }
 }
-#endif
 
-#ifndef HB_NO_VERTICAL
 static hb_bool_t
 hb_coretext_get_glyph_v_origin (hb_font_t *font,
-				void *font_data,
+				void *font_data HB_UNUSED,
 				hb_codepoint_t glyph,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
@@ -294,12 +294,12 @@ hb_coretext_get_glyph_v_origin (hb_font_t *font,
 
 static hb_bool_t
 hb_coretext_get_glyph_extents (hb_font_t *font,
-			       void *font_data,
+			       void *font_data HB_UNUSED,
 			       hb_codepoint_t glyph,
 			       hb_glyph_extents_t *extents,
 			       void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -310,20 +310,21 @@ hb_coretext_get_glyph_extents (hb_font_t *font,
 						    kCTFontOrientationDefault, glyphs, NULL, 1);
 
   extents->x_bearing = round (bounds.origin.x * x_mult);
-  extents->y_bearing = round (bounds.origin.y * y_mult);
+  extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
   extents->width = round (bounds.size.width * x_mult);
-  extents->height = round (bounds.size.height * y_mult);
+  extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
 
   return true;
 }
 
 static hb_bool_t
 hb_coretext_get_font_h_extents (hb_font_t *font,
-				void *font_data,
+				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
+
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
 
@@ -364,14 +365,14 @@ ct_apply_func (void *info, const CGPathElement *element)
   }
 }
 
-static void
-hb_coretext_draw_glyph (hb_font_t *font,
-			void *font_data HB_UNUSED,
-			hb_codepoint_t glyph,
-			hb_draw_funcs_t *draw_funcs, void *draw_data,
-			void *user_data)
+static hb_bool_t
+hb_coretext_draw_glyph_or_fail (hb_font_t *font,
+				void *font_data HB_UNUSED,
+				hb_codepoint_t glyph,
+				hb_draw_funcs_t *draw_funcs, void *draw_data,
+				void *user_data)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@@ -382,13 +383,15 @@ hb_coretext_draw_glyph (hb_font_t *font,
 
   CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform);
   if (!path)
-    return;
+    return false;
 
-  hb_draw_session_t drawing = {draw_funcs, draw_data, font->slant};
+  hb_draw_session_t drawing {draw_funcs, draw_data};
 
   CGPathApply (path, &drawing, ct_apply_func);
 
   CFRelease (path);
+
+  return true;
 }
 #endif
 
@@ -415,17 +418,20 @@ hb_coretext_get_glyph_name (hb_font_t *font,
 		    (UInt8 *) name, size, &len);
 
   name[len] = '\0';
+
+  CFRelease (cf_name);
+
   return true;
 }
 
 static hb_bool_t
-hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
-				 void *font_data,
+hb_coretext_get_glyph_from_name (hb_font_t *font,
+				 void *font_data HB_UNUSED,
 				 const char *name, int len,
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
-  CTFontRef ct_font = (CTFontRef) font_data;
+  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
 
   if (len == -1)
     len = strlen (name);
@@ -458,16 +464,14 @@ static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
 
 #ifndef HB_NO_VERTICAL
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
 #endif
 
 #ifndef HB_NO_DRAW
-    hb_font_funcs_set_draw_glyph_func (funcs, hb_coretext_draw_glyph, nullptr, nullptr);
+    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_coretext_draw_glyph_or_fail, nullptr, nullptr);
 #endif
 
     hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr);
@@ -530,8 +534,7 @@ hb_coretext_font_set_funcs (hb_font_t *font)
 
   hb_font_set_funcs (font,
 		     _hb_coretext_get_font_funcs (),
-		     (void *) CFRetain (ct_font),
-		     _hb_coretext_font_destroy);
+		     nullptr, nullptr);
 }
 
 #undef MAX_GLYPHS

+ 12 - 463
thirdparty/harfbuzz/src/hb-coretext-shape.cc

@@ -32,279 +32,9 @@
 
 #include "hb-shaper-impl.hh"
 
-#include "hb-coretext.h"
+#include "hb-coretext.hh"
 #include "hb-aat-layout.hh"
 
-
-/**
- * SECTION:hb-coretext
- * @title: hb-coretext
- * @short_description: CoreText integration
- * @include: hb-coretext.h
- *
- * Functions for using HarfBuzz with the CoreText fonts.
- **/
-
-static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
-
-static void
-release_table_data (void *user_data)
-{
-  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
-  CFRelease(cf_data);
-}
-
-static hb_blob_t *
-_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
-  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
-  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
-  if (unlikely (!cf_data))
-    return nullptr;
-
-  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
-  const size_t length = CFDataGetLength (cf_data);
-  if (!data || !length)
-  {
-    CFRelease (cf_data);
-    return nullptr;
-  }
-
-  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
-			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_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)
-{
-  CGFontRelease ((CGFontRef) data);
-}
-
-
-static CTFontDescriptorRef
-get_last_resort_font_desc ()
-{
-  // TODO Handle allocation failures?
-  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
-  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
-					   (const void **) &last_resort,
-					   1,
-					   &kCFTypeArrayCallBacks);
-  CFRelease (last_resort);
-  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
-						   (const void **) &kCTFontCascadeListAttribute,
-						   (const void **) &cascade_list,
-						   1,
-						   &kCFTypeDictionaryKeyCallBacks,
-						   &kCFTypeDictionaryValueCallBacks);
-  CFRelease (cascade_list);
-
-  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
-  CFRelease (attributes);
-  return font_desc;
-}
-
-static void
-release_data (void *info, const void *data, size_t size)
-{
-  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
-	  hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
-
-  hb_blob_destroy ((hb_blob_t *) info);
-}
-
-static CGFontRef
-create_cg_font (hb_face_t *face)
-{
-  CGFontRef cg_font = nullptr;
-  if (face->destroy == _hb_cg_font_release)
-  {
-    cg_font = CGFontRetain ((CGFontRef) face->user_data);
-  }
-  else
-  {
-    hb_blob_t *blob = hb_face_reference_blob (face);
-    unsigned int blob_length;
-    const char *blob_data = hb_blob_get_data (blob, &blob_length);
-    if (unlikely (!blob_length))
-      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
-
-    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
-    if (likely (provider))
-    {
-      cg_font = CGFontCreateWithDataProvider (provider);
-      if (unlikely (!cg_font))
-	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
-      CGDataProviderRelease (provider);
-    }
-  }
-  return cg_font;
-}
-
-static CTFontRef
-create_ct_font (CGFontRef cg_font, CGFloat font_size)
-{
-  CTFontRef ct_font = nullptr;
-
-  /* CoreText does not enable trak table usage / tracking when creating a CTFont
-   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
-   * to be through the CTFontCreateUIFontForLanguage call. */
-  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
-  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
-      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
-  {
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
-# define kCTFontUIFontSystem kCTFontSystemFontType
-# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
-#endif
-    CTFontUIFontType font_type = kCTFontUIFontSystem;
-    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
-      font_type = kCTFontUIFontEmphasizedSystem;
-
-    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
-    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
-    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
-    {
-      CFRelease(ct_font);
-      ct_font = nullptr;
-    }
-    CFRelease (ct_result_name);
-  }
-  CFRelease (cg_postscript_name);
-
-  if (!ct_font)
-    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
-
-  if (unlikely (!ct_font)) {
-    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
-    return nullptr;
-  }
-
-  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
-   * bug indicate that the cascade list reconfiguration occasionally causes
-   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
-   * operating system versions. Except for the emoji font, where _not_
-   * reconfiguring the cascade list causes CoreText crashes. For details, see
-   * crbug.com/549610 */
-  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
-#pragma GCC diagnostic pop
-    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
-    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
-    CFRelease (fontName);
-    if (!isEmojiFont)
-      return ct_font;
-  }
-
-  CFURLRef original_url = nullptr;
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-  ATSFontRef atsFont;
-  FSRef fsref;
-  OSStatus status;
-  atsFont = CTFontGetPlatformFont (ct_font, NULL);
-  status = ATSFontGetFileReference (atsFont, &fsref);
-  if (status == noErr)
-    original_url = CFURLCreateFromFSRef (NULL, &fsref);
-#else
-  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
-#endif
-
-  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
-   * font fallback which we don't need anyway. */
-  {
-    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
-    CFRelease (last_resort_font_desc);
-    if (new_ct_font)
-    {
-      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
-       * when reconfiguring the cascade list and may switch to a different font
-       * when there are fonts that go by the same name, since the descriptor is
-       * just name and size.
-       *
-       * Avoid reconfiguring the cascade lists if the new font is outside the
-       * system locations that we cannot access from the sandboxed renderer
-       * process in Blink. This can be detected by the new file URL location
-       * that the newly found font points to. */
-      CFURLRef new_url = nullptr;
-#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
-      status = ATSFontGetFileReference (atsFont, &fsref);
-      if (status == noErr)
-	new_url = CFURLCreateFromFSRef (NULL, &fsref);
-#else
-      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
-#endif
-      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
-      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
-      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
-	CFRelease (ct_font);
-	ct_font = new_ct_font;
-      } else {
-	CFRelease (new_ct_font);
-	DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
-      }
-      if (new_url)
-	CFRelease (new_url);
-    }
-    else
-      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
-  }
-
-  if (original_url)
-    CFRelease (original_url);
-  return ct_font;
-}
-
 hb_coretext_face_data_t *
 _hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
@@ -325,102 +55,6 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
   CFRelease ((CGFontRef) data);
 }
 
-/**
- * hb_coretext_face_create:
- * @cg_font: The CGFontRef to work upon
- *
- * Creates an #hb_face_t face object from the specified
- * CGFontRef.
- *
- * Return value: (transfer full): The new face object
- *
- * Since: 0.9.10
- */
-hb_face_t *
-hb_coretext_face_create (CGFontRef cg_font)
-{
-  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;
-}
-
-/**
- * hb_coretext_face_create_from_file_or_fail:
- * @file_name: A font filename
- * @index: The index of the face within the file
- *
- * Creates an #hb_face_t face object from the specified
- * font file and face index.
- *
- * This is similar in functionality to hb_face_create_from_file_or_fail(),
- * but uses the CoreText library for loading the font file.
- *
- * Return value: (transfer full): The new face object, or `NULL` if
- * no face is found at the specified index or the file cannot be read.
- *
- * Since: 10.1.0
- */
-hb_face_t *
-hb_coretext_face_create_from_file_or_fail (const char   *file_name,
-					   unsigned int  index)
-{
-  auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
-						      (const UInt8 *) file_name,
-						      strlen (file_name),
-						      false);
-  if (unlikely (!url))
-    return nullptr;
-
-  auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
-  if (unlikely (!ct_font_desc_array))
-  {
-    CFRelease (url);
-    return nullptr;
-  }
-  auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
-		      (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
-  if (unlikely (!ct_font_desc))
-  {
-    CFRelease (ct_font_desc_array);
-    CFRelease (url);
-    return nullptr;
-  }
-  CFRelease (url);
-  auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
-  CFRelease (ct_font_desc_array);
-  if (unlikely (!ct_font))
-    return nullptr;
-
-  auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
-  CFRelease (ct_font);
-  if (unlikely (!cg_font))
-    return nullptr;
-
-  hb_face_t *face = hb_coretext_face_create (cg_font);
-  CFRelease (cg_font);
-  if (unlikely (hb_face_is_immutable (face)))
-    return nullptr;
-
-  return face;
-}
-
-/**
- * hb_coretext_face_get_cg_font:
- * @face: The #hb_face_t to work upon
- *
- * Fetches the CGFontRef associated with an #hb_face_t
- * face object
- *
- * Return value: the CGFontRef found
- *
- * Since: 0.9.10
- */
-CGFontRef
-hb_coretext_face_get_cg_font (hb_face_t *face)
-{
-  return (CGFontRef) (const void *) face->data.coretext;
-}
-
 
 hb_coretext_font_data_t *
 _hb_coretext_shaper_font_data_create (hb_font_t *font)
@@ -439,7 +73,9 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
     return nullptr;
   }
 
-  if (font->num_coords)
+  unsigned num_axes = hb_ot_var_get_axis_count (face);
+  // https://github.com/harfbuzz/harfbuzz/issues/5163
+  if (num_axes)
   {
     CFMutableDictionaryRef variations =
       CFDictionaryCreateMutable (kCFAllocatorDefault,
@@ -447,14 +83,15 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
 				 &kCFTypeDictionaryKeyCallBacks,
 				 &kCFTypeDictionaryValueCallBacks);
 
-    for (unsigned i = 0; i < font->num_coords; i++)
+    unsigned count = hb_max (num_axes, font->num_coords);
+    for (unsigned i = 0; i < count; i++)
     {
       hb_ot_var_axis_info_t info;
       unsigned int c = 1;
       hb_ot_var_get_axis_infos (font->face, i, &c, &info);
-      if (font->design_coords[i] == info.default_value)
-	continue;
-      float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
+      float v = i < font->num_coords ?
+		hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
+		info.default_value;
 
       CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
       CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
@@ -489,94 +126,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
   CFRelease ((CTFontRef) data);
 }
 
-/**
- * hb_coretext_font_create:
- * @ct_font: The CTFontRef to work upon
- *
- * Creates an #hb_font_t font object from the specified
- * CTFontRef.
- *
- * The created font uses the default font functions implemented
- * natively by HarfBuzz. If you want to use the CoreText font functions
- * instead (rarely needed), you can do so by calling
- * by hb_coretext_font_set_funcs().
- *
- * Return value: (transfer full): The new font object
- *
- * Since: 1.7.2
- **/
-hb_font_t *
-hb_coretext_font_create (CTFontRef ct_font)
-{
-  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
-  hb_face_t *face = hb_coretext_face_create (cg_font);
-  CFRelease (cg_font);
-  hb_font_t *font = hb_font_create (face);
-  hb_face_destroy (face);
-
-  if (unlikely (hb_object_is_immutable (font)))
-    return font;
-
-  hb_font_set_ptem (font, CTFontGetSize (ct_font));
-
-  /* Copy font variations */
-  CFDictionaryRef variations = CTFontCopyVariation (ct_font);
-  if (variations)
-  {
-    hb_vector_t<hb_variation_t> vars;
-    hb_vector_t<CFTypeRef> keys;
-    hb_vector_t<CFTypeRef> values;
-
-    CFIndex count = CFDictionaryGetCount (variations);
-    if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
-      goto done;
-
-    // Fetch them one by one and collect in a vector of our own.
-    CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
-    for (CFIndex i = 0; i < count; i++)
-    {
-      int tag;
-      float value;
-      CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
-      CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
-
-      hb_variation_t var = {tag, value};
-      vars.push (var);
-    }
-    hb_font_set_variations (font, vars.arrayZ, vars.length);
-
-done:
-    CFRelease (variations);
-  }
-
-  /* Let there be dragons here... */
-  font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
-
-  // https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
-  //hb_coretext_font_set_funcs (font);
-
-  return font;
-}
-
-/**
- * hb_coretext_font_get_ct_font:
- * @font: #hb_font_t to work upon
- *
- * Fetches the CTFontRef associated with the specified
- * #hb_font_t font object.
- *
- * Return value: the CTFontRef found
- *
- * Since: 0.9.10
- */
-CTFontRef
-hb_coretext_font_get_ct_font (hb_font_t *font)
-{
-  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
-  return ct_font ? (CTFontRef) ct_font : nullptr;
-}
-
-
 /*
  * shaper
  */
@@ -646,7 +195,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
    * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
    * continue pointing to B2 even though B2 was merged into B1's
    * cluster... */
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
   {
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
@@ -1010,7 +559,7 @@ resize_and_retry:
 
     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
     unsigned int num_runs = CFArrayGetCount (glyph_runs);
-    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
+    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %u", num_runs);
 
     buffer->len = 0;
     uint32_t status_or = 0;
@@ -1292,7 +841,7 @@ resize_and_retry:
      * or the native OT backend, only that the cluster indices will be
      * monotonic in the output buffer. */
     if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
-	buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+	HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
     {
       hb_glyph_info_t *info = buffer->info;
       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))

+ 580 - 0
thirdparty/harfbuzz/src/hb-coretext.cc

@@ -0,0 +1,580 @@
+/*
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,2013  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CORETEXT
+
+#include "hb-shaper-impl.hh"
+
+#include "hb-coretext.hh"
+
+
+/**
+ * SECTION:hb-coretext
+ * @title: hb-coretext
+ * @short_description: CoreText integration
+ * @include: hb-coretext.h
+ *
+ * Functions for using HarfBuzz with the CoreText fonts.
+ **/
+
+static void
+release_table_data (void *user_data)
+{
+  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
+  CFRelease(cf_data);
+}
+
+static hb_blob_t *
+_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
+  if (unlikely (!cf_data))
+    return nullptr;
+
+  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
+  const size_t length = CFDataGetLength (cf_data);
+  if (!data || !length)
+  {
+    CFRelease (cf_data);
+    return nullptr;
+  }
+
+  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
+			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_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)
+{
+  CGFontRelease ((CGFontRef) data);
+}
+
+
+static CTFontDescriptorRef
+get_last_resort_font_desc ()
+{
+  // TODO Handle allocation failures?
+  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+					   (const void **) &last_resort,
+					   1,
+					   &kCFTypeArrayCallBacks);
+  CFRelease (last_resort);
+  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+						   (const void **) &kCTFontCascadeListAttribute,
+						   (const void **) &cascade_list,
+						   1,
+						   &kCFTypeDictionaryKeyCallBacks,
+						   &kCFTypeDictionaryValueCallBacks);
+  CFRelease (cascade_list);
+
+  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+  CFRelease (attributes);
+  return font_desc;
+}
+
+static void
+release_data (void *info, const void *data, size_t size)
+{
+  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
+	  hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
+
+  hb_blob_destroy ((hb_blob_t *) info);
+}
+
+CGFontRef
+create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
+{
+  if (named_instance_index == 0)
+  {
+    // Default instance. We don't know which one is it. Return the first one.
+    // We will set the correct variations on it later.
+  }
+  else
+    named_instance_index--;
+  auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
+		      (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
+  if (unlikely (!ct_font_desc))
+  {
+    CFRelease (ct_font_desc_array);
+    return nullptr;
+  }
+  auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
+  CFRelease (ct_font_desc_array);
+  if (unlikely (!ct_font))
+    return nullptr;
+
+  auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
+  CFRelease (ct_font);
+
+  return cg_font;
+}
+
+CGFontRef
+create_cg_font (hb_blob_t *blob, unsigned int index)
+{
+  hb_blob_make_immutable (blob);
+  unsigned int blob_length;
+  const char *blob_data = hb_blob_get_data (blob, &blob_length);
+  if (unlikely (!blob_length))
+    DEBUG_MSG (CORETEXT, blob, "Empty blob");
+
+  unsigned ttc_index = index & 0xFFFF;
+  unsigned named_instance_index = index >> 16;
+
+  if (ttc_index != 0)
+  {
+    DEBUG_MSG (CORETEXT, blob, "TTC index %u not supported", ttc_index);
+    return nullptr; // CoreText does not support TTCs
+  }
+
+  if (unlikely (named_instance_index != 0))
+  {
+    // https://github.com/harfbuzz/harfbuzz/issues/5300
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || \
+    (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || \
+    (defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED >= 110000) || \
+    (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED >= 40000) || \
+    (defined(__MACCATALYST_VERSION_MIN_REQUIRED) && __MACCATALYST_VERSION_MIN_REQUIRED >= 130100) || \
+    (defined(__VISION_OS_VERSION_MIN_REQUIRED) && __VISION_OS_VERSION_MIN_REQUIRED >= 10000)
+    auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
+    if (likely (ct_font_desc_array))
+      return create_cg_font (ct_font_desc_array, named_instance_index);
+#endif
+    return nullptr;
+  }
+
+  hb_blob_reference (blob);
+  CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
+  CGFontRef cg_font = nullptr;
+  if (likely (provider))
+  {
+    cg_font = CGFontCreateWithDataProvider (provider);
+    if (unlikely (!cg_font))
+      DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
+    CGDataProviderRelease (provider);
+  }
+  return cg_font;
+}
+
+CGFontRef
+create_cg_font (hb_face_t *face)
+{
+  CGFontRef cg_font = nullptr;
+  if (face->destroy == _hb_cg_font_release)
+    cg_font = CGFontRetain ((CGFontRef) face->user_data);
+  else
+  {
+    hb_blob_t *blob = hb_face_reference_blob (face);
+    cg_font = create_cg_font (blob, face->index);
+    hb_blob_destroy (blob);
+  }
+  return cg_font;
+}
+
+CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+  CTFontRef ct_font = nullptr;
+
+  /* CoreText does not enable trak table usage / tracking when creating a CTFont
+   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
+   * to be through the CTFontCreateUIFontForLanguage call. */
+  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
+  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
+      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
+  {
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+# define kCTFontUIFontSystem kCTFontSystemFontType
+# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
+#endif
+    CTFontUIFontType font_type = kCTFontUIFontSystem;
+    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
+      font_type = kCTFontUIFontEmphasizedSystem;
+
+    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
+    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
+    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
+    {
+      CFRelease(ct_font);
+      ct_font = nullptr;
+    }
+    CFRelease (ct_result_name);
+  }
+  CFRelease (cg_postscript_name);
+
+  if (!ct_font)
+    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
+
+  if (unlikely (!ct_font)) {
+    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+    return nullptr;
+  }
+
+  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
+   * bug indicate that the cascade list reconfiguration occasionally causes
+   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
+   * operating system versions. Except for the emoji font, where _not_
+   * reconfiguring the cascade list causes CoreText crashes. For details, see
+   * crbug.com/549610 */
+  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
+#pragma GCC diagnostic pop
+    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
+    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
+    CFRelease (fontName);
+    if (!isEmojiFont)
+      return ct_font;
+  }
+
+  CFURLRef original_url = nullptr;
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+  ATSFontRef atsFont;
+  FSRef fsref;
+  OSStatus status;
+  atsFont = CTFontGetPlatformFont (ct_font, NULL);
+  status = ATSFontGetFileReference (atsFont, &fsref);
+  if (status == noErr)
+    original_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
+#endif
+
+  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+   * font fallback which we don't need anyway. */
+  {
+    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
+    CFRelease (last_resort_font_desc);
+    if (new_ct_font)
+    {
+      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
+       * when reconfiguring the cascade list and may switch to a different font
+       * when there are fonts that go by the same name, since the descriptor is
+       * just name and size.
+       *
+       * Avoid reconfiguring the cascade lists if the new font is outside the
+       * system locations that we cannot access from the sandboxed renderer
+       * process in Blink. This can be detected by the new file URL location
+       * that the newly found font points to. */
+      CFURLRef new_url = nullptr;
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
+      status = ATSFontGetFileReference (atsFont, &fsref);
+      if (status == noErr)
+	new_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+#endif
+      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
+      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
+      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
+	CFRelease (ct_font);
+	ct_font = new_ct_font;
+      } else {
+	CFRelease (new_ct_font);
+	DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+      }
+      if (new_url)
+	CFRelease (new_url);
+    }
+    else
+      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+  }
+
+  if (original_url)
+    CFRelease (original_url);
+  return ct_font;
+}
+
+/**
+ * hb_coretext_face_create:
+ * @cg_font: The CGFontRef to work upon
+ *
+ * Creates an #hb_face_t face object from the specified
+ * CGFontRef.
+ *
+ * Return value: (transfer full): The new face object
+ *
+ * Since: 0.9.10
+ */
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+  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;
+}
+
+/**
+ * hb_coretext_face_create_from_file_or_fail:
+ * @file_name: A font filename
+ * @index: The index of the face within the file
+ *
+ * Creates an #hb_face_t face object from the specified
+ * font file and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_file_or_fail(),
+ * but uses the CoreText library for loading the font file.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the file cannot be read.
+ *
+ * Since: 10.1.0
+ */
+hb_face_t *
+hb_coretext_face_create_from_file_or_fail (const char   *file_name,
+					   unsigned int  index)
+{
+  auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
+						      (const UInt8 *) file_name,
+						      strlen (file_name),
+						      false);
+  if (unlikely (!url))
+    return nullptr;
+
+  auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
+  if (unlikely (!ct_font_desc_array))
+  {
+    CFRelease (url);
+    return nullptr;
+  }
+
+  unsigned ttc_index = index & 0xFFFF;
+  unsigned named_instance_index = index >> 16;
+
+  if (ttc_index != 0)
+  {
+    DEBUG_MSG (CORETEXT, nullptr, "TTC index %u not supported", ttc_index);
+    return nullptr; // CoreText does not support TTCs
+  }
+
+  auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
+  CFRelease (url);
+
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  if (unlikely (hb_face_is_immutable (face)))
+    return nullptr;
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_coretext_face_create_from_blob_or_fail:
+ * @blob: A blob containing the font data
+ * @index: The index of the face within the blob
+ *
+ * Creates an #hb_face_t face object from the specified
+ * blob and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_blob_or_fail(),
+ * but uses the CoreText library for loading the font data.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * no face is found at the specified index or the blob cannot be read.
+ *
+ * Since: 11.0.0
+ */
+hb_face_t *
+hb_coretext_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					   unsigned int  index)
+{
+  auto cg_font = create_cg_font (blob, index);
+  if (unlikely (!cg_font))
+    return nullptr;
+
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  if (unlikely (hb_face_is_immutable (face)))
+    return nullptr;
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_coretext_face_get_cg_font:
+ * @face: The #hb_face_t to work upon
+ *
+ * Fetches the CGFontRef associated with an #hb_face_t
+ * face object
+ *
+ * Return value: the CGFontRef found
+ *
+ * Since: 0.9.10
+ */
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+  return (CGFontRef) (const void *) face->data.coretext;
+}
+
+/**
+ * hb_coretext_font_create:
+ * @ct_font: The CTFontRef to work upon
+ *
+ * Creates an #hb_font_t font object from the specified
+ * CTFontRef.
+ *
+ * The created font uses the default font functions implemented
+ * natively by HarfBuzz. If you want to use the CoreText font functions
+ * instead (rarely needed), you can do so by calling
+ * by hb_coretext_font_set_funcs().
+ *
+ * Return value: (transfer full): The new font object
+ *
+ * Since: 1.7.2
+ **/
+hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font)
+{
+  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  if (unlikely (hb_object_is_immutable (font)))
+    return font;
+
+  hb_font_set_ptem (font, CTFontGetSize (ct_font));
+
+  /* Copy font variations */
+  CFDictionaryRef variations = CTFontCopyVariation (ct_font);
+  if (variations)
+  {
+    hb_vector_t<hb_variation_t> vars;
+    hb_vector_t<CFTypeRef> keys;
+    hb_vector_t<CFTypeRef> values;
+
+    CFIndex count = CFDictionaryGetCount (variations);
+    if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
+      goto done;
+
+    // Fetch them one by one and collect in a vector of our own.
+    CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
+    for (CFIndex i = 0; i < count; i++)
+    {
+      int tag;
+      float value;
+      CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
+      CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
+
+      hb_variation_t var = {tag, value};
+      vars.push (var);
+    }
+    hb_font_set_variations (font, vars.arrayZ, vars.length);
+
+done:
+    CFRelease (variations);
+  }
+
+  /* Let there be dragons here... */
+  font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
+
+  // https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
+  //hb_coretext_font_set_funcs (font);
+
+  return font;
+}
+
+/**
+ * hb_coretext_font_get_ct_font:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the CTFontRef associated with the specified
+ * #hb_font_t font object.
+ *
+ * Return value: the CTFontRef found
+ *
+ * Since: 0.9.10
+ */
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  return (CTFontRef) (const void *) font->data.coretext;
+}
+
+
+#endif

+ 4 - 0
thirdparty/harfbuzz/src/hb-coretext.h

@@ -84,6 +84,10 @@ HB_EXTERN hb_face_t *
 hb_coretext_face_create_from_file_or_fail (const char   *file_name,
 					   unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_coretext_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					   unsigned int  index);
+
 HB_EXTERN hb_font_t *
 hb_coretext_font_create (CTFontRef ct_font);
 

+ 53 - 0
thirdparty/harfbuzz/src/hb-coretext.hh

@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,2013  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+
+#ifndef HB_CORETEXT_HH
+#define HB_CORETEXT_HH
+
+#include "hb.hh"
+
+#include "hb-coretext.h"
+
+#include "hb-aat-layout.hh"
+
+
+HB_INTERNAL CGFontRef
+create_cg_font (CFArrayRef ct_font_desc_array, unsigned int index);
+
+HB_INTERNAL CGFontRef
+create_cg_font (hb_blob_t *blob, unsigned int index);
+
+HB_INTERNAL CGFontRef
+create_cg_font (hb_face_t *face);
+
+HB_INTERNAL CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size);
+
+
+#endif /* HB_CORETEXT_HH */

+ 3 - 3
thirdparty/harfbuzz/src/hb-debug.hh

@@ -49,15 +49,15 @@ struct hb_options_t
 };
 
 union hb_options_union_t {
-  int i;
+  unsigned i;
   hb_options_t opts;
 };
-static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
+static_assert ((sizeof (hb_atomic_t<unsigned>) >= sizeof (hb_options_union_t)), "");
 
 HB_INTERNAL void
 _hb_options_init ();
 
-extern HB_INTERNAL hb_atomic_int_t _hb_options;
+extern HB_INTERNAL hb_atomic_t<unsigned> _hb_options;
 
 static inline hb_options_t
 hb_options ()

+ 80 - 2
thirdparty/harfbuzz/src/hb-deprecated.h

@@ -275,6 +275,48 @@ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data
 						hb_draw_funcs_t *draw_funcs, void *draw_data,
 						void *user_data);
 
+/**
+ * hb_font_draw_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 7.0.0
+ * XDeprecated: REPLACEME: Use hb_font_draw_glyph_func_or_fail_t instead.
+ **/
+typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
+                                           hb_codepoint_t glyph,
+                                           hb_draw_funcs_t *draw_funcs, void *draw_data,
+                                           void *user_data);
+
+/**
+ * hb_font_paint_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @paint_funcs: The paint functions to use
+ * @paint_data: The data accompanying the paint functions
+ * @palette_index: The color palette to use
+ * @foreground: The foreground color
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 7.0.0
+ * XDeprecated: REPLACEME: Use hb_font_paint_glyph_or_fail_func_t instead.
+ */
+typedef hb_bool_t (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
+						 hb_codepoint_t glyph,
+						 hb_paint_funcs_t *paint_funcs, void *paint_data,
+						 unsigned int palette_index,
+						 hb_color_t foreground,
+						 void *user_data);
+
 /**
  * hb_font_funcs_set_glyph_shape_func:
  * @ffuncs: A font-function structure
@@ -288,13 +330,49 @@ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data
  * Since: 4.0.0
  * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
  **/
-HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func)
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func)
 HB_EXTERN void
 hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
 				    hb_font_get_glyph_shape_func_t func,
 				    void *user_data, hb_destroy_func_t destroy);
 
-HB_DEPRECATED_FOR (hb_font_draw_glyph)
+/**
+ * hb_font_funcs_set_draw_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_draw_glyph_func_t.
+ *
+ * Since: 7.0.0
+ * XDeprecated: REPLACEME: Use hb_font_funcs_set_draw_glyph_or_fail_func instead.
+ **/
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func)
+HB_EXTERN void
+hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
+                                   hb_font_draw_glyph_func_t func,
+                                   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_paint_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is no longer needed
+ *
+ * Sets the implementation function for #hb_font_paint_glyph_func_t.
+ *
+ * Since: 7.0.0
+ * XDeprecated: REPLACEME: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead.
+ */
+HB_DEPRECATED_FOR (hb_font_funcs_set_paint_glyph_or_fail_func)
+HB_EXTERN void
+hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs,
+                                    hb_font_paint_glyph_func_t func,
+                                    void *user_data, hb_destroy_func_t destroy);
+
+HB_DEPRECATED_FOR (hb_font_draw_glyph_or_fail)
 HB_EXTERN void
 hb_font_get_glyph_shape (hb_font_t *font,
 			 hb_codepoint_t glyph,

+ 392 - 0
thirdparty/harfbuzz/src/hb-directwrite-font.cc

@@ -0,0 +1,392 @@
+/*
+ * Copyright © 2025  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_DIRECTWRITE
+
+#include "hb-directwrite.h"
+
+#include <d2d1.h>
+
+#include "hb-draw.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+
+#define MAX_GLYPHS 256u
+
+static unsigned int
+hb_directwrite_get_nominal_glyphs (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   unsigned int count,
+				   const hb_codepoint_t *first_unicode,
+				   unsigned int unicode_stride,
+				   hb_codepoint_t *first_glyph,
+				   unsigned int glyph_stride,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT32 unicodes[MAX_GLYPHS];
+    UINT16 gids[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      unicodes[j] = *first_unicode;
+      first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
+    }
+
+    if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
+      return i;
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      if (!gids[j])
+        return i + j;
+      *first_glyph = gids[j];
+      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+
+    i += n;
+  }
+
+  return count;
+}
+
+static hb_bool_t
+hb_directwrite_get_font_h_extents (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_font_extents_t *metrics,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  DWRITE_FONT_METRICS dw_metrics;
+  dw_face->GetMetrics (&dw_metrics);
+
+  metrics->ascender = font->em_scale_y (dw_metrics.ascent);
+  metrics->descender = -font->em_scale_y (dw_metrics.descent);
+  metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
+
+  return true;
+}
+
+static void
+hb_directwrite_get_glyph_h_advances (hb_font_t* font,
+				     void* font_data HB_UNUSED,
+				     unsigned count,
+				     const hb_codepoint_t *first_glyph,
+				     unsigned glyph_stride,
+				     hb_position_t *first_advance,
+				     unsigned advance_stride,
+				     void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  IDWriteFontFace1 *dw_face1 = nullptr;
+  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
+  assert (dw_face1);
+
+  unsigned int num_glyphs = font->face->get_num_glyphs ();
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT16 gids[MAX_GLYPHS];
+    INT32 advances[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      gids[j] = *first_glyph;
+      advances[j] = 0;
+      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+    dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
+    for (unsigned j = 0; j < n; j++)
+    {
+      // https://github.com/harfbuzz/harfbuzz/issues/5319
+      auto advance = gids[j] < num_glyphs ? advances[j] : 0;
+      *first_advance = font->em_scale_x (advance);
+      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    }
+
+    i += n;
+  }
+}
+
+#ifndef HB_NO_VERTICAL
+
+static void
+hb_directwrite_get_glyph_v_advances (hb_font_t* font,
+				     void* font_data HB_UNUSED,
+				     unsigned count,
+				     const hb_codepoint_t *first_glyph,
+				     unsigned glyph_stride,
+				     hb_position_t *first_advance,
+				     unsigned advance_stride,
+				     void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  IDWriteFontFace1 *dw_face1 = nullptr;
+  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
+  assert (dw_face1);
+
+  for (unsigned i = 0; i < count;)
+  {
+    UINT16 gids[MAX_GLYPHS];
+    INT32 advances[MAX_GLYPHS];
+
+    unsigned n = hb_min (MAX_GLYPHS, count - i);
+
+    for (unsigned j = 0; j < n; j++)
+    {
+      gids[j] = *first_glyph;
+      advances[j] = 0;
+      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
+    }
+    dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
+    for (unsigned j = 0; j < n; j++)
+    {
+      *first_advance = -font->em_scale_y (advances[j]);
+      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    }
+
+    i += n;
+  }
+}
+
+static hb_bool_t
+hb_directwrite_get_glyph_v_origin (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_codepoint_t glyph,
+				   hb_position_t *x,
+				   hb_position_t *y,
+				   void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  UINT16 gid = glyph;
+  DWRITE_GLYPH_METRICS metrics;
+
+  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
+    return false;
+
+  *x = font->em_scale_x (metrics.advanceWidth / 2);
+  *y = font->em_scale_y (metrics.verticalOriginY); // Untested
+
+  return true;
+}
+#endif
+
+static hb_bool_t
+hb_directwrite_get_glyph_extents (hb_font_t *font,
+				  void *font_data HB_UNUSED,
+				  hb_codepoint_t glyph,
+				  hb_glyph_extents_t *extents,
+				  void *user_data HB_UNUSED)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  UINT16 gid = glyph;
+  DWRITE_GLYPH_METRICS metrics;
+
+  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
+    return false;
+
+  extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
+  extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
+  extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
+  extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
+
+  return true;
+}
+
+
+#ifndef HB_NO_DRAW
+
+class GeometrySink : public IDWriteGeometrySink
+{
+  hb_font_t *font;
+  hb_draw_session_t drawing;
+
+public:
+  GeometrySink(hb_font_t *font,
+	       hb_draw_funcs_t *draw_funcs,
+	       void *draw_data)
+    : font (font), drawing ({draw_funcs, draw_data}) {}
+
+  virtual ~GeometrySink() {}
+
+  HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
+  void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
+  void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
+
+  IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
+  IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
+  IFACEMETHOD_(ULONG, Release)() override { return 1; }
+
+  void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
+  {
+    drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
+  }
+
+  void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
+  {
+    for (unsigned i = 0; i < beziersCount; ++i)
+      drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
+			font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
+			font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
+  }
+
+  void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
+  {
+    for (unsigned i = 0; i < pointsCount; ++i)
+      drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
+  }
+
+  void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
+  {
+    drawing.close_path ();
+  }
+};
+
+static hb_bool_t
+hb_directwrite_draw_glyph_or_fail (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_codepoint_t glyph,
+				   hb_draw_funcs_t *draw_funcs, void *draw_data,
+				   void *user_data)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+
+  GeometrySink sink (font, draw_funcs, draw_data);
+  UINT16 gid = static_cast<UINT16>(glyph);
+  unsigned upem = font->face->get_upem();
+
+  return S_OK == dw_face->GetGlyphRunOutline (upem,
+					      &gid, nullptr, nullptr,
+					      1,
+					      false, false,
+					      &sink);
+}
+
+#endif
+
+static inline void free_static_directwrite_funcs ();
+
+static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
+{
+  static hb_font_funcs_t *create ()
+  {
+    hb_font_funcs_t *funcs = hb_font_funcs_create ();
+
+    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
+    //hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
+
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
+
+#ifndef HB_NO_VERTICAL
+    hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
+    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
+#endif
+
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_directwrite_draw_glyph_or_fail, nullptr, nullptr);
+#endif
+
+    hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
+
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
+    //hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
+#endif
+
+    hb_font_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_directwrite_funcs);
+
+    return funcs;
+  }
+} static_directwrite_funcs;
+
+static inline
+void free_static_directwrite_funcs ()
+{
+  static_directwrite_funcs.free_instance ();
+}
+
+static hb_font_funcs_t *
+_hb_directwrite_get_font_funcs ()
+{
+  return static_directwrite_funcs.get_unconst ();
+}
+
+/**
+ * hb_directwrite_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified
+ * #hb_font_t font object to use DirectWrite font functions.
+ *
+ * In particular, you can use this function to configure an
+ * existing #hb_face_t face object for use with DirectWrite font
+ * functions even if that #hb_face_t face object was initially
+ * created with hb_face_create(), and therefore was not
+ * initially configured to use DirectWrite font functions.
+ *
+ * <note>Note: Internally, this function creates a DirectWrite font.
+ * </note>
+ *
+ * Since: 11.0.0
+ **/
+void
+hb_directwrite_font_set_funcs (hb_font_t *font)
+{
+  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
+  if (unlikely (!dw_face))
+  {
+    hb_font_set_funcs (font,
+		       hb_font_funcs_get_empty (),
+		       nullptr, nullptr);
+    return;
+  }
+
+  dw_face->AddRef ();
+  hb_font_set_funcs (font,
+		     _hb_directwrite_get_font_funcs (),
+		     nullptr, nullptr);
+}
+
+#undef MAX_GLYPHS
+
+#endif

+ 656 - 0
thirdparty/harfbuzz/src/hb-directwrite-shape.cc

@@ -0,0 +1,656 @@
+/*
+ *  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_DIRECTWRITE
+
+#include "hb-shaper-impl.hh"
+
+#include "hb-directwrite.hh"
+
+#include "hb-ms-feature-ranges.hh"
+
+
+/*
+* shaper face data
+*/
+
+hb_directwrite_face_data_t *
+_hb_directwrite_shaper_face_data_create (hb_face_t *face)
+{
+  hb_blob_t *blob = hb_face_reference_blob (face);
+
+  hb_directwrite_face_data_t *data = (hb_directwrite_face_data_t *) dw_face_create (blob, face->index);
+
+  hb_blob_destroy (blob);
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
+{
+  ((IDWriteFontFace *) data)->Release ();
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_directwrite_font_data_t {};
+
+hb_directwrite_font_data_t *
+_hb_directwrite_shaper_font_data_create (hb_font_t *font)
+{
+  IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->face->data.directwrite;
+
+  /*
+   * Set up variations.
+   */
+  IDWriteFontFace5 *fontFaceVariations = nullptr;
+  {
+    IDWriteFontFace5 *fontFace5;
+    if (SUCCEEDED (fontFace->QueryInterface (__uuidof (IDWriteFontFace5), (void **) &fontFace5)))
+    {
+      IDWriteFontResource *fontResource;
+      if (SUCCEEDED (fontFace5->GetFontResource (&fontResource)))
+      {
+	hb_vector_t<DWRITE_FONT_AXIS_VALUE> axis_values;
+	if (likely (axis_values.resize_exact (font->num_coords)))
+	{
+	  for (unsigned int i = 0; i < font->num_coords; i++)
+	  {
+	    hb_ot_var_axis_info_t info;
+	    unsigned int c = 1;
+	    hb_ot_var_get_axis_infos (font->face, i, &c, &info);
+	    axis_values[i].axisTag = (DWRITE_FONT_AXIS_TAG) hb_uint32_swap (info.tag);
+	    axis_values[i].value = i < font->num_coords ?
+				   hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
+				   info.default_value;
+	  }
+
+	  fontResource->CreateFontFace (DWRITE_FONT_SIMULATIONS::DWRITE_FONT_SIMULATIONS_NONE,
+					axis_values.arrayZ, axis_values.length, &fontFaceVariations);
+	}
+	fontResource->Release ();
+      }
+      fontFace5->Release ();
+    }
+  }
+
+  return (hb_directwrite_font_data_t *) fontFaceVariations;
+}
+
+void
+_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
+{
+  ((IDWriteFontFace *) (const void *) data)->Release ();
+}
+
+
+// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
+// but now is relicensed to MIT for HarfBuzz use
+class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
+{
+private:
+  hb_reference_count_t mRefCount;
+public:
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // A single contiguous run of characters containing the same analysis
+  // results.
+  struct Run
+  {
+    uint32_t mTextStart;   // starting text position of this run
+    uint32_t mTextLength;  // number of contiguous code units covered
+    uint32_t mGlyphStart;  // starting glyph in the glyphs array
+    uint32_t mGlyphCount;  // number of glyphs associated with this run
+    // text
+    DWRITE_SCRIPT_ANALYSIS mScript;
+    uint8_t mBidiLevel;
+    bool mIsSideways;
+
+    bool ContainsTextPosition (uint32_t aTextPosition) const
+    {
+      return aTextPosition >= mTextStart &&
+	     aTextPosition <  mTextStart + mTextLength;
+    }
+
+    Run *nextRun;
+  };
+
+public:
+  TextAnalysis (const wchar_t* text, uint32_t textLength,
+		const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
+	       : mTextLength (textLength), mText (text), mLocaleName (localeName),
+		 mReadingDirection (readingDirection), mCurrentRun (nullptr)
+  {
+    mRefCount.init ();
+  }
+  virtual ~TextAnalysis ()
+  {
+    // delete runs, except mRunHead which is part of the TextAnalysis object
+    for (Run *run = mRunHead.nextRun; run;)
+    {
+      Run *origRun = run;
+      run = run->nextRun;
+      delete origRun;
+    }
+  }
+
+  STDMETHODIMP
+  GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
+  {
+    // Analyzes the text using the script analyzer and returns
+    // the result as a series of runs.
+
+    HRESULT hr = S_OK;
+
+    // Initially start out with one result that covers the entire range.
+    // This result will be subdivided by the analysis processes.
+    mRunHead.mTextStart = 0;
+    mRunHead.mTextLength = mTextLength;
+    mRunHead.mBidiLevel =
+      (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
+    mRunHead.nextRun = nullptr;
+    mCurrentRun = &mRunHead;
+
+    // Call each of the analyzers in sequence, recording their results.
+    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
+      *runHead = &mRunHead;
+
+    return hr;
+  }
+
+  // IDWriteTextAnalysisSource implementation
+
+  IFACEMETHODIMP
+  GetTextAtPosition (uint32_t textPosition,
+		     OUT wchar_t const** textString,
+		     OUT uint32_t* textLength)
+  {
+    if (textPosition >= mTextLength)
+    {
+      // No text at this position, valid query though.
+      *textString = nullptr;
+      *textLength = 0;
+    }
+    else
+    {
+      *textString = mText + textPosition;
+      *textLength = mTextLength - textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+  GetTextBeforePosition (uint32_t textPosition,
+			 OUT wchar_t const** textString,
+			 OUT uint32_t* textLength)
+  {
+    if (textPosition == 0 || textPosition > mTextLength)
+    {
+      // Either there is no text before here (== 0), or this
+      // is an invalid position. The query is considered valid though.
+      *textString = nullptr;
+      *textLength = 0;
+    }
+    else
+    {
+      *textString = mText;
+      *textLength = textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
+  GetParagraphReadingDirection () { return mReadingDirection; }
+
+  IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
+				wchar_t const** localeName)
+  { return S_OK; }
+
+  IFACEMETHODIMP
+  GetNumberSubstitution (uint32_t textPosition,
+			 OUT uint32_t* textLength,
+			 OUT IDWriteNumberSubstitution** numberSubstitution)
+  {
+    // We do not support number substitution.
+    *numberSubstitution = nullptr;
+    *textLength = mTextLength - textPosition;
+
+    return S_OK;
+  }
+
+  // IDWriteTextAnalysisSink implementation
+
+  IFACEMETHODIMP
+  SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
+		     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
+  {
+    SetCurrentRun (textPosition);
+    SplitCurrentRun (textPosition);
+    while (textLength > 0)
+    {
+      Run *run = FetchNextRun (&textLength);
+      run->mScript = *scriptAnalysis;
+    }
+
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+  SetLineBreakpoints (uint32_t textPosition,
+		      uint32_t textLength,
+		      const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
+  { return S_OK; }
+
+  IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
+			       uint8_t explicitLevel, uint8_t resolvedLevel)
+  { return S_OK; }
+
+  IFACEMETHODIMP
+  SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
+			 IDWriteNumberSubstitution* numberSubstitution)
+  { return S_OK; }
+
+protected:
+  Run *FetchNextRun (IN OUT uint32_t* textLength)
+  {
+    // Used by the sink setters, this returns a reference to the next run.
+    // Position and length are adjusted to now point after the current run
+    // being returned.
+
+    Run *origRun = mCurrentRun;
+    // Split the tail if needed (the length remaining is less than the
+    // current run's size).
+    if (*textLength < mCurrentRun->mTextLength)
+      SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
+    else
+      // Just advance the current run.
+      mCurrentRun = mCurrentRun->nextRun;
+    *textLength -= origRun->mTextLength;
+
+    // Return a reference to the run that was just current.
+    return origRun;
+  }
+
+  void SetCurrentRun (uint32_t textPosition)
+  {
+    // Move the current run to the given position.
+    // Since the analyzers generally return results in a forward manner,
+    // this will usually just return early. If not, find the
+    // corresponding run for the text position.
+
+    if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
+      return;
+
+    for (Run *run = &mRunHead; run; run = run->nextRun)
+      if (run->ContainsTextPosition (textPosition))
+      {
+	mCurrentRun = run;
+	return;
+      }
+    assert (0); // We should always be able to find the text position in one of our runs
+  }
+
+  void SplitCurrentRun (uint32_t splitPosition)
+  {
+    if (!mCurrentRun)
+    {
+      assert (0); // SplitCurrentRun called without current run
+      // Shouldn't be calling this when no current run is set!
+      return;
+    }
+    // Split the current run.
+    if (splitPosition <= mCurrentRun->mTextStart)
+    {
+      // No need to split, already the start of a run
+      // or before it. Usually the first.
+      return;
+    }
+    Run *newRun = new Run;
+
+    *newRun = *mCurrentRun;
+
+    // Insert the new run in our linked list.
+    newRun->nextRun = mCurrentRun->nextRun;
+    mCurrentRun->nextRun = newRun;
+
+    // Adjust runs' text positions and lengths.
+    uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
+    newRun->mTextStart += splitPoint;
+    newRun->mTextLength -= splitPoint;
+    mCurrentRun->mTextLength = splitPoint;
+    mCurrentRun = newRun;
+  }
+
+protected:
+  // Input
+  // (weak references are fine here, since this class is a transient
+  //  stack-based helper that doesn't need to copy data)
+  uint32_t mTextLength;
+  const wchar_t* mText;
+  const wchar_t* mLocaleName;
+  DWRITE_READING_DIRECTION mReadingDirection;
+
+  // Current processing state.
+  Run *mCurrentRun;
+
+  // Output is a list of runs starting here
+  Run  mRunHead;
+};
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
+{
+  IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->data.directwrite;
+  auto *global = get_directwrite_global ();
+  if (unlikely (!global))
+    return false;
+  IDWriteFactory *dwriteFactory = global->dwriteFactory;
+
+  IDWriteTextAnalyzer* analyzer;
+  dwriteFactory->CreateTextAnalyzer (&analyzer);
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+#define ALLOCATE_ARRAY(Type, name, len) \
+  Type *name = (Type *) scratch; \
+  do { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  } while (0)
+
+#define utf16_index() var1.u32
+
+  ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
+
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    buffer->info[i].utf16_index () = chars_len;
+    if (likely (c <= 0xFFFFu))
+      textString[chars_len++] = c;
+    else if (unlikely (c > 0x10FFFFu))
+      textString[chars_len++] = 0xFFFDu;
+    else
+    {
+      textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
+  /* Need log_clusters to assign features. */
+  chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    unsigned int cluster = buffer->info[i].cluster;
+    log_clusters[chars_len++] = cluster;
+    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+      log_clusters[chars_len++] = cluster; /* Surrogates. */
+  }
+
+  DWRITE_READING_DIRECTION readingDirection;
+  readingDirection = buffer->props.direction ?
+		     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
+		     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+  /*
+  * There's an internal 16-bit limit on some things inside the analyzer,
+  * but we never attempt to shape a word longer than 64K characters
+  * in a single gfxShapedWord, so we cannot exceed that limit.
+  */
+  uint32_t textLength = chars_len;
+
+  TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
+  TextAnalysis::Run *runHead;
+  HRESULT hr;
+  hr = analysis.GenerateResults (analyzer, &runHead);
+
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
+    return false; \
+  } HB_STMT_END
+
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to generate results.");
+
+  uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
+  uint32_t glyphCount;
+  bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+  const wchar_t localeName[20] = {0};
+  if (buffer->props.language)
+    mbstowcs ((wchar_t*) localeName,
+	      hb_language_to_string (buffer->props.language), 20);
+
+  /*
+   * Set up features.
+   */
+  static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
+  static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
+  hb_vector_t<hb_ms_features_t *> range_features;
+  hb_vector_t<uint32_t> range_char_counts;
+
+  // https://github.com/harfbuzz/harfbuzz/pull/5114
+  // The data allocated by these two vectors are used by the above two, so they
+  // should remain alive as long as the above two are.
+  hb_vector_t<hb_ms_feature_t> feature_records;
+  hb_vector_t<hb_ms_range_record_t> range_records;
+  if (num_features)
+  {
+    if (hb_ms_setup_features (features, num_features, feature_records, range_records))
+    {
+      hb_ms_make_feature_ranges (feature_records,
+				 range_records,
+				 0,
+				 chars_len,
+				 log_clusters,
+				 range_features,
+				 range_char_counts);
+    }
+  }
+
+  uint16_t* clusterMap;
+  clusterMap = new uint16_t[textLength];
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
+  textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
+
+retry_getglyphs:
+  uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
+  glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
+
+  hr = analyzer->GetGlyphs (textString,
+			    chars_len,
+			    fontFace,
+			    false,
+			    isRightToLeft,
+			    &runHead->mScript,
+			    localeName,
+			    nullptr,
+			    (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+			    range_char_counts.arrayZ,
+			    range_features.length,
+			    maxGlyphCount,
+			    clusterMap,
+			    textProperties,
+			    glyphIndices,
+			    glyphProperties,
+			    &glyphCount);
+
+  if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
+  {
+    delete [] glyphIndices;
+    delete [] glyphProperties;
+
+    maxGlyphCount *= 2;
+
+    goto retry_getglyphs;
+  }
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to get glyphs.");
+
+  float* glyphAdvances = new float[maxGlyphCount];
+  DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
+
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof (WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
+			     / (sizeof (WORD) +
+				sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
+				sizeof (int) +
+				sizeof (DWRITE_GLYPH_OFFSET) +
+				sizeof (uint32_t));
+  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
+
+  unsigned fontEmSize = font->face->get_upem ();
+
+  float x_mult = font->x_multf;
+  float y_mult = font->y_multf;
+
+  hr = analyzer->GetGlyphPlacements (textString,
+				     clusterMap,
+				     textProperties,
+				     chars_len,
+				     glyphIndices,
+				     glyphProperties,
+				     glyphCount,
+				     fontFace,
+				     fontEmSize,
+				     false,
+				     isRightToLeft,
+				     &runHead->mScript,
+				     localeName,
+				     (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+				     range_char_counts.arrayZ,
+				     range_features.length,
+				     glyphAdvances,
+				     glyphOffsets);
+
+  if (FAILED (hr))
+    FAIL ("Analyzer failed to get glyph placements.");
+
+  /* Ok, we've got everything we need, now compose output buffer,
+   * very, *very*, carefully! */
+
+  /* Calculate visual-clusters.  That's what we ship. */
+  for (unsigned int i = 0; i < glyphCount; i++)
+    vis_clusters[i] = (uint32_t) -1;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    uint32_t *p =
+      &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
+    *p = hb_min (*p, buffer->info[i].cluster);
+  }
+  for (unsigned int i = 1; i < glyphCount; i++)
+    if (vis_clusters[i] == (uint32_t) -1)
+      vis_clusters[i] = vis_clusters[i - 1];
+
+#undef utf16_index
+
+  if (unlikely (!buffer->ensure (glyphCount)))
+    FAIL ("Buffer in error");
+
+#undef FAIL
+
+  /* Set glyph infos */
+  buffer->len = 0;
+  for (unsigned int i = 0; i < glyphCount; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[buffer->len++];
+
+    info->codepoint = glyphIndices[i];
+    info->cluster = vis_clusters[i];
+
+    /* The rest is crap.  Let's store position info there for now. */
+    info->mask = glyphAdvances[i];
+    info->var1.i32 = glyphOffsets[i].advanceOffset;
+    info->var2.i32 = glyphOffsets[i].ascenderOffset;
+  }
+
+  /* Set glyph positions */
+  buffer->clear_positions ();
+  for (unsigned int i = 0; i < glyphCount; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[i];
+    hb_glyph_position_t *pos = &buffer->pos[i];
+
+    /* TODO vertical */
+    pos->x_advance = round (x_mult * (int32_t) info->mask);
+    pos->x_offset = round (x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32));
+    pos->y_offset = round (y_mult * info->var2.i32);
+  }
+
+  if (isRightToLeft) hb_buffer_reverse (buffer);
+
+  buffer->clear_glyph_flags ();
+  buffer->unsafe_to_break ();
+
+  delete [] clusterMap;
+  delete [] glyphIndices;
+  delete [] textProperties;
+  delete [] glyphProperties;
+  delete [] glyphAdvances;
+  delete [] glyphOffsets;
+
+  /* Wow, done! */
+  return true;
+}
+
+
+#endif

File diff suppressed because it is too large
+ 155 - 737
thirdparty/harfbuzz/src/hb-directwrite.cc


+ 20 - 3
thirdparty/harfbuzz/src/hb-directwrite.h

@@ -27,19 +27,32 @@
 
 #include "hb.h"
 
+#include <dwrite_3.h>
+
 HB_BEGIN_DECLS
 
 HB_EXTERN hb_face_t *
 hb_directwrite_face_create (IDWriteFontFace *dw_face);
 
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create_from_file_or_fail (const char   *file_name,
+					      unsigned int  index);
+
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create_from_blob_or_fail (hb_blob_t    *blob,
+					      unsigned int  index);
+
 HB_EXTERN IDWriteFontFace *
 hb_directwrite_face_get_dw_font_face (hb_face_t *face);
 
 HB_EXTERN hb_font_t *
-hb_directwrite_font_create (IDWriteFont *dw_font);
+hb_directwrite_font_create (IDWriteFontFace *dw_face);
 
-HB_EXTERN IDWriteFont *
-hb_directwrite_font_get_dw_font (hb_font_t *font);
+HB_EXTERN IDWriteFontFace *
+hb_directwrite_font_get_dw_font_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_directwrite_font_set_funcs (hb_font_t *font);
 
 #ifndef HB_DISABLE_DEPRECATED
 
@@ -47,6 +60,10 @@ HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
 HB_EXTERN IDWriteFontFace *
 hb_directwrite_face_get_font_face (hb_face_t *face);
 
+HB_DEPRECATED
+HB_EXTERN IDWriteFont *
+hb_directwrite_font_get_dw_font (hb_font_t *font);
+
 #endif
 
 HB_END_DECLS

+ 223 - 0
thirdparty/harfbuzz/src/hb-directwrite.hh

@@ -0,0 +1,223 @@
+/*
+ *  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+
+#ifndef HB_DIRECTWRITE_HH
+#define HB_DIRECTWRITE_HH
+
+#include "hb.hh"
+
+#include "hb-directwrite.h"
+
+#include "hb-mutex.hh"
+#include "hb-map.hh"
+
+/*
+ * DirectWrite font stream helpers
+ */
+
+// Have a look at to NativeFontResourceDWrite.cpp in Mozilla
+
+
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
+class DWriteFontFileLoader : public IDWriteFontFileLoader
+{
+private:
+  hb_reference_count_t mRefCount;
+  hb_mutex_t mutex;
+  hb_hashmap_t<uint64_t, IDWriteFontFileStream *> mFontStreams;
+  uint64_t mNextFontFileKey = 0;
+public:
+  DWriteFontFileLoader ()
+  {
+    mRefCount.init ();
+  }
+
+  uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream)
+  {
+    fontFileStream->AddRef ();
+    hb_lock_t lock {mutex};
+    mFontStreams.set (mNextFontFileKey, fontFileStream);
+    return mNextFontFileKey++;
+  }
+  void UnregisterFontFileStream (uint64_t fontFileKey)
+  {
+    hb_lock_t lock {mutex};
+    IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
+    if (stream)
+    {
+      mFontStreams.del (fontFileKey);
+      stream->Release ();
+    }
+  }
+
+  // IUnknown interface
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // IDWriteFontFileLoader methods
+  virtual HRESULT STDMETHODCALLTYPE
+  CreateStreamFromKey (void const* fontFileReferenceKey,
+		       uint32_t fontFileReferenceKeySize,
+		       OUT IDWriteFontFileStream** fontFileStream)
+  {
+    if (fontFileReferenceKeySize != sizeof (uint64_t))
+      return E_INVALIDARG;
+    uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey;
+    IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
+    if (!stream)
+      return E_FAIL;
+    stream->AddRef ();
+    *fontFileStream = stream;
+    return S_OK;
+  }
+
+  virtual ~DWriteFontFileLoader()
+  {
+    for (auto v : mFontStreams.values ())
+      v->Release ();
+  }
+};
+
+class DWriteFontFileStream : public IDWriteFontFileStream
+{
+private:
+  hb_reference_count_t mRefCount;
+  hb_blob_t *mBlob;
+  uint8_t *mData;
+  unsigned mSize;
+  DWriteFontFileLoader *mLoader;
+public:
+  uint64_t fontFileKey;
+public:
+  DWriteFontFileStream (hb_blob_t *blob);
+
+  // IUnknown interface
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
+  { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) ()
+  {
+    return mRefCount.inc () + 1;
+  }
+  IFACEMETHOD_ (ULONG, Release) ()
+  {
+    signed refCount = mRefCount.dec () - 1;
+    assert (refCount >= 0);
+    if (refCount)
+      return refCount;
+    delete this;
+    return 0;
+  }
+
+  // IDWriteFontFileStream methods
+  virtual HRESULT STDMETHODCALLTYPE
+  ReadFileFragment (void const** fragmentStart,
+		    UINT64 fileOffset,
+		    UINT64 fragmentSize,
+		    OUT void** fragmentContext)
+  {
+    // We are required to do bounds checking.
+    if (fileOffset + fragmentSize > mSize) return E_FAIL;
+
+    // truncate the 64 bit fileOffset to size_t sized index into mData
+    size_t index = static_cast<size_t> (fileOffset);
+
+    // We should be alive for the duration of this.
+    *fragmentStart = &mData[index];
+    *fragmentContext = nullptr;
+    return S_OK;
+  }
+
+  virtual void STDMETHODCALLTYPE
+  ReleaseFileFragment (void* fragmentContext) {}
+
+  virtual HRESULT STDMETHODCALLTYPE
+  GetFileSize (OUT UINT64* fileSize)
+  {
+    *fileSize = mSize;
+    return S_OK;
+  }
+
+  virtual HRESULT STDMETHODCALLTYPE
+  GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
+
+  virtual ~DWriteFontFileStream();
+};
+
+struct hb_directwrite_global_t
+{
+  hb_directwrite_global_t ()
+  {
+    HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+				      (IUnknown**) &dwriteFactory);
+
+    if (unlikely (hr != S_OK))
+      return;
+
+    fontFileLoader = new DWriteFontFileLoader ();
+    dwriteFactory->RegisterFontFileLoader (fontFileLoader);
+
+    success = true;
+  }
+  ~hb_directwrite_global_t ()
+  {
+    if (fontFileLoader)
+      fontFileLoader->Release ();
+    if (dwriteFactory)
+      dwriteFactory->Release ();
+  }
+
+  bool success = false;
+  IDWriteFactory *dwriteFactory;
+  DWriteFontFileLoader *fontFileLoader;
+};
+
+
+HB_INTERNAL hb_directwrite_global_t *
+get_directwrite_global ();
+
+HB_INTERNAL IDWriteFontFace *
+dw_face_create (hb_blob_t *blob, unsigned index);
+
+
+#endif /* HB_DIRECTWRITE_HH */

+ 93 - 0
thirdparty/harfbuzz/src/hb-draw.cc

@@ -28,6 +28,11 @@
 
 #include "hb-draw.hh"
 
+#include "hb-geometry.hh"
+
+#include "hb-machinery.hh"
+
+
 /**
  * SECTION:hb-draw
  * @title: hb-draw
@@ -455,4 +460,92 @@ hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
 }
 
 
+static void
+hb_draw_extents_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_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_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_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_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_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (control_x, control_y);
+  extents->add_point (to_x, to_y);
+}
+
+static void
+hb_draw_extents_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_extents_t *extents = (hb_extents_t *) data;
+
+  extents->add_point (control1_x, control1_y);
+  extents->add_point (control2_x, control2_y);
+  extents->add_point (to_x, to_y);
+}
+
+static inline void free_static_draw_extents_funcs ();
+
+static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_draw_extents_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_draw_extents_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_draw_extents_funcs);
+
+    return funcs;
+  }
+} static_draw_extents_funcs;
+
+static inline
+void free_static_draw_extents_funcs ()
+{
+  static_draw_extents_funcs.free_instance ();
+}
+
+hb_draw_funcs_t *
+hb_draw_extents_get_funcs ()
+{
+  return static_draw_extents_funcs.get_unconst ();
+}
+
+
 #endif

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

@@ -70,7 +70,7 @@ typedef struct hb_draw_state_t {
  *
  * The default #hb_draw_state_t at the start of glyph drawing.
  */
-#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
+#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0}, {0}, {0}, {0}, {0}, {0}, {0}}
 
 
 /**

+ 25 - 35
thirdparty/harfbuzz/src/hb-draw.hh

@@ -99,6 +99,7 @@ struct hb_draw_funcs_t
 	   float to_x, float to_y)
   {
     if (unlikely (st.path_open)) close_path (draw_data, st);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -109,7 +110,9 @@ struct hb_draw_funcs_t
 	   float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
     emit_line_to (draw_data, st, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -121,7 +124,9 @@ struct hb_draw_funcs_t
 		float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
     emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -134,7 +139,9 @@ struct hb_draw_funcs_t
 	    float to_x, float to_y)
   {
     if (unlikely (!st.path_open)) start_path (draw_data, st);
+
     emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+
     st.current_x = to_x;
     st.current_y = to_y;
   }
@@ -168,9 +175,8 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
 
 struct hb_draw_session_t
 {
-  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
-    : slant {slant_}, not_slanted {slant == 0.f},
-      funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
+  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_)
+    : funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
   {}
 
   ~hb_draw_session_t () { close_path (); }
@@ -178,36 +184,23 @@ struct hb_draw_session_t
   HB_ALWAYS_INLINE
   void move_to (float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->move_to (draw_data, st,
-		      to_x, to_y);
-    else
-      funcs->move_to (draw_data, st,
-		      to_x + to_y * slant, to_y);
+    funcs->move_to (draw_data, st,
+		    to_x, to_y);
   }
   HB_ALWAYS_INLINE
   void line_to (float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->line_to (draw_data, st,
-		      to_x, to_y);
-    else
-      funcs->line_to (draw_data, st,
-		      to_x + to_y * slant, to_y);
+    funcs->line_to (draw_data, st,
+		    to_x, to_y);
   }
   void
   HB_ALWAYS_INLINE
   quadratic_to (float control_x, float control_y,
 		float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->quadratic_to (draw_data, st,
-			   control_x, control_y,
-			   to_x, to_y);
-    else
-      funcs->quadratic_to (draw_data, st,
-			   control_x + control_y * slant, control_y,
-			   to_x + to_y * slant, to_y);
+    funcs->quadratic_to (draw_data, st,
+			 control_x, control_y,
+			 to_x, to_y);
   }
   void
   HB_ALWAYS_INLINE
@@ -215,16 +208,10 @@ struct hb_draw_session_t
 	    float control2_x, float control2_y,
 	    float to_x, float to_y)
   {
-    if (likely (not_slanted))
-      funcs->cubic_to (draw_data, st,
-		       control1_x, control1_y,
-		       control2_x, control2_y,
-		       to_x, to_y);
-    else
-      funcs->cubic_to (draw_data, st,
-		       control1_x + control1_y * slant, control1_y,
-		       control2_x + control2_y * slant, control2_y,
-		       to_x + to_y * slant, to_y);
+    funcs->cubic_to (draw_data, st,
+		     control1_x, control1_y,
+		     control2_x, control2_y,
+		     to_x, to_y);
   }
   HB_ALWAYS_INLINE
   void close_path ()
@@ -233,11 +220,14 @@ struct hb_draw_session_t
   }
 
   public:
-  float slant;
-  bool not_slanted;
   hb_draw_funcs_t *funcs;
   void *draw_data;
   hb_draw_state_t st;
 };
 
+
+HB_INTERNAL hb_draw_funcs_t *
+hb_draw_extents_get_funcs ();
+
+
 #endif /* HB_DRAW_HH */

+ 220 - 8
thirdparty/harfbuzz/src/hb-face.cc

@@ -34,6 +34,16 @@
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
 
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+#ifdef HAVE_CORETEXT
+#include "hb-coretext.h"
+#endif
+#ifdef HAVE_DIRECTWRITE
+#include "hb-directwrite.h"
+#endif
+
 
 /**
  * SECTION:hb-face
@@ -72,14 +82,14 @@ hb_face_count (hb_blob_t *blob)
   if (unlikely (!blob))
     return 0;
 
-  /* TODO We shouldn't be sanitizing blob.  Port to run sanitizer and return if not sane. */
-  /* Make API signature const after. */
-  hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
-  const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
-  unsigned int ret = ot.get_face_count ();
-  hb_blob_destroy (sanitized);
+  hb_sanitize_context_t c (blob);
+
+  const char *start = hb_blob_get_data (blob, nullptr);
+  auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
+  if (unlikely (!ot->sanitize (&c)))
+    return 0;
 
-  return ret;
+  return ot->get_face_count ();
 }
 
 /*
@@ -318,7 +328,209 @@ hb_face_create_from_file_or_fail (const char   *file_name,
 
   return face;
 }
+
+static struct supported_face_loaders_t {
+	char name[16];
+	hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
+	hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
+} supported_face_loaders[] =
+{
+  {"ot",
+#ifndef HB_NO_OPEN
+   hb_face_create_from_file_or_fail,
+#else
+   nullptr,
+#endif
+   hb_face_create_or_fail
+  },
+#ifdef HAVE_FREETYPE
+  {"ft",
+   hb_ft_face_create_from_file_or_fail,
+   hb_ft_face_create_from_blob_or_fail
+  },
+#endif
+#ifdef HAVE_CORETEXT
+  {"coretext",
+   hb_coretext_face_create_from_file_or_fail,
+   hb_coretext_face_create_from_blob_or_fail
+  },
 #endif
+#ifdef HAVE_DIRECTWRITE
+  {"directwrite",
+   hb_directwrite_face_create_from_file_or_fail,
+   hb_directwrite_face_create_from_blob_or_fail
+  },
+#endif
+};
+
+static const char *get_default_loader_name ()
+{
+  static hb_atomic_t<const char *> static_loader_name;
+  const char *loader_name = static_loader_name.get_acquire ();
+  if (!loader_name)
+  {
+    loader_name = getenv ("HB_FACE_LOADER");
+    if (!loader_name)
+      loader_name = "";
+    if (!static_loader_name.cmpexch (nullptr, loader_name))
+      loader_name = static_loader_name.get_acquire ();
+  }
+  return loader_name;
+}
+
+/**
+ * hb_face_create_from_file_or_fail_using:
+ * @file_name: A font filename
+ * @index: The index of the face within the file
+ * @loader_name: (nullable): The name of the loader to use, or `NULL`
+ *
+ * A thin wrapper around the face loader functions registered with HarfBuzz.
+ * If @loader_name is `NULL` or the empty string, the first available loader
+ * is used.
+ *
+ * For example, the FreeType ("ft") loader might be able to load
+ * WOFF and WOFF2 files if FreeType is built with those features,
+ * whereas the OpenType ("ot") loader will not.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * the file cannot be read or the loader fails to load the face.
+ *
+ * Since: 11.0.0
+ **/
+hb_face_t *
+hb_face_create_from_file_or_fail_using (const char   *file_name,
+					unsigned int  index,
+					const char   *loader_name)
+{
+  // Duplicated in hb_face_create_or_fail_using
+  bool retry = false;
+  if (!loader_name || !*loader_name)
+  {
+    loader_name = get_default_loader_name ();
+    retry = true;
+  }
+  if (loader_name && !*loader_name) loader_name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+  {
+    if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
+      return supported_face_loaders[i].from_file (file_name, index);
+  }
+
+  if (retry)
+  {
+    retry = false;
+    loader_name = nullptr;
+    goto retry;
+  }
+
+  return nullptr;
+}
+
+/**
+ * hb_face_create_or_fail_using:
+ * @blob: #hb_blob_t to work upon
+ * @index: The index of the face within @blob
+ * @loader_name: (nullable): The name of the loader to use, or `NULL`
+ *
+ * A thin wrapper around the face loader functions registered with HarfBuzz.
+ * If @loader_name is `NULL` or the empty string, the first available loader
+ * is used.
+ *
+ * For example, the FreeType ("ft") loader might be able to load
+ * WOFF and WOFF2 files if FreeType is built with those features,
+ * whereas the OpenType ("ot") loader will not.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * the loader fails to load the face.
+ *
+ * Since: 11.0.0
+ **/
+hb_face_t *
+hb_face_create_or_fail_using (hb_blob_t    *blob,
+			      unsigned int  index,
+			      const char   *loader_name)
+{
+  // Duplicated in hb_face_create_from_file_or_fail_using
+  bool retry = false;
+  if (!loader_name || !*loader_name)
+  {
+    loader_name = get_default_loader_name ();
+    retry = true;
+  }
+  if (loader_name && !*loader_name) loader_name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+  {
+    if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
+      return supported_face_loaders[i].from_blob (blob, index);
+  }
+
+  if (retry)
+  {
+    retry = false;
+    loader_name = nullptr;
+    goto retry;
+  }
+
+  return nullptr;
+}
+
+static inline void free_static_face_loader_list ();
+
+static const char * const nil_face_loader_list[] = {nullptr};
+
+static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
+								  hb_face_loader_list_lazy_loader_t>
+{
+  static const char ** create ()
+  {
+    const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
+    if (unlikely (!face_loader_list))
+      return nullptr;
+
+    unsigned i;
+    for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
+      face_loader_list[i] = supported_face_loaders[i].name;
+    face_loader_list[i] = nullptr;
+
+    hb_atexit (free_static_face_loader_list);
+
+    return face_loader_list;
+  }
+  static void destroy (const char **l)
+  { hb_free (l); }
+  static const char * const * get_null ()
+  { return nil_face_loader_list; }
+} static_face_loader_list;
+
+static inline
+void free_static_face_loader_list ()
+{
+  static_face_loader_list.free_instance ();
+}
+
+/**
+ * hb_face_list_loaders:
+ *
+ * Retrieves the list of face loaders supported by HarfBuzz.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): a
+ *    `NULL`-terminated array of supported face loaders
+ *    constant strings. The returned array is owned by HarfBuzz
+ *    and should not be modified or freed.
+ *
+ * Since: 11.0.0
+ **/
+const char **
+hb_face_list_loaders ()
+{
+  return static_face_loader_list.get_unconst ();
+}
+#endif
+
 
 /**
  * hb_face_get_empty:
@@ -460,7 +672,7 @@ hb_face_make_immutable (hb_face_t *face)
  * Since: 0.9.2
  **/
 hb_bool_t
-hb_face_is_immutable (const hb_face_t *face)
+hb_face_is_immutable (hb_face_t *face)
 {
   return hb_object_is_immutable (face);
 }

+ 15 - 1
thirdparty/harfbuzz/src/hb-face.h

@@ -63,10 +63,24 @@ HB_EXTERN hb_face_t *
 hb_face_create_or_fail (hb_blob_t    *blob,
 			unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_face_create_or_fail_using (hb_blob_t    *blob,
+			      unsigned int  index,
+			      const char   *loader_name);
+
 HB_EXTERN hb_face_t *
 hb_face_create_from_file_or_fail (const char   *file_name,
 				  unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_face_create_from_file_or_fail_using (const char   *file_name,
+					unsigned int  index,
+					const char   *loader_name);
+
+HB_EXTERN const char **
+hb_face_list_loaders (void);
+
+
 /**
  * hb_reference_table_func_t:
  * @face: an #hb_face_t to reference table for
@@ -117,7 +131,7 @@ HB_EXTERN void
 hb_face_make_immutable (hb_face_t *face);
 
 HB_EXTERN hb_bool_t
-hb_face_is_immutable (const hb_face_t *face);
+hb_face_is_immutable (hb_face_t *face);
 
 
 HB_EXTERN hb_blob_t *

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

@@ -49,8 +49,8 @@ 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. */
+  mutable hb_atomic_t<unsigned> upem;	/* Units-per-EM. */
+  mutable hb_atomic_t<unsigned> num_glyphs;/* Number of glyphs. */
 
   hb_reference_table_func_t  reference_table_func;
   void                      *user_data;
@@ -70,7 +70,7 @@ struct hb_face_t
     plan_node_t *next;
   };
 #ifndef HB_NO_SHAPER
-  hb_atomic_ptr_t<plan_node_t> shape_plans;
+  hb_atomic_t<plan_node_t *> shape_plans;
 #endif
 
   hb_blob_t *reference_table (hb_tag_t tag) const

+ 487 - 124
thirdparty/harfbuzz/src/hb-font.cc

@@ -38,6 +38,22 @@
 #include "hb-ot-var-avar-table.hh"
 #include "hb-ot-var-fvar-table.hh"
 
+#ifndef HB_NO_OT_FONT
+#include "hb-ot.h"
+#endif
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+#ifdef HAVE_FONTATIONS
+#include "hb-fontations.h"
+#endif
+#ifdef HAVE_CORETEXT
+#include "hb-coretext.h"
+#endif
+#ifdef HAVE_DIRECTWRITE
+#include "hb-directwrite.h"
+#endif
+
 
 /**
  * SECTION:hb-font
@@ -87,7 +103,7 @@ hb_font_get_font_h_extents_default (hb_font_t         *font,
 				    hb_font_extents_t *extents,
 				    void              *user_data HB_UNUSED)
 {
-  hb_bool_t ret = font->parent->get_font_h_extents (extents);
+  hb_bool_t ret = font->parent->get_font_h_extents (extents, false);
   if (ret) {
     extents->ascender = font->parent_scale_y_distance (extents->ascender);
     extents->descender = font->parent_scale_y_distance (extents->descender);
@@ -112,7 +128,7 @@ hb_font_get_font_v_extents_default (hb_font_t         *font,
 				    hb_font_extents_t *extents,
 				    void              *user_data HB_UNUSED)
 {
-  hb_bool_t ret = font->parent->get_font_v_extents (extents);
+  hb_bool_t ret = font->parent->get_font_v_extents (extents, false);
   if (ret) {
     extents->ascender = font->parent_scale_x_distance (extents->ascender);
     extents->descender = font->parent_scale_x_distance (extents->descender);
@@ -218,10 +234,10 @@ hb_font_get_glyph_h_advance_default (hb_font_t      *font,
   if (font->has_glyph_h_advances_func_set ())
   {
     hb_position_t ret;
-    font->get_glyph_h_advances (1, &glyph, 0, &ret, 0);
+    font->get_glyph_h_advances (1, &glyph, 0, &ret, 0, false);
     return ret;
   }
-  return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+  return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph, false));
 }
 
 static hb_position_t
@@ -243,10 +259,10 @@ hb_font_get_glyph_v_advance_default (hb_font_t      *font,
   if (font->has_glyph_v_advances_func_set ())
   {
     hb_position_t ret;
-    font->get_glyph_v_advances (1, &glyph, 0, &ret, 0);
+    font->get_glyph_v_advances (1, &glyph, 0, &ret, 0, false);
     return ret;
   }
-  return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+  return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph, false));
 }
 
 #define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default
@@ -265,7 +281,7 @@ hb_font_get_glyph_h_advances_default (hb_font_t*            font,
   {
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->get_glyph_h_advance (*first_glyph);
+      *first_advance = font->get_glyph_h_advance (*first_glyph, false);
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -274,7 +290,8 @@ hb_font_get_glyph_h_advances_default (hb_font_t*            font,
 
   font->parent->get_glyph_h_advances (count,
 				      first_glyph, glyph_stride,
-				      first_advance, advance_stride);
+				      first_advance, advance_stride,
+				      false);
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_x_distance (*first_advance);
@@ -297,7 +314,7 @@ hb_font_get_glyph_v_advances_default (hb_font_t*            font,
   {
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->get_glyph_v_advance (*first_glyph);
+      *first_advance = font->get_glyph_v_advance (*first_glyph, false);
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -306,7 +323,8 @@ hb_font_get_glyph_v_advances_default (hb_font_t*            font,
 
   font->parent->get_glyph_v_advances (count,
 				      first_glyph, glyph_stride,
-				      first_advance, advance_stride);
+				      first_advance, advance_stride,
+				      false);
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_y_distance (*first_advance);
@@ -426,7 +444,7 @@ hb_font_get_glyph_extents_default (hb_font_t          *font,
 				   hb_glyph_extents_t *extents,
 				   void               *user_data HB_UNUSED)
 {
-  hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+  hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents, false);
   if (ret) {
     font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
     font->parent_scale_distance (&extents->width, &extents->height);
@@ -456,7 +474,7 @@ hb_font_get_glyph_contour_point_default (hb_font_t      *font,
 					 hb_position_t  *y,
 					 void           *user_data HB_UNUSED)
 {
-  hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+  hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y, false);
   if (ret)
     font->parent_scale_position (x, y);
   return ret;
@@ -508,26 +526,28 @@ hb_font_get_glyph_from_name_default (hb_font_t      *font,
   return font->parent->get_glyph_from_name (name, len, glyph);
 }
 
-static void
-hb_font_draw_glyph_nil (hb_font_t       *font HB_UNUSED,
-			void            *font_data HB_UNUSED,
-			hb_codepoint_t   glyph,
-			hb_draw_funcs_t *draw_funcs,
-			void            *draw_data,
-			void            *user_data HB_UNUSED)
+static hb_bool_t
+hb_font_draw_glyph_or_fail_nil (hb_font_t       *font HB_UNUSED,
+				void            *font_data HB_UNUSED,
+				hb_codepoint_t   glyph,
+				hb_draw_funcs_t *draw_funcs,
+				void            *draw_data,
+				void            *user_data HB_UNUSED)
 {
+  return false;
 }
 
-static void
-hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED,
-                         void *font_data HB_UNUSED,
-                         hb_codepoint_t glyph HB_UNUSED,
-                         hb_paint_funcs_t *paint_funcs HB_UNUSED,
-                         void *paint_data HB_UNUSED,
-                         unsigned int palette HB_UNUSED,
-                         hb_color_t foreground HB_UNUSED,
-                         void *user_data HB_UNUSED)
+static hb_bool_t
+hb_font_paint_glyph_or_fail_nil (hb_font_t *font HB_UNUSED,
+				 void *font_data HB_UNUSED,
+				 hb_codepoint_t glyph HB_UNUSED,
+				 hb_paint_funcs_t *paint_funcs HB_UNUSED,
+				 void *paint_data HB_UNUSED,
+				 unsigned int palette HB_UNUSED,
+				 hb_color_t foreground HB_UNUSED,
+				 void *user_data HB_UNUSED)
 {
+  return false;
 }
 
 typedef struct hb_font_draw_glyph_default_adaptor_t {
@@ -535,7 +555,6 @@ typedef struct hb_font_draw_glyph_default_adaptor_t {
   void		  *draw_data;
   float		   x_scale;
   float		   y_scale;
-  float		   slant;
 } hb_font_draw_glyph_default_adaptor_t;
 
 static void
@@ -548,10 +567,9 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
   hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
   float x_scale = adaptor->x_scale;
   float y_scale = adaptor->y_scale;
-  float slant   = adaptor->slant;
 
   adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
-				     x_scale * to_x + slant * to_y, y_scale * to_y);
+				     x_scale * to_x, y_scale * to_y);
 }
 
 static void
@@ -563,13 +581,12 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
   hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
   float x_scale = adaptor->x_scale;
   float y_scale = adaptor->y_scale;
-  float slant   = adaptor->slant;
 
-  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_x = st->current_x * x_scale;
   st->current_y = st->current_y * y_scale;
 
   adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
-				     x_scale * to_x + slant * to_y, y_scale * to_y);
+				     x_scale * to_x, y_scale * to_y);
 }
 
 static void
@@ -582,14 +599,13 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data
   hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
   float x_scale = adaptor->x_scale;
   float y_scale = adaptor->y_scale;
-  float slant   = adaptor->slant;
 
-  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_x = st->current_x * x_scale;
   st->current_y = st->current_y * y_scale;
 
   adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
-					  x_scale * control_x + slant * control_y, y_scale * control_y,
-					  x_scale * to_x + slant * to_y, y_scale * to_y);
+					  x_scale * control_x, y_scale * control_y,
+					  x_scale * to_x, y_scale * to_y);
 }
 
 static void
@@ -603,15 +619,14 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
   hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
   float x_scale = adaptor->x_scale;
   float y_scale = adaptor->y_scale;
-  float slant   = adaptor->slant;
 
-  st->current_x = st->current_x * x_scale + st->current_y * slant;
+  st->current_x = st->current_x * x_scale;
   st->current_y = st->current_y * y_scale;
 
   adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
-				      x_scale * control1_x + slant * control1_y, y_scale * control1_y,
-				      x_scale * control2_x + slant * control2_y, y_scale * control2_y,
-				      x_scale * to_x + slant * to_y, y_scale * to_y);
+				      x_scale * control1_x, y_scale * control1_y,
+				      x_scale * control2_x, y_scale * control2_y,
+				      x_scale * to_x, y_scale * to_y);
 }
 
 static void
@@ -634,49 +649,47 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = {
   }
 };
 
-static void
-hb_font_draw_glyph_default (hb_font_t       *font,
-				 void            *font_data HB_UNUSED,
-				 hb_codepoint_t   glyph,
-				 hb_draw_funcs_t *draw_funcs,
-				 void            *draw_data,
-				 void            *user_data HB_UNUSED)
+static hb_bool_t
+hb_font_draw_glyph_or_fail_default (hb_font_t       *font,
+				    void            *font_data HB_UNUSED,
+				    hb_codepoint_t   glyph,
+				    hb_draw_funcs_t *draw_funcs,
+				    void            *draw_data,
+				    void            *user_data HB_UNUSED)
 {
   hb_font_draw_glyph_default_adaptor_t adaptor = {
     draw_funcs,
     draw_data,
     font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
-    font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
-    font->parent->y_scale ? (font->slant - font->parent->slant) *
-			    (float) font->x_scale / (float) font->parent->y_scale : 0.f
+    font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f
   };
 
-  font->parent->draw_glyph (glyph,
-				 const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
-				 &adaptor);
+  return font->parent->draw_glyph_or_fail (glyph,
+					   const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
+					   &adaptor,
+					   false);
 }
 
-static void
-hb_font_paint_glyph_default (hb_font_t *font,
-                             void *font_data,
-                             hb_codepoint_t glyph,
-                             hb_paint_funcs_t *paint_funcs,
-                             void *paint_data,
-                             unsigned int palette,
-                             hb_color_t foreground,
-                             void *user_data)
+static hb_bool_t
+hb_font_paint_glyph_or_fail_default (hb_font_t *font,
+				     void *font_data,
+				     hb_codepoint_t glyph,
+				     hb_paint_funcs_t *paint_funcs,
+				     void *paint_data,
+				     unsigned int palette,
+				     hb_color_t foreground,
+				     void *user_data)
 {
   paint_funcs->push_transform (paint_data,
-    font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
-    font->parent->y_scale ? (font->slant - font->parent->slant) *
-			    (float) font->x_scale / (float) font->parent->y_scale : 0.f,
-    0.f,
-    font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
-    0.f, 0.f);
+    font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0, 0,
+    0, font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0,
+    0, 0);
 
-  font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground);
+  bool ret = font->parent->paint_glyph_or_fail (glyph, paint_funcs, paint_data, palette, foreground);
 
   paint_funcs->pop_transform (paint_data);
+
+  return ret;
 }
 
 DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
@@ -1413,6 +1426,92 @@ hb_font_get_glyph_shape (hb_font_t *font,
 }
 #endif
 
+/**
+ * hb_font_draw_glyph_or_fail:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Draws the outline that corresponds to a glyph in the specified @font.
+ *
+ * This is a newer name for hb_font_draw_glyph(), that returns `false`
+ * if the font has no outlines for the glyph.
+ *
+ * The outline is returned by way of calls to the callbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Return value: `true` if glyph was drawn, `false` otherwise
+ *
+ * XSince: REPLACEME
+ **/
+hb_bool_t
+hb_font_draw_glyph_or_fail (hb_font_t *font,
+			    hb_codepoint_t glyph,
+			    hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+  return font->draw_glyph_or_fail (glyph, dfuncs, draw_data);
+}
+
+/**
+ * hb_font_paint_glyph_or_fail:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @pfuncs: #hb_paint_funcs_t to paint with
+ * @paint_data: User data to pass to paint callbacks
+ * @palette_index: The index of the font's color palette to use
+ * @foreground: The foreground color, unpremultipled
+ *
+ * Paints a color glyph.
+ *
+ * This function is similar to, but lower-level than,
+ * hb_font_paint_glyph(). It is suitable for clients that
+ * need more control.  If there are no color glyphs available,
+ * it will return `false`. The client can then fall back to
+ * hb_font_draw_glyph_or_fail() for the monochrome outline glyph.
+ *
+ * The painting instructions are returned by way of calls to
+ * the callbacks of the @funcs object, with @paint_data passed
+ * to them.
+ *
+ * If the font has color palettes (see hb_ot_color_has_palettes()),
+ * then @palette_index selects the palette to use. If the font only
+ * has one palette, this will be 0.
+ *
+ * Return value: `true` if glyph was painted, `false` otherwise
+ *
+ * XSince: REPLACEME
+ */
+hb_bool_t
+hb_font_paint_glyph_or_fail (hb_font_t *font,
+			     hb_codepoint_t glyph,
+			     hb_paint_funcs_t *pfuncs, void *paint_data,
+			     unsigned int palette_index,
+			     hb_color_t foreground)
+{
+  return font->paint_glyph_or_fail (glyph, pfuncs, paint_data, palette_index, foreground);
+}
+
+/* A bit higher-level, and with fallback */
+
+void
+hb_font_t::paint_glyph (hb_codepoint_t glyph,
+			hb_paint_funcs_t *paint_funcs, void *paint_data,
+			unsigned int palette,
+			hb_color_t foreground)
+{
+  if (paint_glyph_or_fail (glyph,
+			   paint_funcs, paint_data,
+			   palette, foreground))
+    return;
+
+  /* Fallback for outline glyph. */
+  paint_funcs->push_clip_glyph (paint_data, glyph, this);
+  paint_funcs->color (paint_data, true, foreground);
+  paint_funcs->pop_clip (paint_data);
+}
+
+
 /**
  * hb_font_draw_glyph:
  * @font: #hb_font_t to work upon
@@ -1422,6 +1521,9 @@ hb_font_get_glyph_shape (hb_font_t *font,
  *
  * Draws the outline that corresponds to a glyph in the specified @font.
  *
+ * This is an older name for hb_font_draw_glyph_or_fail(), with no
+ * return value.
+ *
  * The outline is returned by way of calls to the callbacks of the @dfuncs
  * objects, with @draw_data passed to them.
  *
@@ -1429,10 +1531,10 @@ hb_font_get_glyph_shape (hb_font_t *font,
  **/
 void
 hb_font_draw_glyph (hb_font_t *font,
-			 hb_codepoint_t glyph,
-			 hb_draw_funcs_t *dfuncs, void *draw_data)
+		    hb_codepoint_t glyph,
+		    hb_draw_funcs_t *dfuncs, void *draw_data)
 {
-  font->draw_glyph (glyph, dfuncs, draw_data);
+  (void) hb_font_draw_glyph_or_fail (font, glyph, dfuncs, draw_data);
 }
 
 /**
@@ -1444,7 +1546,10 @@ hb_font_draw_glyph (hb_font_t *font,
  * @palette_index: The index of the font's color palette to use
  * @foreground: The foreground color, unpremultipled
  *
- * Paints the glyph.
+ * Paints the glyph. This function is similar to
+ * hb_font_paint_glyph_or_fail(), but if painting a color glyph
+ * failed, it will fall back to painting an outline monochrome
+ * glyph.
  *
  * The painting instructions are returned by way of calls to
  * the callbacks of the @funcs object, with @paint_data passed
@@ -1466,8 +1571,6 @@ hb_font_paint_glyph (hb_font_t *font,
   font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground);
 }
 
-/* A bit higher-level, and with fallback */
-
 /**
  * hb_font_get_extents_for_direction:
  * @font: #hb_font_t to work upon
@@ -1854,10 +1957,7 @@ hb_font_create (hb_face_t *face)
 {
   hb_font_t *font = _hb_font_create (face);
 
-#ifndef HB_NO_OT_FONT
-  /* Install our in-house, very lightweight, funcs. */
-  hb_ot_font_set_funcs (font);
-#endif
+  hb_font_set_funcs_using (font, nullptr);
 
 #ifndef HB_NO_VAR
   if (face && face->index >> 16)
@@ -1880,7 +1980,8 @@ _hb_font_adopt_var_coords (hb_font_t *font,
   font->design_coords = design_coords;
   font->num_coords = coords_length;
 
-  font->mults_changed (); // Easiest to call this to drop cached data
+  font->changed ();
+  font->serial_coords = font->serial;
 }
 
 /**
@@ -1935,7 +2036,8 @@ hb_font_create_sub_font (hb_font_t *parent)
     }
   }
 
-  font->mults_changed ();
+  font->changed ();
+  font->serial_coords = font->serial;
 
   return font;
 }
@@ -2023,7 +2125,7 @@ hb_font_set_user_data (hb_font_t          *font,
 		       hb_bool_t           replace)
 {
   if (!hb_object_is_immutable (font))
-    font->serial++;
+    font->changed ();
 
   return hb_object_set_user_data (font, key, data, destroy, replace);
 }
@@ -2098,7 +2200,7 @@ hb_font_is_immutable (hb_font_t *font)
 unsigned int
 hb_font_get_serial (hb_font_t *font)
 {
-  return font->serial;
+  return font->serial.get_acquire ();
 }
 
 /**
@@ -2117,9 +2219,7 @@ hb_font_changed (hb_font_t *font)
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial++;
-
-  font->mults_changed ();
+  font->changed ();
 }
 
 /**
@@ -2141,8 +2241,6 @@ hb_font_set_parent (hb_font_t *font,
   if (parent == font->parent)
     return;
 
-  font->serial++;
-
   if (!parent)
     parent = hb_font_get_empty ();
 
@@ -2151,6 +2249,8 @@ hb_font_set_parent (hb_font_t *font,
   font->parent = hb_font_reference (parent);
 
   hb_font_destroy (old);
+
+  font->changed ();
 }
 
 /**
@@ -2188,8 +2288,6 @@ hb_font_set_face (hb_font_t *font,
   if (face == font->face)
     return;
 
-  font->serial++;
-
   if (unlikely (!face))
     face = hb_face_get_empty ();
 
@@ -2197,9 +2295,12 @@ hb_font_set_face (hb_font_t *font,
 
   hb_face_make_immutable (face);
   font->face = hb_face_reference (face);
-  font->mults_changed ();
+  font->changed ();
 
   hb_face_destroy (old);
+
+  font->changed ();
+  font->serial_coords = font->serial;
 }
 
 /**
@@ -2244,8 +2345,6 @@ hb_font_set_funcs (hb_font_t         *font,
     return;
   }
 
-  font->serial++;
-
   if (font->destroy)
     font->destroy (font->user_data);
 
@@ -2257,6 +2356,8 @@ hb_font_set_funcs (hb_font_t         *font,
   font->klass = klass;
   font->user_data = font_data;
   font->destroy = destroy;
+
+  font->changed ();
 }
 
 /**
@@ -2283,15 +2384,151 @@ hb_font_set_funcs_data (hb_font_t         *font,
     return;
   }
 
-  font->serial++;
-
   if (font->destroy)
     font->destroy (font->user_data);
 
   font->user_data = font_data;
   font->destroy = destroy;
+
+  font->changed ();
 }
 
+static struct supported_font_funcs_t {
+	char name[16];
+	void (*func) (hb_font_t *);
+} supported_font_funcs[] =
+{
+#ifndef HB_NO_OT_FONT
+  {"ot",	hb_ot_font_set_funcs},
+#endif
+#ifdef HAVE_FREETYPE
+  {"ft",	hb_ft_font_set_funcs},
+#endif
+#ifdef HAVE_FONTATIONS
+  {"fontations",hb_fontations_font_set_funcs},
+#endif
+#ifdef HAVE_CORETEXT
+  {"coretext",	hb_coretext_font_set_funcs},
+#endif
+#ifdef HAVE_DIRECTWRITE
+  {"directwrite",hb_directwrite_font_set_funcs},
+#endif
+};
+
+static const char *get_default_funcs_name ()
+{
+  static hb_atomic_t<const char *> static_funcs_name;
+  const char *name = static_funcs_name.get_acquire ();
+  if (!name)
+  {
+    name = getenv ("HB_FONT_FUNCS");
+    if (!name)
+      name = "";
+    if (!static_funcs_name.cmpexch (nullptr, name))
+      name = static_funcs_name.get_acquire ();
+  }
+  return name;
+}
+
+/**
+ * hb_font_set_funcs_using:
+ * @font: #hb_font_t to work upon
+ * @name: The name of the font-functions structure to use, or `NULL`
+ *
+ * Sets the font-functions structure to use for a font, based on the
+ * specified name.
+ *
+ * If @name is `NULL` or the empty string, the default (first) functioning font-functions
+ * are used.  This default can be changed by setting the `HB_FONT_FUNCS` environment
+ * variable to the name of the desired font-functions.
+ *
+ * Return value: `true` if the font-functions was found and set, `false` otherwise
+ *
+ * Since: 11.0.0
+ **/
+hb_bool_t
+hb_font_set_funcs_using (hb_font_t  *font,
+			 const char *name)
+{
+  bool retry = false;
+
+  if (!name || !*name)
+  {
+    name = get_default_funcs_name ();
+    retry = true;
+  }
+  if (name && !*name) name = nullptr;
+
+retry:
+  for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+    if (!name || strcmp (supported_font_funcs[i].name, name) == 0)
+    {
+      supported_font_funcs[i].func (font);
+      if (name || font->klass != hb_font_funcs_get_empty ())
+	return true;
+    }
+
+  if (retry)
+  {
+    retry = false;
+    name = nullptr;
+    goto retry;
+  }
+
+  return false;
+}
+
+static inline void free_static_font_funcs_list ();
+
+static const char * const nil_font_funcs_list[] = {nullptr};
+
+static struct hb_font_funcs_list_lazy_loader_t : hb_lazy_loader_t<const char *,
+								  hb_font_funcs_list_lazy_loader_t>
+{
+  static const char ** create ()
+  {
+    const char **font_funcs_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_font_funcs), sizeof (const char *));
+    if (unlikely (!font_funcs_list))
+      return nullptr;
+
+    unsigned i;
+    for (i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      font_funcs_list[i] = supported_font_funcs[i].name;
+    font_funcs_list[i] = nullptr;
+
+    hb_atexit (free_static_font_funcs_list);
+
+    return font_funcs_list;
+  }
+  static void destroy (const char **l)
+  { hb_free (l); }
+  static const char * const * get_null ()
+  { return nil_font_funcs_list; }
+} static_font_funcs_list;
+
+static inline
+void free_static_font_funcs_list ()
+{
+  static_font_funcs_list.free_instance ();
+}
+
+/**
+ * hb_font_list_funcs:
+ *
+ * Retrieves the list of font functions supported by HarfBuzz.
+ *
+ * Return value: (transfer none) (array zero-terminated=1): a
+ *    `NULL`-terminated array of supported font functions
+ *    constant strings. The returned array is owned by HarfBuzz
+ *    and should not be modified or freed.
+ *
+ * Since: 11.0.0
+ **/
+const char **
+hb_font_list_funcs ()
+{
+  return static_font_funcs_list.get_unconst ();
+}
 
 /**
  * hb_font_set_scale:
@@ -2339,11 +2576,10 @@ hb_font_set_scale (hb_font_t *font,
   if (font->x_scale == x_scale && font->y_scale == y_scale)
     return;
 
-  font->serial++;
-
   font->x_scale = x_scale;
   font->y_scale = y_scale;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2390,10 +2626,10 @@ hb_font_set_ppem (hb_font_t    *font,
   if (font->x_ppem == x_ppem && font->y_ppem == y_ppem)
     return;
 
-  font->serial++;
-
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
+
+  font->changed ();
 }
 
 /**
@@ -2437,9 +2673,9 @@ hb_font_set_ptem (hb_font_t *font,
   if (font->ptem == ptem)
     return;
 
-  font->serial++;
-
   font->ptem = ptem;
+
+  font->changed ();
 }
 
 /**
@@ -2459,6 +2695,23 @@ hb_font_get_ptem (hb_font_t *font)
   return font->ptem;
 }
 
+/**
+ * hb_font_is_synthetic:
+ * @font: #hb_font_t to work upon
+ *
+ * Tests whether a font is synthetic. A synthetic font is one
+ * that has either synthetic slant or synthetic bold set on it.
+ *
+ * Return value: `true` if the font is synthetic, `false` otherwise.
+ *
+ * XSince: REPLACEME
+ */
+hb_bool_t
+hb_font_is_synthetic (hb_font_t *font)
+{
+  return font->is_synthetic ();
+}
+
 /**
  * hb_font_set_synthetic_bold:
  * @font: #hb_font_t to work upon
@@ -2476,7 +2729,7 @@ hb_font_get_ptem (hb_font_t *font)
  * points of the glyph shape.
  *
  * Synthetic boldness is applied when rendering a glyph via
- * hb_font_draw_glyph().
+ * hb_font_draw_glyph_or_fail().
  *
  * If @in_place is `false`, then glyph advance-widths are also
  * adjusted, otherwise they are not.  The in-place mode is
@@ -2499,12 +2752,11 @@ hb_font_set_synthetic_bold (hb_font_t *font,
       font->embolden_in_place == (bool) in_place)
     return;
 
-  font->serial++;
-
   font->x_embolden = x_embolden;
   font->y_embolden = y_embolden;
   font->embolden_in_place = in_place;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2541,7 +2793,7 @@ hb_font_get_synthetic_bold (hb_font_t *font,
  * HarfBuzz needs to know this value to adjust shaping results,
  * metrics, and style values to match the slanted rendering.
  *
- * <note>Note: The glyph shape fetched via the hb_font_draw_glyph()
+ * <note>Note: The glyph shape fetched via the hb_font_draw_glyph_or_fail()
  * function is slanted to reflect this value as well.</note>
  *
  * <note>Note: The slant value is a ratio.  For example, a
@@ -2558,10 +2810,9 @@ hb_font_set_synthetic_slant (hb_font_t *font, float slant)
   if (font->slant == slant)
     return;
 
-  font->serial++;
-
   font->slant = slant;
-  font->mults_changed ();
+
+  font->changed ();
 }
 
 /**
@@ -2607,8 +2858,6 @@ hb_font_set_variations (hb_font_t            *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE)
   {
     hb_font_set_var_coords_normalized (font, nullptr, 0);
@@ -2677,8 +2926,6 @@ hb_font_set_variation (hb_font_t *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   // TODO Share some of this code with set_variations()
 
   const OT::fvar &fvar = *font->face->table.fvar;
@@ -2749,8 +2996,6 @@ hb_font_set_var_coords_design (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
 
@@ -2787,8 +3032,6 @@ hb_font_set_var_named_instance (hb_font_t *font,
   if (font->instance_index == instance_index)
     return;
 
-  font->serial_coords = ++font->serial;
-
   font->instance_index = instance_index;
   hb_font_set_variations (font, nullptr, 0);
 }
@@ -2834,8 +3077,6 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  font->serial_coords = ++font->serial;
-
   int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
   int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
   float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
@@ -3058,12 +3299,134 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t          *ffuncs,
 
 
 #ifndef HB_DISABLE_DEPRECATED
+
+struct hb_draw_glyph_closure_t
+{
+  hb_font_draw_glyph_func_t func;
+  void *user_data;
+  hb_destroy_func_t destroy;
+};
+static hb_bool_t
+hb_font_draw_glyph_trampoline (hb_font_t       *font,
+			       void            *font_data,
+			       hb_codepoint_t   glyph,
+			       hb_draw_funcs_t *draw_funcs,
+			       void            *draw_data,
+			       void            *user_data)
+{
+  hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) user_data;
+  closure->func (font, font_data, glyph, draw_funcs, draw_data, closure->user_data);
+  return true;
+}
+static void
+hb_font_draw_glyph_closure_destroy (void *user_data)
+{
+  hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) user_data;
+
+  if (closure->destroy)
+    closure->destroy (closure->user_data);
+  hb_free (closure);
+}
+static void
+_hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t           *ffuncs,
+				    hb_font_draw_glyph_func_t  func,
+				    void                      *user_data,
+				    hb_destroy_func_t          destroy /* May be NULL. */)
+{
+  if (hb_object_is_immutable (ffuncs))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+  hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) hb_calloc (1, sizeof (hb_draw_glyph_closure_t));
+  if (unlikely (!closure))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+  closure->func = func;
+  closure->user_data = user_data;
+  closure->destroy = destroy;
+
+  hb_font_funcs_set_draw_glyph_or_fail_func (ffuncs,
+					     hb_font_draw_glyph_trampoline,
+					     closure,
+					     hb_font_draw_glyph_closure_destroy);
+}
+void
+hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t           *ffuncs,
+                                   hb_font_draw_glyph_func_t  func,
+                                   void                      *user_data,
+                                   hb_destroy_func_t          destroy /* May be NULL. */)
+{
+  _hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
+}
 void
 hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t               *ffuncs,
                                    hb_font_get_glyph_shape_func_t  func,
                                    void                           *user_data,
                                    hb_destroy_func_t               destroy /* May be NULL. */)
 {
-  hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
+  _hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
+}
+
+struct hb_paint_glyph_closure_t
+{
+  hb_font_paint_glyph_func_t func;
+  void *user_data;
+  hb_destroy_func_t destroy;
+};
+static hb_bool_t
+hb_font_paint_glyph_trampoline (hb_font_t        *font,
+				void *font_data,
+				hb_codepoint_t glyph,
+				hb_paint_funcs_t *paint_funcs,
+				void *paint_data,
+				unsigned int palette,
+				hb_color_t foreground,
+				void *user_data)
+{
+  hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) user_data;
+  closure->func (font, font_data, glyph, paint_funcs, paint_data, palette, foreground, closure->user_data);
+  return true;
+}
+static void
+hb_font_paint_glyph_closure_destroy (void *user_data)
+{
+  hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) user_data;
+
+  if (closure->destroy)
+    closure->destroy (closure->user_data);
+  hb_free (closure);
+}
+void
+hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t           *ffuncs,
+				    hb_font_paint_glyph_func_t  func,
+				    void                      *user_data,
+				    hb_destroy_func_t          destroy /* May be NULL. */)
+{
+  if (hb_object_is_immutable (ffuncs))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+  hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) hb_calloc (1, sizeof (hb_paint_glyph_closure_t));
+  if (unlikely (!closure))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+  closure->func = func;
+  closure->user_data = user_data;
+  closure->destroy = destroy;
+
+  hb_font_funcs_set_paint_glyph_or_fail_func (ffuncs,
+					      hb_font_paint_glyph_trampoline,
+					      closure,
+					      hb_font_paint_glyph_closure_destroy);
 }
 #endif

+ 61 - 36
thirdparty/harfbuzz/src/hb-font.h

@@ -486,7 +486,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
 							 void *user_data);
 
 /**
- * hb_font_draw_glyph_func_t:
+ * hb_font_draw_glyph_or_fail_func_t:
  * @font: #hb_font_t to work upon
  * @font_data: @font user data pointer
  * @glyph: The glyph ID to query
@@ -496,16 +496,17 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * Since: 7.0.0
+ * Return value: `true` if glyph was drawn, `false` otherwise
  *
+ * XSince: REPLACEME
  **/
-typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
-                                           hb_codepoint_t glyph,
-                                           hb_draw_funcs_t *draw_funcs, void *draw_data,
-                                           void *user_data);
+typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *font_data,
+							hb_codepoint_t glyph,
+							hb_draw_funcs_t *draw_funcs, void *draw_data,
+							void *user_data);
 
 /**
- * hb_font_paint_glyph_func_t:
+ * hb_font_paint_glyph_or_fail_func_t:
  * @font: #hb_font_t to work upon
  * @font_data: @font user data pointer
  * @glyph: The glyph ID to query
@@ -517,14 +518,16 @@ typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
  *
  * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
  *
- * Since: 7.0.0
+ * Return value: `true` if glyph was painted, `false` otherwise
+ *
+ * XSince: REPLACEME
  */
-typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
-                                            hb_codepoint_t glyph,
-                                            hb_paint_funcs_t *paint_funcs, void *paint_data,
-                                            unsigned int palette_index,
-                                            hb_color_t foreground,
-                                            void *user_data);
+typedef hb_bool_t (*hb_font_paint_glyph_or_fail_func_t) (hb_font_t *font, void *font_data,
+							 hb_codepoint_t glyph,
+							 hb_paint_funcs_t *paint_funcs, void *paint_data,
+							 unsigned int palette_index,
+							 hb_color_t foreground,
+							 void *user_data);
 
 /* func setters */
 
@@ -785,36 +788,36 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
 					void *user_data, hb_destroy_func_t destroy);
 
 /**
- * hb_font_funcs_set_draw_glyph_func:
+ * hb_font_funcs_set_draw_glyph_or_fail_func:
  * @ffuncs: A font-function structure
  * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
  * @user_data: Data to pass to @func
  * @destroy: (nullable): The function to call when @user_data is not needed anymore
  *
- * Sets the implementation function for #hb_font_draw_glyph_func_t.
+ * Sets the implementation function for #hb_font_draw_glyph_or_fail_func_t.
  *
- * Since: 7.0.0
+ * XSince: REPLACEME
  **/
 HB_EXTERN void
-hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
-                                   hb_font_draw_glyph_func_t func,
-                                   void *user_data, hb_destroy_func_t destroy);
+hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs,
+					   hb_font_draw_glyph_or_fail_func_t func,
+					   void *user_data, hb_destroy_func_t destroy);
 
 /**
- * hb_font_funcs_set_paint_glyph_func:
+ * hb_font_funcs_set_paint_glyph_or_fail_func:
  * @ffuncs: A font-function structure
  * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
  * @user_data: Data to pass to @func
  * @destroy: (nullable): The function to call when @user_data is no longer needed
  *
- * Sets the implementation function for #hb_font_paint_glyph_func_t.
+ * Sets the implementation function for #hb_font_paint_glyph_or_fail_func_t.
  *
- * Since: 7.0.0
+ * XSince: REPLACEME
  */
 HB_EXTERN void
-hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs,
-                                    hb_font_paint_glyph_func_t func,
-                                    void *user_data, hb_destroy_func_t destroy);
+hb_font_funcs_set_paint_glyph_or_fail_func (hb_font_funcs_t *ffuncs,
+					    hb_font_paint_glyph_or_fail_func_t func,
+					    void *user_data, hb_destroy_func_t destroy);
 
 /* func dispatch */
 
@@ -896,17 +899,17 @@ hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph);
 
-HB_EXTERN void
-hb_font_draw_glyph (hb_font_t *font,
-                    hb_codepoint_t glyph,
-                    hb_draw_funcs_t *dfuncs, void *draw_data);
+HB_EXTERN hb_bool_t
+hb_font_draw_glyph_or_fail (hb_font_t *font,
+			    hb_codepoint_t glyph,
+			    hb_draw_funcs_t *dfuncs, void *draw_data);
 
-HB_EXTERN void
-hb_font_paint_glyph (hb_font_t *font,
-                     hb_codepoint_t glyph,
-                     hb_paint_funcs_t *pfuncs, void *paint_data,
-                     unsigned int palette_index,
-                     hb_color_t foreground);
+HB_EXTERN hb_bool_t
+hb_font_paint_glyph_or_fail (hb_font_t *font,
+			     hb_codepoint_t glyph,
+			     hb_paint_funcs_t *pfuncs, void *paint_data,
+			     unsigned int palette_index,
+			     hb_color_t foreground);
 
 /* high-level funcs, with fallback */
 
@@ -979,6 +982,19 @@ hb_font_glyph_from_string (hb_font_t *font,
 			   const char *s, int len, /* -1 means nul-terminated */
 			   hb_codepoint_t *glyph);
 
+/* Older alias for hb_font_draw_glyph_or_fail() with no return value. */
+HB_EXTERN void
+hb_font_draw_glyph (hb_font_t *font,
+		    hb_codepoint_t glyph,
+		    hb_draw_funcs_t *dfuncs, void *draw_data);
+
+/* Paints color glyph; if failed, draws outline glyph. */
+HB_EXTERN void
+hb_font_paint_glyph (hb_font_t *font,
+		     hb_codepoint_t glyph,
+		     hb_paint_funcs_t *pfuncs, void *paint_data,
+		     unsigned int palette_index,
+		     hb_color_t foreground);
 
 /*
  * hb_font_t
@@ -1052,6 +1068,12 @@ hb_font_set_funcs_data (hb_font_t         *font,
 			void              *font_data,
 			hb_destroy_func_t  destroy);
 
+HB_EXTERN hb_bool_t
+hb_font_set_funcs_using (hb_font_t  *font,
+			 const char *name);
+
+HB_EXTERN const char **
+hb_font_list_funcs (void);
 
 HB_EXTERN void
 hb_font_set_scale (hb_font_t *font,
@@ -1086,6 +1108,9 @@ hb_font_set_ptem (hb_font_t *font, float ptem);
 HB_EXTERN float
 hb_font_get_ptem (hb_font_t *font);
 
+HB_EXTERN hb_bool_t
+hb_font_is_synthetic (hb_font_t *font);
+
 HB_EXTERN void
 hb_font_set_synthetic_bold (hb_font_t *font,
 			    float x_embolden, float y_embolden,

+ 293 - 72
thirdparty/harfbuzz/src/hb-font.hh

@@ -32,7 +32,11 @@
 #include "hb.hh"
 
 #include "hb-face.hh"
+#include "hb-atomic.hh"
+#include "hb-draw.hh"
+#include "hb-paint-extents.hh"
 #include "hb-shaper.hh"
+#include "hb-outline.hh"
 
 
 /*
@@ -57,8 +61,8 @@
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \
   HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \
-  HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \
-  HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \
+  HB_FONT_FUNC_IMPLEMENT (,draw_glyph_or_fail) \
+  HB_FONT_FUNC_IMPLEMENT (,paint_glyph_or_fail) \
   /* ^--- Add new callbacks here */
 
 struct hb_font_funcs_t
@@ -105,8 +109,8 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
 struct hb_font_t
 {
   hb_object_header_t header;
-  unsigned int serial;
-  unsigned int serial_coords;
+  hb_atomic_t<unsigned> serial;
+  hb_atomic_t<unsigned> serial_coords;
 
   hb_font_t *parent;
   hb_face_t *face;
@@ -191,23 +195,35 @@ struct hb_font_t
 
   void scale_glyph_extents (hb_glyph_extents_t *extents)
   {
-    float x1 = em_fscale_x (extents->x_bearing);
-    float y1 = em_fscale_y (extents->y_bearing);
-    float x2 = em_fscale_x (extents->x_bearing + extents->width);
-    float y2 = em_fscale_y (extents->y_bearing + extents->height);
+    float x1 = em_scale_x (extents->x_bearing);
+    float y1 = em_scale_y (extents->y_bearing);
+    float x2 = em_scale_x (extents->x_bearing + extents->width);
+    float y2 = em_scale_y (extents->y_bearing + extents->height);
 
-    /* Apply slant. */
+    extents->x_bearing = roundf (x1);
+    extents->y_bearing = roundf (y1);
+    extents->width = roundf (x2) - extents->x_bearing;
+    extents->height = roundf (y2) - extents->y_bearing;
+  }
+
+  void synthetic_glyph_extents (hb_glyph_extents_t *extents)
+  {
+    /* Slant. */
     if (slant_xy)
     {
-      x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
-      x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
-    }
+      hb_position_t x1 = extents->x_bearing;
+      hb_position_t y1 = extents->y_bearing;
+      hb_position_t x2 = extents->x_bearing + extents->width;
+      hb_position_t y2 = extents->y_bearing + extents->height;
+
+      x1 += floorf (hb_min (y1 * slant_xy, y2 * slant_xy));
+      x2 += ceilf (hb_max (y1 * slant_xy, y2 * slant_xy));
 
-    extents->x_bearing = floorf (x1);
-    extents->y_bearing = floorf (y1);
-    extents->width = ceilf (x2) - extents->x_bearing;
-    extents->height = ceilf (y2) - extents->y_bearing;
+      extents->x_bearing = x1;
+      extents->width = x2 - extents->x_bearing;
+    }
 
+    /* Embolden. */
     if (x_strength || y_strength)
     {
       /* Y */
@@ -250,19 +266,45 @@ struct hb_font_t
   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
-  hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
+  hb_bool_t get_font_h_extents (hb_font_extents_t *extents,
+				bool synthetic = true)
   {
     hb_memset (extents, 0, sizeof (*extents));
-    return klass->get.f.font_h_extents (this, user_data,
-					extents,
-					!klass->user_data ? nullptr : klass->user_data->font_h_extents);
+    bool ret = klass->get.f.font_h_extents (this, user_data,
+					    extents,
+					    !klass->user_data ? nullptr : klass->user_data->font_h_extents);
+
+    if (synthetic && ret)
+    {
+      /* Embolden */
+      int y_shift = y_scale < 0 ? -y_strength : y_strength;
+      extents->ascender += y_shift;
+    }
+
+    return ret;
   }
-  hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
+  hb_bool_t get_font_v_extents (hb_font_extents_t *extents,
+				bool synthetic = true)
   {
     hb_memset (extents, 0, sizeof (*extents));
-    return klass->get.f.font_v_extents (this, user_data,
-					extents,
-					!klass->user_data ? nullptr : klass->user_data->font_v_extents);
+    bool ret = klass->get.f.font_v_extents (this, user_data,
+					    extents,
+					    !klass->user_data ? nullptr : klass->user_data->font_v_extents);
+
+    if (synthetic && ret)
+    {
+      /* Embolden */
+      int x_shift = x_scale < 0 ? -x_strength : x_strength;
+      if (embolden_in_place)
+      {
+	extents->ascender += x_shift / 2;
+	extents->descender -= x_shift - x_shift / 2;
+      }
+      else
+	extents->ascender += x_shift;
+    }
+
+    return ret;
   }
 
   bool has_glyph (hb_codepoint_t unicode)
@@ -303,44 +345,88 @@ struct hb_font_t
 					 !klass->user_data ? nullptr : klass->user_data->variation_glyph);
   }
 
-  hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+  hb_position_t get_glyph_h_advance (hb_codepoint_t glyph,
+				     bool synthetic = true)
   {
-    return klass->get.f.glyph_h_advance (this, user_data,
-					 glyph,
-					 !klass->user_data ? nullptr : klass->user_data->glyph_h_advance);
+    hb_position_t advance = klass->get.f.glyph_h_advance (this, user_data,
+							  glyph,
+							  !klass->user_data ? nullptr : klass->user_data->glyph_h_advance);
+
+    if (synthetic && x_strength && !embolden_in_place)
+    {
+      /* Embolden */
+      hb_position_t strength = x_scale >= 0 ? x_strength : -x_strength;
+      advance += advance ? strength : 0;
+    }
+
+    return advance;
   }
 
-  hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+  hb_position_t get_glyph_v_advance (hb_codepoint_t glyph,
+				     bool synthetic = true)
   {
-    return klass->get.f.glyph_v_advance (this, user_data,
-					 glyph,
-					 !klass->user_data ? nullptr : klass->user_data->glyph_v_advance);
+    hb_position_t advance = klass->get.f.glyph_v_advance (this, user_data,
+							  glyph,
+							  !klass->user_data ? nullptr : klass->user_data->glyph_v_advance);
+
+    if (synthetic && y_strength && !embolden_in_place)
+    {
+      /* Embolden */
+      hb_position_t strength = y_scale >= 0 ? y_strength : -y_strength;
+      advance += advance ? strength : 0;
+    }
+
+    return advance;
   }
 
   void get_glyph_h_advances (unsigned int count,
 			     const hb_codepoint_t *first_glyph,
 			     unsigned int glyph_stride,
 			     hb_position_t *first_advance,
-			     unsigned int advance_stride)
+			     unsigned int advance_stride,
+			     bool synthetic = true)
   {
-    return klass->get.f.glyph_h_advances (this, user_data,
-					  count,
-					  first_glyph, glyph_stride,
-					  first_advance, advance_stride,
-					  !klass->user_data ? nullptr : klass->user_data->glyph_h_advances);
+    klass->get.f.glyph_h_advances (this, user_data,
+				   count,
+				   first_glyph, glyph_stride,
+				   first_advance, advance_stride,
+				   !klass->user_data ? nullptr : klass->user_data->glyph_h_advances);
+
+    if (synthetic && x_strength && !embolden_in_place)
+    {
+      /* Embolden */
+      hb_position_t strength = x_scale >= 0 ? x_strength : -x_strength;
+      for (unsigned int i = 0; i < count; i++)
+      {
+	*first_advance += *first_advance ? strength : 0;
+	first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+      }
+    }
   }
 
   void get_glyph_v_advances (unsigned int count,
 			     const hb_codepoint_t *first_glyph,
 			     unsigned int glyph_stride,
 			     hb_position_t *first_advance,
-			     unsigned int advance_stride)
+			     unsigned int advance_stride,
+			     bool synthetic = true)
   {
-    return klass->get.f.glyph_v_advances (this, user_data,
-					  count,
-					  first_glyph, glyph_stride,
-					  first_advance, advance_stride,
-					  !klass->user_data ? nullptr : klass->user_data->glyph_v_advances);
+    klass->get.f.glyph_v_advances (this, user_data,
+				   count,
+				   first_glyph, glyph_stride,
+				   first_advance, advance_stride,
+				   !klass->user_data ? nullptr : klass->user_data->glyph_v_advances);
+
+    if (synthetic && y_strength && !embolden_in_place)
+    {
+      /* Embolden */
+      hb_position_t strength = y_scale >= 0 ? y_strength : -y_strength;
+      for (unsigned int i = 0; i < count; i++)
+      {
+	*first_advance += *first_advance ? strength : 0;
+	first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+      }
+    }
   }
 
   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
@@ -386,23 +472,86 @@ struct hb_font_t
   }
 
   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
-			       hb_glyph_extents_t *extents)
+			       hb_glyph_extents_t *extents,
+			       bool synthetic = true)
   {
     hb_memset (extents, 0, sizeof (*extents));
-    return klass->get.f.glyph_extents (this, user_data,
-				       glyph,
-				       extents,
-				       !klass->user_data ? nullptr : klass->user_data->glyph_extents);
+
+    /* This is rather messy, but necessary. */
+
+    if (!synthetic)
+    {
+      return klass->get.f.glyph_extents (this, user_data,
+					 glyph,
+					 extents,
+					 !klass->user_data ? nullptr : klass->user_data->glyph_extents);
+    }
+    if (!is_synthetic () &&
+	klass->get.f.glyph_extents (this, user_data,
+				    glyph,
+				    extents,
+				    !klass->user_data ? nullptr : klass->user_data->glyph_extents))
+      return true;
+
+    /* Try getting extents from paint(), then draw(), *then* get_extents()
+     * and apply synthetic settings in the last case. */
+
+#ifndef HB_NO_PAINT
+    hb_paint_extents_context_t paint_extents;
+    if (paint_glyph_or_fail (glyph,
+			     hb_paint_extents_get_funcs (), &paint_extents,
+			     0, 0))
+    {
+      *extents = paint_extents.get_extents ().to_glyph_extents ();
+      return true;
+    }
+#endif
+
+#ifndef HB_NO_DRAW
+    hb_extents_t draw_extents;
+    if (draw_glyph_or_fail (glyph,
+			    hb_draw_extents_get_funcs (), &draw_extents))
+    {
+      *extents = draw_extents.to_glyph_extents ();
+      return true;
+    }
+#endif
+
+    bool ret = klass->get.f.glyph_extents (this, user_data,
+					   glyph,
+					   extents,
+					   !klass->user_data ? nullptr : klass->user_data->glyph_extents);
+    if (ret)
+      synthetic_glyph_extents (extents);
+
+    return ret;
   }
 
   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
-				     hb_position_t *x, hb_position_t *y)
+				     hb_position_t *x, hb_position_t *y,
+				     bool synthetic = true)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_contour_point (this, user_data,
-					     glyph, point_index,
-					     x, y,
-					     !klass->user_data ? nullptr : klass->user_data->glyph_contour_point);
+    bool ret = klass->get.f.glyph_contour_point (this, user_data,
+						 glyph, point_index,
+						 x, y,
+						 !klass->user_data ? nullptr : klass->user_data->glyph_contour_point);
+
+    if (synthetic && ret)
+    {
+      /* Slant */
+      if (slant_xy)
+        *x += roundf (*y * slant_xy);
+
+      /* Embolden */
+      if (!embolden_in_place)
+      {
+	int x_shift = x_scale < 0 ? -x_strength : x_strength;
+	*x += x_shift;
+      }
+    }
+
+    return ret;
   }
 
   hb_bool_t get_glyph_name (hb_codepoint_t glyph,
@@ -426,29 +575,94 @@ struct hb_font_t
 					 !klass->user_data ? nullptr : klass->user_data->glyph_from_name);
   }
 
-  void draw_glyph (hb_codepoint_t glyph,
-		   hb_draw_funcs_t *draw_funcs, void *draw_data)
+  bool draw_glyph_or_fail (hb_codepoint_t glyph,
+			   hb_draw_funcs_t *draw_funcs, void *draw_data,
+			   bool synthetic = true)
   {
-    klass->get.f.draw_glyph (this, user_data,
-			     glyph,
-			     draw_funcs, draw_data,
-			     !klass->user_data ? nullptr : klass->user_data->draw_glyph);
+#ifndef HB_NO_DRAW
+#ifndef HB_NO_OUTLINE
+    bool embolden = x_strength || y_strength;
+    bool slanted = slant_xy;
+    synthetic = synthetic && (embolden || slanted);
+#else
+    synthetic = false;
+#endif
+
+    if (!synthetic)
+    {
+      return klass->get.f.draw_glyph_or_fail (this, user_data,
+					      glyph,
+					      draw_funcs, draw_data,
+					      !klass->user_data ? nullptr : klass->user_data->draw_glyph_or_fail);
+    }
+
+#ifndef HB_NO_OUTLINE
+
+    hb_outline_t outline;
+    if (!klass->get.f.draw_glyph_or_fail (this, user_data,
+					  glyph,
+					  hb_outline_recording_pen_get_funcs (), &outline,
+					  !klass->user_data ? nullptr : klass->user_data->draw_glyph_or_fail))
+      return false;
+
+    // Slant before embolden; produces nicer results.
+
+    if (slanted)
+      outline.slant (slant_xy);
+
+    if (embolden)
+    {
+      float x_shift = embolden_in_place ? 0 : (float) x_strength / 2;
+      float y_shift = (float) y_strength / 2;
+      if (x_scale < 0) x_shift = -x_shift;
+      if (y_scale < 0) y_shift = -y_shift;
+      outline.embolden (x_strength, y_strength, x_shift, y_shift);
+    }
+
+    outline.replay (draw_funcs, draw_data);
+
+    return true;
+#endif
+#endif
+    return false;
   }
 
-  void paint_glyph (hb_codepoint_t glyph,
-                    hb_paint_funcs_t *paint_funcs, void *paint_data,
-                    unsigned int palette,
-                    hb_color_t foreground)
+  bool paint_glyph_or_fail (hb_codepoint_t glyph,
+			    hb_paint_funcs_t *paint_funcs, void *paint_data,
+			    unsigned int palette,
+			    hb_color_t foreground,
+			    bool synthetic = true)
   {
-    klass->get.f.paint_glyph (this, user_data,
-                              glyph,
-                              paint_funcs, paint_data,
-                              palette, foreground,
-                              !klass->user_data ? nullptr : klass->user_data->paint_glyph);
+#ifndef HB_NO_PAINT
+    /* Slant */
+    if (synthetic && slant_xy)
+      hb_paint_push_transform (paint_funcs, paint_data,
+			       1.f, 0.f,
+			       slant_xy, 1.f,
+			       0.f, 0.f);
+
+    bool ret = klass->get.f.paint_glyph_or_fail (this, user_data,
+						 glyph,
+						 paint_funcs, paint_data,
+						 palette, foreground,
+						 !klass->user_data ? nullptr : klass->user_data->paint_glyph_or_fail);
+
+    if (synthetic && slant_xy)
+      hb_paint_pop_transform (paint_funcs, paint_data);
+
+    return ret;
+#endif
+    return false;
   }
 
   /* A bit higher-level, and with fallback */
 
+  HB_INTERNAL
+  void paint_glyph (hb_codepoint_t glyph,
+		    hb_paint_funcs_t *paint_funcs, void *paint_data,
+		    unsigned int palette,
+		    hb_color_t foreground);
+
   void get_h_extents_with_fallback (hb_font_extents_t *extents)
   {
     if (!get_font_h_extents (extents))
@@ -686,7 +900,12 @@ struct hb_font_t
     return false;
   }
 
-  void mults_changed ()
+  bool is_synthetic () const
+  {
+    return x_embolden || y_embolden || slant;
+  }
+
+  void changed ()
   {
     float upem = face->get_upem ();
 
@@ -697,12 +916,14 @@ struct hb_font_t
     bool y_neg = y_scale < 0;
     y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
 
-    x_strength = fabsf (roundf (x_scale * x_embolden));
-    y_strength = fabsf (roundf (y_scale * y_embolden));
+    x_strength = roundf (abs (x_scale) * x_embolden);
+    y_strength = roundf (abs (y_scale) * y_embolden);
 
     slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
 
     data.fini ();
+
+    serial++;
   }
 
   hb_position_t em_mult (int16_t v, int64_t mult)

+ 56 - 0
thirdparty/harfbuzz/src/hb-fontations.h

@@ -0,0 +1,56 @@
+/*
+ *  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.
+ *
+ * Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_FONTATIONS_H
+#define HB_FONTATIONS_H
+
+#include "hb.h"
+
+/**
+ * SECTION: hb-fontations
+ * @title: hb-fontations
+ * @short_description: Fontations integration
+ * @include: hb-fontations.h
+ *
+ * Functions for using HarfBuzz with
+ * [Fontations](https://github.com/googlefonts/fontations/) fonts.
+ **/
+
+HB_BEGIN_DECLS
+
+/**
+ * hb_fontations_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified #hb_font_t font
+ * object to use Fontations font functions.
+ *
+ * Since: 11.0.0
+ **/
+HB_EXTERN void
+hb_fontations_font_set_funcs (hb_font_t *font);
+
+HB_END_DECLS
+
+#endif /* HB_FONTATIONS_H */

+ 59 - 46
thirdparty/harfbuzz/src/hb-ft-colr.hh

@@ -28,7 +28,7 @@
 #include "hb.hh"
 
 #include "hb-decycler.hh"
-#include "hb-paint-extents.hh"
+#include "hb-paint-bounded.hh"
 
 #include FT_COLOR_H
 
@@ -80,15 +80,30 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
 
 struct hb_ft_paint_context_t
 {
-  hb_ft_paint_context_t (const hb_ft_font_t *ft_font,
-			 hb_font_t *font,
+  hb_ft_paint_context_t (const hb_ft_font_t *ft_font_,
+			 hb_font_t *font_,
 			 hb_paint_funcs_t *paint_funcs, void *paint_data,
-			 FT_Color *palette,
+			 hb_array_t<const FT_Color> palette,
 			 unsigned palette_index,
 			 hb_color_t foreground) :
-    ft_font (ft_font), font(font),
+    ft_font (ft_font_), font (font_),
     funcs (paint_funcs), data (paint_data),
-    palette (palette), palette_index (palette_index), foreground (foreground) {}
+    palette (palette), palette_index (palette_index), foreground (foreground)
+  {
+    if (font->is_synthetic ())
+    {
+      font = hb_font_create_sub_font (font);
+      hb_font_set_synthetic_bold (font, 0, 0, true);
+      hb_font_set_synthetic_slant (font, 0);
+    }
+    else
+      hb_font_reference (font);
+  }
+
+  ~hb_ft_paint_context_t ()
+  {
+    hb_font_destroy (font);
+  }
 
   void recurse (FT_OpaquePaint paint)
   {
@@ -103,7 +118,7 @@ struct hb_ft_paint_context_t
   hb_font_t *font;
   hb_paint_funcs_t *funcs;
   void *data;
-  FT_Color *palette;
+  hb_array_t<const FT_Color> palette;
   unsigned palette_index;
   hb_color_t foreground;
   hb_decycler_t glyphs_decycler;
@@ -167,7 +182,7 @@ _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
 					 hb_color_get_red (color),
 					 (hb_color_get_alpha (color) * stop.color.alpha) >> 14);
 	}
-	else
+	else if (c->palette)
 	{
 	  FT_Color ft_color = c->palette[stop.color.palette_index];
 	  color_stops->color = HB_COLOR (ft_color.blue,
@@ -175,6 +190,8 @@ _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
 					 ft_color.red,
 					 (ft_color.alpha * stop.color.alpha) >> 14);
 	}
+	else
+	  color_stops->color = HB_COLOR (0, 0, 0, 0);
       }
 
       color_stops++;
@@ -229,9 +246,7 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
 	if (unlikely (!node.visit ((uintptr_t) other_paint.p)))
 	  continue;
 
-	c->funcs->push_group (c->data);
 	c->recurse (other_paint);
-	c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
       }
     }
     break;
@@ -316,11 +331,11 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
     break;
     case FT_COLR_PAINTFORMAT_GLYPH:
     {
-      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->funcs->push_inverse_font_transform (c->data, c->font);
       c->ft_font->lock.unlock ();
       c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font);
       c->ft_font->lock.lock ();
-      c->funcs->push_root_transform (c->data, c->font);
+      c->funcs->push_font_transform (c->data, c->font);
       c->recurse (paint.u.glyph.paint);
       c->funcs->pop_transform (c->data);
       c->funcs->pop_clip (c->data);
@@ -335,7 +350,7 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
       if (unlikely (!node.visit (gid)))
 	return;
 
-      c->funcs->push_inverse_root_transform (c->data, c->font);
+      c->funcs->push_inverse_font_transform (c->data, c->font);
       c->ft_font->lock.unlock ();
       if (c->funcs->color_glyph (c->data, gid, c->font))
       {
@@ -451,10 +466,12 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
     break;
     case FT_COLR_PAINTFORMAT_COMPOSITE:
     {
+      c->funcs->push_group (c->data);
       c->recurse (paint.u.composite.backdrop_paint);
       c->funcs->push_group (c->data);
       c->recurse (paint.u.composite.source_paint);
       c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
+      c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
     }
     break;
 
@@ -479,17 +496,24 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
 
   /* Face is locked. */
 
-  FT_Error error;
-  FT_Color*         palette;
+  FT_Palette_Data   palette_data = {};
+  FT_Color*         palette = NULL;
   FT_LayerIterator  iterator;
 
   FT_Bool  have_layers;
   FT_UInt  layer_glyph_index;
   FT_UInt  layer_color_index;
 
-  error = FT_Palette_Select(ft_face, palette_index, &palette);
-  if (error)
-    palette = NULL;
+  (void) FT_Palette_Data_Get(ft_face, &palette_data);
+  (void) FT_Palette_Select(ft_face, palette_index, &palette);
+  if (!palette)
+  {
+    // https://github.com/harfbuzz/harfbuzz/issues/5116
+    (void) FT_Palette_Select(ft_face, 0, &palette);
+  }
+
+  auto palette_array = hb_array ((const FT_Color *) palette,
+				 palette ? palette_data.num_palette_entries : 0);
 
   /* COLRv1 */
   FT_OpaquePaint paint = {0};
@@ -499,56 +523,45 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
   {
     hb_ft_paint_context_t c (ft_font, font,
 			     paint_funcs, paint_data,
-			     palette, palette_index, foreground);
+			     palette_array, palette_index, foreground);
     hb_decycler_node_t node (c.glyphs_decycler);
     node.visit (gid);
 
-    bool is_bounded = true;
+    bool clip = false;
+    bool is_bounded = false;
     FT_ClipBox clip_box;
     if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box))
     {
       c.funcs->push_clip_rectangle (c.data,
-				    clip_box.bottom_left.x +
-				      roundf (hb_min (font->slant_xy * clip_box.bottom_left.y,
-						      font->slant_xy * clip_box.top_left.y)),
+				    clip_box.bottom_left.x,
 				    clip_box.bottom_left.y,
-				    clip_box.top_right.x +
-				      roundf (hb_max (font->slant_xy * clip_box.bottom_right.y,
-						      font->slant_xy * clip_box.top_right.y)),
+				    clip_box.top_right.x,
 				    clip_box.top_right.y);
+      clip = true;
+      is_bounded = true;
     }
-    else
+    if (!is_bounded)
     {
-
-      auto *extents_funcs = hb_paint_extents_get_funcs ();
-      hb_paint_extents_context_t extents_data;
+      auto *bounded_funcs = hb_paint_bounded_get_funcs ();
+      hb_paint_bounded_context_t bounded_data;
       hb_ft_paint_context_t ce (ft_font, font,
-			        extents_funcs, &extents_data,
-			        palette, palette_index, foreground);
+			        bounded_funcs, &bounded_data,
+			        palette_array, palette_index, foreground);
       hb_decycler_node_t node2 (ce.glyphs_decycler);
       node2.visit (gid);
-      ce.funcs->push_root_transform (ce.data, font);
       ce.recurse (paint);
-      ce.funcs->pop_transform (ce.data);
-      hb_extents_t extents = extents_data.get_extents ();
-      is_bounded = extents_data.is_bounded ();
-
-      c.funcs->push_clip_rectangle (c.data,
-				    extents.xmin,
-				    extents.ymin,
-				    extents.xmax,
-				    extents.ymax);
+      is_bounded = bounded_data.is_bounded ();
     }
 
-    c.funcs->push_root_transform (c.data, font);
+    c.funcs->push_font_transform (c.data, font);
 
     if (is_bounded)
-     {
       c.recurse (paint);
-     }
 
     c.funcs->pop_transform (c.data);
-    c.funcs->pop_clip (c.data);
+
+    if (clip)
+      c.funcs->pop_clip (c.data);
 
     return true;
   }

+ 183 - 165
thirdparty/harfbuzz/src/hb-ft.cc

@@ -37,11 +37,7 @@
 #include "hb-draw.hh"
 #include "hb-font.hh"
 #include "hb-machinery.hh"
-#ifndef HB_NO_AAT
-#include "hb-aat-layout-trak-table.hh"
-#endif
 #include "hb-ot-os2-table.hh"
-#include "hb-ot-stat-table.hh"
 #include "hb-ot-shaper-arabic-pua.hh"
 #include "hb-paint.hh"
 
@@ -101,7 +97,7 @@ struct hb_ft_font_t
 
   mutable hb_mutex_t lock; /* Protects members below. */
   FT_Face ft_face;
-  mutable unsigned cached_serial;
+  mutable hb_atomic_t<unsigned> cached_serial;
   mutable hb_ft_advance_cache_t advance_cache;
 };
 
@@ -118,7 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_serial = (unsigned) -1;
+  ft_font->cached_serial = UINT_MAX;
   new (&ft_font->advance_cache) hb_ft_advance_cache_t;
 
   return ft_font;
@@ -213,9 +209,10 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
 {
   if (font->serial != ft_font->cached_serial)
   {
+    hb_lock_t lock (ft_font->lock);
     _hb_ft_hb_font_changed (font, ft_font->ft_face);
     ft_font->advance_cache.clear ();
-    ft_font->cached_serial = font->serial;
+    ft_font->cached_serial.set_release (font->serial.get_acquire ());
     return true;
   }
   return false;
@@ -478,7 +475,8 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
 			    void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
-  hb_position_t *orig_first_advance = first_advance;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   int load_flags = ft_font->load_flags;
@@ -519,38 +517,6 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
-
-  if (font->x_strength && !font->embolden_in_place)
-  {
-    /* Emboldening. */
-    hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += *first_advance ? x_strength : 0;
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
-  }
-
-#ifndef HB_NO_AAT
-  /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
-#ifndef HB_NO_STYLE
-  bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
-#else
-  bool apply_trak = false;
-#endif
-  if (apply_trak)
-  {
-    hb_position_t tracking = font->face->table.trak->get_h_tracking (font);
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += tracking;
-      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
-  }
-#endif
 }
 
 #ifndef HB_NO_VERTICAL
@@ -561,6 +527,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Fixed v;
   float y_mult;
@@ -581,26 +549,11 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
     return 0;
 
-  v = (int) (y_mult * v);
-
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
+  v = ((-v + (1<<9)) >> 10);
 
-  hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
-  v = ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength);
-
-#ifndef HB_NO_AAT
-  /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
-#ifndef HB_NO_STYLE
-  bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
-#else
-  bool apply_trak = false;
-#endif
-  if (apply_trak)
-    v += font->face->table.trak->get_v_tracking (font);
-#endif
-
-  return v;
+  return (hb_position_t) (y_mult * v);
 }
 #endif
 
@@ -614,6 +567,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float x_mult, y_mult;
@@ -658,6 +613,8 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Vector kerningv;
 
@@ -669,6 +626,41 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font,
 }
 #endif
 
+static bool
+hb_ft_is_colr_glyph (hb_font_t *font,
+		     void *font_data,
+		     hb_codepoint_t gid)
+{
+#ifndef HB_NO_PAINT
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+
+
+  /* COLRv1 */
+  FT_OpaquePaint paint = {0};
+  if (FT_Get_Color_Glyph_Paint (ft_face, gid,
+			        FT_COLOR_NO_ROOT_TRANSFORM,
+			        &paint))
+    return true;
+
+  /* COLRv0 */
+  FT_LayerIterator  iterator;
+  FT_UInt  layer_glyph_index;
+  FT_UInt  layer_color_index;
+  iterator.p  = NULL;
+  if (FT_Get_Color_Glyph_Layer (ft_face,
+				gid,
+				&layer_glyph_index,
+				&layer_color_index,
+				&iterator))
+    return true;
+#endif
+#endif
+
+  return false;
+}
+
 static hb_bool_t
 hb_ft_get_glyph_extents (hb_font_t *font,
 			 void *font_data,
@@ -676,11 +668,17 @@ hb_ft_get_glyph_extents (hb_font_t *font,
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
+  // FreeType doesn't return COLR glyph extents.
+  if (hb_ft_is_colr_glyph (font, font_data, glyph))
+    return false;
+
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float x_mult, y_mult;
-  float slant_xy = font->slant_xy;
+
 #ifdef HAVE_FT_GET_TRANSFORM
   if (ft_font->transform)
   {
@@ -708,33 +706,10 @@ hb_ft_get_glyph_extents (hb_font_t *font,
   float x2 = x1 + x_mult *  ft_face->glyph->metrics.width;
   float y2 = y1 + y_mult * -ft_face->glyph->metrics.height;
 
-  /* Apply slant. */
-  if (slant_xy)
-  {
-    x1 += hb_min (y1 * slant_xy, y2 * slant_xy);
-    x2 += hb_max (y1 * slant_xy, y2 * slant_xy);
-  }
-
-  extents->x_bearing = floorf (x1);
-  extents->y_bearing = floorf (y1);
-  extents->width = ceilf (x2) - extents->x_bearing;
-  extents->height = ceilf (y2) - extents->y_bearing;
-
-  if (font->x_strength || font->y_strength)
-  {
-    /* Y */
-    int y_shift = font->y_strength;
-    if (font->y_scale < 0) y_shift = -y_shift;
-    extents->y_bearing += y_shift;
-    extents->height -= y_shift;
-
-    /* X */
-    int x_shift = font->x_strength;
-    if (font->x_scale < 0) x_shift = -x_shift;
-    if (font->embolden_in_place)
-      extents->x_bearing -= x_shift / 2;
-    extents->width += x_shift;
-  }
+  extents->x_bearing = roundf (x1);
+  extents->y_bearing = roundf (y1);
+  extents->width = roundf (x2) - extents->x_bearing;
+  extents->height = roundf (y2) - extents->y_bearing;
 
   return true;
 }
@@ -749,6 +724,8 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 			       void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
@@ -826,6 +803,8 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   float y_mult;
@@ -857,7 +836,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
     metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
   }
 
-  metrics->ascender  = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength));
+  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
   metrics->descender = (hb_position_t) (y_mult * metrics->descender);
   metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
 
@@ -908,23 +887,25 @@ _hb_ft_cubic_to (const FT_Vector *control1,
   return FT_Err_Ok;
 }
 
-static void
-hb_ft_draw_glyph (hb_font_t *font,
-		  void *font_data,
-		  hb_codepoint_t glyph,
-		  hb_draw_funcs_t *draw_funcs, void *draw_data,
-		  void *user_data HB_UNUSED)
+static hb_bool_t
+hb_ft_draw_glyph_or_fail (hb_font_t *font,
+			  void *font_data,
+			  hb_codepoint_t glyph,
+			  hb_draw_funcs_t *draw_funcs, void *draw_data,
+			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph,
 			       FT_LOAD_NO_BITMAP | ft_font->load_flags)))
-    return;
+    return false;
 
   if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
-    return;
+    return false;
 
   const FT_Outline_Funcs outline_funcs = {
     _hb_ft_move_to,
@@ -935,43 +916,13 @@ hb_ft_draw_glyph (hb_font_t *font,
     0, /* delta */
   };
 
-  hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
-
-  /* Embolden */
-  if (font->x_strength || font->y_strength)
-  {
-    FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength);
-
-    int x_shift = 0;
-    int y_shift = 0;
-    if (font->embolden_in_place)
-    {
-      /* Undo the FreeType shift. */
-      x_shift = -font->x_strength / 2;
-      y_shift = 0;
-      if (font->y_scale < 0) y_shift = -font->y_strength;
-    }
-    else
-    {
-      /* FreeType applied things in the wrong direction for negative scale; fix up. */
-      if (font->x_scale < 0) x_shift = -font->x_strength;
-      if (font->y_scale < 0) y_shift = -font->y_strength;
-    }
-    if (x_shift || y_shift)
-    {
-      auto &outline = ft_face->glyph->outline;
-      for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1))
-      {
-	point.x += x_shift;
-	point.y += y_shift;
-      }
-    }
-  }
-
+  hb_draw_session_t draw_session {draw_funcs, draw_data};
 
   FT_Outline_Decompose (&ft_face->glyph->outline,
 			&outline_funcs,
 			&draw_session);
+
+  return true;
 }
 #endif
 
@@ -980,20 +931,22 @@ hb_ft_draw_glyph (hb_font_t *font,
 
 #include "hb-ft-colr.hh"
 
-static void
-hb_ft_paint_glyph (hb_font_t *font,
-                   void *font_data,
-                   hb_codepoint_t gid,
-                   hb_paint_funcs_t *paint_funcs, void *paint_data,
-                   unsigned int palette_index,
-                   hb_color_t foreground,
-                   void *user_data)
+static hb_bool_t
+hb_ft_paint_glyph_or_fail (hb_font_t *font,
+			   void *font_data,
+			   hb_codepoint_t gid,
+			   hb_paint_funcs_t *paint_funcs, void *paint_data,
+			   unsigned int palette_index,
+			   hb_color_t foreground,
+			   void *user_data)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  _hb_ft_hb_font_check_changed (font, ft_font);
+
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
-  FT_Long load_flags = ft_font->load_flags | FT_LOAD_NO_BITMAP | FT_LOAD_COLOR;
+  FT_Long load_flags = ft_font->load_flags | FT_LOAD_COLOR;
 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301
   load_flags |= FT_LOAD_NO_SVG;
 #endif
@@ -1002,7 +955,7 @@ hb_ft_paint_glyph (hb_font_t *font,
    * eg. draw API can call back into the face.*/
 
   if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags)))
-    return;
+    return false;
 
   if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
   {
@@ -1010,26 +963,21 @@ hb_ft_paint_glyph (hb_font_t *font,
 				paint_funcs, paint_data,
 				palette_index, foreground,
 				user_data))
-      return;
-
-    /* Simple outline. */
-    ft_font->lock.unlock ();
-    paint_funcs->push_clip_glyph (paint_data, gid, font);
-    ft_font->lock.lock ();
-    paint_funcs->color (paint_data, true, foreground);
-    paint_funcs->pop_clip (paint_data);
+      return true;
 
-    return;
+    // Outline glyph
+    return false;
   }
 
   auto *glyph = ft_face->glyph;
   if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
   {
+    bool ret = false;
     auto &bitmap = glyph->bitmap;
     if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
     {
       if (bitmap.pitch != (signed) bitmap.width * 4)
-        return;
+        return ret;
 
       ft_font->lock.unlock ();
 
@@ -1039,27 +987,26 @@ hb_ft_paint_glyph (hb_font_t *font,
 					nullptr, nullptr);
 
       hb_glyph_extents_t extents;
-      if (!hb_font_get_glyph_extents (font, gid, &extents))
+      if (!font->get_glyph_extents (gid, &extents, false))
 	goto out;
 
-      if (!paint_funcs->image (paint_data,
-			       blob,
-			       bitmap.width,
-			       bitmap.rows,
-			       HB_PAINT_IMAGE_FORMAT_BGRA,
-			       font->slant_xy,
-			       &extents))
-      {
-        /* TODO Try a forced outline load and paint? */
-      }
+      if (paint_funcs->image (paint_data,
+			      blob,
+			      bitmap.width,
+			      bitmap.rows,
+			      HB_PAINT_IMAGE_FORMAT_BGRA,
+			      0.f,
+			      &extents))
+        ret = true;
 
     out:
       hb_blob_destroy (blob);
       ft_font->lock.lock ();
     }
 
-    return;
+    return ret;
   }
+  return false;
 }
 #endif
 #endif
@@ -1079,10 +1026,8 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
 
 #ifndef HB_NO_VERTICAL
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
 #endif
@@ -1090,19 +1035,18 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 #ifndef HB_NO_OT_SHAPE_FALLBACK
     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
 #endif
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
 #ifndef HB_NO_DRAW
-    hb_font_funcs_set_draw_glyph_func (funcs, hb_ft_draw_glyph, nullptr, nullptr);
+    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ft_draw_glyph_or_fail, nullptr, nullptr);
 #endif
 
 #ifndef HB_NO_PAINT
 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
-    hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr);
+    hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ft_paint_glyph_or_fail, nullptr, nullptr);
 #endif
 #endif
 
@@ -1456,6 +1400,10 @@ hb_ft_font_changed (hb_font_t *font)
  * variation-axis settings on the @font.
  * This call is fast if nothing has changed on @font.
  *
+ * Note that as of version 11.0.0, calling this function is not necessary,
+ * as HarfBuzz will automatically detect changes to the font and update
+ * the underlying FT_Face as needed.
+ *
  * Return value: true if changed, false otherwise
  *
  * Since: 4.4.0
@@ -1587,7 +1535,8 @@ destroy_ft_library (void *arg)
  * font file and face index.
  *
  * This is similar in functionality to hb_face_create_from_file_or_fail(),
- * but uses the FreeType library for loading the font file.
+ * but uses the FreeType library for loading the font file. This can
+ * be useful, for example, to load WOFF and WOFF2 font data.
  *
  * Return value: (transfer full): The new face object, or `NULL` if
  * no face is found at the specified index or the file cannot be read.
@@ -1624,6 +1573,75 @@ hb_ft_face_create_from_file_or_fail (const char   *file_name,
   return face;
 }
 
+static hb_user_data_key_t ft_blob_key = {0};
+
+static void
+_destroy_blob (void *p)
+{
+  hb_blob_destroy ((hb_blob_t *) p);
+}
+
+/**
+ * hb_ft_face_create_from_blob_or_fail:
+ * @blob: A blob
+ * @index: The index of the face within the blob
+ *
+ * Creates an #hb_face_t face object from the specified
+ * font blob and face index.
+ *
+ * This is similar in functionality to hb_face_create_from_blob_or_fail(),
+ * but uses the FreeType library for loading the font blob. This can
+ * be useful, for example, to load WOFF and WOFF2 font data.
+ *
+ * Return value: (transfer full): The new face object, or `NULL` if
+ * loading fails (eg. blob does not contain valid font data).
+ *
+ * Since: 11.0.0
+ */
+hb_face_t *
+hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
+				     unsigned int  index)
+{
+  FT_Library ft_library = reference_ft_library ();
+  if (unlikely (!ft_library))
+  {
+    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
+    return nullptr;
+  }
+
+  hb_blob_make_immutable (blob);
+  unsigned blob_size;
+  const char *blob_data = hb_blob_get_data (blob, &blob_size);
+
+  FT_Face ft_face;
+  if (unlikely (FT_New_Memory_Face (ft_library,
+				    (const FT_Byte *) blob_data,
+				    blob_size,
+				    index,
+				    &ft_face)))
+    return nullptr;
+
+  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
+  FT_Done_Face (ft_face);
+
+  ft_face->generic.data = ft_library;
+  ft_face->generic.finalizer = finalize_ft_library;
+
+  if (hb_face_is_immutable (face))
+    return nullptr;
+
+  // Hook the blob to the hb_face_t, since FT_Face still needs it.
+  hb_blob_reference (blob);
+  if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true))
+  {
+    hb_blob_destroy (blob);
+    hb_face_destroy (face);
+    return nullptr;
+  }
+
+  return face;
+}
+
 static void
 _release_blob (void *arg)
 {

+ 4 - 0
thirdparty/harfbuzz/src/hb-ft.h

@@ -88,6 +88,10 @@ HB_EXTERN hb_face_t *
 hb_ft_face_create_from_file_or_fail (const char   *file_name,
 				     unsigned int  index);
 
+HB_EXTERN hb_face_t *
+hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
+				     unsigned int  index);
+
 /*
  * hb-font from ft-face.
  */

+ 29 - 1
thirdparty/harfbuzz/src/hb-geometry.hh

@@ -30,6 +30,11 @@
 struct hb_extents_t
 {
   hb_extents_t () {}
+  hb_extents_t (const hb_glyph_extents_t &extents) :
+		xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)),
+		ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)),
+		xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)),
+		ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {}
   hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
     xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
 
@@ -38,6 +43,12 @@ struct hb_extents_t
 
   void union_ (const hb_extents_t &o)
   {
+    if (o.is_empty ()) return;
+    if (is_empty ())
+    {
+      *this = o;
+      return;
+    }
     xmin = hb_min (xmin, o.xmin);
     ymin = hb_min (ymin, o.ymin);
     xmax = hb_max (xmax, o.xmax);
@@ -46,6 +57,11 @@ struct hb_extents_t
 
   void intersect (const hb_extents_t &o)
   {
+    if (o.is_empty () || is_empty ())
+    {
+      *this = hb_extents_t {};
+      return;
+    }
     xmin = hb_max (xmin, o.xmin);
     ymin = hb_max (ymin, o.ymin);
     xmax = hb_min (xmax, o.xmax);
@@ -69,6 +85,18 @@ struct hb_extents_t
     }
   }
 
+  hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const
+  {
+    hb_position_t x0 = (hb_position_t) roundf (xmin);
+    hb_position_t y0 = (hb_position_t) roundf (ymin);
+    hb_position_t x1 = (hb_position_t) roundf (xmax);
+    hb_position_t y1 = (hb_position_t) roundf (ymax);
+    return hb_glyph_extents_t {xneg ? x1 : x0,
+			       yneg ? y0 : y1,
+			       xneg ? x0 - x1 : x1 - x0,
+			       yneg ? y1 - y0 : y0 - y1};
+  }
+
   float xmin = 0.f;
   float ymin = 0.f;
   float xmax = -1.f;
@@ -218,7 +246,7 @@ struct hb_bounds_t
     EMPTY,
   };
 
-  hb_bounds_t (status_t status) : status (status) {}
+  hb_bounds_t (status_t status = UNBOUNDED) : status (status) {}
   hb_bounds_t (const hb_extents_t &extents) :
     status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
 

+ 1 - 1
thirdparty/harfbuzz/src/hb-graphite2.cc

@@ -68,7 +68,7 @@ struct hb_graphite2_face_data_t
 {
   hb_face_t *face;
   gr_face   *grface;
-  hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
+  hb_atomic_t<hb_graphite2_tablelist_t *> tlist;
 };
 
 static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)

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

@@ -273,7 +273,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 
   private:
   /* Must only have one pointer. */
-  hb_atomic_ptr_t<Stored *> instance;
+  mutable hb_atomic_t<Stored *> instance;
 };
 
 /* Specializations. */

+ 6 - 0
thirdparty/harfbuzz/src/hb-mutex.hh

@@ -99,6 +99,8 @@ struct hb_mutex_t
 
   hb_mutex_t () { init (); }
   ~hb_mutex_t () { fini (); }
+  hb_mutex_t (const hb_mutex_t &) = delete;
+  hb_mutex_t &operator= (const hb_mutex_t &) = delete;
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
@@ -114,6 +116,10 @@ struct hb_lock_t
   hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); }
   hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); }
   ~hb_lock_t () { if (mutex) mutex->unlock (); }
+
+  hb_lock_t (const hb_lock_t &) = delete;
+  hb_lock_t &operator= (const hb_lock_t &) = delete;
+
   private:
   hb_mutex_t *mutex;
 };

+ 3 - 3
thirdparty/harfbuzz/src/hb-object.hh

@@ -142,7 +142,7 @@ struct hb_lockable_set_t
 
 struct hb_reference_count_t
 {
-  mutable hb_atomic_int_t ref_count;
+  mutable hb_atomic_t<int> ref_count;
 
   void init (int v = 1) { ref_count = v; }
   int get_relaxed () const { return ref_count; }
@@ -213,8 +213,8 @@ struct hb_user_data_array_t
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  mutable hb_atomic_int_t writable = 0;
-  hb_atomic_ptr_t<hb_user_data_array_t> user_data;
+  mutable hb_atomic_t<bool> writable = false;
+  hb_atomic_t<hb_user_data_array_t *> user_data;
 
   bool is_inert () const { return !ref_count.get_relaxed (); }
 };

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

@@ -1888,7 +1888,7 @@ struct TupleValues
 
     bool ensure_run ()
     {
-      if (likely (run_count > 0)) return true;
+      if (run_count > 0) return true;
 
       if (unlikely (p >= end))
       {
@@ -1943,6 +1943,11 @@ struct TupleValues
 	unsigned count = hb_min (n - i, (unsigned) run_count);
 	switch (width)
 	{
+	  case 0:
+	  {
+	    arrayZ += count;
+	    break;
+	  }
 	  case 1:
 	  {
 	    const auto *pp = (const HBINT8 *) p;
@@ -1958,6 +1963,8 @@ struct TupleValues
 #endif
 	    for (; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	  case 2:
@@ -1975,6 +1982,8 @@ struct TupleValues
 #endif
 	    for (; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	  case 4:
@@ -1982,10 +1991,11 @@ struct TupleValues
 	    const auto *pp = (const HBINT32 *) p;
 	    for (unsigned j = 0; j < count; j++)
 	      *arrayZ++ += scaled ? *pp++ * scale : *pp++;
+
+	    p = (const unsigned char *) pp;
 	  }
 	  break;
 	}
-	p += count * width;
 	run_count -= count;
 	i += count;
       }

+ 6 - 4
thirdparty/harfbuzz/src/hb-ot-cff1-table.hh

@@ -1073,7 +1073,7 @@ struct cff1
 
       this->blob = sc.reference_table<cff1> (face);
 
-      /* setup for run-time santization */
+      /* setup for run-time sanitization */
       sc.init (this->blob);
       sc.start_processing ();
 
@@ -1176,7 +1176,8 @@ 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;
+	  if (unlikely (font->privateDictInfo.size &&
+			privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
 	  num_interp_env_t env2 (privDictStr);
 	  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
 	  priv->init ();
@@ -1191,7 +1192,8 @@ 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;
+	if (font->privateDictInfo.size &&
+	    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 ();
@@ -1483,7 +1485,7 @@ struct cff1
       int cmp (const gname_t &a) const { return cmp (&a, this); }
     };
 
-    mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names;
+    mutable hb_atomic_t<hb_sorted_vector_t<gname_t> *> glyph_names;
 
     typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
   };

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

@@ -102,6 +102,14 @@ struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_e
 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
 					   hb_codepoint_t glyph,
 					   hb_glyph_extents_t *extents) const
+{
+  return get_extents_at (font, glyph, extents, hb_array (font->coords, font->num_coords));
+}
+
+bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font,
+					      hb_codepoint_t glyph,
+					      hb_glyph_extents_t *extents,
+					      hb_array_t<const int> coords) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
@@ -112,7 +120,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
 
   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_extents_t, cff2_extents_param_t, number_t> interp (env);
   cff2_extents_param_t  param;
   if (unlikely (!interp.interpret (param))) return false;

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

@@ -405,7 +405,7 @@ struct cff2
 
       this->blob = sc.reference_table<cff2> (face);
 
-      /* setup for run-time santization */
+      /* setup for run-time sanitization */
       sc.init (this->blob);
       sc.start_processing ();
 
@@ -458,7 +458,8 @@ 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;
+	if (unlikely (font->privateDictInfo.size &&
+		      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 ();
@@ -481,6 +482,13 @@ struct cff2
       privateDicts.fini ();
       hb_blob_destroy (blob);
       blob = nullptr;
+
+      auto *scalars = cached_scalars_vector.get_acquire ();
+      if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr))
+      {
+	scalars->fini ();
+	hb_free (scalars);
+      }
     }
 
     hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
@@ -508,6 +516,8 @@ struct cff2
     hb_vector_t<cff2_font_dict_values_t>     fontDicts;
     hb_vector_t<PRIVDICTVAL>  privateDicts;
 
+    mutable hb_atomic_t<hb_vector_t<float> *> cached_scalars_vector;
+
     unsigned int	      num_glyphs = 0;
   };
 
@@ -518,6 +528,10 @@ struct cff2
     HB_INTERNAL bool get_extents (hb_font_t *font,
 				  hb_codepoint_t glyph,
 				  hb_glyph_extents_t *extents) const;
+    HB_INTERNAL bool get_extents_at (hb_font_t *font,
+				     hb_codepoint_t glyph,
+				     hb_glyph_extents_t *extents,
+				     hb_array_t<const int> coords) 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;
   };

+ 52 - 31
thirdparty/harfbuzz/src/hb-ot-cmap-table.hh

@@ -2014,7 +2014,8 @@ struct cmap
 
   struct accelerator_t
   {
-    using cache_t = hb_cache_t<21, 16, 8, true>;
+    using cache_t = hb_cache_t<21, 19>;
+    static_assert (sizeof (cache_t) == 1024, "");
 
     accelerator_t (hb_face_t *face)
     {
@@ -2028,6 +2029,14 @@ struct cmap
 	  subtable_uvs = &st->u.format14;
       }
 
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+      cache = (cache_t *) hb_malloc (sizeof (cache_t));
+      if (cache)
+	new (cache) cache_t ();
+      else
+        return; // Such that get_glyph_funcZ remains null.
+#endif
+
       this->get_glyph_data = subtable;
 #ifndef HB_NO_CMAP_LEGACY_SUBTABLES
       if (unlikely (symbol))
@@ -2061,62 +2070,71 @@ struct cmap
 #endif
       {
 	switch (subtable->u.format) {
-	/* Accelerate format 4 and format 12. */
-	default:
-	  this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
-	  break;
-	case 12:
-	  this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
-	  break;
-	case  4:
-	{
-	  this->format4_accel.init (&subtable->u.format4);
-	  this->get_glyph_data = &this->format4_accel;
-	  this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
-	  break;
-	}
+	  /* Accelerate format 4 and format 12. */
+	  default:
+	    this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
+	    break;
+	  case 12:
+	    this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
+	    break;
+	  case  4:
+	  {
+	    this->format4_accel.init (&subtable->u.format4);
+	    this->get_glyph_data = &this->format4_accel;
+	    this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
+	    break;
+	  }
 	}
       }
     }
-    ~accelerator_t () { this->table.destroy (); }
+    ~accelerator_t ()
+    {
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+      hb_free (cache);
+#endif
+      table.destroy ();
+    }
 
     inline bool _cached_get (hb_codepoint_t unicode,
-			     hb_codepoint_t *glyph,
-			     cache_t *cache) const
+			     hb_codepoint_t *glyph) const
     {
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+      // cache is always non-null if we have a get_glyph_funcZ
       unsigned v;
-      if (cache && cache->get (unicode, &v))
+      if (cache->get (unicode, &v))
       {
         *glyph = v;
 	return true;
       }
+#endif
       bool ret  = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
 
-      if (cache && ret)
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+      if (ret)
         cache->set (unicode, *glyph);
+#endif
+
       return ret;
     }
 
     bool get_nominal_glyph (hb_codepoint_t  unicode,
-			    hb_codepoint_t *glyph,
-			    cache_t *cache = nullptr) const
+			    hb_codepoint_t *glyph) const
     {
       if (unlikely (!this->get_glyph_funcZ)) return false;
-      return _cached_get (unicode, glyph, cache);
+      return _cached_get (unicode, glyph);
     }
 
     unsigned int get_nominal_glyphs (unsigned int count,
 				     const hb_codepoint_t *first_unicode,
 				     unsigned int unicode_stride,
 				     hb_codepoint_t *first_glyph,
-				     unsigned int glyph_stride,
-				     cache_t *cache = nullptr) const
+				     unsigned int glyph_stride) const
     {
       if (unlikely (!this->get_glyph_funcZ)) return 0;
 
       unsigned int done;
       for (done = 0;
-	   done < count && _cached_get (*first_unicode, first_glyph, cache);
+	   done < count && _cached_get (*first_unicode, first_glyph);
 	   done++)
       {
 	first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
@@ -2127,8 +2145,7 @@ struct cmap
 
     bool get_variation_glyph (hb_codepoint_t  unicode,
 			      hb_codepoint_t  variation_selector,
-			      hb_codepoint_t *glyph,
-			      cache_t *cache = nullptr) const
+			      hb_codepoint_t *glyph) const
     {
       switch (this->subtable_uvs->get_glyph_variant (unicode,
 						     variation_selector,
@@ -2139,7 +2156,7 @@ struct cmap
 	case GLYPH_VARIANT_USE_DEFAULT:	break;
       }
 
-      return get_nominal_glyph (unicode, glyph, cache);
+      return get_nominal_glyph (unicode, glyph);
     }
 
     void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
@@ -2209,11 +2226,15 @@ struct cmap
     hb_nonnull_ptr_t<const CmapSubtable> subtable;
     hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
 
-    hb_cmap_get_glyph_func_t get_glyph_funcZ;
-    const void *get_glyph_data;
+    hb_cmap_get_glyph_func_t get_glyph_funcZ = nullptr;
+    const void *get_glyph_data = nullptr;
 
     CmapSubtableFormat4::accelerator_t format4_accel;
 
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+    cache_t *cache = nullptr;
+#endif
+
     public:
     hb_blob_ptr_t<cmap> table;
   };

+ 4 - 4
thirdparty/harfbuzz/src/hb-ot-color.cc

@@ -204,7 +204,7 @@ hb_ot_color_palette_get_colors (hb_face_t     *face,
 hb_bool_t
 hb_ot_color_has_layers (hb_face_t *face)
 {
-  return face->table.COLR->has_v0_data ();
+  return face->table.COLR->colr->has_v0_data ();
 }
 
 /**
@@ -221,7 +221,7 @@ hb_ot_color_has_layers (hb_face_t *face)
 hb_bool_t
 hb_ot_color_has_paint (hb_face_t *face)
 {
-  return face->table.COLR->has_v1_data ();
+  return face->table.COLR->colr->has_v1_data ();
 }
 
 /**
@@ -240,7 +240,7 @@ hb_bool_t
 hb_ot_color_glyph_has_paint (hb_face_t      *face,
                              hb_codepoint_t  glyph)
 {
-  return face->table.COLR->has_paint_for_glyph (glyph);
+  return face->table.COLR->colr->has_paint_for_glyph (glyph);
 }
 
 /**
@@ -266,7 +266,7 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
 			      unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
 			      hb_ot_color_layer_t *layers /* OUT.     May be NULL. */)
 {
-  return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
+  return face->table.COLR->colr->get_glyph_layers (glyph, start_offset, layer_count, layers);
 }
 
 

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

@@ -136,7 +136,7 @@ HB_OT_TABLE (AAT, feat)
 
 /* OpenType color fonts. */
 #ifndef HB_NO_COLOR
-HB_OT_CORE_TABLE (OT, COLR)
+HB_OT_ACCELERATOR (OT, COLR)
 HB_OT_CORE_TABLE (OT, CPAL)
 HB_OT_ACCELERATOR (OT, CBDT)
 HB_OT_ACCELERATOR (OT, sbix)

+ 1 - 0
thirdparty/harfbuzz/src/hb-ot-face.cc

@@ -36,6 +36,7 @@
 #include "hb-ot-name-table.hh"
 #include "hb-ot-post-table.hh"
 #include "OT/Color/CBDT/CBDT.hh"
+#include "OT/Color/COLR/COLR.hh"
 #include "OT/Color/sbix/sbix.hh"
 #include "OT/Color/svg/svg.hh"
 #include "hb-ot-layout-gdef-table.hh"

+ 155 - 240
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -34,11 +34,7 @@
 #include "hb-font.hh"
 #include "hb-machinery.hh"
 #include "hb-ot-face.hh"
-#include "hb-outline.hh"
 
-#ifndef HB_NO_AAT
-#include "hb-aat-layout-trak-table.hh"
-#endif
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
 #include "hb-ot-cff2-table.hh"
@@ -65,28 +61,111 @@
  * never need to call these functions directly.
  **/
 
-using hb_ot_font_cmap_cache_t    = hb_cache_t<21, 16, 8, true>;
-using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
-
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
-#endif
+using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>;
+static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, "");
 
 struct hb_ot_font_t
 {
   const hb_ot_face_t *ot_face;
 
-#ifndef HB_NO_AAT
-  bool apply_trak;
-#endif
+  /* h_advance caching */
+  mutable hb_atomic_t<int> cached_coords_serial;
+  struct advance_cache_t
+  {
+    mutable hb_atomic_t<hb_ot_font_advance_cache_t *> advance_cache;
+    mutable hb_atomic_t<OT::ItemVariationStore::cache_t *> varStore_cache;
 
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-  hb_ot_font_cmap_cache_t *cmap_cache;
-#endif
+    ~advance_cache_t ()
+    {
+      clear ();
+    }
 
-  /* h_advance caching */
-  mutable hb_atomic_int_t cached_coords_serial;
-  mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
+    hb_ot_font_advance_cache_t *acquire_advance_cache () const
+    {
+    retry:
+      auto *cache = advance_cache.get_acquire ();
+      if (!cache)
+      {
+        cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
+	if (!cache)
+	  return nullptr;
+	new (cache) hb_ot_font_advance_cache_t;
+	return cache;
+      }
+      if (advance_cache.cmpexch (cache, nullptr))
+        return cache;
+      else
+        goto retry;
+    }
+    void release_advance_cache (hb_ot_font_advance_cache_t *cache) const
+    {
+      if (!cache)
+        return;
+      if (!advance_cache.cmpexch (nullptr, cache))
+        hb_free (cache);
+    }
+    void clear_advance_cache () const
+    {
+    retry:
+      auto *cache = advance_cache.get_acquire ();
+      if (!cache)
+	return;
+      if (advance_cache.cmpexch (cache, nullptr))
+	hb_free (cache);
+      else
+        goto retry;
+    }
+
+    OT::ItemVariationStore::cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
+    {
+    retry:
+      auto *cache = varStore_cache.get_acquire ();
+      if (!cache)
+	return varStore.create_cache ();
+      if (varStore_cache.cmpexch (cache, nullptr))
+	return cache;
+      else
+	goto retry;
+    }
+    void release_varStore_cache (OT::ItemVariationStore::cache_t *cache) const
+    {
+      if (!cache)
+	return;
+      if (!varStore_cache.cmpexch (nullptr, cache))
+	OT::ItemVariationStore::destroy_cache (cache);
+    }
+    void clear_varStore_cache () const
+    {
+    retry:
+      auto *cache = varStore_cache.get_acquire ();
+      if (!cache)
+	return;
+      if (varStore_cache.cmpexch (cache, nullptr))
+	OT::ItemVariationStore::destroy_cache (cache);
+      else
+	goto retry;
+    }
+
+    void clear () const
+    {
+      clear_advance_cache ();
+      clear_varStore_cache ();
+    }
+
+  } h, v;
+
+  void check_serial (hb_font_t *font) const
+  {
+    int font_serial = font->serial_coords.get_acquire ();
+
+    if (cached_coords_serial.get_acquire () == font_serial)
+      return;
+
+    h.clear ();
+    v.clear ();
+
+    cached_coords_serial.set_release (font_serial);
+  }
 };
 
 static hb_ot_font_t *
@@ -98,44 +177,6 @@ _hb_ot_font_create (hb_font_t *font)
 
   ot_font->ot_face = &font->face->table;
 
-#ifndef HB_NO_AAT
-  /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
-#ifndef HB_NO_STYLE
-  ot_font->apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data ();
-#else
-  ot_font->apply_trak = false;
-#endif
-#endif
-
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-  // retry:
-  auto *cmap_cache  = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
-									 &hb_ot_font_cmap_cache_user_data_key);
-  if (!cmap_cache)
-  {
-    cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
-    if (unlikely (!cmap_cache)) goto out;
-    new (cmap_cache) hb_ot_font_cmap_cache_t ();
-    if (unlikely (!hb_face_set_user_data (font->face,
-					  &hb_ot_font_cmap_cache_user_data_key,
-					  cmap_cache,
-					  hb_free,
-					  false)))
-    {
-      hb_free (cmap_cache);
-      cmap_cache = nullptr;
-      /* Normally we would retry here, but that would
-       * infinite-loop if the face is the empty-face.
-       * Just let it go and this font will be uncached if it
-       * happened to collide with another thread creating the
-       * cache at the same time. */
-      // goto retry;
-    }
-  }
-  out:
-  ot_font->cmap_cache = cmap_cache;
-#endif
-
   return ot_font;
 }
 
@@ -144,8 +185,7 @@ _hb_ot_font_destroy (void *font_data)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data;
 
-  auto *cache = ot_font->advance_cache.get_relaxed ();
-  hb_free (cache);
+  ot_font->~hb_ot_font_t ();
 
   hb_free (ot_font);
 }
@@ -159,11 +199,7 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
-  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-  cmap_cache = ot_font->cmap_cache;
-#endif
-  return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache);
+  return ot_face->cmap->get_nominal_glyph (unicode, glyph);
 }
 
 static unsigned int
@@ -178,14 +214,9 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
-  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-  cmap_cache = ot_font->cmap_cache;
-#endif
   return ot_face->cmap->get_nominal_glyphs (count,
 					    first_unicode, unicode_stride,
-					    first_glyph, glyph_stride,
-					    cmap_cache);
+					    first_glyph, glyph_stride);
 }
 
 static hb_bool_t
@@ -198,13 +229,8 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
-  hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
-#ifndef HB_NO_OT_FONT_CMAP_CACHE
-  cmap_cache = ot_font->cmap_cache;
-#endif
   return ot_face->cmap->get_variation_glyph (unicode,
-                                             variation_selector, glyph,
-                                             cmap_cache);
+                                             variation_selector, glyph);
 }
 
 static void
@@ -216,47 +242,25 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
 			    unsigned advance_stride,
 			    void *user_data HB_UNUSED)
 {
+
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
-  hb_position_t *orig_first_advance = first_advance;
-
-#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+  ot_font->check_serial (font);
   const OT::HVAR &HVAR = *hmtx.var_table;
   const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
-  OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+  OT::ItemVariationStore::cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore);
 
-  bool use_cache = font->num_coords;
-#else
-  OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
-  bool use_cache = false;
-#endif
+  hb_ot_font_advance_cache_t *advance_cache = nullptr;
 
-  hb_ot_font_advance_cache_t *cache = nullptr;
+  bool use_cache = font->num_coords;
   if (use_cache)
   {
-  retry:
-    cache = ot_font->advance_cache.get_acquire ();
-    if (unlikely (!cache))
-    {
-      cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
-      if (unlikely (!cache))
-      {
-	use_cache = false;
-	goto out;
-      }
-      new (cache) hb_ot_font_advance_cache_t;
-
-      if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
-      {
-	hb_free (cache);
-	goto retry;
-      }
-      ot_font->cached_coords_serial.set_release (font->serial_coords);
-    }
+    advance_cache = ot_font->h.acquire_advance_cache ();
+    if (!advance_cache)
+      use_cache = false;
   }
-  out:
 
   if (!use_cache)
   {
@@ -269,58 +273,26 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   }
   else
   { /* Use cache. */
-    if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
-    {
-      ot_font->advance_cache->clear ();
-      ot_font->cached_coords_serial.set_release (font->serial_coords);
-    }
-
     for (unsigned int i = 0; i < count; i++)
     {
       hb_position_t v;
       unsigned cv;
-      if (ot_font->advance_cache->get (*first_glyph, &cv))
+      if (advance_cache->get (*first_glyph, &cv))
 	v = cv;
       else
       {
         v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
-	ot_font->advance_cache->set (*first_glyph, v);
+	advance_cache->set (*first_glyph, v);
       }
       *first_advance = font->em_scale_x (v);
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
-  }
-
-#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
-  OT::ItemVariationStore::destroy_cache (varStore_cache);
-#endif
 
-  if (font->x_strength && !font->embolden_in_place)
-  {
-    /* Emboldening. */
-    hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += *first_advance ? x_strength : 0;
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
+    ot_font->h.release_advance_cache (advance_cache);
   }
 
-#ifndef HB_NO_AAT
-  if (ot_font->apply_trak)
-  {
-    hb_position_t tracking = font->face->table.trak->get_h_tracking (font);
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += tracking;
-      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
-  }
-#endif
+  ot_font->h.release_varStore_cache (varStore_cache);
 }
 
 #ifndef HB_NO_VERTICAL
@@ -337,17 +309,13 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
   const hb_ot_face_t *ot_face = ot_font->ot_face;
   const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
 
-  hb_position_t *orig_first_advance = first_advance;
-
   if (vmtx.has_data ())
   {
-#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+    ot_font->check_serial (font);
     const OT::VVAR &VVAR = *vmtx.var_table;
     const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
-    OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
-#else
-    OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
-#endif
+    OT::ItemVariationStore::cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore);
+    // TODO Use advance_cache.
 
     for (unsigned int i = 0; i < count; i++)
     {
@@ -356,9 +324,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
 
-#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
-    OT::ItemVariationStore::destroy_cache (varStore_cache);
-#endif
+    ot_font->v.release_varStore_cache (varStore_cache);
   }
   else
   {
@@ -373,32 +339,6 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
   }
-
-  if (font->y_strength && !font->embolden_in_place)
-  {
-    /* Emboldening. */
-    hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += *first_advance ? y_strength : 0;
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
-  }
-
-#ifndef HB_NO_AAT
-  if (ot_font->apply_trak)
-  {
-    hb_position_t tracking = font->face->table.trak->get_v_tracking (font);
-    first_advance = orig_first_advance;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      *first_advance += tracking;
-      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
-    }
-  }
-#endif
 }
 #endif
 
@@ -435,7 +375,8 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
   }
 
   hb_glyph_extents_t extents = {0};
-  if (ot_face->glyf->get_extents (font, glyph, &extents))
+
+  if (hb_font_get_glyph_extents (font, glyph, &extents))
   {
     const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
     int tsb = 0;
@@ -448,7 +389,7 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
     hb_font_extents_t font_extents;
     font->get_h_extents_with_fallback (&font_extents);
     hb_position_t advance = font_extents.ascender - font_extents.descender;
-    int diff = advance - -extents.height;
+    hb_position_t diff = advance - -extents.height;
     *y = extents.y_bearing + (diff >> 1);
     return true;
   }
@@ -477,6 +418,9 @@ hb_ot_get_glyph_extents (hb_font_t *font,
 #endif
 #if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
   if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
+#endif
+#ifndef HB_NO_VAR_COMPOSITES
+  if (ot_face->VARC->get_extents (font, glyph, extents)) return true;
 #endif
   if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
 #ifndef HB_NO_OT_FONT_CFF
@@ -528,16 +472,9 @@ hb_ot_get_font_h_extents (hb_font_t *font,
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
-  bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
-	     _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
-	     _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
-
-  /* Embolden */
-  int y_shift = font->y_strength;
-  if (font->y_scale < 0) y_shift = -y_shift;
-  metrics->ascender += y_shift;
-
-  return ret;
+  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
 }
 
 #ifndef HB_NO_VERTICAL
@@ -554,68 +491,46 @@ hb_ot_get_font_v_extents (hb_font_t *font,
 #endif
 
 #ifndef HB_NO_DRAW
-static void
-hb_ot_draw_glyph (hb_font_t *font,
-		  void *font_data HB_UNUSED,
-		  hb_codepoint_t glyph,
-		  hb_draw_funcs_t *draw_funcs, void *draw_data,
-		  void *user_data)
+static hb_bool_t
+hb_ot_draw_glyph_or_fail (hb_font_t *font,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t glyph,
+			  hb_draw_funcs_t *draw_funcs, void *draw_data,
+			  void *user_data)
 {
-  bool embolden = font->x_strength || font->y_strength;
-  hb_outline_t outline;
-
-  { // 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);
+  hb_draw_session_t draw_session {draw_funcs, draw_data};
 #ifndef HB_NO_VAR_COMPOSITES
-    if (!font->face->table.VARC->get_path (font, glyph, draw_session))
+  if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true;
 #endif
-    // Keep the following in synch with VARC::get_path_at()
-    if (!font->face->table.glyf->get_path (font, glyph, draw_session))
+  // Keep the following in synch with VARC::get_path_at()
+  if (font->face->table.glyf->get_path (font, glyph, draw_session)) return true;
 #ifndef HB_NO_CFF
-    if (!font->face->table.cff2->get_path (font, glyph, draw_session))
-    if (!font->face->table.cff1->get_path (font, glyph, draw_session))
+  if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true;
+  if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true;
 #endif
-    {}
-  }
-
-  if (embolden)
-  {
-    float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2;
-    float y_shift = (float) font->y_strength / 2;
-    if (font->x_scale < 0) x_shift = -x_shift;
-    if (font->y_scale < 0) y_shift = -y_shift;
-    outline.embolden (font->x_strength, font->y_strength,
-		      x_shift, y_shift);
-
-    outline.replay (draw_funcs, draw_data);
-  }
+  return false;
 }
 #endif
 
 #ifndef HB_NO_PAINT
-static void
-hb_ot_paint_glyph (hb_font_t *font,
-                   void *font_data,
-                   hb_codepoint_t glyph,
-                   hb_paint_funcs_t *paint_funcs, void *paint_data,
-                   unsigned int palette,
-                   hb_color_t foreground,
-                   void *user_data)
+static hb_bool_t
+hb_ot_paint_glyph_or_fail (hb_font_t *font,
+			   void *font_data,
+			   hb_codepoint_t glyph,
+			   hb_paint_funcs_t *paint_funcs, void *paint_data,
+			   unsigned int palette,
+			   hb_color_t foreground,
+			   void *user_data)
 {
 #ifndef HB_NO_COLOR
-  if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return;
-  if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
+  if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true;
+  if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
 #ifndef HB_NO_OT_FONT_BITMAP
-  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;
+  if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
+  if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
 #endif
 #endif
-
-  // Outline glyph
-  paint_funcs->push_clip_glyph (paint_data, glyph, font);
-  paint_funcs->color (paint_data, true, foreground);
-  paint_funcs->pop_clip (paint_data);
+  return false;
 }
 #endif
 
@@ -642,11 +557,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
 #endif
 
 #ifndef HB_NO_DRAW
-    hb_font_funcs_set_draw_glyph_func (funcs, hb_ot_draw_glyph, nullptr, nullptr);
+    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ot_draw_glyph_or_fail, nullptr, nullptr);
 #endif
 
 #ifndef HB_NO_PAINT
-    hb_font_funcs_set_paint_glyph_func (funcs, hb_ot_paint_glyph, nullptr, nullptr);
+    hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ot_paint_glyph_or_fail, nullptr, nullptr);
 #endif
 
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);

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

@@ -359,7 +359,13 @@ struct hmtxvmtx
 	return true;
       }
 
-      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
+      // If there's no vmtx data, the phantom points from glyf table are not accurate,
+      // so we cannot take the next path.
+      bool is_vertical = T::tableTag == HB_OT_TAG_vmtx;
+      if (is_vertical && !has_data ())
+        return false;
+
+      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
 #else
       return false;
 #endif

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

@@ -27,6 +27,7 @@
 #ifndef HB_OT_KERN_TABLE_HH
 #define HB_OT_KERN_TABLE_HH
 
+#include "hb-aat-layout-common.hh"
 #include "hb-aat-layout-kerx-table.hh"
 
 
@@ -400,6 +401,7 @@ struct kern
 
     hb_blob_ptr_t<kern> table;
     AAT::kern_accelerator_data_t accel_data;
+    AAT::hb_aat_scratch_t scratch;
   };
 
   protected:

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

@@ -182,7 +182,7 @@ struct BaseCoord
   void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
   {
     switch (u.format) {
-    case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set);
+    case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); return;
     default:return;
     }
   }

+ 31 - 24
thirdparty/harfbuzz/src/hb-ot-layout-common.hh

@@ -1850,7 +1850,7 @@ struct ClassDefFormat2_4
     hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
     hb_set_t orig_klasses;
 
-    if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
+    if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len)
 	< get_population ())
     {
       for (hb_codepoint_t g : glyph_set)
@@ -1931,7 +1931,7 @@ struct ClassDefFormat2_4
 
   bool intersects (const hb_set_t *glyphs) const
   {
-    if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
+    if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
     {
       for (auto g : *glyphs)
         if (get_class (g))
@@ -2000,7 +2000,7 @@ struct ClassDefFormat2_4
     }
 
     unsigned count = rangeRecord.len;
-    if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
+    if (count > glyphs->get_population () * hb_bit_storage (count))
     {
       for (auto g : *glyphs)
       {
@@ -2548,11 +2548,13 @@ struct SparseVarRegionAxis
   DEFINE_SIZE_STATIC (8);
 };
 
-#define REGION_CACHE_ITEM_CACHE_INVALID 2.f
+#define REGION_CACHE_ITEM_CACHE_INVALID INT_MIN
+#define REGION_CACHE_ITEM_MULTIPLIER (float (1 << ((sizeof (int) * 8) - 2)))
+#define REGION_CACHE_ITEM_DIVISOR (1.f / float (1 << ((sizeof (int) * 8) - 2)))
 
 struct VarRegionList
 {
-  using cache_t = float;
+  using cache_t = hb_atomic_t<int>;
 
   float evaluate (unsigned int region_index,
 		  const int *coords, unsigned int coord_len,
@@ -2561,12 +2563,12 @@ struct VarRegionList
     if (unlikely (region_index >= regionCount))
       return 0.;
 
-    float *cached_value = nullptr;
+    cache_t *cached_value = nullptr;
     if (cache)
     {
       cached_value = &(cache[region_index]);
-      if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
-	return *cached_value;
+      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
+	return *cached_value * REGION_CACHE_ITEM_DIVISOR;
     }
 
     const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
@@ -2587,7 +2589,7 @@ struct VarRegionList
     }
 
     if (cache)
-      *cached_value = v;
+      *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER;
     return v;
   }
 
@@ -2730,7 +2732,7 @@ struct SparseVariationRegion : Array16Of<SparseVarRegionAxis>
 
 struct SparseVarRegionList
 {
-  using cache_t = float;
+  using cache_t = hb_atomic_t<int>;
 
   float evaluate (unsigned int region_index,
 		  const int *coords, unsigned int coord_len,
@@ -2739,12 +2741,12 @@ struct SparseVarRegionList
     if (unlikely (region_index >= regions.len))
       return 0.;
 
-    float *cached_value = nullptr;
+    cache_t *cached_value = nullptr;
     if (cache)
     {
       cached_value = &(cache[region_index]);
-      if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
-	return *cached_value;
+      if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)
+	return *cached_value * REGION_CACHE_ITEM_DIVISOR;
     }
 
     const SparseVariationRegion &region = this+regions[region_index];
@@ -2752,7 +2754,7 @@ struct SparseVarRegionList
     float v = region.evaluate (coords, coord_len);
 
     if (cache)
-      *cached_value = v;
+      *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER;
     return v;
   }
 
@@ -2861,8 +2863,13 @@ struct VarData
                   const hb_vector_t<const hb_vector_t<int>*>& rows)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
     unsigned row_count = rows.length;
+    if (!row_count) {
+      // Nothing to serialize, will be empty.
+      return false;
+    }
+
+    if (unlikely (!c->extend_min (this))) return_trace (false);    
     itemCount = row_count;
 
     int min_threshold = has_long ? -65536 : -128;
@@ -3187,10 +3194,10 @@ struct ItemVariationStore
 #ifdef HB_NO_VAR
     return nullptr;
 #endif
-    auto &r = this+regions;
-    unsigned count = r.regionCount;
+    unsigned count = (this+regions).regionCount;
+    if (!count) return nullptr;
 
-    float *cache = (float *) hb_malloc (sizeof (float) * count);
+    cache_t *cache = (cache_t *) hb_malloc (sizeof (float) * count);
     if (unlikely (!cache)) return nullptr;
 
     for (unsigned i = 0; i < count; i++)
@@ -3440,7 +3447,7 @@ struct MultiItemVariationStore
 {
   using cache_t = SparseVarRegionList::cache_t;
 
-  cache_t *create_cache (hb_array_t<float> static_cache = hb_array_t<float> ()) const
+  cache_t *create_cache (hb_array_t<cache_t> static_cache = hb_array_t<cache_t> ()) const
   {
 #ifdef HB_NO_VAR
     return nullptr;
@@ -3448,12 +3455,12 @@ struct MultiItemVariationStore
     auto &r = this+regions;
     unsigned count = r.regions.len;
 
-    float *cache;
+    cache_t *cache;
     if (count <= static_cache.length)
       cache = static_cache.arrayZ;
     else
     {
-      cache = (float *) hb_malloc (sizeof (float) * count);
+      cache = (cache_t *) hb_malloc (sizeof (float) * count);
       if (unlikely (!cache)) return nullptr;
     }
 
@@ -3464,7 +3471,7 @@ struct MultiItemVariationStore
   }
 
   static void destroy_cache (cache_t *cache,
-			     hb_array_t<float> static_cache = hb_array_t<float> ())
+			     hb_array_t<cache_t> static_cache = hb_array_t<cache_t> ())
   {
     if (cache != static_cache.arrayZ)
       hb_free (cache);
@@ -4777,12 +4784,12 @@ struct VariationDevice
   hb_position_t get_x_delta (hb_font_t *font,
 			     const ItemVariationStore &store,
 			     ItemVariationStore::cache_t *store_cache = nullptr) const
-  { return font->em_scalef_x (get_delta (font, store, store_cache)); }
+  { return !font->num_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); }
 
   hb_position_t get_y_delta (hb_font_t *font,
 			     const ItemVariationStore &store,
 			     ItemVariationStore::cache_t *store_cache = nullptr) const
-  { return font->em_scalef_y (get_delta (font, store, store_cache)); }
+  { return !font->num_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); }
 
   VariationDevice* copy (hb_serialize_context_t *c,
                          const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const

+ 218 - 245
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh

@@ -397,292 +397,277 @@ struct hb_collect_coverage_context_t :
   set_t *set;
 };
 
-struct hb_ot_apply_context_t :
-       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
+struct matcher_t
 {
-  struct matcher_t
-  {
-    typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
-
-    void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
-    void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
-    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_; }
-    void set_syllable (uint8_t syllable_)  { syllable = per_syllable ? syllable_ : 0; }
-    void set_match_func (match_func_t match_func_,
-			 const void *match_data_)
-    { match_func = match_func_; match_data = match_data_; }
-
-    enum may_match_t {
-      MATCH_NO,
-      MATCH_YES,
-      MATCH_MAYBE
-    };
+  typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
+
+  template <typename context_t>
+  void init (const context_t *c, bool context_match = false)
+  {
+    set_match_func (nullptr, nullptr);
+    lookup_props = c->lookup_props;
+    /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
+    ignore_zwnj = c->table_index == 1 || (context_match && c->auto_zwnj);
+    /* Ignore ZWJ if we are matching context, or asked to. */
+    ignore_zwj = context_match || c->auto_zwj;
+    /* Ignore hidden glyphs (like CGJ) during GPOS. */
+    ignore_hidden = c->table_index == 1;
+    mask = context_match ? -1 : c->lookup_mask;
+    /* Per syllable matching is only for GSUB. */
+    per_syllable = c->table_index == 0 && c->per_syllable;
+    syllable = 0;
+  }
+
+  void set_match_func (match_func_t match_func_,
+		       const void *match_data_)
+  { match_func = match_func_; match_data = match_data_; }
+
+  enum may_match_t {
+    MATCH_NO,
+    MATCH_YES,
+    MATCH_MAYBE
+  };
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_match_t may_match (hb_glyph_info_t &info,
-			   hb_codepoint_t glyph_data) const
-    {
-      if (!(info.mask & mask) ||
-	  (syllable && syllable != info.syllable ()))
-	return MATCH_NO;
+  may_match_t may_match (hb_glyph_info_t &info,
+			 hb_codepoint_t glyph_data) const
+  {
+    if (!(info.mask & mask) ||
+	(per_syllable && syllable && syllable != info.syllable ()))
+      return MATCH_NO;
 
-      if (match_func)
-	return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+    if (match_func)
+      return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
 
-      return MATCH_MAYBE;
-    }
+    return MATCH_MAYBE;
+  }
 
-    enum may_skip_t {
-      SKIP_NO,
-      SKIP_YES,
-      SKIP_MAYBE
-    };
+  enum may_skip_t {
+    SKIP_NO,
+    SKIP_YES,
+    SKIP_MAYBE
+  };
 
+  template <typename context_t>
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_skip_t may_skip (const hb_ot_apply_context_t *c,
-			 const hb_glyph_info_t       &info) const
-    {
-      if (!c->check_glyph_property (&info, lookup_props))
-	return SKIP_YES;
+  may_skip_t may_skip (const context_t *c,
+		       const hb_glyph_info_t       &info) const
+  {
+    if (!c->check_glyph_property (&info, lookup_props))
+      return SKIP_YES;
 
-      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_hidden || !_hb_glyph_info_is_hidden (&info))))
-	return SKIP_MAYBE;
+    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_hidden || !_hb_glyph_info_is_hidden (&info))))
+      return SKIP_MAYBE;
 
-      return SKIP_NO;
-    }
+    return SKIP_NO;
+  }
 
-    protected:
-    unsigned int lookup_props = 0;
-    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;
-    const void *match_data = nullptr;
-  };
+  public:
+  unsigned int lookup_props = 0;
+  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;
+  const void *match_data = nullptr;
+};
 
-  struct skipping_iterator_t
+template <typename context_t>
+struct skipping_iterator_t
+{
+  void init (context_t *c_, bool context_match = false)
   {
-    void init (hb_ot_apply_context_t *c_, bool context_match = false)
-    {
-      c = c_;
-      end = c->buffer->len;
-      match_glyph_data16 = nullptr;
+    c = c_;
+    end = c->buffer->len;
+    match_glyph_data16 = nullptr;
 #ifndef HB_NO_BEYOND_64K
-      match_glyph_data24 = nullptr;
+    match_glyph_data24 = nullptr;
 #endif
-      matcher.set_match_func (nullptr, nullptr);
-      matcher.set_lookup_props (c->lookup_props);
-      /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
-      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);
-      matcher.set_syllable (0);
-    }
-    void set_lookup_props (unsigned int lookup_props)
-    {
-      matcher.set_lookup_props (lookup_props);
-    }
-    void set_match_func (matcher_t::match_func_t match_func_,
-			 const void *match_data_)
-    {
-      matcher.set_match_func (match_func_, match_data_);
-    }
-    void set_glyph_data (const HBUINT16 glyph_data[])
-    {
-      match_glyph_data16 = glyph_data;
+    matcher.init (c, context_match);
+  }
+  void set_lookup_props (unsigned int lookup_props)
+  {
+    matcher.lookup_props = lookup_props;
+  }
+  void set_match_func (matcher_t::match_func_t match_func_,
+		       const void *match_data_)
+  {
+    matcher.set_match_func (match_func_, match_data_);
+  }
+  void set_glyph_data (const HBUINT16 glyph_data[])
+  {
+    match_glyph_data16 = glyph_data;
 #ifndef HB_NO_BEYOND_64K
-      match_glyph_data24 = nullptr;
+    match_glyph_data24 = nullptr;
 #endif
-    }
+  }
 #ifndef HB_NO_BEYOND_64K
-    void set_glyph_data (const HBUINT24 glyph_data[])
-    {
-      match_glyph_data16 = nullptr;
-      match_glyph_data24 = glyph_data;
-    }
+  void set_glyph_data (const HBUINT24 glyph_data[])
+  {
+    match_glyph_data16 = nullptr;
+    match_glyph_data24 = glyph_data;
+  }
 #endif
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    void reset (unsigned int start_index_)
-    {
-      idx = start_index_;
-      end = c->buffer->len;
-      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
-    }
+  void reset (unsigned int start_index_)
+  {
+    idx = start_index_;
+    end = c->buffer->len;
+    matcher.syllable = start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0;
+  }
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    void reset_fast (unsigned int start_index_)
-    {
-      // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
-      idx = start_index_;
-    }
-
-    void reject ()
-    {
-      backup_glyph_data ();
-    }
+  void reset_fast (unsigned int start_index_)
+  {
+    // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
+    idx = start_index_;
+  }
 
-    matcher_t::may_skip_t
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    may_skip (const hb_glyph_info_t &info) const
-    { return matcher.may_skip (c, info); }
+  matcher_t::may_skip_t may_skip (const hb_glyph_info_t &info) const
+  { return matcher.may_skip (c, info); }
 
-    enum match_t {
-      MATCH,
-      NOT_MATCH,
-      SKIP
-    };
+  enum match_t {
+    MATCH,
+    NOT_MATCH,
+    SKIP
+  };
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    match_t match (hb_glyph_info_t &info)
-    {
-      matcher_t::may_skip_t skip = matcher.may_skip (c, info);
-      if (unlikely (skip == matcher_t::SKIP_YES))
-	return SKIP;
+  match_t match (hb_glyph_info_t &info)
+  {
+    matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+    if (unlikely (skip == matcher_t::SKIP_YES))
+      return SKIP;
 
-      matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
-      if (match == matcher_t::MATCH_YES ||
-	  (match == matcher_t::MATCH_MAYBE &&
-	   skip == matcher_t::SKIP_NO))
-	return MATCH;
+    matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
+    if (match == matcher_t::MATCH_YES ||
+	(match == matcher_t::MATCH_MAYBE &&
+	 skip == matcher_t::SKIP_NO))
+      return MATCH;
 
-      if (skip == matcher_t::SKIP_NO)
-        return NOT_MATCH;
+    if (skip == matcher_t::SKIP_NO)
+      return NOT_MATCH;
 
-      return SKIP;
+    return SKIP;
   }
 
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    bool next (unsigned *unsafe_to = nullptr)
+  bool next (unsigned *unsafe_to = nullptr)
+  {
+    const signed stop = (signed) end - 1;
+    while ((signed) idx < stop)
     {
-      const signed stop = (signed) end - 1;
-      while ((signed) idx < stop)
+      idx++;
+      switch (match (c->buffer->info[idx]))
       {
-	idx++;
-	switch (match (c->buffer->info[idx]))
+	case MATCH:
 	{
-	  case MATCH:
-	  {
-	    advance_glyph_data ();
-	    return true;
-	  }
-	  case NOT_MATCH:
-	  {
-	    if (unsafe_to)
-	      *unsafe_to = idx + 1;
-	    return false;
-	  }
-	  case SKIP:
-	    continue;
+	  advance_glyph_data ();
+	  return true;
+	}
+	case NOT_MATCH:
+	{
+	  if (unsafe_to)
+	    *unsafe_to = idx + 1;
+	  return false;
 	}
+	case SKIP:
+	  continue;
       }
-      if (unsafe_to)
-        *unsafe_to = end;
-      return false;
     }
+    if (unsafe_to)
+      *unsafe_to = end;
+    return false;
+  }
 #ifndef HB_OPTIMIZE_SIZE
-    HB_ALWAYS_INLINE
+  HB_ALWAYS_INLINE
 #endif
-    bool prev (unsigned *unsafe_from = nullptr)
+  bool prev (unsigned *unsafe_from = nullptr)
+  {
+    const unsigned stop = 0;
+    while (idx > stop)
     {
-      const unsigned stop = 0;
-      while (idx > stop)
+      idx--;
+      switch (match (c->buffer->out_info[idx]))
       {
-	idx--;
-	switch (match (c->buffer->out_info[idx]))
+	case MATCH:
 	{
-	  case MATCH:
-	  {
-	    advance_glyph_data ();
-	    return true;
-	  }
-	  case NOT_MATCH:
-	  {
-	    if (unsafe_from)
-	      *unsafe_from = hb_max (1u, idx) - 1u;
-	    return false;
-	  }
-	  case SKIP:
-	    continue;
+	  advance_glyph_data ();
+	  return true;
+	}
+	case NOT_MATCH:
+	{
+	  if (unsafe_from)
+	    *unsafe_from = hb_max (1u, idx) - 1u;
+	  return false;
 	}
+	case SKIP:
+	  continue;
       }
-      if (unsafe_from)
-        *unsafe_from = 0;
-      return false;
     }
+    if (unsafe_from)
+      *unsafe_from = 0;
+    return false;
+  }
 
-    HB_ALWAYS_INLINE
-    hb_codepoint_t
-    get_glyph_data ()
-    {
-      if (match_glyph_data16) return *match_glyph_data16;
-#ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) return *match_glyph_data24;
-#endif
-      return 0;
-    }
-    HB_ALWAYS_INLINE
-    void
-    advance_glyph_data ()
-    {
-      if (match_glyph_data16) match_glyph_data16++;
+  HB_ALWAYS_INLINE
+  hb_codepoint_t
+  get_glyph_data ()
+  {
+    if (match_glyph_data16) return *match_glyph_data16;
 #ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) match_glyph_data24++;
+    else
+    if (match_glyph_data24) return *match_glyph_data24;
 #endif
-    }
-    void
-    backup_glyph_data ()
-    {
-      if (match_glyph_data16) match_glyph_data16--;
+    return 0;
+  }
+  HB_ALWAYS_INLINE
+  void
+  advance_glyph_data ()
+  {
+    if (match_glyph_data16) match_glyph_data16++;
 #ifndef HB_NO_BEYOND_64K
-      else
-      if (match_glyph_data24) match_glyph_data24--;
+    else
+    if (match_glyph_data24) match_glyph_data24++;
 #endif
-    }
+  }
 
-    unsigned int idx;
-    protected:
-    hb_ot_apply_context_t *c;
-    matcher_t matcher;
-    const HBUINT16 *match_glyph_data16;
+  unsigned int idx;
+  protected:
+  context_t *c;
+  matcher_t matcher;
+  const HBUINT16 *match_glyph_data16;
 #ifndef HB_NO_BEYOND_64K
-    const HBUINT24 *match_glyph_data24;
+  const HBUINT24 *match_glyph_data24;
 #endif
 
-    unsigned int end;
-  };
-
+  unsigned int end;
+};
 
+struct hb_ot_apply_context_t :
+       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
+{
   const char *get_name () { return "APPLY"; }
   typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
@@ -703,7 +688,7 @@ struct hb_ot_apply_context_t :
     return ret;
   }
 
-  skipping_iterator_t iter_input, iter_context;
+  skipping_iterator_t<hb_ot_apply_context_t> iter_input, iter_context;
 
   unsigned int table_index; /* GSUB/GPOS */
   hb_font_t *font;
@@ -737,7 +722,8 @@ struct hb_ot_apply_context_t :
   hb_ot_apply_context_t (unsigned int table_index_,
 			 hb_font_t *font_,
 			 hb_buffer_t *buffer_,
-			 hb_blob_t *table_blob_) :
+			 hb_blob_t *table_blob_,
+			 ItemVariationStore::cache_t *var_store_cache_ = nullptr) :
 			table_index (table_index_),
 			font (font_), face (font->face), buffer (buffer_),
 			sanitizer (table_blob_),
@@ -756,13 +742,7 @@ struct hb_ot_apply_context_t :
 #endif
 			     ),
 			var_store (gdef.get_var_store ()),
-			var_store_cache (
-#ifndef HB_NO_VAR
-					 table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr
-#else
-					 nullptr
-#endif
-					),
+			var_store_cache (var_store_cache_),
 			direction (buffer_->props.direction),
 			has_glyph_classes (gdef.has_glyph_classes ())
   {
@@ -770,13 +750,6 @@ struct hb_ot_apply_context_t :
     buffer->collect_codepoints (digest);
   }
 
-  ~hb_ot_apply_context_t ()
-  {
-#ifndef HB_NO_VAR
-    ItemVariationStore::destroy_cache (var_store_cache);
-#endif
-  }
-
   void init_iters ()
   {
     iter_input.init (this, false);
@@ -1282,7 +1255,7 @@ static bool match_input (hb_ot_apply_context_t *c,
 
   hb_buffer_t *buffer = c->buffer;
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+  auto &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx);
   skippy_iter.set_match_func (match_func, match_data);
   skippy_iter.set_glyph_data (input);
@@ -1361,7 +1334,7 @@ static bool match_input (hb_ot_apply_context_t *c,
 	    j--;
 	  }
 
-	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
+	  if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES)
 	    ligbase = LIGBASE_MAY_SKIP;
 	  else
 	    ligbase = LIGBASE_MAY_NOT_SKIP;
@@ -1524,7 +1497,7 @@ static bool match_backtrack (hb_ot_apply_context_t *c,
 {
   TRACE_APPLY (nullptr);
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  auto &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len ());
   skippy_iter.set_match_func (match_func, match_data);
   skippy_iter.set_glyph_data (backtrack);
@@ -1557,7 +1530,7 @@ static bool match_lookahead (hb_ot_apply_context_t *c,
 {
   TRACE_APPLY (nullptr);
 
-  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  auto &skippy_iter = c->iter_context;
   assert (start_index >= 1);
   skippy_iter.reset (start_index - 1);
   skippy_iter.set_match_func (match_func, match_data);
@@ -2221,7 +2194,7 @@ struct RuleSet
      *
      * Replicated from LigatureSet::apply(). */
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
@@ -3432,7 +3405,7 @@ struct ChainRuleSet
     if (!c->auto_zwnj || !c->auto_zwj)
       goto slow;
 
-    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    auto &skippy_iter = c->iter_input;
     skippy_iter.reset (c->buffer->idx);
     skippy_iter.set_match_func (match_always, nullptr);
     skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
@@ -4900,7 +4873,7 @@ struct GSUBGPOS
 
       this->lookup_count = table->get_lookup_count ();
 
-      this->accels = (hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *) hb_calloc (this->lookup_count, sizeof (*accels));
+      this->accels = (hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *) hb_calloc (this->lookup_count, sizeof (*accels));
       if (unlikely (!this->accels))
       {
 	this->lookup_count = 0;
@@ -4948,7 +4921,7 @@ struct GSUBGPOS
 
     hb_blob_ptr_t<T> table;
     unsigned int lookup_count;
-    hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *accels;
+    hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *accels;
   };
 
   protected:

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

@@ -131,13 +131,15 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
 		   hb_font_t *font,
 		   hb_buffer_t  *buffer)
 {
-  hb_blob_t *blob = font->face->table.kern.get_blob ();
-  const auto& kern = *font->face->table.kern;
+  auto &accel = *font->face->table.kern;
+  hb_blob_t *blob = accel.get_blob ();
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
   if (!buffer->message (font, "start table kern")) return;
-  kern.apply (&c);
+  c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
+  accel.apply (&c);
+  accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
   (void) buffer->message (font, "end table kern");
 }
 #endif
@@ -2013,7 +2015,11 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
 {
   const unsigned int table_index = proxy.table_index;
   unsigned int i = 0;
-  OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ());
+
+  auto *font_data = font->data.ot.get ();
+  auto *var_store_cache = font_data == HB_SHAPER_DATA_SUCCEEDED ? nullptr : (OT::ItemVariationStore::cache_t *) font_data;
+
+  OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob (), var_store_cache);
   c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);
 
   for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
@@ -2626,7 +2632,8 @@ struct hb_get_glyph_alternates_dispatch_t :
  * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
  *                    Alternate glyphs associated with the glyph id.
  *
- * Fetches alternates of a glyph from a given GSUB lookup index.
+ * Fetches alternates of a glyph from a given GSUB lookup index. Note that for one-to-one GSUB
+ * glyph substitutions, this function fetches the substituted glyph.
  *
  * Return value: Total number of alternates found in the specific lookup index for the given glyph id.
  *

+ 16 - 1
thirdparty/harfbuzz/src/hb-ot-layout.hh

@@ -202,7 +202,8 @@ enum hb_unicode_props_flags_t {
   /* If GEN_CAT=FORMAT, top byte masks: */
   UPROPS_MASK_Cf_ZWJ	= 0x0100u,
   UPROPS_MASK_Cf_ZWNJ	= 0x0200u,
-  UPROPS_MASK_Cf_VS	= 0x0400u
+  UPROPS_MASK_Cf_VS	= 0x0400u,
+  UPROPS_MASK_Cf_AAT_DELETED	= 0x0800u
 };
 HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 
@@ -386,6 +387,8 @@ _hb_grapheme_group_func (const hb_glyph_info_t& a HB_UNUSED,
 static inline void
 _hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer)
 {
+  // MONOTONE_GRAPHEMES was already applied and is taken care of by _hb_grapheme_group_func.
+  // So we just check for MONOTONE_CHARACTERS here.
   buffer->reverse_groups (_hb_grapheme_group_func,
 			  buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 }
@@ -418,6 +421,18 @@ _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
     return;
   info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
 }
+static inline bool
+_hb_glyph_info_is_aat_deleted (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_AAT_DELETED);
+}
+static inline void
+_hb_glyph_info_set_aat_deleted (hb_glyph_info_t *info)
+{
+  _hb_glyph_info_set_general_category (info, HB_UNICODE_GENERAL_CATEGORY_FORMAT);
+  info->unicode_props() |= UPROPS_MASK_Cf_AAT_DELETED;
+  info->unicode_props() |= UPROPS_MASK_HIDDEN;
+}
 
 /* lig_props: aka lig_id / lig_comp
  *

+ 18 - 0
thirdparty/harfbuzz/src/hb-ot-math-table.hh

@@ -1104,6 +1104,24 @@ struct MATH
 		  mathVariants.sanitize (c, this));
   }
 
+  // https://github.com/harfbuzz/harfbuzz/issues/4653
+  HB_INTERNAL bool is_bad_cambria (hb_font_t *font) const
+  {
+#ifndef HB_NO_MATH
+    switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length,
+                                 get_constant (HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT, font),
+                                 get_constant (HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT, font))
+    {
+      /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5  cambria.ttc
+       * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9  cambria.ttc
+       * sha1sum:b1e5a3feaca2ea3dfcf79ccb377de749ecf60343  cambria.ttc */
+      case HB_CODEPOINT_ENCODE3 (25722, 2500, 3000):
+        return true;
+    }
+#endif
+    return false;
+  }
+
   hb_position_t get_constant (hb_ot_math_constant_t  constant,
 			      hb_font_t		   *font) const
   { return (this+mathConstants).get_value (constant, font); }

+ 14 - 0
thirdparty/harfbuzz/src/hb-ot-math.cc

@@ -87,6 +87,20 @@ hb_position_t
 hb_ot_math_get_constant (hb_font_t *font,
 			 hb_ot_math_constant_t constant)
 {
+  /* https://github.com/harfbuzz/harfbuzz/issues/4653
+   * Cambria Math has incorrect value for displayOperatorMinHeight, and
+   * apparently Microsoft implementation swaps displayOperatorMinHeight and
+   * delimitedSubFormulaMinHeight, so we do the same if we detect Cambria Math
+   * with the swapped values. */
+  if ((constant == HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT ||
+       constant == HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT) &&
+      font->face->table.MATH->is_bad_cambria (font))
+  {
+    if (constant == HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT)
+      constant = HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT;
+    else
+      constant = HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT;
+  }
   return font->face->table.MATH->get_constant(constant, font);
 }
 

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

@@ -290,7 +290,7 @@ struct post
     const Array16Of<HBUINT16> *glyphNameIndex = nullptr;
     hb_vector_t<uint32_t> index_to_offset;
     const uint8_t *pool = nullptr;
-    hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
+    mutable hb_atomic_t<uint16_t *> gids_sorted_by_name;
   };
 
   bool has_data () const { return version.to_int (); }

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

@@ -427,8 +427,13 @@ position_cluster (const hb_ot_shape_plan_t *plan,
       /* Find mark glyphs */
       unsigned int j;
       for (j = i + 1; j < end; j++)
+      {
+        if (_hb_glyph_info_is_hidden (&info[j]) ||
+	    _hb_glyph_info_is_default_ignorable (&info[j]))
+	  continue;
 	if (!_hb_glyph_info_is_unicode_mark (&info[j]))
 	  break;
+      }
 
       position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
 
@@ -455,7 +460,9 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]))) {
+    if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]) &&
+		!_hb_glyph_info_is_hidden (&info[i]) &&
+		!_hb_glyph_info_is_default_ignorable (&info[i]))) {
       position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }

+ 34 - 10
thirdparty/harfbuzz/src/hb-ot-shape.cc

@@ -46,6 +46,7 @@
 #include "hb-set.hh"
 
 #include "hb-aat-layout.hh"
+#include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-stat-table.hh"
 
 
@@ -84,6 +85,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *fac
 						props (props),
 						map (face, props)
 #ifndef HB_NO_AAT_SHAPE
+						, aat_map (face, props)
 						, apply_morx (_hb_apply_morx (face, props))
 #endif
 {
@@ -106,6 +108,10 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
   plan.props = props;
   plan.shaper = shaper;
   map.compile (plan.map, key);
+#ifndef HB_NO_AAT_SHAPE
+  if (apply_morx)
+    aat_map.compile (plan.aat_map);
+#endif
 
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
@@ -205,6 +211,14 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t           &plan,
      https://github.com/harfbuzz/harfbuzz/issues/2967. */
   if (plan.apply_morx)
     plan.adjust_mark_positioning_when_zeroing = false;
+
+  /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */
+#ifndef HB_NO_STYLE
+  plan.apply_trak = hb_aat_layout_has_tracking (face) && face->table.STAT->has_data ();
+#else
+  plan.apply_trak = false;
+#endif
+
 #endif
 }
 
@@ -269,6 +283,11 @@ hb_ot_shape_plan_t::position (hb_font_t   *font,
 #endif
   else if (this->apply_fallback_kern)
     _hb_ot_shape_fallback_kern (this, font, buffer);
+
+#ifndef HB_NO_AAT_SHAPE
+  if (this->apply_trak)
+    hb_aat_layout_track (this, font, buffer);
+#endif
 }
 
 
@@ -405,17 +424,26 @@ _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
  * shaper font data
  */
 
-struct hb_ot_font_data_t {};
+struct hb_ot_font_data_t {
+  OT::ItemVariationStore::cache_t unused; // Just for alignment
+};
 
 hb_ot_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+_hb_ot_shaper_font_data_create (hb_font_t *font)
 {
-  return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+  if (!font->num_coords)
+    return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+
+  const OT::ItemVariationStore &var_store = font->face->table.GDEF->table->get_var_store ();
+  auto *cache = (hb_ot_font_data_t *) var_store.create_cache ();
+  return cache ? cache : (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED)
+_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
 {
+  if (data == HB_SHAPER_DATA_SUCCEEDED) return;
+  OT::ItemVariationStore::destroy_cache ((OT::ItemVariationStore::cache_t *) data);
 }
 
 
@@ -551,7 +579,7 @@ hb_form_clusters (hb_buffer_t *buffer)
   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
     return;
 
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
     foreach_grapheme (buffer, start, end)
       buffer->merge_clusters (start, end);
   else
@@ -609,7 +637,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
    * first. */
   if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
-       direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
+       direction != horiz_dir && HB_DIRECTION_IS_VALID (horiz_dir)) ||
       (HB_DIRECTION_IS_VERTICAL   (direction) &&
        direction != HB_DIRECTION_TTB))
   {
@@ -1109,10 +1137,6 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
   /* Finish off.  Has to follow a certain order. */
   hb_ot_layout_position_finish_advances (c->font, c->buffer);
   hb_ot_zero_width_default_ignorables (c->buffer);
-#ifndef HB_NO_AAT_SHAPE
-  if (c->plan->apply_morx)
-    hb_aat_layout_zero_width_deleted_glyphs (c->buffer);
-#endif
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
 
   /* The nil glyph_h_origin() func returns 0, so no need to apply it. */

+ 4 - 0
thirdparty/harfbuzz/src/hb-ot-shape.hh

@@ -66,6 +66,7 @@ struct hb_ot_shape_plan_t
   hb_segment_properties_t props;
   const struct hb_ot_shaper_t *shaper;
   hb_ot_map_t map;
+  hb_aat_map_t aat_map;
   const void *data;
 #ifndef HB_NO_OT_SHAPE_FRACTIONS
   hb_mask_t frac_mask, numr_mask, dnom_mask;
@@ -108,9 +109,11 @@ struct hb_ot_shape_plan_t
 #ifndef HB_NO_AAT_SHAPE
   bool apply_kerx : 1;
   bool apply_morx : 1;
+  bool apply_trak : 1;
 #else
   static constexpr bool apply_kerx = false;
   static constexpr bool apply_morx = false;
+  static constexpr bool apply_trak = false;
 #endif
 
   void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
@@ -141,6 +144,7 @@ struct hb_ot_shape_planner_t
   hb_segment_properties_t props;
   hb_ot_map_builder_t map;
 #ifndef HB_NO_AAT_SHAPE
+  hb_aat_map_builder_t aat_map;
   bool apply_morx : 1;
 #else
   static constexpr bool apply_morx = false;

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

@@ -260,7 +260,7 @@ struct arabic_shape_plan_t
    * mask_array[NONE] == 0. */
   hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
-  hb_atomic_ptr_t<arabic_fallback_plan_t> fallback_plan;
+  mutable hb_atomic_t<arabic_fallback_plan_t *> fallback_plan;
 
   unsigned int do_fallback : 1;
   unsigned int has_stch : 1;

+ 2 - 4
thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc

@@ -298,8 +298,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	  end = start + 2;
 	if (unlikely (!buffer->successful))
 	  break;
-	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
-	  buffer->merge_out_clusters (start, end);
+	buffer->merge_out_clusters (start, end);
 	continue;
       }
     }
@@ -372,8 +371,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
 	  if (i < end)
 	    info[i++].hangul_shaping_feature() = TJMO;
 
-	  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
-	    buffer->merge_out_clusters (start, end);
+	  buffer->merge_out_clusters (start, end);
 	  continue;
 	}
 	else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint)))

Some files were not shown because too many files changed in this diff