浏览代码

HarfBuzz: Update to version 4.2.0

bruvzg 3 年之前
父节点
当前提交
56544d8013
共有 57 个文件被更改,包括 3041 次插入2368 次删除
  1. 1 1
      thirdparty/README.md
  2. 110 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
  3. 51 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
  4. 128 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
  5. 18 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh
  6. 21 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh
  7. 18 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh
  8. 22 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh
  9. 58 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
  10. 135 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
  11. 118 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh
  12. 59 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
  13. 165 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
  14. 53 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
  15. 120 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
  16. 36 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
  17. 228 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
  18. 103 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
  19. 75 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
  20. 122 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
  21. 120 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
  22. 224 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
  23. 77 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh
  24. 72 0
      thirdparty/harfbuzz/src/hb-bit-page.hh
  25. 8 0
      thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
  26. 98 4
      thirdparty/harfbuzz/src/hb-bit-set.hh
  27. 1 1
      thirdparty/harfbuzz/src/hb-buffer.cc
  28. 1 17
      thirdparty/harfbuzz/src/hb-coretext.cc
  29. 1 0
      thirdparty/harfbuzz/src/hb-ft.cc
  30. 2 2
      thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
  31. 31 7
      thirdparty/harfbuzz/src/hb-ot-font.cc
  32. 1 2
      thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
  33. 4 3
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  34. 23 38
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  35. 4 1717
      thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
  36. 27 14
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  37. 68 63
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  38. 8 13
      thirdparty/harfbuzz/src/hb-ot-layout.hh
  39. 6 2
      thirdparty/harfbuzz/src/hb-ot-map.cc
  40. 6 2
      thirdparty/harfbuzz/src/hb-ot-map.hh
  41. 2 2
      thirdparty/harfbuzz/src/hb-ot-metrics.cc
  42. 19 21
      thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
  43. 1 0
      thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
  44. 8 14
      thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
  45. 3 5
      thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
  46. 479 408
      thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
  47. 14 14
      thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
  48. 8 9
      thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
  49. 8 2
      thirdparty/harfbuzz/src/hb-ot-shape.cc
  50. 3 2
      thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
  51. 48 0
      thirdparty/harfbuzz/src/hb-set.cc
  52. 11 0
      thirdparty/harfbuzz/src/hb-set.h
  53. 3 0
      thirdparty/harfbuzz/src/hb-set.hh
  54. 2 0
      thirdparty/harfbuzz/src/hb-static.cc
  55. 3 1
      thirdparty/harfbuzz/src/hb-subset-plan.cc
  56. 3 1
      thirdparty/harfbuzz/src/hb-subset.cc
  57. 3 3
      thirdparty/harfbuzz/src/hb-version.h

+ 1 - 1
thirdparty/README.md

@@ -204,7 +204,7 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 4.0.1 (1f79ba9407ecd54e382997940cbcc3fb71bef8be, 2022)
+- Version: 4.2.0 (9d5730b958974bc9db95e46e6bad52e9e9cd6e1c, 2022)
 - License: MIT
 
 Files extracted from upstream source:

+ 110 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh

@@ -0,0 +1,110 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH
+#define OT_LAYOUT_GSUB_ALTERNATESET_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct AlternateSet
+{
+  protected:
+  Array16Of<HBGlyphID16>
+                alternates;             /* Array of alternate GlyphIDs--in
+                                         * arbitrary order */
+  public:
+  DEFINE_SIZE_ARRAY (2, alternates);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (alternates.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_any (alternates, glyphs); }
+
+  void closure (hb_closure_context_t *c) const
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = alternates.len;
+
+    if (unlikely (!count)) return_trace (false);
+
+    hb_mask_t glyph_mask = c->buffer->cur().mask;
+    hb_mask_t lookup_mask = c->lookup_mask;
+
+    /* Note: This breaks badly if two features enabled this lookup together. */
+    unsigned int shift = hb_ctz (lookup_mask);
+    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
+    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
+    {
+      /* Maybe we can do better than unsafe-to-break all; but since we are
+       * changing random state, it would be hard to track that.  Good 'nough. */
+      c->buffer->unsafe_to_break (0, c->buffer->len);
+      alt_index = c->random_number () % count + 1;
+    }
+
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+    c->replace_glyph (alternates[alt_index - 1]);
+
+    return_trace (true);
+  }
+
+  unsigned
+  get_alternates (unsigned        start_offset,
+                  unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                  hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  {
+    if (alternates.len && alternate_count)
+    {
+      + alternates.sub_array (start_offset, alternate_count)
+      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
+      ;
+    }
+    return alternates.len;
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator alts)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (alternates.serialize (c, alts));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+      + hb_iter (alternates)
+      | hb_filter (glyphset)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it) &&
+                  out->alternates);
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */

+ 51 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh

@@ -0,0 +1,51 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBST_HH
+
+#include "AlternateSubstFormat1.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct AlternateSubst
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  AlternateSubstFormat1 format1;
+  } u;
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> alternate_len_list,
+                  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
+    default:return_trace (false);
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_ALTERNATESUBST_HH */

+ 128 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh

@@ -0,0 +1,128 @@
+#ifndef OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH
+
+#include "AlternateSet.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct AlternateSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16OfOffset16To<AlternateSet>
+                alternateSet;           /* Array of AlternateSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, alternateSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
+    ;
+
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  unsigned
+  get_glyph_alternates (hb_codepoint_t  gid,
+                        unsigned        start_offset,
+                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  { return (this+alternateSet[(this+coverage).get_coverage (gid)])
+           .get_alternates (start_offset, alternate_count, alternate_glyphs); }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    return_trace ((this+alternateSet[index]).apply (c));
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> alternate_len_list,
+                  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < glyphs.length; i++)
+    {
+      unsigned int alternate_len = alternate_len_list[i];
+      if (unlikely (!alternateSet[i]
+                        .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
+        return_trace (false);
+      alternate_glyphs_list += alternate_len;
+    }
+    return_trace (coverage.serialize_serialize (c, glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_ALTERNATESUBSTFORMAT1_HH */

+ 18 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh

@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct ChainContextSubst : ChainContext {};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_CHAINCONTEXTSUBST_HH */

+ 21 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh

@@ -0,0 +1,21 @@
+#ifndef OT_LAYOUT_GSUB_COMMON_HH
+#define OT_LAYOUT_GSUB_COMMON_HH
+
+#include "../../../hb-serialize.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
+
+template<typename Iterator>
+static void SingleSubst_serialize (hb_serialize_context_t *c,
+                                   Iterator it);
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_COMMON_HH */

+ 18 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh

@@ -0,0 +1,18 @@
+#ifndef OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+#define OT_LAYOUT_GSUB_CONTEXTSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct ContextSubst : Context {};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_CONTEXTSUBST_HH */

+ 22 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh

@@ -0,0 +1,22 @@
+#ifndef OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+#define OT_LAYOUT_GSUB_EXTENSIONSUBST_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct ExtensionSubst : Extension<ExtensionSubst>
+{
+  typedef struct SubstLookupSubTable SubTable;
+  bool is_reverse () const;
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_EXTENSIONSUBST_HH */

+ 58 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh

@@ -0,0 +1,58 @@
+#ifndef OT_LAYOUT_GSUB_GSUB_HH
+#define OT_LAYOUT_GSUB_GSUB_HH
+
+// TODO(garretrieger): move to new layout.
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "SubstLookup.hh"
+
+using OT::Layout::GSUB::SubstLookup;
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+/*
+ * GSUB -- Glyph Substitution
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
+ */
+
+struct GSUB : GSUBGPOS
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
+
+  const SubstLookup& get_lookup (unsigned int i) const
+  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
+    return GSUBGPOS::subset<SubstLookup> (&l);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return GSUBGPOS::sanitize<SubstLookup> (c); }
+
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+                                   hb_face_t *face) const;
+
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
+
+  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
+};
+
+
+}
+}
+
+struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t {
+  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {}
+};
+
+
+}
+
+#endif  /* OT_LAYOUT_GSUB_GSUB_HH */

+ 135 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh

@@ -0,0 +1,135 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURE_HH
+#define OT_LAYOUT_GSUB_LIGATURE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct Ligature
+{
+  protected:
+  HBGlyphID16   ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArrayOf<HBGlyphID16>
+                component;              /* Array of component GlyphIDs--start
+                                         * with the second  component--ordered
+                                         * in writing direction */
+  public:
+  DEFINE_SIZE_ARRAY (4, component);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (component, glyphs); }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!intersects (c->glyphs)) return;
+    c->output->add (ligGlyph);
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    c->input->add_array (component.arrayZ, component.get_length ());
+    c->output->add (ligGlyph);
+  }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    if (c->len != component.lenP1)
+      return false;
+
+    for (unsigned int i = 1; i < c->len; i++)
+      if (likely (c->glyphs[i] != component[i]))
+        return false;
+
+    return true;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = component.lenP1;
+
+    if (unlikely (!count)) return_trace (false);
+
+    /* Special-case to make it in-place and not consider this
+     * as a "ligated" substitution. */
+    if (unlikely (count == 1))
+    {
+      c->replace_glyph (ligGlyph);
+      return_trace (true);
+    }
+
+    unsigned int total_component_count = 0;
+
+    unsigned int match_end = 0;
+    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+
+    if (likely (!match_input (c, count,
+                              &component[1],
+                              match_glyph,
+                              nullptr,
+                              &match_end,
+                              match_positions,
+                              &total_component_count)))
+    {
+      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
+      return_trace (false);
+    }
+
+    ligate_input (c,
+                  count,
+                  match_positions,
+                  match_end,
+                  ligGlyph,
+                  total_component_count);
+
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  hb_codepoint_t ligature,
+                  Iterator components /* Starting from second */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    ligGlyph = ligature;
+    if (unlikely (!component.serialize (c, components))) return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
+    // Ensure Coverage table is always packed after this.
+    c->serializer->add_virtual_link (coverage_idx);
+
+    auto it =
+      + hb_iter (component)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer,
+                                  glyph_map[ligGlyph],
+                                  it));  }
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURE_HH */

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

@@ -0,0 +1,118 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH
+#define OT_LAYOUT_GSUB_LIGATURESET_HH
+
+#include "Common.hh"
+#include "Ligature.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct LigatureSet
+{
+  protected:
+  Array16OfOffset16To<Ligature>
+                ligature;               /* Array LigatureSet tables
+                                         * ordered by preference */
+  public:
+  DEFINE_SIZE_ARRAY (2, ligature);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (ligature.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
+    | hb_any
+    ;
+  }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
+    ;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
+    | hb_any
+    ;
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+    {
+      const Ligature &lig = this+ligature[i];
+      if (lig.apply (c)) return_trace (true);
+    }
+
+    return_trace (false);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_array_t<const HBGlyphID16> ligatures,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
+    for (unsigned int i = 0; i < ligatures.length; i++)
+    {
+      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
+      if (unlikely (!ligature[i].serialize_serialize (c,
+                                                      ligatures[i],
+                                                      component_list.sub_array (0, component_count))))
+        return_trace (false);
+      component_list += component_count;
+    }
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (ligature)
+    | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
+    | hb_drain
+    ;
+
+    if (bool (out->ligature))
+      // Ensure Coverage table is always packed after this.
+      c->serializer->add_virtual_link (coverage_idx);
+
+    return_trace (bool (out->ligature));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESET_HH */

+ 59 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh

@@ -0,0 +1,59 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBST_HH
+
+#include "Common.hh"
+#include "LigatureSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct LigatureSubst
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  LigatureSubstFormat1  format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                  hb_array_t<const HBGlyphID16> ligatures_list,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c,
+                                               first_glyphs,
+                                               ligature_per_first_glyph_count_list,
+                                               ligatures_list,
+                                               component_count_list,
+                                               component_list));
+    default:return_trace (false);
+    }
+  }
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */

+ 165 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh

@@ -0,0 +1,165 @@
+#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "LigatureSet.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct LigatureSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16OfOffset16To<LigatureSet>
+                ligatureSet;            /* Array LigatureSet tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, ligatureSet);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
+              { return (this+_).intersects (glyphs); })
+    | hb_any
+    ;
+  }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
+    ;
+
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  {
+    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return false;
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return lig_set.would_apply (c);
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return_trace (lig_set.apply (c));
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                  hb_array_t<const HBGlyphID16> ligatures_list,
+                  hb_array_t<const unsigned int> component_count_list,
+                  hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < first_glyphs.length; i++)
+    {
+      unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
+      if (unlikely (!ligatureSet[i]
+                        .serialize_serialize (c,
+                                              ligatures_list.sub_array (0, ligature_count),
+                                              component_count_list.sub_array (0, ligature_count),
+                                              component_list))) return_trace (false);
+      ligatures_list += ligature_count;
+      component_count_list += ligature_count;
+    }
+    return_trace (coverage.serialize_serialize (c, first_glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    // Due to a bug in some older versions of windows 7 the Coverage table must be
+    // packed after the LigatureSet and Ligature tables, so serialize Coverage first
+    // which places it last in the packed order.
+    hb_set_t new_coverage;
+    + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([&] (const LigatureSet& _) {
+      return _.intersects (&glyphset);
+    }, hb_second)
+    | hb_map (hb_first)
+    | hb_sink (new_coverage);
+
+    if (!c->serializer->push<Coverage> ()
+        ->serialize (c->serializer,
+                     + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
+    {
+      c->serializer->pop_discard ();
+      return_trace (false);
+    }
+
+    unsigned coverage_idx = c->serializer->pop_pack ();
+     c->serializer->add_link (out->coverage, coverage_idx);
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (new_coverage, hb_first)
+    | hb_map (hb_second)
+    // to ensure that the repacker always orders the coverage table after the LigatureSet
+    // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
+    // the coverage table object idx is passed down to facilitate this.
+    | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
+    ;
+
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */

+ 53 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh

@@ -0,0 +1,53 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBST_HH
+
+#include "Common.hh"
+#include "MultipleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct MultipleSubst
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  MultipleSubstFormat1  format1;
+  } u;
+
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> substitute_len_list,
+                  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned int format = 1;
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
+    default:return_trace (false);
+    }
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBST_HH */

+ 120 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh

@@ -0,0 +1,120 @@
+#ifndef OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+#include "Sequence.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct MultipleSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16OfOffset16To<Sequence>
+                sequence;               /* Array of Sequence tables
+                                         * ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_ARRAY (6, sequence);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return true; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, sequence)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    return_trace ((this+sequence[index]).apply (c));
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  hb_sorted_array_t<const HBGlyphID16> glyphs,
+                  hb_array_t<const unsigned int> substitute_len_list,
+                  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < glyphs.length; i++)
+    {
+      unsigned int substitute_len = substitute_len_list[i];
+      if (unlikely (!sequence[i]
+                        .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
+        return_trace (false);
+      substitute_glyphs_list += substitute_len;
+    }
+    return_trace (coverage.serialize_serialize (c, glyphs));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_MULTIPLESUBSTFORMAT1_HH */

+ 36 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh

@@ -0,0 +1,36 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH
+
+#include "Common.hh"
+#include "ReverseChainSingleSubstFormat1.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct ReverseChainSingleSubst
+{
+  protected:
+  union {
+  HBUINT16                              format;         /* Format identifier */
+  ReverseChainSingleSubstFormat1        format1;
+  } u;
+
+  public:
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBST_HH */

+ 228 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh

@@ -0,0 +1,228 @@
+#ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct ReverseChainSingleSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of table */
+  Array16OfOffset16To<Coverage>
+                backtrack;              /* Array of coverage tables
+                                         * in backtracking sequence, in glyph
+                                         * sequence order */
+  Array16OfOffset16To<Coverage>
+                lookaheadX;             /* Array of coverage tables
+                                         * in lookahead sequence, in glyph
+                                         * sequence order */
+  Array16Of<HBGlyphID16>
+                substituteX;            /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+  public:
+  DEFINE_SIZE_MIN (10);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
+      return_trace (false);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    if (!lookahead.sanitize (c, this))
+      return_trace (false);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    return_trace (substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+backtrack[i]).intersects (glyphs))
+        return false;
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+lookahead[i]).intersects (glyphs))
+        return false;
+
+    return true;
+  }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    if (!intersects (c->glyphs)) return;
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
+
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    count = substitute.len;
+    c->output->add_array (substitute.arrayZ, substitute.len);
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+      return_trace (false); /* No chaining to this type */
+
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+
+    if (unlikely (index >= substitute.len)) return_trace (false);
+
+    unsigned int start_index = 0, end_index = 0;
+    if (match_backtrack (c,
+                         backtrack.len, (HBUINT16 *) backtrack.arrayZ,
+                         match_coverage, this,
+                         &start_index) &&
+        match_lookahead (c,
+                         lookahead.len, (HBUINT16 *) lookahead.arrayZ,
+                         match_coverage, this,
+                         c->buffer->idx + 1, &end_index))
+    {
+      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+      c->replace_glyph_inplace (substitute[index]);
+      /* Note: We DON'T decrease buffer->idx.  The main loop does it
+       * for us.  This is useful for preventing surprises if someone
+       * calls us through a Context lookup. */
+      return_trace (true);
+    }
+    else
+    {
+      c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
+      return_trace (false);
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
+
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+      return_trace (false);
+
+    for (auto& offset : it) {
+      auto *o = out->serialize_append (c->serializer);
+      if (unlikely (!o) || !o->serialize_subset (c, offset, this))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
+  template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
+           hb_requires (hb_is_iterator (BacktrackIterator)),
+           hb_requires (hb_is_iterator (LookaheadIterator))>
+  bool serialize (hb_subset_context_t *c,
+                  Iterator coverage_subst_iter,
+                  BacktrackIterator backtrack_iter,
+                  LookaheadIterator lookahead_iter) const
+  {
+    TRACE_SERIALIZE (this);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->check_success (out))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
+
+    if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
+    if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
+
+    auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
+    auto substitutes =
+    + coverage_subst_iter
+    | hb_map (hb_second)
+    ;
+
+    auto glyphs =
+    + coverage_subst_iter
+    | hb_map_retains_sorting (hb_first)
+    ;
+    if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
+        return_trace (false);
+
+    if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
+      return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
+  }
+};
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */

+ 103 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh

@@ -0,0 +1,103 @@
+#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
+#define OT_LAYOUT_GSUB_SEQUENCE_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct Sequence
+{
+  protected:
+  Array16Of<HBGlyphID16>
+                substitute;             /* String of GlyphIDs to substitute */
+  public:
+  DEFINE_SIZE_ARRAY (2, substitute);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (substitute, glyphs); }
+
+  void closure (hb_closure_context_t *c) const
+  { c->output->add_array (substitute.arrayZ, substitute.len); }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  { c->output->add_array (substitute.arrayZ, substitute.len); }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = substitute.len;
+
+    /* Special-case to make it in-place and not consider this
+     * as a "multiplied" substitution. */
+    if (unlikely (count == 1))
+    {
+      c->replace_glyph (substitute.arrayZ[0]);
+      return_trace (true);
+    }
+    /* Spec disallows this, but Uniscribe allows it.
+     * https://github.com/harfbuzz/harfbuzz/issues/253 */
+    else if (unlikely (count == 0))
+    {
+      c->buffer->delete_glyph ();
+      return_trace (true);
+    }
+
+    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      /* If is attached to a ligature, don't disturb that.
+       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
+      if (!lig_id)
+        _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+      c->output_glyph_for_component (substitute.arrayZ[i], klass);
+    }
+    c->buffer->skip_glyph ();
+
+    return_trace (true);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator subst)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (substitute.serialize (c, subst));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset)) return_trace (false);
+
+    auto it =
+    + hb_iter (substitute)
+    | hb_map (glyph_map)
+    ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it));
+  }
+};
+
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */

+ 75 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh

@@ -0,0 +1,75 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBST_HH
+#define OT_LAYOUT_GSUB_SINGLESUBST_HH
+
+#include "Common.hh"
+#include "SingleSubstFormat1.hh"
+#include "SingleSubstFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct SingleSubst
+{
+  protected:
+  union {
+  HBUINT16              format;         /* Format identifier */
+  SingleSubstFormat1    format1;
+  SingleSubstFormat2    format2;
+  } u;
+
+  public:
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                const hb_codepoint_pair_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
+    unsigned format = 2;
+    unsigned delta = 0;
+    if (glyphs)
+    {
+      format = 1;
+      auto get_delta = [=] (hb_codepoint_pair_t _)
+                       { return (unsigned) (_.second - _.first) & 0xFFFF; };
+      delta = get_delta (*glyphs);
+      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
+    }
+    u.format = format;
+    switch (u.format) {
+    case 1: return_trace (u.format1.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
+    default:return_trace (false);
+    }
+  }
+};
+
+template<typename Iterator>
+static void
+SingleSubst_serialize (hb_serialize_context_t *c,
+                       Iterator it)
+{ c->start_embed<SingleSubst> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBST_HH */

+ 122 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh

@@ -0,0 +1,122 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct SingleSubstFormat1
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 1 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  HBUINT16      deltaGlyphID;           /* Add to original GlyphID to get
+                                         * substitute GlyphID, modulo 0x10000 */
+
+  public:
+  DEFINE_SIZE_STATIC (6);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    unsigned d = deltaGlyphID;
+
+    + hb_iter (this+coverage)
+    | hb_filter (c->parent_active_glyphs ())
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
+
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    unsigned d = deltaGlyphID;
+    + hb_iter (this+coverage)
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    /* According to the Adobe Annotated OpenType Suite, result is always
+     * limited to 16bit. */
+    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
+    c->replace_glyph (glyph_id);
+
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator glyphs,
+                  unsigned delta)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    hb_codepoint_t delta = deltaGlyphID;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
+                                return hb_codepoint_pair_t (g,
+                                                            (g + delta) & 0xFFFF); })
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */

+ 120 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh

@@ -0,0 +1,120 @@
+#ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+#define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH
+
+#include "Common.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct SingleSubstFormat2
+{
+  protected:
+  HBUINT16      format;                 /* Format identifier--format = 2 */
+  Offset16To<Coverage>
+                coverage;               /* Offset to Coverage table--from
+                                         * beginning of Substitution table */
+  Array16Of<HBGlyphID16>
+                substitute;             /* Array of substitute
+                                         * GlyphIDs--ordered by Coverage Index */
+
+  public:
+  DEFINE_SIZE_ARRAY (6, substitute);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
+  bool may_have_non_1to1 () const
+  { return false; }
+
+  void closure (hb_closure_context_t *c) const
+  {
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, substitute)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
+  }
+
+  const Coverage &get_coverage () const { return this+coverage; }
+
+  bool would_apply (hb_would_apply_context_t *c) const
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    if (likely (index == NOT_COVERED)) return_trace (false);
+
+    if (unlikely (index >= substitute.len)) return_trace (false);
+
+    c->replace_glyph (substitute[index]);
+
+    return_trace (true);
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                hb_codepoint_pair_t))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    auto substitutes =
+      + it
+      | hb_map (hb_second)
+      ;
+    auto glyphs =
+      + it
+      | hb_map_retains_sorting (hb_first)
+      ;
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+};
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT2_HH */

+ 224 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh

@@ -0,0 +1,224 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
+
+#include "Common.hh"
+#include "SubstLookupSubTable.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct SubstLookup : Lookup
+{
+  typedef SubstLookupSubTable SubTable;
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return Lookup::sanitize<SubTable> (c); }
+
+  const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
+
+  static inline bool lookup_type_is_reverse (unsigned int lookup_type)
+  { return lookup_type == SubTable::ReverseChainSingle; }
+
+  bool is_reverse () const
+  {
+    unsigned int type = get_type ();
+    if (unlikely (type == SubTable::Extension))
+      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
+    return lookup_type_is_reverse (type);
+  }
+
+  bool may_have_non_1to1 () const
+  {
+    hb_have_non_1to1_context_t c;
+    return dispatch (&c);
+  }
+
+  bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
+  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
+  {
+    if (!c->should_visit_lookup (this_index))
+      return hb_closure_context_t::default_return_value ();
+
+    c->set_recurse_func (dispatch_closure_recurse_func);
+
+    hb_closure_context_t::return_t ret = dispatch (c);
+
+    c->flush ();
+
+    return ret;
+  }
+
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+  {
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+
+    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
+  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+    return dispatch (c);
+  }
+
+  template <typename set_t>
+  void collect_coverage (set_t *glyphs) const
+  {
+    hb_collect_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
+
+  bool would_apply (hb_would_apply_context_t *c,
+                    const hb_ot_layout_lookup_accelerator_t *accel) const
+  {
+    if (unlikely (!c->len)) return false;
+    if (!accel->may_have (c->glyphs[0])) return false;
+      return dispatch (c);
+  }
+
+  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+
+  bool serialize_single (hb_serialize_context_t *c,
+                         uint32_t lookup_props,
+                         hb_sorted_array_t<const HBGlyphID16> glyphs,
+                         hb_array_t<const HBGlyphID16> substitutes)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  bool serialize_multiple (hb_serialize_context_t *c,
+                           uint32_t lookup_props,
+                           hb_sorted_array_t<const HBGlyphID16> glyphs,
+                           hb_array_t<const unsigned int> substitute_len_list,
+                           hb_array_t<const HBGlyphID16> substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.multiple.
+        serialize (c,
+                   glyphs,
+                   substitute_len_list,
+                   substitute_glyphs_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  bool serialize_alternate (hb_serialize_context_t *c,
+                            uint32_t lookup_props,
+                            hb_sorted_array_t<const HBGlyphID16> glyphs,
+                            hb_array_t<const unsigned int> alternate_len_list,
+                            hb_array_t<const HBGlyphID16> alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
+
+    if (c->push<SubTable> ()->u.alternate.
+        serialize (c,
+                   glyphs,
+                   alternate_len_list,
+                   alternate_glyphs_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  bool serialize_ligature (hb_serialize_context_t *c,
+                           uint32_t lookup_props,
+                           hb_sorted_array_t<const HBGlyphID16> first_glyphs,
+                           hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
+                           hb_array_t<const HBGlyphID16> ligatures_list,
+                           hb_array_t<const unsigned int> component_count_list,
+                           hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
+    if (c->push<SubTable> ()->u.ligature.
+        serialize (c,
+                   first_glyphs,
+                   ligature_per_first_glyph_count_list,
+                   ligatures_list,
+                   component_count_list,
+                   component_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
+  }
+
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+
+  static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
+
+  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
+  {
+    if (!c->should_visit_lookup (lookup_index))
+      return hb_empty_t ();
+
+    hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
+
+    /* While in theory we should flush here, it will cause timeouts because a recursive
+     * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
+     * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
+    //c->flush ();
+
+    return ret;
+  }
+
+  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
+
+  bool subset (hb_subset_context_t *c) const
+  { return Lookup::subset<SubTable> (c); }
+};
+
+
+}
+}
+}
+
+#endif  /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */

+ 77 - 0
thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh

@@ -0,0 +1,77 @@
+#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+#define OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH
+
+#include "Common.hh"
+#include "SingleSubst.hh"
+#include "MultipleSubst.hh"
+#include "AlternateSubst.hh"
+#include "LigatureSubst.hh"
+#include "ContextSubst.hh"
+#include "ChainContextSubst.hh"
+#include "ExtensionSubst.hh"
+#include "ReverseChainSingleSubst.hh"
+
+namespace OT {
+namespace Layout {
+namespace GSUB {
+
+struct SubstLookupSubTable
+{
+  friend struct ::OT::Lookup;
+  friend struct SubstLookup;
+
+  protected:
+  union {
+  SingleSubst                   single;
+  MultipleSubst                 multiple;
+  AlternateSubst                alternate;
+  LigatureSubst                 ligature;
+  ContextSubst                  context;
+  ChainContextSubst             chainContext;
+  ExtensionSubst                extension;
+  ReverseChainSingleSubst       reverseChainContextSingle;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+
+  enum Type {
+    Single              = 1,
+    Multiple            = 2,
+    Alternate           = 3,
+    Ligature            = 4,
+    Context             = 5,
+    ChainContext        = 6,
+    Extension           = 7,
+    ReverseChainSingle  = 8
+  };
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, lookup_type);
+    switch (lookup_type) {
+    case Single:                return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
+    case Multiple:              return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
+    case Alternate:             return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
+    case Ligature:              return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
+    case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
+    default:                    return_trace (c->default_return_value ());
+    }
+  }
+
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+};
+
+
+}
+}
+}
+
+#endif  /* HB_OT_LAYOUT_GSUB_SUBSTLOOKUPSUBTABLE_HH */

+ 72 - 0
thirdparty/harfbuzz/src/hb-bit-page.hh

@@ -86,6 +86,72 @@ struct hb_bit_page_t
   void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
   { if (v) add_range (a, b); else del_range (a, b); }
 
+
+  // Writes out page values to the array p. Returns the number of values
+  // written. At most size codepoints will be written.
+  unsigned int write (uint32_t        base,
+		      unsigned int    start_value,
+		      hb_codepoint_t *p,
+		      unsigned int    size) const
+  {
+    unsigned int start_v = start_value >> ELT_BITS_LOG_2;
+    unsigned int start_bit = start_value & ELT_MASK;
+    unsigned int count = 0;
+    for (unsigned i = start_v; i < len () && count < size; i++)
+    {
+      elt_t bits = v[i];
+      uint32_t v_base = base | (i << ELT_BITS_LOG_2);
+      for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+      {
+	if ((elt_t(1) << j) & bits) {
+	  *p++ = v_base | j;
+	  count++;
+	}
+      }
+      start_bit = 0;
+    }
+    return count;
+  }
+
+  // Writes out the values NOT in this page to the array p. Returns the
+  // number of values written. At most size codepoints will be written.
+  // Returns the number of codepoints written. next_value holds the next value
+  // that should be written (if not present in this page). This is used to fill
+  // any missing value gaps between this page and the previous page, if any.
+  // next_value is updated to one more than the last value present in this page.
+  unsigned int write_inverted (uint32_t        base,
+			       unsigned int    start_value,
+			       hb_codepoint_t *p,
+			       unsigned int    size,
+			       hb_codepoint_t *next_value) const
+  {
+    unsigned int start_v = start_value >> ELT_BITS_LOG_2;
+    unsigned int start_bit = start_value & ELT_MASK;
+    unsigned int count = 0;
+    for (unsigned i = start_v; i < len () && count < size; i++)
+    {
+      elt_t bits = v[i];
+      uint32_t v_offset = i << ELT_BITS_LOG_2;
+      for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
+      {
+	if ((elt_t(1) << j) & bits)
+	{
+	  hb_codepoint_t value = base | v_offset | j;
+	  // Emit all the missing values from next_value up to value - 1.
+	  for (hb_codepoint_t k = *next_value; k < value && count < size; k++)
+	  {
+	    *p++ = k;
+	    count++;
+	  }
+	  // Skip over this value;
+	  *next_value = value + 1;
+	}
+      }
+      start_bit = 0;
+    }
+    return count;
+  }
+
   bool is_equal (const hb_bit_page_t &other) const
   {
     return 0 == hb_memcmp (&v, &other.v, sizeof (v));
@@ -179,6 +245,9 @@ struct hb_bit_page_t
   typedef unsigned long long elt_t;
   static constexpr unsigned PAGE_BITS = 512;
   static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+  static constexpr unsigned PAGE_BITS_LOG_2 = 9;
+  static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
+  static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
 
   static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
   static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
@@ -186,7 +255,10 @@ struct hb_bit_page_t
   typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
 
   static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_BITS_LOG_2 = 6;
+  static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, "");
   static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+
   static constexpr unsigned BITS = sizeof (vector_t) * 8;
   static constexpr unsigned MASK = BITS - 1;
   static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");

+ 8 - 0
thirdparty/harfbuzz/src/hb-bit-set-invertible.hh

@@ -323,6 +323,14 @@ struct hb_bit_set_invertible_t
     return true;
   }
 
+  unsigned int next_many (hb_codepoint_t  codepoint,
+			  hb_codepoint_t *out,
+			  unsigned int    size) const
+  {
+    return inverted ? s.next_many_inverted (codepoint, out, size)
+		    : s.next_many (codepoint, out, size);
+  }
+
   static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
 
   /*

+ 98 - 4
thirdparty/harfbuzz/src/hb-bit-set.hh

@@ -203,7 +203,7 @@ struct hb_bit_set_t
   bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
   {
     if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
-    if (!count) return true;
+    if (unlikely (!count)) return true;
     dirty ();
     hb_codepoint_t g = *array;
     hb_codepoint_t last_g = g;
@@ -222,7 +222,7 @@ struct hb_bit_set_t
         if (v || page) /* The v check is to optimize out the page check if v is true. */
 	  page->add (g);
 
-	array = (const T *) ((const char *) array + stride);
+	array = &StructAtOffsetUnaligned<T> (array, stride);
 	count--;
       }
       while (count && (g = *array, g < end));
@@ -700,6 +700,99 @@ struct hb_bit_set_t
     return true;
   }
 
+  unsigned int next_many (hb_codepoint_t  codepoint,
+			  hb_codepoint_t *out,
+			  unsigned int    size) const
+  {
+    // By default, start at the first bit of the first page of values.
+    unsigned int start_page = 0;
+    unsigned int start_page_value = 0;
+    if (unlikely (codepoint != INVALID))
+    {
+      const auto* page_map_array = page_map.arrayZ;
+      unsigned int major = get_major (codepoint);
+      unsigned int i = last_page_lookup;
+      if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+      {
+	page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+	if (i >= page_map.length)
+	  return 0;  // codepoint is greater than our max element.
+      }
+      start_page = i;
+      start_page_value = page_remainder (codepoint + 1);
+      if (unlikely (start_page_value == 0))
+      {
+        // The export-after value was last in the page. Start on next page.
+        start_page++;
+        start_page_value = 0;
+      }
+    }
+
+    unsigned int initial_size = size;
+    for (unsigned int i = start_page; i < page_map.length && size; i++)
+    {
+      uint32_t base = major_start (page_map[i].major);
+      unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
+      out += n;
+      size -= n;
+      start_page_value = 0;
+    }
+    return initial_size - size;
+  }
+
+  unsigned int next_many_inverted (hb_codepoint_t  codepoint,
+				   hb_codepoint_t *out,
+				   unsigned int    size) const
+  {
+    unsigned int initial_size = size;
+    // By default, start at the first bit of the first page of values.
+    unsigned int start_page = 0;
+    unsigned int start_page_value = 0;
+    if (unlikely (codepoint != INVALID))
+    {
+      const auto* page_map_array = page_map.arrayZ;
+      unsigned int major = get_major (codepoint);
+      unsigned int i = last_page_lookup;
+      if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+      {
+        page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+        if (unlikely (i >= page_map.length))
+        {
+          // codepoint is greater than our max element.
+          while (++codepoint != INVALID && size)
+          {
+            *out++ = codepoint;
+            size--;
+          }
+          return initial_size - size;
+        }
+      }
+      start_page = i;
+      start_page_value = page_remainder (codepoint + 1);
+      if (unlikely (start_page_value == 0))
+      {
+        // The export-after value was last in the page. Start on next page.
+        start_page++;
+        start_page_value = 0;
+      }
+    }
+
+    hb_codepoint_t next_value = codepoint + 1;
+    for (unsigned int i=start_page; i<page_map.length && size; i++)
+    {
+      uint32_t base = major_start (page_map[i].major);
+      unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
+      out += n;
+      size -= n;
+      start_page_value = 0;
+    }
+    while (next_value < HB_SET_VALUE_INVALID && size) {
+      *out++ = next_value++;
+      size--;
+    }
+    return initial_size - size;
+  }
+
   bool has_population () const { return population != UINT_MAX; }
   unsigned int get_population () const
   {
@@ -809,8 +902,9 @@ struct hb_bit_set_t
   }
   page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
   const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
-  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
-  hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
+  unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
+  unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
+  hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
 };
 
 

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

@@ -295,7 +295,6 @@ hb_buffer_t::clear ()
   idx = 0;
   len = 0;
   out_len = 0;
-
   out_info = info;
 
   memset (context, 0, sizeof context);
@@ -405,6 +404,7 @@ hb_buffer_t::sync ()
 reset:
   have_output = false;
   out_len = 0;
+  out_info = info;
   idx = 0;
 }
 

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

@@ -897,7 +897,7 @@ resize_and_retry:
     DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
 
     buffer->len = 0;
-    uint32_t status_and = ~0, status_or = 0;
+    uint32_t status_or = 0;
     CGFloat advances_so_far = 0;
     /* For right-to-left runs, CoreText returns the glyphs positioned such that
      * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
@@ -918,7 +918,6 @@ resize_and_retry:
       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
       CTRunStatus run_status = CTRunGetStatus (run);
       status_or  |= run_status;
-      status_and &= run_status;
       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
       CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
@@ -1140,21 +1139,6 @@ resize_and_retry:
       buffer->len += num_glyphs;
     }
 
-    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
-     * or if it does, it doesn't respect it.  So we get runs with wrong
-     * directions.  As such, disable the assert...  It wouldn't crash, but
-     * cursoring will be off...
-     *
-     * https://crbug.com/419769
-     */
-    if (false)
-    {
-      /* Make sure all runs had the expected direction. */
-      HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
-      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
-    }
-
     buffer->clear_positions ();
 
     unsigned int count = buffer->len;

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

@@ -382,6 +382,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
+
   return (-v + (1<<9)) >> 10;
 }
 #endif

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

@@ -714,7 +714,7 @@ struct CmapSubtableLongSegmented
       if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
 	end = start + (hb_codepoint_t) num_glyphs - gid;
 
-      out->add_range (start, end);
+      out->add_range (start, hb_min (end, 0x10FFFFu));
     }
   }
 
@@ -883,7 +883,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
       hb_codepoint_t first = arrayZ[i].startUnicodeValue;
       hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
 				    (hb_codepoint_t) HB_UNICODE_MAX);
-      out->add_range (first, last);
+      out->add_range (first, hb_min (last, 0x10FFFFu));
     }
   }
 

+ 31 - 7
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -131,11 +131,25 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
 
-  for (unsigned int i = 0; i < count; i++)
+  if (vmtx.has_data ())
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
+  else
   {
-    *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
-    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    hb_font_extents_t font_extents;
+    font->get_h_extents_with_fallback (&font_extents);
+    hb_position_t advance = -(font_extents.ascender - font_extents.descender);
+
+    for (unsigned int i = 0; i < count; i++)
+    {
+      *first_advance = advance;
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+    }
   }
 }
 #endif
@@ -163,9 +177,19 @@ 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))
   {
-    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
-    *y = extents.y_bearing + font->em_scale_y (tsb);
+    if (ot_face->vmtx->has_data ())
+    {
+      const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+      hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
+      *y = extents.y_bearing + font->em_scale_y (tsb);
+      return true;
+    }
+
+    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;
+    *y = extents.y_bearing + (diff >> 1);
     return true;
   }
 

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

@@ -820,8 +820,7 @@ struct glyf
       }
 
 #ifndef HB_NO_VAR
-      if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
-	return false;
+      glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
 #endif
 
       switch (type) {

+ 4 - 3
thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh

@@ -170,13 +170,12 @@ struct hmtxvmtx
   {
     friend struct hmtxvmtx;
 
-    accelerator_t (hb_face_t *face,
-		   unsigned int default_advance_ = 0)
+    accelerator_t (hb_face_t *face)
     {
       table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
       var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
 
-      default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
+      default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
 
       /* Populate count variables and sort them out as we go */
 
@@ -220,6 +219,8 @@ struct hmtxvmtx
       var_table.destroy ();
     }
 
+    bool has_data () const { return (bool) num_bearings; }
+
     int get_side_bearing (hb_codepoint_t glyph) const
     {
       if (glyph < num_long_metrics)

+ 23 - 38
thirdparty/harfbuzz/src/hb-ot-layout-common.hh

@@ -37,7 +37,7 @@
 
 
 #ifndef HB_MAX_NESTING_LEVEL
-#define HB_MAX_NESTING_LEVEL	6
+#define HB_MAX_NESTING_LEVEL	64
 #endif
 #ifndef HB_MAX_CONTEXT_LENGTH
 #define HB_MAX_CONTEXT_LENGTH	64
@@ -60,6 +60,10 @@
 #define HB_MAX_LANGSYS	2000
 #endif
 
+#ifndef HB_MAX_LANGSYS_FEATURE_COUNT
+#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
+#endif
+
 #ifndef HB_MAX_FEATURES
 #define HB_MAX_FEATURES 750
 #endif
@@ -105,34 +109,15 @@ struct hb_prune_langsys_context_t
       script_langsys_map (script_langsys_map_),
       duplicate_feature_map (duplicate_feature_map_),
       new_feature_indexes (new_collected_feature_indexes_),
-      script_count (0),langsys_count (0) {}
+      script_count (0),langsys_feature_count (0) {}
 
-  bool visitedScript (const void *s)
-  {
-    if (script_count++ > HB_MAX_SCRIPTS)
-      return true;
-
-    return visited (s, visited_script);
-  }
+  bool visitScript ()
+  { return script_count++ < HB_MAX_SCRIPTS; }
 
-  bool visitedLangsys (const void *l)
+  bool visitLangsys (unsigned feature_count)
   {
-    if (langsys_count++ > HB_MAX_LANGSYS)
-      return true;
-
-    return visited (l, visited_langsys);
-  }
-
-  private:
-  template <typename T>
-  bool visited (const T *p, hb_set_t &visited_set)
-  {
-    hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
-    if (visited_set.in_error () || visited_set.has (delta))
-      return true;
-
-    visited_set.add (delta);
-    return false;
+    langsys_feature_count += feature_count;
+    return langsys_feature_count < HB_MAX_LANGSYS_FEATURE_COUNT;
   }
 
   public:
@@ -142,10 +127,8 @@ struct hb_prune_langsys_context_t
   hb_set_t           *new_feature_indexes;
 
   private:
-  hb_set_t visited_script;
-  hb_set_t visited_langsys;
   unsigned script_count;
-  unsigned langsys_count;
+  unsigned langsys_feature_count;
 };
 
 struct hb_subset_layout_context_t :
@@ -643,11 +626,14 @@ struct LangSys
     | hb_map (feature_index_map)
     ;
 
-    if (iter.len () != o_iter.len ())
-      return false;
+    for (; iter && o_iter; iter++, o_iter++)
+    {
+      unsigned a = *iter;
+      unsigned b = *o_iter;
+      if (a != b) return false;
+    }
 
-    for (const auto _ : + hb_zip (iter, o_iter))
-      if (_.first != _.second) return false;
+    if (iter || o_iter) return false;
 
     return true;
   }
@@ -732,7 +718,7 @@ struct Script
                       unsigned script_index) const
   {
     if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
-    if (c->visitedScript (this)) return;
+    if (!c->visitScript ()) return;
 
     if (!c->script_langsys_map->has (script_index))
     {
@@ -749,15 +735,14 @@ struct Script
     {
       //only collect features from non-redundant langsys
       const LangSys& d = get_default_lang_sys ();
-      if (!c->visitedLangsys (&d)) {
+      if (c->visitLangsys (d.get_feature_count ())) {
         d.collect_features (c);
       }
 
       for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
       {
-
         const LangSys& l = this+_.first.offset;
-        if (c->visitedLangsys (&l)) continue;
+        if (!c->visitLangsys (l.get_feature_count ())) continue;
         if (l.compare (d, c->duplicate_feature_map)) continue;
 
         l.collect_features (c);
@@ -769,7 +754,7 @@ struct Script
       for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
       {
         const LangSys& l = this+_.first.offset;
-        if (c->visitedLangsys (&l)) continue;
+        if (!c->visitLangsys (l.get_feature_count ())) continue;
         l.collect_features (c);
         c->script_langsys_map->get (script_index)->add (_.second);
       }

+ 4 - 1717
thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh

@@ -29,1727 +29,14 @@
 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
 #define HB_OT_LAYOUT_GSUB_TABLE_HH
 
-#include "hb-ot-layout-gsubgpos.hh"
-
+#include "OT/Layout/GSUB/GSUB.hh"
 
 namespace OT {
 
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
-template<typename Iterator>
-static void SingleSubst_serialize (hb_serialize_context_t *c,
-				   Iterator it);
-
-
-struct SingleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    unsigned d = deltaGlyphID;
-
-    + hb_iter (this+coverage)
-    | hb_filter (c->parent_active_glyphs ())
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
-    | hb_sink (c->output)
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned d = deltaGlyphID;
-    + hb_iter (this+coverage)
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
-    | hb_sink (c->output)
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    /* According to the Adobe Annotated OpenType Suite, result is always
-     * limited to 16bit. */
-    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
-    c->replace_glyph (glyph_id);
-
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  Iterator glyphs,
-		  unsigned delta)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
-    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    hb_codepoint_t delta = deltaGlyphID;
-
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
-				return hb_codepoint_pair_t (g,
-							    (g + delta) & 0xFFFF); })
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
-			      { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    bool ret = bool (it);
-    SingleSubst_serialize (c->serializer, it);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of Substitution table */
-  HBUINT16	deltaGlyphID;		/* Add to original GlyphID to get
-					 * substitute GlyphID, modulo 0x10000 */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-struct SingleSubstFormat2
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, substitute)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    if (unlikely (index >= substitute.len)) return_trace (false);
-
-    c->replace_glyph (substitute[index]);
-
-    return_trace (true);
-  }
-
-  template<typename Iterator,
-	   hb_requires (hb_is_sorted_source_of (Iterator,
-						hb_codepoint_pair_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  Iterator it)
-  {
-    TRACE_SERIALIZE (this);
-    auto substitutes =
-      + it
-      | hb_map (hb_second)
-      ;
-    auto glyphs =
-      + it
-      | hb_map_retains_sorting (hb_first)
-      ;
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
-    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
-			      { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    bool ret = bool (it);
-    SingleSubst_serialize (c->serializer, it);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 2 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of Substitution table */
-  Array16Of<HBGlyphID16>
-		substitute;		/* Array of substitute
-					 * GlyphIDs--ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, substitute);
-};
-
-struct SingleSubst
-{
-
-  template<typename Iterator,
-	   hb_requires (hb_is_sorted_source_of (Iterator,
-						const hb_codepoint_pair_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  Iterator glyphs)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned format = 2;
-    unsigned delta = 0;
-    if (glyphs)
-    {
-      format = 1;
-      auto get_delta = [=] (hb_codepoint_pair_t _)
-		       { return (unsigned) (_.second - _.first) & 0xFFFF; };
-      delta = get_delta (*glyphs);
-      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
-    }
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c,
-					       + glyphs
-					       | hb_map_retains_sorting (hb_first),
-					       delta));
-    case 2: return_trace (u.format2.serialize (c, glyphs));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  SingleSubstFormat1	format1;
-  SingleSubstFormat2	format2;
-  } u;
-};
-
-template<typename Iterator>
-static void
-SingleSubst_serialize (hb_serialize_context_t *c,
-		       Iterator it)
-{ c->start_embed<SingleSubst> ()->serialize (c, it); }
-
-struct Sequence
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_all (substitute, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  { c->output->add_array (substitute.arrayZ, substitute.len); }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { c->output->add_array (substitute.arrayZ, substitute.len); }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int count = substitute.len;
-
-    /* Special-case to make it in-place and not consider this
-     * as a "multiplied" substitution. */
-    if (unlikely (count == 1))
-    {
-      c->replace_glyph (substitute.arrayZ[0]);
-      return_trace (true);
-    }
-    /* Spec disallows this, but Uniscribe allows it.
-     * https://github.com/harfbuzz/harfbuzz/issues/253 */
-    else if (unlikely (count == 0))
-    {
-      c->buffer->delete_glyph ();
-      return_trace (true);
-    }
-
-    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
-			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
-    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
-
-    for (unsigned int i = 0; i < count; i++)
-    {
-      /* If is attached to a ligature, don't disturb that.
-       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
-      if (!lig_id)
-	_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
-      c->output_glyph_for_component (substitute.arrayZ[i], klass);
-    }
-    c->buffer->skip_glyph ();
-
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  Iterator subst)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (substitute.serialize (c, subst));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    if (!intersects (&glyphset)) return_trace (false);
-
-    auto it =
-    + hb_iter (substitute)
-    | hb_map (glyph_map)
-    ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer, it));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (substitute.sanitize (c));
-  }
-
-  protected:
-  Array16Of<HBGlyphID16>
-		substitute;		/* String of GlyphIDs to substitute */
-  public:
-  DEFINE_SIZE_ARRAY (2, substitute);
-};
-
-struct MultipleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return true; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, sequence)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, sequence)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    return_trace ((this+sequence[index]).apply (c));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> glyphs,
-		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
-    for (unsigned int i = 0; i < glyphs.length; i++)
-    {
-      unsigned int substitute_len = substitute_len_list[i];
-      if (unlikely (!sequence[i]
-                        .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
-	return_trace (false);
-      substitute_glyphs_list += substitute_len;
-    }
-    return_trace (coverage.serialize_serialize (c, glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, sequence)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of Substitution table */
-  Array16OfOffset16To<Sequence>
-		sequence;		/* Array of Sequence tables
-					 * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, sequence);
-};
-
-struct MultipleSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> glyphs,
-		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  MultipleSubstFormat1	format1;
-  } u;
-};
-
-struct AlternateSet
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_any (alternates, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  { c->output->add_array (alternates.arrayZ, alternates.len); }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { c->output->add_array (alternates.arrayZ, alternates.len); }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int count = alternates.len;
-
-    if (unlikely (!count)) return_trace (false);
-
-    hb_mask_t glyph_mask = c->buffer->cur().mask;
-    hb_mask_t lookup_mask = c->lookup_mask;
-
-    /* Note: This breaks badly if two features enabled this lookup together. */
-    unsigned int shift = hb_ctz (lookup_mask);
-    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
-
-    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
-    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
-    {
-      /* Maybe we can do better than unsafe-to-break all; but since we are
-       * changing random state, it would be hard to track that.  Good 'nough. */
-      c->buffer->unsafe_to_break (0, c->buffer->len);
-      alt_index = c->random_number () % count + 1;
-    }
-
-    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
-
-    c->replace_glyph (alternates[alt_index - 1]);
-
-    return_trace (true);
-  }
-
-  unsigned
-  get_alternates (unsigned        start_offset,
-		  unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
-		  hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
-  {
-    if (alternates.len && alternate_count)
-    {
-      + alternates.sub_array (start_offset, alternate_count)
-      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
-      ;
-    }
-    return alternates.len;
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  Iterator alts)
-  {
-    TRACE_SERIALIZE (this);
-    return_trace (alternates.serialize (c, alts));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto it =
-      + hb_iter (alternates)
-      | hb_filter (glyphset)
-      | hb_map (glyph_map)
-      ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer, it) &&
-		  out->alternates);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (alternates.sanitize (c));
-  }
-
-  protected:
-  Array16Of<HBGlyphID16>
-		alternates;		/* Array of alternate GlyphIDs--in
-					 * arbitrary order */
-  public:
-  DEFINE_SIZE_ARRAY (2, alternates);
-};
-
-struct AlternateSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return (this+coverage).intersects (glyphs); }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, alternateSet)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    + hb_zip (this+coverage, alternateSet)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  unsigned
-  get_glyph_alternates (hb_codepoint_t  gid,
-			unsigned        start_offset,
-			unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
-			hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
-  { return (this+alternateSet[(this+coverage).get_coverage (gid)])
-	   .get_alternates (start_offset, alternate_count, alternate_glyphs); }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    return_trace ((this+alternateSet[index]).apply (c));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> glyphs,
-		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
-    for (unsigned int i = 0; i < glyphs.length; i++)
-    {
-      unsigned int alternate_len = alternate_len_list[i];
-      if (unlikely (!alternateSet[i]
-                        .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
-	return_trace (false);
-      alternate_glyphs_list += alternate_len;
-    }
-    return_trace (coverage.serialize_serialize (c, glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
-    + hb_zip (this+coverage, alternateSet)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
-    | hb_map (hb_first)
-    | hb_map (glyph_map)
-    | hb_sink (new_coverage)
-    ;
-    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of Substitution table */
-  Array16OfOffset16To<AlternateSet>
-		alternateSet;		/* Array of AlternateSet tables
-					 * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, alternateSet);
-};
-
-struct AlternateSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> glyphs,
-		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  AlternateSubstFormat1	format1;
-  } u;
-};
-
-
-struct Ligature
-{
-  bool intersects (const hb_set_t *glyphs) const
-  { return hb_all (component, glyphs); }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    if (!intersects (c->glyphs)) return;
-    c->output->add (ligGlyph);
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    c->input->add_array (component.arrayZ, component.get_length ());
-    c->output->add (ligGlyph);
-  }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    if (c->len != component.lenP1)
-      return false;
-
-    for (unsigned int i = 1; i < c->len; i++)
-      if (likely (c->glyphs[i] != component[i]))
-	return false;
-
-    return true;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int count = component.lenP1;
-
-    if (unlikely (!count)) return_trace (false);
-
-    /* Special-case to make it in-place and not consider this
-     * as a "ligated" substitution. */
-    if (unlikely (count == 1))
-    {
-      c->replace_glyph (ligGlyph);
-      return_trace (true);
-    }
-
-    unsigned int total_component_count = 0;
-
-    unsigned int match_end = 0;
-    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
-
-    if (likely (!match_input (c, count,
-			      &component[1],
-			      match_glyph,
-			      nullptr,
-			      &match_end,
-			      match_positions,
-			      &total_component_count)))
-    {
-      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
-      return_trace (false);
-    }
-
-    ligate_input (c,
-		  count,
-		  match_positions,
-		  match_end,
-		  ligGlyph,
-		  total_component_count);
-
-    return_trace (true);
-  }
-
-  template <typename Iterator,
-	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
-  bool serialize (hb_serialize_context_t *c,
-		  hb_codepoint_t ligature,
-		  Iterator components /* Starting from second */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    ligGlyph = ligature;
-    if (unlikely (!component.serialize (c, components))) return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
-    // Ensure Coverage table is always packed after this.
-    c->serializer->add_virtual_link (coverage_idx);
-
-    auto it =
-      + hb_iter (component)
-      | hb_map (glyph_map)
-      ;
-
-    auto *out = c->serializer->start_embed (*this);
-    return_trace (out->serialize (c->serializer,
-				  glyph_map[ligGlyph],
-				  it));
-  }
-
-  public:
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
-  }
-
-  protected:
-  HBGlyphID16	ligGlyph;		/* GlyphID of ligature to substitute */
-  HeadlessArrayOf<HBGlyphID16>
-		component;		/* Array of component GlyphIDs--start
-					 * with the second  component--ordered
-					 * in writing direction */
-  public:
-  DEFINE_SIZE_ARRAY (4, component);
-};
-
-struct LigatureSet
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
-    | hb_any
-    ;
-  }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
-    ;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    return
-    + hb_iter (ligature)
-    | hb_map (hb_add (this))
-    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
-    | hb_any
-    ;
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-    {
-      const Ligature &lig = this+ligature[i];
-      if (lig.apply (c)) return_trace (true);
-    }
-
-    return_trace (false);
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const HBGlyphID16> ligatures,
-		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
-    for (unsigned int i = 0; i < ligatures.length; i++)
-    {
-      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
-      if (unlikely (!ligature[i].serialize_serialize (c,
-                                                      ligatures[i],
-                                                      component_list.sub_array (0, component_count))))
-	return_trace (false);
-      component_list += component_count;
-    }
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    + hb_iter (ligature)
-    | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
-    | hb_drain
-    ;
-
-    if (bool (out->ligature))
-      // Ensure Coverage table is always packed after this.
-      c->serializer->add_virtual_link (coverage_idx);
-
-    return_trace (bool (out->ligature));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (ligature.sanitize (c, this));
-  }
-
-  protected:
-  Array16OfOffset16To<Ligature>
-		ligature;		/* Array LigatureSet tables
-					 * ordered by preference */
-  public:
-  DEFINE_SIZE_ARRAY (2, ligature);
-};
-
-struct LigatureSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    return
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (*glyphs, hb_first)
-    | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
-	      { return (this+_).intersects (glyphs); })
-    | hb_any
-    ;
-  }
-
-  bool may_have_non_1to1 () const
-  { return true; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
-    ;
-
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_map (hb_second)
-    | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
-    ;
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  {
-    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
-    if (likely (index == NOT_COVERED)) return false;
-
-    const LigatureSet &lig_set = this+ligatureSet[index];
-    return lig_set.would_apply (c);
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    const LigatureSet &lig_set = this+ligatureSet[index];
-    return_trace (lig_set.apply (c));
-  }
-
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const HBGlyphID16> ligatures_list,
-		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (this))) return_trace (false);
-    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
-    for (unsigned int i = 0; i < first_glyphs.length; i++)
-    {
-      unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
-      if (unlikely (!ligatureSet[i]
-                        .serialize_serialize (c,
-                                              ligatures_list.sub_array (0, ligature_count),
-                                              component_count_list.sub_array (0, ligature_count),
-                                              component_list))) return_trace (false);
-      ligatures_list += ligature_count;
-      component_count_list += ligature_count;
-    }
-    return_trace (coverage.serialize_serialize (c, first_glyphs));
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->format = format;
-
-    // Due to a bug in some older versions of windows 7 the Coverage table must be
-    // packed after the LigatureSet and Ligature tables, so serialize Coverage first
-    // which places it last in the packed order.
-    hb_set_t new_coverage;
-    + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
-    | hb_filter (glyphset, hb_first)
-    | hb_filter ([&] (const LigatureSet& _) {
-      return _.intersects (&glyphset);
-    }, hb_second)
-    | hb_map (hb_first)
-    | hb_sink (new_coverage);
-
-    if (!c->serializer->push<Coverage> ()
-        ->serialize (c->serializer,
-                     + new_coverage.iter () | hb_map_retains_sorting (glyph_map)))
-    {
-      c->serializer->pop_discard ();
-      return_trace (false);
-    }
-
-    unsigned coverage_idx = c->serializer->pop_pack ();
-     c->serializer->add_link (out->coverage, coverage_idx);
-
-    + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (new_coverage, hb_first)
-    | hb_map (hb_second)
-    // to ensure that the repacker always orders the coverage table after the LigatureSet
-    // and LigatureSubtable's they will be linked to the Coverage table via a virtual link
-    // the coverage table object idx is passed down to facilitate this.
-    | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx))
-    ;
-
-    return_trace (bool (new_coverage));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of Substitution table */
-  Array16OfOffset16To<LigatureSet>
-		ligatureSet;		/* Array LigatureSet tables
-					 * ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_ARRAY (6, ligatureSet);
-};
-
-struct LigatureSubst
-{
-  bool serialize (hb_serialize_context_t *c,
-		  hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const HBGlyphID16> ligatures_list,
-		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 1;
-    u.format = format;
-    switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c,
-					       first_glyphs,
-					       ligature_per_first_glyph_count_list,
-					       ligatures_list,
-					       component_count_list,
-					       component_list));
-    default:return_trace (false);
-    }
-  }
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16		format;		/* Format identifier */
-  LigatureSubstFormat1	format1;
-  } u;
-};
-
-
-struct ContextSubst : Context {};
-
-struct ChainContextSubst : ChainContext {};
-
-struct ExtensionSubst : Extension<ExtensionSubst>
-{
-  typedef struct SubstLookupSubTable SubTable;
-  bool is_reverse () const;
-};
-
-
-struct ReverseChainSingleSubstFormat1
-{
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    if (!(this+coverage).intersects (glyphs))
-      return false;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-
-    unsigned int count;
-
-    count = backtrack.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+backtrack[i]).intersects (glyphs))
-	return false;
-
-    count = lookahead.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+lookahead[i]).intersects (glyphs))
-	return false;
-
-    return true;
-  }
-
-  bool may_have_non_1to1 () const
-  { return false; }
-
-  void closure (hb_closure_context_t *c) const
-  {
-    if (!intersects (c->glyphs)) return;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (c->parent_active_glyphs (), hb_first)
-    | hb_map (hb_second)
-    | hb_sink (c->output)
-    ;
-  }
-
-  void closure_lookups (hb_closure_lookups_context_t *c) const {}
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-
-    unsigned int count;
-
-    count = backtrack.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    count = lookahead.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
-
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-    count = substitute.len;
-    c->output->add_array (substitute.arrayZ, substitute.len);
-  }
-
-  const Coverage &get_coverage () const { return this+coverage; }
-
-  bool would_apply (hb_would_apply_context_t *c) const
-  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
-      return_trace (false); /* No chaining to this type */
-
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
-    if (likely (index == NOT_COVERED)) return_trace (false);
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    if (unlikely (index >= substitute.len)) return_trace (false);
-
-    unsigned int start_index = 0, end_index = 0;
-    if (match_backtrack (c,
-			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
-			 match_coverage, this,
-			 &start_index) &&
-	match_lookahead (c,
-			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
-			 match_coverage, this,
-			 c->buffer->idx + 1, &end_index))
-    {
-      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
-      c->replace_glyph_inplace (substitute[index]);
-      /* Note: We DON'T decrease buffer->idx.  The main loop does it
-       * for us.  This is useful for preventing surprises if someone
-       * calls us through a Context lookup. */
-      return_trace (true);
-    }
-    else
-    {
-      c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
-      return_trace (false);
-    }
-  }
-
-  template<typename Iterator,
-           hb_requires (hb_is_iterator (Iterator))>
-  bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
-
-    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
-      return_trace (false);
-
-    for (auto& offset : it) {
-      auto *o = out->serialize_append (c->serializer);
-      if (unlikely (!o) || !o->serialize_subset (c, offset, this))
-        return_trace (false);
-    }
-
-    return_trace (true);
-  }
-
-  template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
-           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
-           hb_requires (hb_is_iterator (BacktrackIterator)),
-           hb_requires (hb_is_iterator (LookaheadIterator))>
-  bool serialize (hb_subset_context_t *c,
-                  Iterator coverage_subst_iter,
-                  BacktrackIterator backtrack_iter,
-                  LookaheadIterator lookahead_iter) const
-  {
-    TRACE_SERIALIZE (this);
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->check_success (out))) return_trace (false);
-    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
-    if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
-
-    if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
-    if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
-
-    auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
-    auto substitutes =
-    + coverage_subst_iter
-    | hb_map (hb_second)
-    ;
-
-    auto glyphs =
-    + coverage_subst_iter
-    | hb_map_retains_sorting (hb_first)
-    ;
-    if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
-        return_trace (false);
-
-    if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
-      return_trace (false);
-    return_trace (true);
-  }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-
-    auto it =
-    + hb_zip (this+coverage, substitute)
-    | hb_filter (glyphset, hb_first)
-    | hb_filter (glyphset, hb_second)
-    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
-                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
-    ;
-
-    return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
-      return_trace (false);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    if (!lookahead.sanitize (c, this))
-      return_trace (false);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
-    return_trace (substitute.sanitize (c));
-  }
-
-  protected:
-  HBUINT16	format;			/* Format identifier--format = 1 */
-  Offset16To<Coverage>
-		coverage;		/* Offset to Coverage table--from
-					 * beginning of table */
-  Array16OfOffset16To<Coverage>
-		backtrack;		/* Array of coverage tables
-					 * in backtracking sequence, in glyph
-					 * sequence order */
-  Array16OfOffset16To<Coverage>
-		lookaheadX;		/* Array of coverage tables
-					 * in lookahead sequence, in glyph
-					 * sequence order */
-  Array16Of<HBGlyphID16>
-		substituteX;		/* Array of substitute
-					 * GlyphIDs--ordered by Coverage Index */
-  public:
-  DEFINE_SIZE_MIN (10);
-};
-
-struct ReverseChainSingleSubst
-{
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
-    switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
-    default:return_trace (c->default_return_value ());
-    }
-  }
-
-  protected:
-  union {
-  HBUINT16				format;		/* Format identifier */
-  ReverseChainSingleSubstFormat1	format1;
-  } u;
-};
-
-
-
-/*
- * SubstLookup
- */
-
-struct SubstLookupSubTable
-{
-  friend struct Lookup;
-  friend struct SubstLookup;
-
-  enum Type {
-    Single		= 1,
-    Multiple		= 2,
-    Alternate		= 3,
-    Ligature		= 4,
-    Context		= 5,
-    ChainContext	= 6,
-    Extension		= 7,
-    ReverseChainSingle	= 8
-  };
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
-  {
-    TRACE_DISPATCH (this, lookup_type);
-    switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
-    case Multiple:		return_trace (u.multiple.dispatch (c, std::forward<Ts> (ds)...));
-    case Alternate:		return_trace (u.alternate.dispatch (c, std::forward<Ts> (ds)...));
-    case Ligature:		return_trace (u.ligature.dispatch (c, std::forward<Ts> (ds)...));
-    case Context:		return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
-    case Extension:		return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
-    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c, std::forward<Ts> (ds)...));
-    default:			return_trace (c->default_return_value ());
-    }
-  }
-
-  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c, lookup_type);
-  }
-
-  protected:
-  union {
-  SingleSubst			single;
-  MultipleSubst			multiple;
-  AlternateSubst		alternate;
-  LigatureSubst			ligature;
-  ContextSubst			context;
-  ChainContextSubst		chainContext;
-  ExtensionSubst		extension;
-  ReverseChainSingleSubst	reverseChainContextSingle;
-  } u;
-  public:
-  DEFINE_SIZE_MIN (0);
-};
-
-
-struct SubstLookup : Lookup
-{
-  typedef SubstLookupSubTable SubTable;
-
-  const SubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<SubTable> (i); }
-
-  static inline bool lookup_type_is_reverse (unsigned int lookup_type)
-  { return lookup_type == SubTable::ReverseChainSingle; }
-
-  bool is_reverse () const
-  {
-    unsigned int type = get_type ();
-    if (unlikely (type == SubTable::Extension))
-      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
-    return lookup_type_is_reverse (type);
-  }
-
-  bool may_have_non_1to1 () const
-  {
-    hb_have_non_1to1_context_t c;
-    return dispatch (&c);
-  }
-
-  bool apply (hb_ot_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    return_trace (dispatch (c));
-  }
-
-  bool intersects (const hb_set_t *glyphs) const
-  {
-    hb_intersects_context_t c (glyphs);
-    return dispatch (&c);
-  }
-
-  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
-  {
-    if (!c->should_visit_lookup (this_index))
-      return hb_closure_context_t::default_return_value ();
-
-    c->set_recurse_func (dispatch_closure_recurse_func);
-
-    hb_closure_context_t::return_t ret = dispatch (c);
-
-    c->flush ();
-
-    return ret;
-  }
-
-  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
-  {
-    if (c->is_lookup_visited (this_index))
-      return hb_closure_lookups_context_t::default_return_value ();
-
-    c->set_lookup_visited (this_index);
-    if (!intersects (c->glyphs))
-    {
-      c->set_lookup_inactive (this_index);
-      return hb_closure_lookups_context_t::default_return_value ();
-    }
-
-    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
-
-    hb_closure_lookups_context_t::return_t ret = dispatch (c);
-    return ret;
-  }
-
-  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
-    return dispatch (c);
-  }
-
-  template <typename set_t>
-  void collect_coverage (set_t *glyphs) const
-  {
-    hb_collect_coverage_context_t<set_t> c (glyphs);
-    dispatch (&c);
-  }
-
-  bool would_apply (hb_would_apply_context_t *c,
-		    const hb_ot_layout_lookup_accelerator_t *accel) const
-  {
-    if (unlikely (!c->len)) return false;
-    if (!accel->may_have (c->glyphs[0])) return false;
-      return dispatch (c);
-  }
-
-  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
-
-  bool serialize_single (hb_serialize_context_t *c,
-			 uint32_t lookup_props,
-			 hb_sorted_array_t<const HBGlyphID16> glyphs,
-			 hb_array_t<const HBGlyphID16> substitutes)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_multiple (hb_serialize_context_t *c,
-			   uint32_t lookup_props,
-			   hb_sorted_array_t<const HBGlyphID16> glyphs,
-			   hb_array_t<const unsigned int> substitute_len_list,
-			   hb_array_t<const HBGlyphID16> substitute_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.multiple.
-        serialize (c,
-                   glyphs,
-                   substitute_len_list,
-                   substitute_glyphs_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_alternate (hb_serialize_context_t *c,
-			    uint32_t lookup_props,
-			    hb_sorted_array_t<const HBGlyphID16> glyphs,
-			    hb_array_t<const unsigned int> alternate_len_list,
-			    hb_array_t<const HBGlyphID16> alternate_glyphs_list)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-
-    if (c->push<SubTable> ()->u.alternate.
-        serialize (c,
-                   glyphs,
-                   alternate_len_list,
-                   alternate_glyphs_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  bool serialize_ligature (hb_serialize_context_t *c,
-			   uint32_t lookup_props,
-			   hb_sorted_array_t<const HBGlyphID16> first_glyphs,
-			   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-			   hb_array_t<const HBGlyphID16> ligatures_list,
-			   hb_array_t<const unsigned int> component_count_list,
-			   hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
-    if (c->push<SubTable> ()->u.ligature.
-        serialize (c,
-                   first_glyphs,
-                   ligature_per_first_glyph_count_list,
-                   ligatures_list,
-                   component_count_list,
-                   component_list))
-    {
-      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
-      return_trace (true);
-    }
-    c->pop_discard ();
-    return_trace (false);
-  }
-
-  template <typename context_t>
-  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
-
-  static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
-
-  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
-  {
-    if (!c->should_visit_lookup (lookup_index))
-      return hb_empty_t ();
-
-    hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
-
-    /* While in theory we should flush here, it will cause timeouts because a recursive
-     * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
-     * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
-    //c->flush ();
-
-    return ret;
-  }
-
-  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
-
-  template <typename context_t, typename ...Ts>
-  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
-  { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
-
-  bool subset (hb_subset_context_t *c) const
-  { return Lookup::subset<SubTable> (c); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return Lookup::sanitize<SubTable> (c); }
-};
-
-/*
- * GSUB -- Glyph Substitution
- * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
- */
-
-struct GSUB : GSUBGPOS
-{
-  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
-
-  const SubstLookup& get_lookup (unsigned int i) const
-  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
-
-  bool subset (hb_subset_context_t *c) const
-  {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
-    return GSUBGPOS::subset<SubstLookup> (&l);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<SubstLookup> (c); }
-
-  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
-				   hb_face_t *face) const;
-
-  void closure_lookups (hb_face_t      *face,
-			const hb_set_t *glyphs,
-			hb_set_t       *lookup_indexes /* IN/OUT */) const
-  { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
-
-  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
-};
-
-
-struct GSUB_accelerator_t : GSUB::accelerator_t {
-  GSUB_accelerator_t (hb_face_t *face) : GSUB::accelerator_t (face) {}
-};
-
+using Layout::GSUB::SubstLookup;
+using Layout::GSUB::ExtensionSubst;
 
+// TODO(garretrieger): Move into the new layout directory.
 /* Out-of-class implementation for methods recursing */
 
 #ifndef HB_NO_OT_LAYOUT

+ 27 - 14
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh

@@ -408,12 +408,11 @@ struct hb_ot_apply_context_t :
   {
     matcher_t () :
 	     lookup_props (0),
+	     mask (-1),
 	     ignore_zwnj (false),
 	     ignore_zwj (false),
-	     mask (-1),
-#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
-	     syllable arg1(0),
-#undef arg1
+	     per_syllable (false),
+	     syllable {0},
 	     match_func (nullptr),
 	     match_data (nullptr) {}
 
@@ -423,7 +422,8 @@ struct hb_ot_apply_context_t :
     void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
     void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     void set_mask (hb_mask_t mask_) { mask = mask_; }
-    void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
+    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_; }
@@ -469,9 +469,10 @@ struct hb_ot_apply_context_t :
 
     protected:
     unsigned int lookup_props;
+    hb_mask_t mask;
     bool ignore_zwnj;
     bool ignore_zwj;
-    hb_mask_t mask;
+    bool per_syllable;
     uint8_t syllable;
     match_func_t match_func;
     const void *match_data;
@@ -490,6 +491,7 @@ struct hb_ot_apply_context_t :
       /* Ignore ZWJ if we are matching context, or asked to. */
       matcher.set_ignore_zwj  (context_match || c->auto_zwj);
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
+      matcher.set_per_syllable (c->per_syllable);
     }
     void set_lookup_props (unsigned int lookup_props)
     {
@@ -636,6 +638,7 @@ struct hb_ot_apply_context_t :
   bool has_glyph_classes;
   bool auto_zwnj;
   bool auto_zwj;
+  bool per_syllable;
   bool random;
 
   uint32_t random_state;
@@ -664,6 +667,7 @@ struct hb_ot_apply_context_t :
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			auto_zwnj (true),
 			auto_zwj (true),
+			per_syllable (false),
 			random (false),
 			random_state (1) { init_iters (); }
 
@@ -676,6 +680,7 @@ struct hb_ot_apply_context_t :
   void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
   void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
   void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
+  void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
   void set_random (bool random_) { random = random_; }
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
@@ -1415,13 +1420,18 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
       continue;
 
+    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+
+    /* This can happen if earlier recursed lookups deleted many entries. */
+    if (unlikely (match_positions[idx] >= orig_len))
+      continue;
+
     if (unlikely (!buffer->move_to (match_positions[idx])))
       break;
 
     if (unlikely (buffer->max_ops <= 0))
       break;
 
-    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
     if (!c->recurse (lookupRecord[i].lookupListIndex))
       continue;
 
@@ -1457,15 +1467,18 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
      */
 
     end += delta;
-    if (end <= int (match_positions[idx]))
+    if (end < int (match_positions[idx]))
     {
       /* End might end up being smaller than match_positions[idx] if the recursed
-       * lookup ended up removing many items, more than we have had matched.
-       * Just never rewind end back and get out of here.
-       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
+       * lookup ended up removing many items.
+       * Just never rewind end beyond start of current position, since that is
+       * not possible in the recursed lookup.  Also adjust delta as such.
+       *
+       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
+       * https://github.com/harfbuzz/harfbuzz/issues/1611
+       */
+      delta += match_positions[idx] - end;
       end = match_positions[idx];
-      /* There can't be any further changes. */
-      break;
     }
 
     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@@ -1477,7 +1490,7 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     }
     else
     {
-      /* NOTE: delta is negative. */
+      /* NOTE: delta is non-positive. */
       delta = hb_max (delta, (int) next - (int) count);
       next -= delta;
     }

+ 68 - 63
thirdparty/harfbuzz/src/hb-ot-layout.cc

@@ -54,6 +54,8 @@
 #include "hb-aat-layout-morx-table.hh"
 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
+using OT::Layout::GSUB::GSUB;
+
 /**
  * SECTION:hb-ot-layout
  * @title: hb-ot-layout
@@ -389,7 +391,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t      *font,
  */
 
 bool
-OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
+GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face) const
 {
 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST
@@ -1006,7 +1008,7 @@ struct hb_collect_features_context_t
   hb_collect_features_context_t (hb_face_t *face,
 				 hb_tag_t   table_tag,
 				 hb_set_t  *feature_indices_,
-                                 const hb_tag_t *features)
+				 const hb_tag_t *features)
 
     : g (get_gsubgpos_table (face, table_tag)),
       feature_indices (feature_indices_),
@@ -1033,7 +1035,7 @@ struct hb_collect_features_context_t
     {
       hb_tag_t tag = g.get_feature_tag (i);
       if (features_set.has (tag))
-        feature_indices_filter.add(i);
+	feature_indices_filter.add(i);
     }
   }
 
@@ -1529,7 +1531,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
   hb_map_t done_lookups_glyph_count;
   hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
-  const OT::GSUB& gsub = *face->table.GSUB->table;
+  const GSUB& gsub = *face->table.GSUB->table;
 
   unsigned int iteration_count = 0;
   unsigned int glyphs_length;
@@ -1808,7 +1810,7 @@ struct GSUBProxy
     table (*face->table.GSUB->table),
     accels (face->table.GSUB->accels) {}
 
-  const OT::GSUB &table;
+  const GSUB &table;
   const OT::hb_ot_layout_lookup_accelerator_t *accels;
 };
 
@@ -1929,6 +1931,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
       c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
       c.set_random (lookups[table_index][i].random);
+      c.set_per_syllable (lookups[table_index][i].per_syllable);
 
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
@@ -2086,11 +2089,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
 					 hb_position_t               *coord /* OUT */)
 {
   if (hb_ot_layout_get_baseline (font,
-                                 baseline_tag,
-                                 direction,
-                                 script_tag,
-                                 language_tag,
-                                 coord))
+				 baseline_tag,
+				 direction,
+				 script_tag,
+				 language_tag,
+				 coord))
     return;
 
   /* Synthesize missing baselines.
@@ -2107,17 +2110,19 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
       hb_codepoint_t glyph;
       hb_glyph_extents_t extents;
       if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
-          (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
-           hb_font_get_nominal_glyph (font, '-', &glyph)) &&
-          hb_font_get_glyph_extents (font, glyph, &extents))
+	  (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
+	   hb_font_get_nominal_glyph (font, '-', &glyph)) &&
+	  hb_font_get_glyph_extents (font, glyph, &extents))
       {
-        *coord = extents.y_bearing + extents.height / 2;
+	*coord = extents.y_bearing + extents.height / 2;
       }
       else
       {
-        hb_position_t x_height = 0;
-        hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
-        *coord = x_height / 2;
+	hb_position_t x_height = font->y_scale / 2;
+#ifndef HB_NO_METRICS
+	hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
+#endif
+	*coord = x_height / 2;
       }
     }
     break;
@@ -2128,32 +2133,32 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
       hb_position_t embox_top, embox_bottom;
 
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &embox_top);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &embox_top);
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &embox_bottom);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &embox_bottom);
 
       if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
-        *coord = embox_top + (embox_bottom - embox_top) / 10;
+	*coord = embox_top + (embox_bottom - embox_top) / 10;
       else
-        *coord = embox_bottom + (embox_top - embox_bottom) / 10;
+	*coord = embox_bottom + (embox_top - embox_bottom) / 10;
     }
     break;
 
   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
     if (hb_ot_layout_get_baseline (font,
-                                   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
-                                   direction,
-                                   script_tag,
-                                   language_tag,
-                                   coord))
+				   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+				   direction,
+				   script_tag,
+				   language_tag,
+				   coord))
       *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
     else
     {
@@ -2165,11 +2170,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
 
   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
     if (hb_ot_layout_get_baseline (font,
-                                   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
-                                   direction,
-                                   script_tag,
-                                   language_tag,
-                                   coord))
+				   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+				   direction,
+				   script_tag,
+				   language_tag,
+				   coord))
       *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
     else
     {
@@ -2226,11 +2231,11 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
       }
 
       if (ch &&
-          hb_font_get_nominal_glyph (font, ch, &glyph) &&
-          hb_font_get_glyph_extents (font, glyph, &extents))
-        *coord = extents.y_bearing;
+	  hb_font_get_nominal_glyph (font, ch, &glyph) &&
+	  hb_font_get_glyph_extents (font, glyph, &extents))
+	*coord = extents.y_bearing;
       else
-        *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
+	*coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
     }
     else
       *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
@@ -2240,17 +2245,17 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
     {
       hb_position_t top, bottom;
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &top);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &top);
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &bottom);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &bottom);
       *coord = (top + bottom) / 2;
 
     }
@@ -2260,17 +2265,17 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
     {
       hb_position_t top, bottom;
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &top);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &top);
       hb_ot_layout_get_baseline_with_fallback (font,
-                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
-                                               direction,
-                                               script_tag,
-                                               language_tag,
-                                               &bottom);
+					       HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
+					       direction,
+					       script_tag,
+					       language_tag,
+					       &bottom);
       *coord = (top + bottom) / 2;
 
     }

+ 8 - 13
thirdparty/harfbuzz/src/hb-ot-layout.hh

@@ -108,13 +108,17 @@ hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
 
 namespace OT {
   struct hb_ot_apply_context_t;
-  struct SubstLookup;
   struct hb_ot_layout_lookup_accelerator_t;
+namespace Layout {
+namespace GSUB {
+  struct SubstLookup;
+}
+}
 }
 
 HB_INTERNAL void
 hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
-				const OT::SubstLookup &lookup,
+				const OT::Layout::GSUB::SubstLookup &lookup,
 				const OT::hb_ot_layout_lookup_accelerator_t &accel);
 
 
@@ -168,17 +172,6 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
   return start;
 }
 
-static inline void
-_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		     hb_font_t *font HB_UNUSED,
-		     hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 /* unicode_props */
 
@@ -485,6 +478,8 @@ static inline uint8_t
 _hb_allocate_lig_id (hb_buffer_t *buffer)
 {
   uint8_t lig_id = buffer->next_serial () & 0x07;
+  if (unlikely (!lig_id))
+    lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
   return lig_id;
 }
 

+ 6 - 2
thirdparty/harfbuzz/src/hb-ot-map.cc

@@ -117,7 +117,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
 				  hb_mask_t     mask,
 				  bool          auto_zwnj,
 				  bool          auto_zwj,
-				  bool          random)
+				  bool          random,
+				  bool          per_syllable)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -145,6 +146,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
       lookup->auto_zwnj = auto_zwnj;
       lookup->auto_zwj = auto_zwj;
       lookup->random = random;
+      lookup->per_syllable = per_syllable;
     }
 
     offset += len;
@@ -277,6 +279,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
     map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
     map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
     map->random = !!(info->flags & F_RANDOM);
+    map->per_syllable = !!(info->flags & F_PER_SYLLABLE);
     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = global_bit_shift;
@@ -319,7 +322,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
 		       m.features[i].mask,
 		       m.features[i].auto_zwnj,
 		       m.features[i].auto_zwj,
-		       m.features[i].random);
+		       m.features[i].random,
+		       m.features[i].per_syllable);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].length)

+ 6 - 2
thirdparty/harfbuzz/src/hb-ot-map.hh

@@ -56,6 +56,7 @@ struct hb_ot_map_t
     unsigned int auto_zwnj : 1;
     unsigned int auto_zwj : 1;
     unsigned int random : 1;
+    unsigned int per_syllable : 1;
 
     int cmp (const hb_tag_t tag_) const
     { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
@@ -66,6 +67,7 @@ struct hb_ot_map_t
     unsigned short auto_zwnj : 1;
     unsigned short auto_zwj : 1;
     unsigned short random : 1;
+    unsigned short per_syllable : 1;
     hb_mask_t mask;
 
     HB_INTERNAL static int cmp (const void *pa, const void *pb)
@@ -183,7 +185,8 @@ enum hb_ot_map_feature_flags_t
   F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
   F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
   F_GLOBAL_SEARCH	= 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
-  F_RANDOM		= 0x0020u  /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
+  F_RANDOM		= 0x0020u, /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
+  F_PER_SYLLABLE	= 0x0040u  /* Contain lookup application to within syllable. */
 };
 HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 
@@ -237,7 +240,8 @@ struct hb_ot_map_builder_t
 				hb_mask_t     mask,
 				bool          auto_zwnj = true,
 				bool          auto_zwj = true,
-				bool          random = false);
+				bool          random = false,
+				bool          per_syllable = false);
 
   struct feature_info_t {
     hb_tag_t tag;

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-metrics.cc

@@ -316,9 +316,9 @@ hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
     break;
 
   case HB_OT_METRICS_TAG_X_HEIGHT:
-    if (hb_font_get_nominal_glyph (font, 'o', &glyph) &&
+    if (hb_font_get_nominal_glyph (font, 'x', &glyph) &&
         hb_font_get_glyph_extents (font, glyph, &extents))
-      *position = extents.height + 2 * extents.y_bearing;
+      *position = extents.y_bearing;
     else
       *position = font->y_scale / 2;
     break;

+ 19 - 21
thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc

@@ -109,17 +109,17 @@ indic_features[] =
    * These features are applied in order, one at a time, after initial_reordering,
    * constrained to the syllable.
    */
-  {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('r','p','h','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('p','r','e','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('b','l','w','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('a','b','v','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('h','a','l','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('p','s','t','f'),        F_MANUAL_JOINERS},
-  {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
+  {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('r','p','h','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','r','e','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('h','a','l','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','f'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
   /*
    * Other features.
    * These features are applied all at once, after final_reordering, constrained
@@ -127,12 +127,12 @@ indic_features[] =
    * Default Bengali font in Windows for example has intermixed
    * lookups for init,pres,abvs,blws features.
    */
-  {HB_TAG('i','n','i','t'),        F_MANUAL_JOINERS},
-  {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
-  {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
+  {HB_TAG('i','n','i','t'),        F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS | F_PER_SYLLABLE},
 };
 
 /*
@@ -183,10 +183,10 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables_indic);
 
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
   /* The Indic specs do not require ccmp, but we apply it here since if
    * there is a use of it, it's typically at the beginning. */
-  map->enable_feature (HB_TAG('c','c','m','p'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
 
   unsigned int i = 0;
@@ -201,8 +201,6 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
 
   for (; i < INDIC_NUM_FEATURES; i++)
     map->add_feature (indic_features[i]);
-
-  map->add_gsub_pause (_hb_clear_syllables);
 }
 
 static void

+ 1 - 0
thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh

@@ -368,6 +368,7 @@ set_indic_properties (hb_glyph_info_t &info)
   else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
   else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
   else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
+  else if (unlikely (u == 0x0D04u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/3511 */
   else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
 				    cat = OT_PLACEHOLDER;
   else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;

+ 8 - 14
thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc

@@ -45,11 +45,11 @@ khmer_features[] =
    * These features are applied all at once, before reordering, constrained
    * to the syllable.
    */
-  {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
-  {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
-  {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
-  {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
-  {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
+  {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
+  {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS | F_PER_SYLLABLE},
   /*
    * Other features.
    * These features are applied all at once after clearing syllables.
@@ -107,16 +107,10 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
    *
    * https://github.com/harfbuzz/harfbuzz/issues/974
    */
-  map->enable_feature (HB_TAG('l','o','c','l'));
-  map->enable_feature (HB_TAG('c','c','m','p'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
-  unsigned int i = 0;
-  for (; i < KHMER_BASIC_FEATURES; i++)
-    map->add_feature (khmer_features[i]);
-
-  map->add_gsub_pause (_hb_clear_syllables);
-
-  for (; i < KHMER_NUM_FEATURES; i++)
+  for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++)
     map->add_feature (khmer_features[i]);
 }
 

+ 3 - 5
thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc

@@ -79,22 +79,20 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables_myanmar);
 
-  map->enable_feature (HB_TAG('l','o','c','l'));
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
   /* The Indic specs do not require ccmp, but we apply it here since if
    * there is a use of it, it's typically at the beginning. */
-  map->enable_feature (HB_TAG('c','c','m','p'));
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
 
 
   map->add_gsub_pause (reorder_myanmar);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
   {
-    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
     map->add_gsub_pause (nullptr);
   }
 
-  map->add_gsub_pause (_hb_clear_syllables);
-
   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
     map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
 }

文件差异内容过多而无法显示
+ 479 - 408
thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh


+ 14 - 14
thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh

@@ -53,7 +53,7 @@
 #define GB	USE(GB)	/* BASE_OTHER */
 #define H	USE(H)	/* HALANT */
 #define HN	USE(HN)	/* HALANT_NUM */
-#define HVM	USE(HVM)	/* HALANT_OR_VOWEL_MODIFIER */
+#define IS	USE(IS)	/* INVISIBLE_STACKER */
 #define J	USE(J)	/* HIEROGLYPH_JOINER */
 #define N	USE(N)	/* BASE_NUM */
 #define O	USE(O)	/* OTHER */
@@ -278,7 +278,7 @@ static const uint8_t use_table[] = {
   /* 1000 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VAbv,  VAbv,  VBlw,
-  /* 1030 */  VBlw,  VPre,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMBlw, VMPst,     H,  VAbv,  MPst,  MPre,  MBlw,  MBlw,     B,
+  /* 1030 */  VBlw,  VPre,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMBlw, VMPst,    IS,  VAbv,  MPst,  MPre,  MBlw,  MBlw,     B,
   /* 1040 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,     O,     O,    GB,     O,
   /* 1050 */     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VBlw,  VBlw,     B,     B,     B,     B,  MBlw,  MBlw,
   /* 1060 */  MBlw,     B,  VPst, VMPst, VMPst,     B,     B,  VPst,  VPst, VMPst, VMPst, VMPst, VMPst, VMPst,     B,     B,
@@ -316,7 +316,7 @@ static const uint8_t use_table[] = {
   /* 17A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 17B0 */     B,     B,     B,     B,   CGJ,   CGJ,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPre,  VPre,
   /* 17C0 */  VPre,  VPre,  VPre,  VPre,  VPre,  VPre, VMAbv, VMPst,  VPst, VMAbv, VMAbv, FMAbv,  FAbv, CMAbv, FMAbv, VMAbv,
-  /* 17D0 */ FMAbv,  VAbv,     H, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,    WJ,    WJ,
+  /* 17D0 */ FMAbv,  VAbv,    IS, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,    WJ,    WJ,
   /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
   /* 17F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
@@ -396,7 +396,7 @@ static const uint8_t use_table[] = {
 
   /* 1B80 */ VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1B90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1BA0 */     B,   SUB,   SUB,   SUB,  VAbv,  VBlw,  VPre,  VPst,  VAbv,  VAbv,  VPst,     H,   SUB,   SUB,     B,     B,
+  /* 1BA0 */     B,   SUB,   SUB,   SUB,  VAbv,  VBlw,  VPre,  VPst,  VAbv,  VAbv,  VPst,    IS,   SUB,   SUB,     B,     B,
   /* 1BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
 
   /* Batak */
@@ -555,7 +555,7 @@ static const uint8_t use_table[] = {
   /* Meetei Mayek Extensions */
 
   /* AAE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPre,  VBlw,  VAbv,  VPre,  VPst,
-  /* AAF0 */     O,     O,     O,     O,     O, VMPst,     H,    WJ,
+  /* AAF0 */     O,     O,     O,     O,     O, VMPst,    IS,    WJ,
 
 #define use_offset_0xabc0u 4040
 
@@ -606,7 +606,7 @@ static const uint8_t use_table[] = {
   /* 10A00 */     B,  VBlw,  VBlw,  VBlw,    WJ,  VAbv,  VBlw,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst, VMBlw, VMBlw, VMAbv,
   /* 10A10 */     B,     B,     B,     B,    WJ,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,
   /* 10A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 10A30 */     B,     B,     B,     B,     B,     B,    WJ,    WJ, CMAbv, CMBlw, CMBlw,    WJ,    WJ,    WJ,    WJ,     H,
+  /* 10A30 */     B,     B,     B,     B,     B,     B,    WJ,    WJ, CMAbv, CMBlw, CMBlw,    WJ,    WJ,    WJ,    WJ,    IS,
   /* 10A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
 #define use_offset_0x10ac0u 4304
@@ -699,7 +699,7 @@ static const uint8_t use_table[] = {
   /* 11100 */ VMAbv, VMAbv, VMAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11120 */     B,     B,     B,     B,     B,     B,     B,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VBlw,  VAbv,  VAbv,
-  /* 11130 */  VBlw,  VAbv,  VAbv,     H, CMAbv,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11130 */  VBlw,  VAbv,  VAbv,    IS, CMAbv,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
   /* Mahajani */
@@ -752,7 +752,7 @@ static const uint8_t use_table[] = {
   /* 11310 */     B,    WJ,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
   /* 11330 */     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,    WJ, CMBlw, CMBlw,     B,  VPst,  VPst,
-  /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,    WJ,    WJ,  VPre,  VPre,    WJ,    WJ,  VPre,  VPre,   HVM,    WJ,    WJ,
+  /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,    WJ,    WJ,  VPre,  VPre,    WJ,    WJ,  VPre,  VPre,     H,    WJ,    WJ,
   /* 11350 */     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,  VPst,    WJ,    WJ,    WJ,    WJ,    WJ,     O,     B,     B,
   /* 11360 */     B,     B,  VPst,  VPst,    WJ,    WJ, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    WJ,    WJ,    WJ,
   /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    WJ,    WJ,    WJ,
@@ -842,7 +842,7 @@ static const uint8_t use_table[] = {
   /* 11900 */     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,     B,    WJ,    WJ,     B,     B,     B,     B,
   /* 11910 */     B,     B,     B,     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11930 */  VPst,  VPst,  VPst,  VPst,  VPst,  VPre,    WJ,  VPre,  VPre,    WJ,    WJ, VMAbv, VMAbv,  VPst,     H,     R,
+  /* 11930 */  VPst,  VPst,  VPst,  VPst,  VPst,  VPre,    WJ,  VPre,  VPre,    WJ,    WJ, VMAbv, VMAbv,  VPst,    IS,     R,
   /* 11940 */  MPst,     R,  MPst, CMBlw,     O,     O,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
   /* 11950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
@@ -864,7 +864,7 @@ static const uint8_t use_table[] = {
   /* 11A10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A30 */     B,     B,     B, FMBlw,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
-  /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,     H,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
+  /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,    IS,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
   /* Soyombo */
 
@@ -872,7 +872,7 @@ static const uint8_t use_table[] = {
   /* 11A60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A80 */     B,     B,     B,     B,     R,     R,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
-  /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,     H,     O,     O,     O,     B,     O,     O,
+  /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,    IS,     O,     O,     O,     B,     O,     O,
 
 #define use_offset_0x11c00u 6592
 
@@ -904,7 +904,7 @@ static const uint8_t use_table[] = {
   /* 11D10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11D30 */     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,    WJ,    WJ,    WJ,  VAbv,    WJ,  VAbv,  VAbv,    WJ,  VAbv,
-  /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,     H,     R,  MBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
+  /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,    IS,     R,  MBlw,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
   /* 11D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
   /* Gunjala Gondi */
@@ -912,7 +912,7 @@ static const uint8_t use_table[] = {
   /* 11D60 */     B,     B,     B,     B,     B,     B,    WJ,     B,     B,    WJ,     B,     B,     B,     B,     B,     B,
   /* 11D70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11D80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VPst,  VPst,  VPst,    WJ,
-  /* 11D90 */  VAbv,  VAbv,    WJ,  VPst,  VPst, VMAbv, VMPst,     H,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
+  /* 11D90 */  VAbv,  VAbv,    WJ,  VPst,  VPst, VMAbv, VMPst,    IS,     O,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
   /* 11DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    WJ,    WJ,    WJ,    WJ,    WJ,    WJ,
 
 #define use_offset_0x11ee0u 6952
@@ -1531,7 +1531,7 @@ hb_use_get_category (hb_glyph_info_t info)
 #undef GB
 #undef H
 #undef HN
-#undef HVM
+#undef IS
 #undef J
 #undef N
 #undef O

+ 8 - 9
thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc

@@ -115,25 +115,24 @@ collect_features_use (hb_ot_shape_planner_t *plan)
   map->add_gsub_pause (setup_syllables_use);
 
   /* "Default glyph pre-processing group" */
-  map->enable_feature (HB_TAG('l','o','c','l'));
-  map->enable_feature (HB_TAG('c','c','m','p'));
-  map->enable_feature (HB_TAG('n','u','k','t'));
-  map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
+  map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
 
   /* "Reordering group" */
   map->add_gsub_pause (_hb_clear_substitution_flags);
-  map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
+  map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
   map->add_gsub_pause (record_rphf_use);
   map->add_gsub_pause (_hb_clear_substitution_flags);
-  map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
+  map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
   map->add_gsub_pause (record_pref_use);
 
   /* "Orthographic unit shaping group" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
-    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
 
   map->add_gsub_pause (reorder_use);
-  map->add_gsub_pause (_hb_clear_syllables);
 
   /* "Topographical features" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
@@ -350,7 +349,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
 static inline bool
 is_halant_use (const hb_glyph_info_t &info)
 {
-  return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
+  return (info.use_category() == USE(H) || info.use_category() == USE(IS)) &&
 	 !_hb_glyph_info_ligated (&info);
 }
 

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

@@ -935,17 +935,23 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
   _hb_buffer_allocate_gsubgpos_vars (c->buffer);
 
   hb_ot_substitute_complex (c);
+
+#ifndef HB_NO_AAT_SHAPE
+  if (c->plan->apply_morx && c->plan->apply_gpos)
+    hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
 }
 
 static inline void
 hb_ot_substitute_post (const hb_ot_shape_context_t *c)
 {
-  hb_ot_hide_default_ignorables (c->buffer, c->font);
 #ifndef HB_NO_AAT_SHAPE
-  if (c->plan->apply_morx)
+  if (c->plan->apply_morx && !c->plan->apply_gpos)
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
 #endif
 
+  hb_ot_hide_default_ignorables (c->buffer, c->font);
+
   if (c->plan->shaper->postprocess_glyphs &&
     c->buffer->message(c->font, "start postprocess-glyphs")) {
     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);

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

@@ -577,10 +577,11 @@ struct gvar
 
 	hb_bytes_t bytes ((const char *) p, length);
 	hb_vector_t<unsigned int> private_indices;
-	if (iterator.current_tuple->has_private_points () &&
+	bool has_private_points = iterator.current_tuple->has_private_points ();
+	if (has_private_points &&
 	    !GlyphVariationData::unpack_points (p, private_indices, bytes))
 	  return false;
-	const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
+	const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
 
 	bool apply_to_all = (indices.length == 0);
 	unsigned int num_deltas = apply_to_all ? points.length : indices.length;

+ 48 - 0
thirdparty/harfbuzz/src/hb-set.cc

@@ -256,6 +256,29 @@ hb_set_add (hb_set_t       *set,
   set->add (codepoint);
 }
 
+/**
+ * hb_set_add_sorted_array:
+ * @set: A set
+ * @sorted_codepoints: (array length=num_codepoints): Array of codepoints to add
+ * @num_codepoints: Length of @sorted_codepoints
+ *
+ * Adds @num_codepoints codepoints to a set at once.
+ * The codepoints array must be in increasing order,
+ * with size at least @num_codepoints.
+ *
+ * Since: 4.1.0
+ */
+HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t             *set,
+		         const hb_codepoint_t *sorted_codepoints,
+		         unsigned int          num_codepoints)
+{
+  /* Immutible-safe. */
+  set->add_sorted_array (sorted_codepoints,
+		         num_codepoints,
+		         sizeof(hb_codepoint_t));
+}
+
 /**
  * hb_set_add_range:
  * @set: A set
@@ -591,3 +614,28 @@ hb_set_previous_range (const hb_set_t *set,
 {
   return set->previous_range (first, last);
 }
+
+/**
+ * hb_set_next_many:
+ * @set: A set
+ * @codepoint: Outputting codepoints starting after this one.
+ *             Use #HB_SET_VALUE_INVALID to get started.
+ * @out: (array length=size): An array of codepoints to write to.
+ * @size: The maximum number of codepoints to write out.
+ *
+ * Finds the next element in @set that is greater than @codepoint. Writes out
+ * codepoints to @out, until either the set runs out of elements, or @size
+ * codepoints are written, whichever comes first.
+ *
+ * Return value: the number of values written.
+ *
+ * Since: 4.2.0
+ **/
+unsigned int
+hb_set_next_many (const hb_set_t *set,
+		  hb_codepoint_t  codepoint,
+		  hb_codepoint_t *out,
+		  unsigned int    size)
+{
+  return set->next_many (codepoint, out, size);
+}

+ 11 - 0
thirdparty/harfbuzz/src/hb-set.h

@@ -110,6 +110,11 @@ hb_set_add_range (hb_set_t       *set,
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last);
 
+HB_EXTERN void
+hb_set_add_sorted_array (hb_set_t             *set,
+		         const hb_codepoint_t *sorted_codepoints,
+		         unsigned int          num_codepoints);
+
 HB_EXTERN void
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
@@ -180,6 +185,12 @@ hb_set_previous_range (const hb_set_t *set,
 		       hb_codepoint_t *first,
 		       hb_codepoint_t *last);
 
+/* Pass HB_SET_VALUE_INVALID in to get started. */
+HB_EXTERN unsigned int
+hb_set_next_many (const hb_set_t *set,
+		  hb_codepoint_t  codepoint,
+		  hb_codepoint_t *out,
+		  unsigned int    size);
 
 HB_END_DECLS
 

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

@@ -109,6 +109,7 @@ struct hb_sparseset_t
   typedef bool value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+
   /* Predicate. */
   bool operator () (hb_codepoint_t k) const { return has (k); }
 
@@ -138,6 +139,8 @@ struct hb_sparseset_t
   { return s.next_range (first, last); }
   bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
   { return s.previous_range (first, last); }
+  unsigned int next_many (hb_codepoint_t codepoint, hb_codepoint_t *out, unsigned int size) const
+  { return s.next_many (codepoint, out, size); }
 
   unsigned int get_population () const { return s.get_population (); }
   hb_codepoint_t get_min () const { return s.get_min (); }

+ 2 - 0
thirdparty/harfbuzz/src/hb-static.cc

@@ -56,6 +56,7 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
 
 /* hb_face_t */
 
+#ifndef HB_NO_BORING_EXPANSION
 static inline unsigned
 load_num_glyphs_from_loca (const hb_face_t *face)
 {
@@ -72,6 +73,7 @@ load_num_glyphs_from_loca (const hb_face_t *face)
 
   return ret;
 }
+#endif
 
 static inline unsigned
 load_num_glyphs_from_maxp (const hb_face_t *face)

+ 3 - 1
thirdparty/harfbuzz/src/hb-subset-plan.cc

@@ -40,6 +40,8 @@
 #include "hb-ot-stat-table.hh"
 #include "hb-ot-math-table.hh"
 
+using OT::Layout::GSUB::GSUB;
+
 
 typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map;
 #ifndef HB_NO_SUBSET_CFF
@@ -358,7 +360,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
 #ifndef HB_NO_SUBSET_LAYOUT
   if (close_over_gsub)
     // closure all glyphs/lookups/features needed for GSUB substitutions.
-    _closure_glyphs_lookups_features<OT::GSUB> (
+    _closure_glyphs_lookups_features<GSUB> (
         plan->source,
         plan->_glyphset_gsub,
         plan->layout_features,

+ 3 - 1
thirdparty/harfbuzz/src/hb-subset.cc

@@ -55,6 +55,8 @@
 #include "hb-ot-math-table.hh"
 #include "hb-repacker.hh"
 
+using OT::Layout::GSUB::GSUB;
+
 /**
  * SECTION:hb-subset
  * @title: hb-subset
@@ -312,7 +314,7 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
 
 #ifndef HB_NO_SUBSET_LAYOUT
   case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
-  case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan);
+  case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan);
   case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
   case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
   case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);

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

@@ -47,20 +47,20 @@ HB_BEGIN_DECLS
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 0
+#define HB_VERSION_MINOR 2
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 0
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "4.0.1"
+#define HB_VERSION_STRING "4.2.0"
 
 /**
  * HB_VERSION_ATLEAST:

部分文件因为文件数量过多而无法显示