2
0
Эх сурвалжийг харах

Merge pull request #63404 from bruvzg/hb-501

Rémi Verschelde 3 жил өмнө
parent
commit
72c2f7ef16
100 өөрчлөгдсөн 3593 нэмэгдсэн , 1737 устгасан
  1. 1 1
      thirdparty/README.md
  2. 338 0
      thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
  3. 126 0
      thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat1.hh
  4. 233 0
      thirdparty/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh
  5. 85 0
      thirdparty/harfbuzz/src/OT/Layout/Common/RangeRecord.hh
  6. 7 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
  7. 20 14
      thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
  8. 56 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh
  9. 8 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
  10. 8 6
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
  11. 8 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
  12. 9 47
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
  13. 8 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
  14. 8 7
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
  15. 11 3
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
  16. 13 240
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
  17. 6 5
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
  18. 173 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
  19. 97 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
  20. 0 3
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
  21. 4 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
  22. 3 2
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
  23. 14 3
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
  24. 8 8
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
  25. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ChainContextSubst.hh
  26. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Common.hh
  27. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ContextSubst.hh
  28. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ExtensionSubst.hh
  29. 9 8
      thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
  30. 7 5
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
  31. 8 7
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh
  32. 15 3
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
  33. 12 11
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
  34. 14 3
      thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
  35. 8 7
      thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
  36. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
  37. 12 12
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
  38. 3 2
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
  39. 34 6
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
  40. 34 20
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
  41. 7 6
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
  42. 9 4
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh
  43. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookupSubTable.hh
  44. 66 0
      thirdparty/harfbuzz/src/OT/Layout/types.hh
  45. 32 4
      thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
  46. 11 9
      thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
  47. 5 3
      thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh
  48. 2 2
      thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
  49. 34 25
      thirdparty/harfbuzz/src/OT/glyf/glyf.hh
  50. 67 13
      thirdparty/harfbuzz/src/graph/graph.hh
  51. 2 2
      thirdparty/harfbuzz/src/hb-aat-layout-bsln-table.hh
  52. 8 12
      thirdparty/harfbuzz/src/hb-aat-layout-common.hh
  53. 1 1
      thirdparty/harfbuzz/src/hb-aat-layout-feat-table.hh
  54. 6 6
      thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
  55. 1 1
      thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
  56. 9 0
      thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
  57. 1 1
      thirdparty/harfbuzz/src/hb-aat-layout-opbd-table.hh
  58. 3 3
      thirdparty/harfbuzz/src/hb-aat-layout.cc
  59. 4 2
      thirdparty/harfbuzz/src/hb-aat-map.hh
  60. 11 10
      thirdparty/harfbuzz/src/hb-algs.hh
  61. 6 8
      thirdparty/harfbuzz/src/hb-array.hh
  62. 13 0
      thirdparty/harfbuzz/src/hb-atomic.hh
  63. 1 1
      thirdparty/harfbuzz/src/hb-bit-page.hh
  64. 12 5
      thirdparty/harfbuzz/src/hb-bit-set.hh
  65. 5 7
      thirdparty/harfbuzz/src/hb-blob.cc
  66. 6 6
      thirdparty/harfbuzz/src/hb-blob.hh
  67. 248 183
      thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
  68. 390 182
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
  69. 12 12
      thirdparty/harfbuzz/src/hb-buffer-serialize.cc
  70. 19 19
      thirdparty/harfbuzz/src/hb-buffer.cc
  71. 3 3
      thirdparty/harfbuzz/src/hb-buffer.h
  72. 7 0
      thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh
  73. 45 13
      thirdparty/harfbuzz/src/hb-common.cc
  74. 3 0
      thirdparty/harfbuzz/src/hb-common.h
  75. 5 0
      thirdparty/harfbuzz/src/hb-config.hh
  76. 10 2
      thirdparty/harfbuzz/src/hb-cplusplus.hh
  77. 1 1
      thirdparty/harfbuzz/src/hb-deprecated.h
  78. 34 2
      thirdparty/harfbuzz/src/hb-directwrite.cc
  79. 6 2
      thirdparty/harfbuzz/src/hb-draw.cc
  80. 2 2
      thirdparty/harfbuzz/src/hb-face.cc
  81. 25 20
      thirdparty/harfbuzz/src/hb-font.cc
  82. 7 7
      thirdparty/harfbuzz/src/hb-font.h
  83. 103 44
      thirdparty/harfbuzz/src/hb-ft.cc
  84. 4 4
      thirdparty/harfbuzz/src/hb-graphite2.cc
  85. 2 0
      thirdparty/harfbuzz/src/hb-iter.hh
  86. 5 9
      thirdparty/harfbuzz/src/hb-map.cc
  87. 53 19
      thirdparty/harfbuzz/src/hb-map.hh
  88. 1 1
      thirdparty/harfbuzz/src/hb-meta.hh
  89. 30 1
      thirdparty/harfbuzz/src/hb-null.hh
  90. 4 4
      thirdparty/harfbuzz/src/hb-number-parser.hh
  91. 7 1
      thirdparty/harfbuzz/src/hb-object.hh
  92. 37 10
      thirdparty/harfbuzz/src/hb-open-type.hh
  93. 4 1
      thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
  94. 4 4
      thirdparty/harfbuzz/src/hb-ot-color.cc
  95. 4 0
      thirdparty/harfbuzz/src/hb-ot-color.h
  96. 26 14
      thirdparty/harfbuzz/src/hb-ot-font.cc
  97. 47 33
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  98. 1 1
      thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
  99. 444 470
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  100. 272 104
      thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh

+ 1 - 1
thirdparty/README.md

@@ -213,7 +213,7 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 4.4.1 (096aaa62a6e0d07c02a4894fc036efc927e5aaf9, 2022)
+- Version: 5.0.1 (cbccadba8d1e51d6cc03a891b7c3a17f598e774c, 2022)
 - License: MIT
 
 Files extracted from upstream source:

+ 338 - 0
thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh

@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGE_HH
+#define OT_LAYOUT_COMMON_COVERAGE_HH
+
+#include "../types.hh"
+#include "CoverageFormat1.hh"
+#include "CoverageFormat2.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template<typename Iterator>
+static inline void Coverage_serialize (hb_serialize_context_t *c,
+                                       Iterator it);
+
+struct Coverage
+{
+
+  protected:
+  union {
+  HBUINT16                      format;         /* Format identifier */
+  CoverageFormat1_3<SmallTypes> format1;
+  CoverageFormat2_4<SmallTypes> format2;
+#ifndef HB_NO_BORING_EXPANSION
+  CoverageFormat1_3<MediumTypes>format3;
+  CoverageFormat2_4<MediumTypes>format4;
+#endif
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format)
+    {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+#endif
+    default:return_trace (true);
+    }
+  }
+
+  /* Has interface. */
+  static constexpr unsigned SENTINEL = NOT_COVERED;
+  typedef unsigned int 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); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_coverage (glyph_id);
+    case 2: return u.format2.get_coverage (glyph_id);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.get_coverage (glyph_id);
+    case 4: return u.format4.get_coverage (glyph_id);
+#endif
+    default:return NOT_COVERED;
+    }
+  }
+
+  unsigned get_population () const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_population ();
+    case 2: return u.format2.get_population ();
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.get_population ();
+    case 4: return u.format4.get_population ();
+#endif
+    default:return NOT_COVERED;
+    }
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    unsigned count = 0;
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
+        num_ranges++;
+      last = g;
+      count++;
+    }
+    u.format = count <= num_ranges * 3 ? 1 : 2;
+
+#ifndef HB_NO_BORING_EXPANSION
+    if (count && last > 0xFFFFu)
+      u.format += 2;
+#endif
+
+    switch (u.format)
+    {
+    case 1: return_trace (u.format1.serialize (c, glyphs));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (u.format3.serialize (c, glyphs));
+    case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
+    default:return_trace (false);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto it =
+    + iter ()
+    | hb_filter (c->plan->glyph_map_gsub)
+    | hb_map_retains_sorting (c->plan->glyph_map_gsub)
+    ;
+
+    // Cache the iterator result as it will be iterated multiple times
+    // by the serialize code below.
+    hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
+    Coverage_serialize (c->serializer, glyphs.iter ());
+    return_trace (bool (glyphs));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.intersects (glyphs);
+    case 2: return u.format2.intersects (glyphs);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.intersects (glyphs);
+    case 4: return u.format4.intersects (glyphs);
+#endif
+    default:return false;
+    }
+  }
+  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.intersects_coverage (glyphs, index);
+    case 2: return u.format2.intersects_coverage (glyphs, index);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.intersects_coverage (glyphs, index);
+    case 4: return u.format4.intersects_coverage (glyphs, index);
+#endif
+    default:return false;
+    }
+  }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.collect_coverage (glyphs);
+    case 2: return u.format2.collect_coverage (glyphs);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.collect_coverage (glyphs);
+    case 4: return u.format4.collect_coverage (glyphs);
+#endif
+    default:return false;
+    }
+  }
+
+  template <typename IterableOut,
+	    hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
+    case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
+    case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
+#endif
+    default:return ;
+    }
+  }
+
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const Coverage &c_ = Null (Coverage))
+    {
+      memset (this, 0, sizeof (*this));
+      format = c_.u.format;
+      switch (format)
+      {
+      case 1: u.format1.init (c_.u.format1); return;
+      case 2: u.format2.init (c_.u.format2); return;
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: u.format3.init (c_.u.format3); return;
+      case 4: u.format4.init (c_.u.format4); return;
+#endif
+      default:                               return;
+      }
+    }
+    bool __more__ () const
+    {
+      switch (format)
+      {
+      case 1: return u.format1.__more__ ();
+      case 2: return u.format2.__more__ ();
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: return u.format3.__more__ ();
+      case 4: return u.format4.__more__ ();
+#endif
+      default:return false;
+      }
+    }
+    void __next__ ()
+    {
+      switch (format)
+      {
+      case 1: u.format1.__next__ (); break;
+      case 2: u.format2.__next__ (); break;
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: u.format3.__next__ (); break;
+      case 4: u.format4.__next__ (); break;
+#endif
+      default:                   break;
+      }
+    }
+    typedef hb_codepoint_t __item_t__;
+    __item_t__ __item__ () const { return get_glyph (); }
+
+    hb_codepoint_t get_glyph () const
+    {
+      switch (format)
+      {
+      case 1: return u.format1.get_glyph ();
+      case 2: return u.format2.get_glyph ();
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: return u.format3.get_glyph ();
+      case 4: return u.format4.get_glyph ();
+#endif
+      default:return 0;
+      }
+    }
+    bool operator != (const iter_t& o) const
+    {
+      if (unlikely (format != o.format)) return true;
+      switch (format)
+      {
+      case 1: return u.format1 != o.u.format1;
+      case 2: return u.format2 != o.u.format2;
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: return u.format3 != o.u.format3;
+      case 4: return u.format4 != o.u.format4;
+#endif
+      default:return false;
+      }
+    }
+    iter_t __end__ () const
+    {
+      iter_t it = {};
+      it.format = format;
+      switch (format)
+      {
+      case 1: it.u.format1 = u.format1.__end__ (); break;
+      case 2: it.u.format2 = u.format2.__end__ (); break;
+#ifndef HB_NO_BORING_EXPANSION
+      case 3: it.u.format3 = u.format3.__end__ (); break;
+      case 4: it.u.format4 = u.format4.__end__ (); break;
+#endif
+      default: break;
+      }
+      return it;
+    }
+
+    private:
+    unsigned int format;
+    union {
+#ifndef HB_NO_BORING_EXPANSION
+    CoverageFormat2_4<MediumTypes>::iter_t      format4; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1_3<MediumTypes>::iter_t      format3;
+#endif
+    CoverageFormat2_4<SmallTypes>::iter_t       format2; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1_3<SmallTypes>::iter_t       format1;
+    } u;
+  };
+  iter_t iter () const { return iter_t (*this); }
+};
+
+template<typename Iterator>
+static inline void
+Coverage_serialize (hb_serialize_context_t *c,
+                    Iterator it)
+{ c->start_embed<Coverage> ()->serialize (c, it); }
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH

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

@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+#define NOT_COVERED             ((unsigned int) -1)
+
+template <typename Types>
+struct CoverageFormat1_3
+{
+  friend struct Coverage;
+
+  protected:
+  HBUINT16      coverageFormat; /* Format identifier--format = 1 */
+  SortedArray16Of<typename Types::HBGlyphID>
+                glyphArray;     /* Array of GlyphIDs--in numerical order */
+  public:
+  DEFINE_SIZE_ARRAY (4, glyphArray);
+
+  private:
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (glyphArray.sanitize (c));
+  }
+
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    unsigned int i;
+    glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
+    return i;
+  }
+
+  unsigned get_population () const
+  {
+    return glyphArray.len;
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (glyphArray.serialize (c, glyphs));
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    for (const auto& g : glyphArray.as_array ())
+      if (glyphs->has (g))
+        return true;
+    return false;
+  }
+  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  { return glyphs->has (glyphArray[index]); }
+
+  template <typename IterableOut,
+	    hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+  {
+    unsigned count = glyphArray.len;
+    for (unsigned i = 0; i < count; i++)
+      if (glyphs.has (glyphArray[i]))
+        intersect_glyphs << glyphArray[i];
+  }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_sorted_array (glyphArray.as_array ()); }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct iter_t
+  {
+    void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; }
+    bool __more__ () const { return i < c->glyphArray.len; }
+    void __next__ () { i++; }
+    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i; }
+    iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; }
+
+    private:
+    const struct CoverageFormat1_3 *c;
+    unsigned int i;
+  };
+  private:
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH

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

@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
+
+#include "RangeRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct CoverageFormat2_4
+{
+  friend struct Coverage;
+
+  protected:
+  HBUINT16      coverageFormat; /* Format identifier--format = 2 */
+  SortedArray16Of<RangeRecord<Types>>
+                rangeRecord;    /* Array of glyph ranges--ordered by
+                                 * Start GlyphID. rangeCount entries
+                                 * long */
+  public:
+  DEFINE_SIZE_ARRAY (4, rangeRecord);
+
+  private:
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rangeRecord.sanitize (c));
+  }
+
+  unsigned int get_coverage (hb_codepoint_t glyph_id) const
+  {
+    const RangeRecord<Types> &range = rangeRecord.bsearch (glyph_id);
+    return likely (range.first <= range.last)
+         ? (unsigned int) range.value + (glyph_id - range.first)
+         : NOT_COVERED;
+  }
+
+  unsigned get_population () const
+  {
+    typename Types::large_int ret = 0;
+    for (const auto &r : rangeRecord)
+      ret += r.get_population ();
+    return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
+  }
+
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+
+    /* TODO(iter) Write more efficiently? */
+
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
+        num_ranges++;
+      last = g;
+    }
+
+    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
+    if (!num_ranges) return_trace (true);
+
+    unsigned count = 0;
+    unsigned range = (unsigned) -1;
+    last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
+      {
+        range++;
+        rangeRecord[range].first = g;
+        rangeRecord[range].value = count;
+      }
+      rangeRecord[range].last = g;
+      last = g;
+      count++;
+    }
+
+    return_trace (true);
+  }
+
+  bool intersects (const hb_set_t *glyphs) const
+  {
+    return hb_any (+ hb_iter (rangeRecord)
+                   | hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
+  }
+  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  {
+    auto cmp = [] (const void *pk, const void *pr) -> int
+    {
+      unsigned index = * (const unsigned *) pk;
+      const RangeRecord<Types> &range = * (const RangeRecord<Types> *) pr;
+      if (index < range.value) return -1;
+      if (index > (unsigned int) range.value + (range.last - range.first)) return +1;
+      return 0;
+    };
+
+    auto arr = rangeRecord.as_array ();
+    unsigned idx;
+    if (hb_bsearch_impl (&idx, index,
+                         arr.arrayZ, arr.length, sizeof (arr[0]),
+                         (int (*)(const void *_key, const void *_item)) cmp))
+      return arr.arrayZ[idx].intersects (*glyphs);
+    return false;
+  }
+
+  template <typename IterableOut,
+	    hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
+  void intersect_set (const hb_set_t &glyphs, IterableOut &intersect_glyphs) const
+  {
+    for (const auto& range : rangeRecord)
+    {
+      hb_codepoint_t last = range.last;
+      for (hb_codepoint_t g = range.first - 1;
+	   glyphs.next (&g) && g <= last;)
+	intersect_glyphs << g;
+    }
+  }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  {
+    for (const auto& range: rangeRecord)
+      if (unlikely (!range.collect_coverage (glyphs)))
+        return false;
+    return true;
+  }
+
+  public:
+  /* Older compilers need this to be public. */
+  struct iter_t
+  {
+    void init (const CoverageFormat2_4 &c_)
+    {
+      c = &c_;
+      coverage = 0;
+      i = 0;
+      j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
+      if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
+      {
+        /* Broken table. Skip. */
+        i = c->rangeRecord.len;
+        j = 0;
+      }
+    }
+    bool __more__ () const { return i < c->rangeRecord.len; }
+    void __next__ ()
+    {
+      if (j >= c->rangeRecord[i].last)
+      {
+        i++;
+        if (__more__ ())
+        {
+          unsigned int old = coverage;
+          j = c->rangeRecord[i].first;
+          coverage = c->rangeRecord[i].value;
+          if (unlikely (coverage != old + 1))
+          {
+            /* Broken table. Skip. Important to avoid DoS.
+             * Also, our callers depend on coverage being
+             * consecutive and monotonically increasing,
+             * ie. iota(). */
+           i = c->rangeRecord.len;
+           j = 0;
+           return;
+          }
+        }
+        else
+          j = 0;
+        return;
+      }
+      coverage++;
+      j++;
+    }
+    hb_codepoint_t get_glyph () const { return j; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || j != o.j; }
+    iter_t __end__ () const
+    {
+      iter_t it;
+      it.init (*c);
+      it.i = c->rangeRecord.len;
+      it.j = 0;
+      return it;
+    }
+
+    private:
+    const struct CoverageFormat2_4 *c;
+    unsigned int i, coverage;
+    hb_codepoint_t j;
+  };
+  private:
+};
+
+}
+}
+}
+
+#endif  // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH

+ 85 - 0
thirdparty/harfbuzz/src/OT/Layout/Common/RangeRecord.hh

@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
+#define OT_LAYOUT_COMMON_RANGERECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace Common {
+
+template <typename Types>
+struct RangeRecord
+{
+  typename Types::HBGlyphID     first;          /* First GlyphID in the range */
+  typename Types::HBGlyphID     last;           /* Last GlyphID in the range */
+  HBUINT16                      value;          /* Value */
+
+  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  int cmp (hb_codepoint_t g) const
+  { return g < first ? -1 : g <= last ? 0 : +1; }
+
+  unsigned get_population () const
+  {
+    if (unlikely (last < first)) return 0;
+    return (last - first + 1);
+  }
+
+  bool intersects (const hb_set_t &glyphs) const
+  { return glyphs.intersects (first, last); }
+
+  template <typename set_t>
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_range (first, last); }
+};
+
+}
+}
+}
+
+// TODO(garretrieger): This was previously implemented using
+//    DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9);
+//    but that only works when there is only a single namespace level.
+//    The macro should probably be fixed so it can work in this situation.
+extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9];
+template <typename Spec>
+struct Null<OT::Layout::Common::RangeRecord<Spec>> {
+  static OT::Layout::Common::RangeRecord<Spec> const & get_null () {
+    return *reinterpret_cast<const OT::Layout::Common::RangeRecord<Spec> *> (_hb_Null_OT_RangeRecord);
+  }
+};
+
+
+#endif  // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH

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

@@ -140,7 +140,7 @@ struct CursivePosFormat1
     unsigned int i = skippy_iter.idx;
     unsigned int j = buffer->idx;
 
-    buffer->unsafe_to_break (i, j);
+    buffer->unsafe_to_break (i, j + 1);
     float entry_x, entry_y, exit_x, exit_y;
     (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
     (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
@@ -223,7 +223,13 @@ struct CursivePosFormat1
      * https://github.com/harfbuzz/harfbuzz/issues/2469
      */
     if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+    {
       pos[parent].attach_chain() = 0;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+	pos[parent].y_offset = 0;
+      else
+	pos[parent].x_offset = 0;
+    }
 
     buffer->idx++;
     return_trace (true);

+ 20 - 14
thirdparty/harfbuzz/src/OT/Layout/GPOS.hh → thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh

@@ -1,12 +1,15 @@
-#ifndef OT_LAYOUT_GPOS_HH
-#define OT_LAYOUT_GPOS_HH
+#ifndef OT_LAYOUT_GPOS_GPOS_HH
+#define OT_LAYOUT_GPOS_GPOS_HH
 
-#include "../../hb-ot-layout-common.hh"
-#include "../../hb-ot-layout-gsubgpos.hh"
-#include "GPOS/Common.hh"
-#include "GPOS/PosLookup.hh"
+#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-layout-gsubgpos.hh"
+#include "Common.hh"
+#include "PosLookup.hh"
 
 namespace OT {
+
+using Layout::GPOS_impl::PosLookup;
+
 namespace Layout {
 
 static void
@@ -25,10 +28,10 @@ struct GPOS : GSUBGPOS
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
-  using Lookup = GPOS_impl::PosLookup;
+  using Lookup = PosLookup;
 
-  const GPOS_impl::PosLookup& get_lookup (unsigned int i) const
-  { return static_cast<const GPOS_impl::PosLookup &> (GSUBGPOS::get_lookup (i)); }
+  const PosLookup& get_lookup (unsigned int i) const
+  { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
@@ -37,11 +40,14 @@ struct GPOS : GSUBGPOS
   bool subset (hb_subset_context_t *c) const
   {
     hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
-    return GSUBGPOS::subset<GPOS_impl::PosLookup> (&l);
+    return GSUBGPOS::subset<PosLookup> (&l);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<GPOS_impl::PosLookup> (c); }
+  {
+    TRACE_SANITIZE (this);
+    return_trace (GSUBGPOS::sanitize<PosLookup> (c));
+  }
 
   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
@@ -51,7 +57,7 @@ struct GPOS : GSUBGPOS
     for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
     {
       if (!c->gpos_lookups->has (i)) continue;
-      const GPOS_impl::PosLookup &l = get_lookup (i);
+      const PosLookup &l = get_lookup (i);
       l.dispatch (c);
     }
   }
@@ -59,7 +65,7 @@ struct GPOS : GSUBGPOS
   void closure_lookups (hb_face_t      *face,
                         const hb_set_t *glyphs,
                         hb_set_t       *lookup_indexes /* IN/OUT */) const
-  { GSUBGPOS::closure_lookups<GPOS_impl::PosLookup> (face, glyphs, lookup_indexes); }
+  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
 
   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
 };
@@ -162,4 +168,4 @@ struct GPOS_accelerator_t : Layout::GPOS::accelerator_t {
 
 }
 
-#endif  /* OT_LAYOUT_GPOS_HH */
+#endif  /* OT_LAYOUT_GPOS_GPOS_HH */

+ 56 - 0
thirdparty/harfbuzz/src/OT/Layout/GPOS/LigatureArray.hh

@@ -0,0 +1,56 @@
+#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH
+#define OT_LAYOUT_GPOS_LIGATUREARRAY_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+typedef AnchorMatrix LigatureAttach;    /* component-major--
+                                         * in order of writing direction--,
+                                         * mark-minor--
+                                         * ordered by class--zero-based. */
+
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : List16OfOffset16To<LigatureAttach>
+{
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  bool subset (hb_subset_context_t *c,
+               Iterator             coverage,
+               unsigned             class_count,
+               const hb_map_t      *klass_mapping) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
+
+    for (const auto _ : + hb_zip (coverage, *this)
+                  | hb_filter (glyphset, hb_first))
+    {
+      auto *matrix = out->serialize_append (c->serializer);
+      if (unlikely (!matrix)) return_trace (false);
+
+      const LigatureAttach& src = (this + _.second);
+      auto indexes =
+          + hb_range (src.rows * class_count)
+          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
+          ;
+      matrix->serialize_subset (c,
+                                _.second,
+                                this,
+                                src.rows,
+                                indexes);
+    }
+    return_trace (this->len);
+  }
+};
+
+
+}
+}
+}
+
+#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */

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

@@ -11,8 +11,11 @@ struct MarkBasePos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkBasePosFormat1    format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkBasePosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkBasePosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkBasePos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }

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

@@ -12,26 +12,27 @@ typedef AnchorMatrix BaseArray;         /* base-major--
                                          * mark-minor--
                                          * ordered by class--zero-based. */
 
-struct MarkBasePosFormat1
+template <typename Types>
+struct MarkBasePosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 markCoverage;           /* Offset to MarkCoverage table--from
                                          * beginning of MarkBasePos subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 baseCoverage;           /* Offset to BaseCoverage table--from
                                          * beginning of MarkBasePos subtable */
   HBUINT16      classCount;             /* Number of classes defined for marks */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 markArray;              /* Offset to MarkArray table--from
                                          * beginning of MarkBasePos subtable */
-  Offset16To<BaseArray>
+  typename Types::template OffsetTo<BaseArray>
                 baseArray;              /* Offset to BaseArray table--from
                                          * beginning of MarkBasePos subtable */
 
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
     bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -117,6 +118,7 @@ struct MarkBasePosFormat1
           0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
           (skippy_iter.idx == 0 ||
            _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
+           !_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
            _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
            _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=

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

@@ -11,8 +11,11 @@ struct MarkLigPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkLigPosFormat1     format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkLigPosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkLigPosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkLigPos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }

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

@@ -1,72 +1,34 @@
 #ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
 #define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
 
+#include "LigatureArray.hh"
+
 namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-typedef AnchorMatrix LigatureAttach;    /* component-major--
-                                         * in order of writing direction--,
-                                         * mark-minor--
-                                         * ordered by class--zero-based. */
-
-/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : List16OfOffset16To<LigatureAttach>
-{
-  template <typename Iterator,
-            hb_requires (hb_is_iterator (Iterator))>
-  bool subset (hb_subset_context_t *c,
-               Iterator             coverage,
-               unsigned             class_count,
-               const hb_map_t      *klass_mapping) const
-  {
-    TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-
-    auto *out = c->serializer->start_embed (this);
-    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-
-    for (const auto _ : + hb_zip (coverage, *this)
-                  | hb_filter (glyphset, hb_first))
-    {
-      auto *matrix = out->serialize_append (c->serializer);
-      if (unlikely (!matrix)) return_trace (false);
-
-      const LigatureAttach& src = (this + _.second);
-      auto indexes =
-          + hb_range (src.rows * class_count)
-          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
-          ;
-      matrix->serialize_subset (c,
-                                _.second,
-                                this,
-                                src.rows,
-                                indexes);
-    }
-    return_trace (this->len);
-  }
-};
 
-struct MarkLigPosFormat1
+template <typename Types>
+struct MarkLigPosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 markCoverage;           /* Offset to Mark Coverage table--from
                                          * beginning of MarkLigPos subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 ligatureCoverage;       /* Offset to Ligature Coverage
                                          * table--from beginning of MarkLigPos
                                          * subtable */
   HBUINT16      classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 markArray;              /* Offset to MarkArray table--from
                                          * beginning of MarkLigPos subtable */
-  Offset16To<LigatureArray>
+  typename Types::template OffsetTo<LigatureArray>
                 ligatureArray;          /* Offset to LigatureArray table--from
                                          * beginning of MarkLigPos subtable */
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {

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

@@ -11,8 +11,11 @@ struct MarkMarkPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MarkMarkPosFormat1    format1;
+  HBUINT16				format;         /* Format identifier */
+  MarkMarkPosFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MarkMarkPosFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -23,6 +26,9 @@ struct MarkMarkPos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }

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

@@ -12,27 +12,28 @@ typedef AnchorMatrix Mark2Array;        /* mark2-major--
                                          * mark1-minor--
                                          * ordered by class--zero-based. */
 
-struct MarkMarkPosFormat1
+template <typename Types>
+struct MarkMarkPosFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
                                          * table--from beginning of MarkMarkPos
                                          * subtable */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
                                          * table--from beginning of MarkMarkPos
                                          * subtable */
   HBUINT16      classCount;             /* Number of defined mark classes */
-  Offset16To<MarkArray>
+  typename Types::template OffsetTo<MarkArray>
                 mark1Array;             /* Offset to Mark1Array table--from
                                          * beginning of MarkMarkPos subtable */
-  Offset16To<Mark2Array>
+  typename Types::template OffsetTo<Mark2Array>
                 mark2Array;             /* Offset to Mark2Array table--from
                                          * beginning of MarkMarkPos subtable */
   public:
-  DEFINE_SIZE_STATIC (12);
+  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -100,7 +101,7 @@ struct MarkMarkPosFormat1
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
-    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+    skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
     unsigned unsafe_from;
     if (!skippy_iter.prev (&unsafe_from))
     {

+ 11 - 3
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh

@@ -12,9 +12,13 @@ struct PairPos
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  PairPosFormat1        format1;
-  PairPosFormat2        format2;
+  HBUINT16			format;         /* Format identifier */
+  PairPosFormat1_3<SmallTypes>	format1;
+  PairPosFormat2_4<SmallTypes>	format2;
+#ifndef HB_NO_BORING_EXPANSION
+  PairPosFormat1_3<MediumTypes>	format3;
+  PairPosFormat2_4<MediumTypes>	format4;
+#endif
   } u;
 
   public:
@@ -26,6 +30,10 @@ struct PairPos
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }

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

@@ -1,248 +1,22 @@
 #ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
 #define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
 
+#include "PairSet.hh"
+
 namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-struct PairValueRecord
-{
-  friend struct PairSet;
-
-  int cmp (hb_codepoint_t k) const
-  { return secondGlyph.cmp (k); }
-
-  struct context_t
-  {
-    const void          *base;
-    const ValueFormat   *valueFormats;
-    const ValueFormat   *newFormats;
-    unsigned            len1; /* valueFormats[0].get_len() */
-    const hb_map_t      *glyph_map;
-    const hb_map_t      *layout_variation_idx_map;
-  };
-
-  bool subset (hb_subset_context_t *c,
-               context_t *closure) const
-  {
-    TRACE_SERIALIZE (this);
-    auto *s = c->serializer;
-    auto *out = s->start_embed (*this);
-    if (unlikely (!s->extend_min (out))) return_trace (false);
-
-    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
-
-    closure->valueFormats[0].copy_values (s,
-                                          closure->newFormats[0],
-                                          closure->base, &values[0],
-                                          closure->layout_variation_idx_map);
-    closure->valueFormats[1].copy_values (s,
-                                          closure->newFormats[1],
-                                          closure->base,
-                                          &values[closure->len1],
-                                          closure->layout_variation_idx_map);
-
-    return_trace (true);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                  const ValueFormat *valueFormats,
-                                  const void *base) const
-  {
-    unsigned record1_len = valueFormats[0].get_len ();
-    unsigned record2_len = valueFormats[1].get_len ();
-    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
-
-    if (valueFormats[0].has_device ())
-      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
-
-    if (valueFormats[1].has_device ())
-      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
-  }
-
-  bool intersects (const hb_set_t& glyphset) const
-  {
-    return glyphset.has(secondGlyph);
-  }
-
-  const Value* get_values_1 () const
-  {
-    return &values[0];
-  }
-
-  const Value* get_values_2 (ValueFormat format1) const
-  {
-    return &values[format1.get_len ()];
-  }
 
-  protected:
-  HBGlyphID16   secondGlyph;            /* GlyphID of second glyph in the
-                                         * pair--first glyph is listed in the
-                                         * Coverage table */
-  ValueRecord   values;                 /* Positioning data for the first glyph
-                                         * followed by for second glyph */
-  public:
-  DEFINE_SIZE_ARRAY (2, values);
-};
-
-struct PairSet
+template <typename Types>
+struct PairPosFormat1_3
 {
-  friend struct PairPosFormat1;
-
-  bool intersects (const hb_set_t *glyphs,
-                   const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (glyphs->has (record->secondGlyph))
-        return true;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-    return false;
-  }
-
-  void collect_glyphs (hb_collect_glyphs_context_t *c,
-                       const ValueFormat *valueFormats) const
-  {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    c->input->add_array (&record->secondGlyph, len, record_size);
-  }
-
-  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
-                                  const ValueFormat *valueFormats) const
-  {
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (c->glyph_set->has (record->secondGlyph))
-      { record->collect_variation_indices (c, valueFormats, this); }
-
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-  }
+  using PairSet = GPOS_impl::PairSet<Types>;
+  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
 
-  bool apply (hb_ot_apply_context_t *c,
-              const ValueFormat *valueFormats,
-              unsigned int pos) const
-  {
-    TRACE_APPLY (this);
-    hb_buffer_t *buffer = c->buffer;
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
-
-    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
-                                                &firstPairValueRecord,
-                                                len,
-                                                record_size);
-    if (record)
-    {
-      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
-      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
-      if (applied_first || applied_second)
-        buffer->unsafe_to_break (buffer->idx, pos + 1);
-      if (len2)
-        pos++;
-      buffer->idx = pos;
-      return_trace (true);
-    }
-    buffer->unsafe_to_concat (buffer->idx, pos + 1);
-    return_trace (false);
-  }
-
-  bool subset (hb_subset_context_t *c,
-               const ValueFormat valueFormats[2],
-               const ValueFormat newFormats[2]) const
-  {
-    TRACE_SUBSET (this);
-    auto snap = c->serializer->snapshot ();
-
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-    out->len = 0;
-
-    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
-    const hb_map_t &glyph_map = *c->plan->glyph_map;
-
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
-
-    PairValueRecord::context_t context =
-    {
-      this,
-      valueFormats,
-      newFormats,
-      len1,
-      &glyph_map,
-      c->plan->layout_variation_idx_map
-    };
-
-    const PairValueRecord *record = &firstPairValueRecord;
-    unsigned count = len, num = 0;
-    for (unsigned i = 0; i < count; i++)
-    {
-      if (glyphset.has (record->secondGlyph)
-         && record->subset (c, &context)) num++;
-      record = &StructAtOffset<const PairValueRecord> (record, record_size);
-    }
-
-    out->len = num;
-    if (!num) c->serializer->revert (snap);
-    return_trace (num);
-  }
-
-  struct sanitize_closure_t
-  {
-    const ValueFormat *valueFormats;
-    unsigned int len1; /* valueFormats[0].get_len() */
-    unsigned int stride; /* 1 + len1 + len2 */
-  };
-
-  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
-  {
-    TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)
-       && c->check_range (&firstPairValueRecord,
-                          len,
-                          HBUINT16::static_size,
-                          closure->stride))) return_trace (false);
-
-    unsigned int count = len;
-    const PairValueRecord *record = &firstPairValueRecord;
-    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
-                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
-  }
-
-  protected:
-  HBUINT16              len;    /* Number of PairValueRecords */
-  PairValueRecord       firstPairValueRecord;
-                                /* Array of PairValueRecords--ordered
-                                 * by GlyphID of the second glyph */
-  public:
-  DEFINE_SIZE_MIN (2);
-};
-
-struct PairPosFormat1
-{
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of subtable */
   ValueFormat   valueFormat[2];         /* [0] Defines the types of data in
@@ -251,11 +25,11 @@ struct PairPosFormat1
                                         /* [1] Defines the types of data in
                                          * ValueRecord2--for the second glyph
                                          * in the pair--may be zero (0) */
-  Array16OfOffset16To<PairSet>
+  Array16Of<typename Types::template OffsetTo<PairSet>>
                 pairSet;                /* Array of PairSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (10, pairSet);
+  DEFINE_SIZE_ARRAY (8 + Types::size, pairSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -265,7 +39,7 @@ struct PairPosFormat1
 
     unsigned int len1 = valueFormat[0].get_len ();
     unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure =
+    typename PairSet::sanitize_closure_t closure =
     {
       valueFormat,
       len1,
@@ -275,14 +49,13 @@ struct PairPosFormat1
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
-
   bool intersects (const hb_set_t *glyphs) const
   {
     return
     + hb_zip (this+coverage, pairSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
+    | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
               { return (this+_).intersects (glyphs, valueFormat); })
     | hb_any
     ;
@@ -358,7 +131,7 @@ struct PairPosFormat1
 
     + hb_zip (this+coverage, pairSet)
     | hb_filter (glyphset, hb_first)
-    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
+    | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
                  {
                    auto snap = c->serializer->snapshot ();
                    auto *o = out->pairSet.serialize_append (c->serializer);
@@ -391,7 +164,7 @@ struct PairPosFormat1
 
     unsigned format1 = 0;
     unsigned format2 = 0;
-    for (const Offset16To<PairSet>& _ :
+    for (const auto & _ :
              + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
     {
       const PairSet& set = (this + _);

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

@@ -7,11 +7,12 @@ namespace OT {
 namespace Layout {
 namespace GPOS_impl {
 
-struct PairPosFormat2
+template <typename Types>
+struct PairPosFormat2_4
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of subtable */
   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
@@ -20,11 +21,11 @@ struct PairPosFormat2
   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
                                          * second glyph of the pair--may be
                                          * zero (0) */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                 classDef1;              /* Offset to ClassDef table--from
                                          * beginning of PairPos subtable--for
                                          * the first glyph of the pair */
-  Offset16To<ClassDef>
+  typename Types::template OffsetTo<ClassDef>
                 classDef2;              /* Offset to ClassDef table--from
                                          * beginning of PairPos subtable--for
                                          * the second glyph of the pair */
@@ -36,7 +37,7 @@ struct PairPosFormat2
                                          * class1-major, class2-minor,
                                          * Each entry has value1 and value2 */
   public:
-  DEFINE_SIZE_ARRAY (16, values);
+  DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {

+ 173 - 0
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh

@@ -0,0 +1,173 @@
+#ifndef OT_LAYOUT_GPOS_PAIRSET_HH
+#define OT_LAYOUT_GPOS_PAIRSET_HH
+
+#include "PairValueRecord.hh"
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairSet
+{
+  template <typename Types2>
+  friend struct PairPosFormat1_3;
+
+  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
+
+  protected:
+  HBUINT16              len;    /* Number of PairValueRecords */
+  PairValueRecord       firstPairValueRecord;
+                                /* Array of PairValueRecords--ordered
+                                 * by GlyphID of the second glyph */
+  public:
+  DEFINE_SIZE_MIN (2);
+
+  struct sanitize_closure_t
+  {
+    const ValueFormat *valueFormats;
+    unsigned int len1; /* valueFormats[0].get_len() */
+    unsigned int stride; /* 1 + len1 + len2 */
+  };
+
+  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (!(c->check_struct (this)
+       && c->check_range (&firstPairValueRecord,
+                          len,
+                          HBUINT16::static_size,
+                          closure->stride))) return_trace (false);
+
+    unsigned int count = len;
+    const PairValueRecord *record = &firstPairValueRecord;
+    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+  }
+
+  bool intersects (const hb_set_t *glyphs,
+                   const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs->has (record->secondGlyph))
+        return true;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+    return false;
+  }
+
+  void collect_glyphs (hb_collect_glyphs_context_t *c,
+                       const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    c->input->add_array (&record->secondGlyph, len, record_size);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats) const
+  {
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (c->glyph_set->has (record->secondGlyph))
+      { record->collect_variation_indices (c, valueFormats, this); }
+
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+  }
+
+  bool apply (hb_ot_apply_context_t *c,
+              const ValueFormat *valueFormats,
+              unsigned int pos) const
+  {
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+                                                &firstPairValueRecord,
+                                                len,
+                                                record_size);
+    if (record)
+    {
+      bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+      bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+      if (applied_first || applied_second)
+        buffer->unsafe_to_break (buffer->idx, pos + 1);
+      if (len2)
+        pos++;
+      buffer->idx = pos;
+      return_trace (true);
+    }
+    buffer->unsafe_to_concat (buffer->idx, pos + 1);
+    return_trace (false);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const ValueFormat valueFormats[2],
+               const ValueFormat newFormats[2]) const
+  {
+    TRACE_SUBSET (this);
+    auto snap = c->serializer->snapshot ();
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->len = 0;
+
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+    typename PairValueRecord::context_t context =
+    {
+      this,
+      valueFormats,
+      newFormats,
+      len1,
+      &glyph_map,
+      c->plan->layout_variation_idx_map
+    };
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len, num = 0;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (glyphset.has (record->secondGlyph)
+         && record->subset (c, &context)) num++;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+
+    out->len = num;
+    if (!num) c->serializer->revert (snap);
+    return_trace (num);
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRSET_HH

+ 97 - 0
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh

@@ -0,0 +1,97 @@
+#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+
+namespace OT {
+namespace Layout {
+namespace GPOS_impl {
+
+
+template <typename Types>
+struct PairValueRecord
+{
+  template <typename Types2>
+  friend struct PairSet;
+
+  protected:
+  typename Types::HBGlyphID
+	        secondGlyph;            /* GlyphID of second glyph in the
+                                         * pair--first glyph is listed in the
+                                         * Coverage table */
+  ValueRecord   values;                 /* Positioning data for the first glyph
+                                         * followed by for second glyph */
+  public:
+  DEFINE_SIZE_ARRAY (Types::size, values);
+
+  int cmp (hb_codepoint_t k) const
+  { return secondGlyph.cmp (k); }
+
+  struct context_t
+  {
+    const void          *base;
+    const ValueFormat   *valueFormats;
+    const ValueFormat   *newFormats;
+    unsigned            len1; /* valueFormats[0].get_len() */
+    const hb_map_t      *glyph_map;
+    const hb_map_t      *layout_variation_idx_map;
+  };
+
+  bool subset (hb_subset_context_t *c,
+               context_t *closure) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *s = c->serializer;
+    auto *out = s->start_embed (*this);
+    if (unlikely (!s->extend_min (out))) return_trace (false);
+
+    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
+
+    closure->valueFormats[0].copy_values (s,
+                                          closure->newFormats[0],
+                                          closure->base, &values[0],
+                                          closure->layout_variation_idx_map);
+    closure->valueFormats[1].copy_values (s,
+                                          closure->newFormats[1],
+                                          closure->base,
+                                          &values[closure->len1],
+                                          closure->layout_variation_idx_map);
+
+    return_trace (true);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats,
+                                  const void *base) const
+  {
+    unsigned record1_len = valueFormats[0].get_len ();
+    unsigned record2_len = valueFormats[1].get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
+
+    if (valueFormats[0].has_device ())
+      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
+
+    if (valueFormats[1].has_device ())
+      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
+  }
+
+  bool intersects (const hb_set_t& glyphset) const
+  {
+    return glyphset.has(secondGlyph);
+  }
+
+  const Value* get_values_1 () const
+  {
+    return &values[0];
+  }
+
+  const Value* get_values_2 (ValueFormat format1) const
+  {
+    return &values[format1.get_len ()];
+  }
+};
+
+
+}
+}
+}
+
+#endif  // OT_LAYOUT_GPOS_PAIRVALUERECORD_HH

+ 0 - 3
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh

@@ -45,10 +45,7 @@ struct SinglePos
     ValueFormat new_format = src->get_value_format ();
 
     if (glyph_val_iter_pairs)
-    {
       format = get_format (glyph_val_iter_pairs);
-      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
-    }
 
     u.format = format;
     switch (u.format) {

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

@@ -104,9 +104,11 @@ struct SinglePosFormat1
     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
+
     auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
+    + hb_iter (intersection)
     | hb_map_retains_sorting (glyph_map)
     | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
     ;

+ 3 - 2
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh

@@ -5,12 +5,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct AlternateSet
 {
   protected:
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 alternates;             /* Array of alternate GlyphIDs--in
                                          * arbitrary order */
   public:

+ 14 - 3
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh

@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct AlternateSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  AlternateSubstFormat1 format1;
+  HBUINT16				format;         /* Format identifier */
+  AlternateSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  AlternateSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
   public:
 
@@ -24,10 +27,15 @@ struct AlternateSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+   * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
   bool serialize (hb_serialize_context_t *c,
                   hb_sorted_array_t<const HBGlyphID16> glyphs,
                   hb_array_t<const unsigned int> alternate_len_list,
@@ -42,6 +50,9 @@ struct AlternateSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 }

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

@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct AlternateSubstFormat1
+template <typename Types>
+struct AlternateSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<AlternateSet>
+  Array16Of<typename Types::template OffsetTo<AlternateSet<Types>>>
                 alternateSet;           /* Array of AlternateSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, alternateSet);
+  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -39,9 +40,8 @@ struct AlternateSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
     ;
-
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -52,7 +52,7 @@ struct AlternateSubstFormat1
     + hb_zip (this+coverage, alternateSet)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const AlternateSet<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 

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

@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ChainContextSubst : ChainContext {};
 

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

@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
 

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

@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ContextSubst : Context {};
 

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

@@ -7,7 +7,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ExtensionSubst : Extension<ExtensionSubst>
 {

+ 9 - 8
thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh

@@ -1,16 +1,15 @@
 #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 {
+
+using Layout::GSUB_impl::SubstLookup;
+
 namespace Layout {
-namespace GSUB {
 
 /*
  * GSUB -- Glyph Substitution
@@ -33,7 +32,10 @@ struct GSUB : GSUBGPOS
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
-  { return GSUBGPOS::sanitize<SubstLookup> (c); }
+  {
+    TRACE_SANITIZE (this);
+    return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
+  }
 
   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
@@ -47,11 +49,10 @@ struct GSUB : GSUBGPOS
 };
 
 
-}
 }
 
-struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t {
-  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {}
+struct GSUB_accelerator_t : Layout::GSUB::accelerator_t {
+  GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {}
 };
 
 

+ 7 - 5
thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh

@@ -5,18 +5,20 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct Ligature
 {
   protected:
-  HBGlyphID16   ligGlyph;               /* GlyphID of ligature to substitute */
-  HeadlessArrayOf<HBGlyphID16>
-                component;              /* Array of component GlyphIDs--start
+  typename Types::HBGlyphID
+		ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArrayOf<typename Types::HBGlyphID>
+		component;              /* Array of component GlyphIDs--start
                                          * with the second  component--ordered
                                          * in writing direction */
   public:
-  DEFINE_SIZE_ARRAY (4, component);
+  DEFINE_SIZE_ARRAY (Types::size + 2, component);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {

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

@@ -6,12 +6,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct LigatureSet
 {
   protected:
-  Array16OfOffset16To<Ligature>
+  Array16OfOffset16To<Ligature<Types>>
                 ligature;               /* Array LigatureSet tables
                                          * ordered by preference */
   public:
@@ -28,7 +29,7 @@ struct LigatureSet
     return
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
+    | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
     | hb_any
     ;
   }
@@ -37,7 +38,7 @@ struct LigatureSet
   {
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
+    | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
     ;
   }
 
@@ -45,7 +46,7 @@ struct LigatureSet
   {
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
@@ -54,7 +55,7 @@ struct LigatureSet
     return
     + hb_iter (ligature)
     | hb_map (hb_add (this))
-    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
+    | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
     | hb_any
     ;
   }
@@ -65,7 +66,7 @@ struct LigatureSet
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
-      const Ligature &lig = this+ligature[i];
+      const auto &lig = this+ligature[i];
       if (lig.apply (c)) return_trace (true);
     }
 

+ 15 - 3
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh

@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct LigatureSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  LigatureSubstFormat1  format1;
+  HBUINT16				format;         /* Format identifier */
+  LigatureSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  LigatureSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -24,10 +27,16 @@ struct LigatureSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should
+   * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t
+   * instead. */
   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,
@@ -49,6 +58,9 @@ struct LigatureSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 

+ 12 - 11
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh

@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct LigatureSubstFormat1
+template <typename Types>
+struct LigatureSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<LigatureSet>
+  Array16Of<typename Types::template OffsetTo<LigatureSet<Types>>>
                 ligatureSet;            /* Array LigatureSet tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, ligatureSet);
+  DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -33,7 +34,7 @@ struct LigatureSubstFormat1
     + hb_zip (this+coverage, ligatureSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
+    | hb_map ([this, glyphs] (const typename Types::template OffsetTo<LigatureSet<Types>> &_)
               { return (this+_).intersects (glyphs); })
     | hb_any
     ;
@@ -48,7 +49,7 @@ struct LigatureSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.closure (c); })
     ;
 
   }
@@ -62,7 +63,7 @@ struct LigatureSubstFormat1
     + hb_zip (this+coverage, ligatureSet)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const LigatureSet<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 
@@ -73,7 +74,7 @@ struct LigatureSubstFormat1
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
     if (likely (index == NOT_COVERED)) return false;
 
-    const LigatureSet &lig_set = this+ligatureSet[index];
+    const auto &lig_set = this+ligatureSet[index];
     return lig_set.would_apply (c);
   }
 
@@ -84,7 +85,7 @@ struct LigatureSubstFormat1
     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];
+    const auto &lig_set = this+ligatureSet[index];
     return_trace (lig_set.apply (c));
   }
 
@@ -128,7 +129,7 @@ struct LigatureSubstFormat1
     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& _) {
+    | hb_filter ([&] (const LigatureSet<Types>& _) {
       return _.intersects (&glyphset);
     }, hb_second)
     | hb_map (hb_first)

+ 14 - 3
thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh

@@ -6,14 +6,17 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct MultipleSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  MultipleSubstFormat1  format1;
+  HBUINT16				format;         /* Format identifier */
+  MultipleSubstFormat1_2<SmallTypes>	format1;
+#ifndef HB_NO_BORING_EXPANSION
+  MultipleSubstFormat1_2<MediumTypes>	format2;
+#endif
   } u;
 
   public:
@@ -25,10 +28,15 @@ struct MultipleSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
 
+  /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
+   * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
   bool serialize (hb_serialize_context_t *c,
                   hb_sorted_array_t<const HBGlyphID16> glyphs,
                   hb_array_t<const unsigned int> substitute_len_list,
@@ -43,6 +51,9 @@ struct MultipleSubst
     default:return_trace (false);
     }
   }
+
+  /* TODO subset() should choose format. */
+
 };
 
 

+ 8 - 7
thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubstFormat1.hh

@@ -6,20 +6,21 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct MultipleSubstFormat1
+template <typename Types>
+struct MultipleSubstFormat1_2
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16OfOffset16To<Sequence>
+  Array16Of<typename Types::template OffsetTo<Sequence<Types>>>
                 sequence;               /* Array of Sequence tables
                                          * ordered by Coverage Index */
   public:
-  DEFINE_SIZE_ARRAY (6, sequence);
+  DEFINE_SIZE_ARRAY (4 + Types::size, sequence);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -39,7 +40,7 @@ struct MultipleSubstFormat1
     | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
+    | hb_apply ([c] (const Sequence<Types> &_) { _.closure (c); })
     ;
   }
 
@@ -51,7 +52,7 @@ struct MultipleSubstFormat1
     + hb_zip (this+coverage, sequence)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
-    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
+    | hb_apply ([c] (const Sequence<Types> &_) { _.collect_glyphs (c); })
     ;
   }
 

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

@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ReverseChainSingleSubst
 {

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

@@ -5,7 +5,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct ReverseChainSingleSubstFormat1
 {
@@ -33,10 +33,10 @@ struct ReverseChainSingleSubstFormat1
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
@@ -45,7 +45,7 @@ struct ReverseChainSingleSubstFormat1
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
 
     unsigned int count;
 
@@ -69,8 +69,8 @@ struct ReverseChainSingleSubstFormat1
   {
     if (!intersects (c->glyphs)) return;
 
-    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
-    const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     + hb_zip (this+coverage, substitute)
     | hb_filter (c->parent_active_glyphs (), hb_first)
@@ -91,12 +91,12 @@ struct ReverseChainSingleSubstFormat1
     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);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (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);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -115,8 +115,8 @@ struct ReverseChainSingleSubstFormat1
     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);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
@@ -206,8 +206,8 @@ struct ReverseChainSingleSubstFormat1
     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);
+    const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
+    const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
 
     auto it =
     + hb_zip (this+coverage, substitute)

+ 3 - 2
thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh

@@ -5,12 +5,13 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
+template <typename Types>
 struct Sequence
 {
   protected:
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 substitute;             /* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);

+ 34 - 6
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh

@@ -7,15 +7,19 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SingleSubst
 {
   protected:
   union {
-  HBUINT16              format;         /* Format identifier */
-  SingleSubstFormat1    format1;
-  SingleSubstFormat2    format2;
+  HBUINT16				format;         /* Format identifier */
+  SingleSubstFormat1_3<SmallTypes>	format1;
+  SingleSubstFormat2_4<SmallTypes>	format2;
+#ifndef HB_NO_BORING_EXPANSION
+  SingleSubstFormat1_3<MediumTypes>	format3;
+  SingleSubstFormat2_4<MediumTypes>	format4;
+#endif
   } u;
 
   public:
@@ -28,6 +32,10 @@ struct SingleSubst
     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)...));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+#endif
     default:return_trace (c->default_return_value ());
     }
   }
@@ -45,11 +53,24 @@ struct SingleSubst
     if (glyphs)
     {
       format = 1;
+      hb_codepoint_t mask = 0xFFFFu;
+
+#ifndef HB_NO_BORING_EXPANSION
+       if (+ glyphs
+	   | hb_map_retains_sorting (hb_first)
+	   | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
+       {
+	 format += 2;
+	 mask = 0xFFFFFFu;
+       }
+#endif
+
       auto get_delta = [=] (hb_codepoint_pair_t _)
-                       { return (unsigned) (_.second - _.first) & 0xFFFF; };
+                       { return (unsigned) (_.second - _.first) & mask; };
       delta = get_delta (*glyphs);
-      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
+      if (!hb_all (++(+glyphs), delta, get_delta)) format += 1;
     }
+
     u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c,
@@ -57,6 +78,13 @@ struct SingleSubst
                                                | hb_map_retains_sorting (hb_first),
                                                delta));
     case 2: return_trace (u.format2.serialize (c, glyphs));
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: return_trace (u.format3.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 4: return_trace (u.format4.serialize (c, glyphs));
+#endif
     default:return_trace (false);
     }
   }

+ 34 - 20
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh

@@ -5,20 +5,22 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct SingleSubstFormat1
+template <typename Types>
+struct SingleSubstFormat1_3
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  HBUINT16      deltaGlyphID;           /* Add to original GlyphID to get
+  typename Types::HBUINT
+                deltaGlyphID;           /* Add to original GlyphID to get
                                          * substitute GlyphID, modulo 0x10000 */
 
   public:
-  DEFINE_SIZE_STATIC (6);
+  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -26,6 +28,9 @@ struct SingleSubstFormat1
     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
+  hb_codepoint_t get_mask () const
+  { return (1 << (8 * Types::size)) - 1; }
+
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
@@ -34,14 +39,16 @@ struct SingleSubstFormat1
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned d = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
 
-    + hb_iter (this+coverage)
-    | hb_filter (c->parent_active_glyphs ())
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    hb_set_t intersection;
+    (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
+
+    + hb_iter (intersection)
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     | hb_sink (c->output)
     ;
-
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -49,9 +56,11 @@ struct SingleSubstFormat1
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
-    unsigned d = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
     + hb_iter (this+coverage)
-    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     | hb_sink (c->output)
     ;
   }
@@ -68,9 +77,11 @@ struct SingleSubstFormat1
     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;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    glyph_id = (glyph_id + d) & mask;
+
     c->replace_glyph (glyph_id);
 
     return_trace (true);
@@ -95,14 +106,17 @@ struct SingleSubstFormat1
     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
-    hb_codepoint_t delta = deltaGlyphID;
+    hb_codepoint_t d = deltaGlyphID;
+    hb_codepoint_t mask = get_mask ();
+
+    hb_set_t intersection;
+    (this+coverage).intersect_set (glyphset, intersection);
 
     auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (glyphset)
-    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
+    + hb_iter (intersection)
+    | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
                                 return hb_codepoint_pair_t (g,
-                                                            (g + delta) & 0xFFFF); })
+                                                            (g + d) & mask); })
     | 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]); })

+ 7 - 6
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh

@@ -5,21 +5,22 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
-struct SingleSubstFormat2
+template <typename Types>
+struct SingleSubstFormat2_4
 {
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
-  Offset16To<Coverage>
+  typename Types::template OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  Array16Of<HBGlyphID16>
+  Array16Of<typename Types::HBGlyphID>
                 substitute;             /* Array of substitute
                                          * GlyphIDs--ordered by Coverage Index */
 
   public:
-  DEFINE_SIZE_ARRAY (6, substitute);
+  DEFINE_SIZE_ARRAY (4 + Types::size, substitute);
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -103,7 +104,7 @@ struct SingleSubstFormat2
     + 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
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const typename Types::HBGlyphID &> p) -> hb_codepoint_pair_t
                               { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
     ;
 

+ 9 - 4
thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh

@@ -6,7 +6,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SubstLookup : Lookup
 {
@@ -25,7 +25,7 @@ struct SubstLookup : Lookup
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubTable::Extension))
-      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
+      return get_subtable (0).u.extension.is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
@@ -98,10 +98,15 @@ struct SubstLookup : Lookup
       return dispatch (c);
   }
 
+  template<typename Glyphs, typename Substitutes,
+	   hb_requires (hb_is_sorted_source_of (Glyphs,
+						const hb_codepoint_t) &&
+			hb_is_source_of (Substitutes,
+					 const hb_codepoint_t))>
   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)
+                         Glyphs glyphs,
+                         Substitutes substitutes)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);

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

@@ -13,7 +13,7 @@
 
 namespace OT {
 namespace Layout {
-namespace GSUB {
+namespace GSUB_impl {
 
 struct SubstLookupSubTable
 {

+ 66 - 0
thirdparty/harfbuzz/src/OT/Layout/types.hh

@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger
+ */
+
+#ifndef OT_LAYOUT_TYPES_HH
+#define OT_LAYOUT_TYPES_HH
+
+namespace OT {
+namespace Layout {
+
+struct SmallTypes {
+  static constexpr unsigned size = 2;
+  using large_int = uint32_t;
+  using HBUINT = HBUINT16;
+  using HBGlyphID = HBGlyphID16;
+  using Offset = Offset16;
+  template <typename Type, bool has_null=true>
+  using OffsetTo = OT::Offset16To<Type, has_null>;
+  template <typename Type>
+  using ArrayOf = OT::Array16Of<Type>;
+  template <typename Type>
+  using SortedArrayOf = OT::SortedArray16Of<Type>;
+};
+
+struct MediumTypes {
+  static constexpr unsigned size = 3;
+  using large_int = uint64_t;
+  using HBUINT = HBUINT24;
+  using HBGlyphID = HBGlyphID24;
+  using Offset = Offset24;
+  template <typename Type, bool has_null=true>
+  using OffsetTo = OT::Offset24To<Type, has_null>;
+  template <typename Type>
+  using ArrayOf = OT::Array24Of<Type>;
+  template <typename Type>
+  using SortedArrayOf = OT::SortedArray24Of<Type>;
+};
+
+}
+}
+
+#endif  /* OT_LAYOUT_TYPES_HH */

+ 32 - 4
thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh

@@ -25,13 +25,16 @@ struct CompositeGlyphRecord
     USE_MY_METRICS		= 0x0200,
     OVERLAP_COMPOUND		= 0x0400,
     SCALED_COMPONENT_OFFSET	= 0x0800,
-    UNSCALED_COMPONENT_OFFSET	= 0x1000
+    UNSCALED_COMPONENT_OFFSET	= 0x1000,
+    GID_IS_24BIT		= 0x2000
   };
 
   public:
   unsigned int get_size () const
   {
     unsigned int size = min_size;
+    /* glyphIndex is 24bit instead of 16bit */
+    if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
     /* arg1 and 2 are int16 */
     if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
     /* arg1 and 2 are int8 */
@@ -60,7 +63,11 @@ struct CompositeGlyphRecord
   bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
   void get_anchor_points (unsigned int &point1, unsigned int &point2) const
   {
-    const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
+    const auto *p = &StructAfter<const HBUINT8> (flags);
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+      p += HBGlyphID16::static_size;
     if (flags & ARG_1_AND_2_ARE_WORDS)
     {
       point1 = ((const HBUINT16 *) p)[0];
@@ -101,8 +108,12 @@ struct CompositeGlyphRecord
     matrix[0] = matrix[3] = 1.f;
     matrix[1] = matrix[2] = 0.f;
 
+    const auto *p = &StructAfter<const HBINT8> (flags);
+    if (flags & GID_IS_24BIT)
+      p += HBGlyphID24::static_size;
+    else
+      p += HBGlyphID16::static_size;
     int tx, ty;
-    const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
     if (flags & ARG_1_AND_2_ARE_WORDS)
     {
       tx = *(const HBINT16 *) p;
@@ -145,8 +156,25 @@ struct CompositeGlyphRecord
   }
 
   public:
+  hb_codepoint_t get_gid () const
+  {
+    if (flags & GID_IS_24BIT)
+      return StructAfter<const HBGlyphID24> (flags);
+    else
+      return StructAfter<const HBGlyphID16> (flags);
+  }
+  void set_gid (hb_codepoint_t gid)
+  {
+    if (flags & GID_IS_24BIT)
+      StructAfter<HBGlyphID24> (flags) = gid;
+    else
+      /* TODO assert? */
+      StructAfter<HBGlyphID16> (flags) = gid;
+  }
+
+  protected:
   HBUINT16	flags;
-  HBGlyphID16	glyphIndex;
+  HBUINT24	pad;
   public:
   DEFINE_SIZE_MIN (4);
 };

+ 11 - 9
thirdparty/harfbuzz/src/OT/glyf/Glyph.hh

@@ -105,19 +105,21 @@ struct Glyph
     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
     hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
     {
-      int h_delta = (int) header->xMin -
-		    glyf_accelerator.hmtx->get_side_bearing (gid);
+      int lsb = 0;
+      int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+		    (int) header->xMin - lsb : 0;
+      int tsb = 0;
       int v_orig  = (int) header->yMax +
 #ifndef HB_NO_VERTICAL
-		    glyf_accelerator.vmtx->get_side_bearing (gid)
+		    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
 #else
 		    0
 #endif
 		    ;
-      unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
+      unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
       unsigned v_adv =
 #ifndef HB_NO_VERTICAL
-		       glyf_accelerator.vmtx->get_advance (gid)
+		       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
 #else
 		       - font->face->get_upem ()
 #endif
@@ -144,7 +146,7 @@ struct Glyph
       for (auto &item : get_composite_iterator ())
       {
         comp_points.reset ();
-	if (unlikely (!glyf_accelerator.glyph_for_gid (item.glyphIndex)
+	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 				       .get_points (font, glyf_accelerator, comp_points,
 						    phantom_only, depth + 1)))
 	  return false;
@@ -198,11 +200,11 @@ struct Glyph
     return !all_points.in_error ();
   }
 
-  bool get_extents (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
-		    hb_glyph_extents_t *extents) const
+  bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
+				       hb_glyph_extents_t *extents) const
   {
     if (type == EMPTY) return true; /* Empty glyph; zero extents. */
-    return header->get_extents (font, glyf_accelerator, gid, extents);
+    return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
   }
 
   hb_bytes_t get_bytes () const { return bytes; }

+ 5 - 3
thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh

@@ -14,12 +14,14 @@ struct GlyphHeader
   bool has_data () const { return numberOfContours; }
 
   template <typename accelerator_t>
-  bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
-		    hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+  bool get_extents_without_var_scaled (hb_font_t *font, const accelerator_t &glyf_accelerator,
+				       hb_codepoint_t gid, hb_glyph_extents_t *extents) const
   {
     /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
     /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
-    extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
+    int lsb = hb_min (xMin, xMax);
+    (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
+    extents->x_bearing = font->em_scale_x (lsb);
     extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
     extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
     extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));

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

@@ -42,8 +42,8 @@ struct SubsetGlyph
     for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
     {
       hb_codepoint_t new_gid;
-      if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid))
-	const_cast<CompositeGlyphRecord &> (_).glyphIndex = new_gid;
+      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
+	const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
     }
 
     if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)

+ 34 - 25
thirdparty/harfbuzz/src/OT/glyf/glyf.hh

@@ -194,6 +194,7 @@ struct glyf_accelerator_t
     hb_font_t *font;
     hb_glyph_extents_t *extents;
     contour_point_t *phantoms;
+    bool scaled;
 
     struct contour_bounds_t
     {
@@ -209,7 +210,7 @@ struct glyf_accelerator_t
 
       bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
 
-      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
+      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled)
       {
 	if (unlikely (empty ()))
 	{
@@ -219,26 +220,37 @@ struct glyf_accelerator_t
 	  extents->y_bearing = 0;
 	  return;
 	}
-	extents->x_bearing = font->em_scalef_x (min_x);
-	extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
-	extents->y_bearing = font->em_scalef_y (max_y);
-	extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
+	if (scaled)
+	{
+	  extents->x_bearing = font->em_scalef_x (min_x);
+	  extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
+	  extents->y_bearing = font->em_scalef_y (max_y);
+	  extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
+	}
+	else
+	{
+	  extents->x_bearing = roundf (min_x);
+	  extents->width = roundf (max_x - extents->x_bearing);
+	  extents->y_bearing = roundf (max_y);
+	  extents->height = roundf (min_y - extents->y_bearing);
+	}
       }
 
       protected:
       float min_x, min_y, max_x, max_y;
     } bounds;
 
-    points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
+    points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_)
     {
       font = font_;
       extents = extents_;
       phantoms = phantoms_;
+      scaled = scaled_;
       if (extents) bounds = contour_bounds_t ();
     }
 
     void consume_point (const contour_point_t &point) { bounds.add (point); }
-    void points_end () { bounds.get_extents (font, extents); }
+    void points_end () { bounds.get_extents (font, extents, scaled); }
 
     bool is_consuming_contour_points () { return extents; }
     contour_point_t *get_phantoms_sink () { return phantoms; }
@@ -246,22 +258,22 @@ struct glyf_accelerator_t
 
   public:
   unsigned
-  get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+  get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
   {
     if (unlikely (gid >= num_glyphs)) return 0;
 
     bool success = false;
 
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (likely (font->num_coords == gvar->get_axis_count ()))
-      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
+    if (font->num_coords)
+      success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
 
     if (unlikely (!success))
       return
 #ifndef HB_NO_VERTICAL
-	is_vertical ? vmtx->get_advance (gid) :
+	is_vertical ? vmtx->get_advance_without_var_unscaled (gid) :
 #endif
-	hmtx->get_advance (gid);
+	hmtx->get_advance_without_var_unscaled (gid);
 
     float result = is_vertical
 		 ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
@@ -269,23 +281,20 @@ struct glyf_accelerator_t
     return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
   }
 
-  int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+  bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const
   {
-    if (unlikely (gid >= num_glyphs)) return 0;
+    if (unlikely (gid >= num_glyphs)) return false;
 
     hb_glyph_extents_t extents;
 
     contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
-    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
-      return
-#ifndef HB_NO_VERTICAL
-	is_vertical ? vmtx->get_side_bearing (gid) :
-#endif
-	hmtx->get_side_bearing (gid);
+    if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
+      return false;
 
-    return is_vertical
-	 ? ceilf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
-	 : floorf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+    *lsb = is_vertical
+	 ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing
+	 : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x);
+    return true;
   }
 #endif
 
@@ -296,9 +305,9 @@ struct glyf_accelerator_t
 
 #ifndef HB_NO_VAR
     if (font->num_coords)
-      return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
+      return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
 #endif
-    return glyph_for_gid (gid).get_extents (font, *this, extents);
+    return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
   }
 
   const glyf_impl::Glyph

+ 67 - 13
thirdparty/harfbuzz/src/graph/graph.hh

@@ -265,28 +265,64 @@ struct graph_t
   }
 
   /*
-   * Assign unique space numbers to each connected subgraph of 32 bit offset(s).
+   * Finds the set of nodes (placed into roots) that should be assigned unique spaces.
+   * More specifically this looks for the top most 24 bit or 32 bit links in the graph.
+   * Some special casing is done that is specific to the layout of GSUB/GPOS tables.
    */
-  bool assign_32bit_spaces ()
+  void find_space_roots (hb_set_t& visited, hb_set_t& roots)
   {
-    unsigned root_index = root_idx ();
-    hb_set_t visited;
-    hb_set_t roots;
-    for (unsigned i = 0; i <= root_index; i++)
+    int root_index = (int) root_idx ();
+    for (int i = root_index; i >= 0; i--)
     {
+      if (visited.has (i)) continue;
+
       // Only real links can form 32 bit spaces
       for (auto& l : vertices_[i].obj.real_links)
       {
-        if (l.width == 4 && !l.is_signed)
+        if (l.is_signed || l.width < 3)
+          continue;
+
+        if (i == root_index && l.width == 3)
+          // Ignore 24bit links from the root node, this skips past the single 24bit
+          // pointer to the lookup list.
+          continue;
+
+        if (l.width == 3)
         {
-          roots.add (l.objidx);
-          find_subgraph (l.objidx, visited);
+          // A 24bit offset forms a root, unless there is 32bit offsets somewhere
+          // in it's subgraph, then those become the roots instead. This is to make sure
+          // that extension subtables beneath a 24bit lookup become the spaces instead
+          // of the offset to the lookup.
+          hb_set_t sub_roots;
+          find_32bit_roots (l.objidx, sub_roots);
+          if (sub_roots) {
+            for (unsigned sub_root_idx : sub_roots) {
+              roots.add (sub_root_idx);
+              find_subgraph (sub_root_idx, visited);
+            }
+            continue;
+          }
         }
+
+        roots.add (l.objidx);
+        find_subgraph (l.objidx, visited);
       }
     }
+  }
 
-    // Mark everything not in the subgraphs of 32 bit roots as visited.
-    // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs.
+  /*
+   * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
+   * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
+   * (including with 24bit offsets) table.
+   */
+  bool assign_spaces ()
+  {
+    hb_set_t visited;
+    hb_set_t roots;
+    find_space_roots (visited, roots);
+
+    // Mark everything not in the subgraphs of the roots as visited. This prevents
+    // subgraphs from being connected via nodes not in those subgraphs.
     visited.invert ();
 
     if (!roots) return false;
@@ -422,6 +458,22 @@ struct graph_t
       find_subgraph (link.objidx, subgraph);
   }
 
+  /*
+   * Finds the topmost children of 32bit offsets in the subgraph starting
+   * at node_idx. Found indices are placed into 'found'.
+   */
+  void find_32bit_roots (unsigned node_idx, hb_set_t& found)
+  {
+    for (const auto& link : vertices_[node_idx].obj.all_links ())
+    {
+      if (!link.is_signed && link.width == 4) {
+        found.add (link.objidx);
+        continue;
+      }
+      find_32bit_roots (link.objidx, found);
+    }
+  }
+
   /*
    * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
    * links. index_map is updated with mappings from old id to new id. If a duplication has already
@@ -622,7 +674,7 @@ struct graph_t
  private:
 
   /*
-   * Returns the numbers of incoming edges that are 32bits wide.
+   * Returns the numbers of incoming edges that are 24 or 32 bits wide.
    */
   unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
   {
@@ -636,7 +688,9 @@ struct graph_t
       // Only real links can be wide
       for (const auto& l : vertices_[p].obj.real_links)
       {
-        if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
+        if (l.objidx == node_idx
+            && (l.width == 3 || l.width == 4)
+            && !l.is_signed)
         {
           count++;
           parents.add (p);

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

@@ -42,7 +42,7 @@ struct BaselineTableFormat0Part
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -78,7 +78,7 @@ struct BaselineTableFormat2Part
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:

+ 8 - 12
thirdparty/harfbuzz/src/hb-aat-layout-common.hh

@@ -415,18 +415,7 @@ struct Lookup
   public:
   DEFINE_SIZE_UNION (2, format);
 };
-/* Lookup 0 has unbounded size (dependant on num_glyphs).  So we need to defined
- * special NULL objects for Lookup<> objects, but since it's template our macros
- * don't work.  So we have to hand-code them here.  UGLY. */
-} /* Close namespace. */
-/* Ugly hand-coded null objects for template Lookup<> :(. */
-extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
-template <typename T>
-struct Null<AAT::Lookup<T>> {
-  static AAT::Lookup<T> const & get_null ()
-  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
-};
-namespace AAT {
+DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
 
 enum { DELETED_GLYPH = 0xFFFF };
 
@@ -681,6 +670,13 @@ struct ObsoleteTypes
 				     const void *base,
 				     const T *array)
   {
+    /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
+    /* If offset is less than base, return an offset that would
+     * result in an address half a 32bit address-space away,
+     * to make sure sanitize fails even on 32bit builds. */
+    if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
+      return INT_MAX / T::static_size;
+
     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
   }

+ 1 - 1
thirdparty/harfbuzz/src/hb-aat-layout-feat-table.hh

@@ -62,7 +62,7 @@ struct SettingName
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:

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

@@ -48,7 +48,7 @@ struct ActionSubrecordHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   HBUINT16	actionClass;	/* The JustClass value associated with this
@@ -65,7 +65,7 @@ struct DecompositionAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   ActionSubrecordHeader
@@ -112,7 +112,7 @@ struct ConditionalAddGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -137,7 +137,7 @@ struct DuctileGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -163,7 +163,7 @@ struct RepeatedAddGlyphAction
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -294,7 +294,7 @@ struct WidthDeltaPair
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:

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

@@ -751,7 +751,7 @@ struct KerxSubTableHeader
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:

+ 9 - 0
thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh

@@ -980,6 +980,15 @@ struct Chain
 	  setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
 	  goto retry;
 	}
+#ifndef HB_NO_AAT
+	else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
+		 /* TODO: Rudimentary language matching. */
+		 hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
+	{
+	  flags &= feature.disableFlags;
+	  flags |= feature.enableFlags;
+	}
+#endif
       }
     }
     return flags;

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

@@ -42,7 +42,7 @@ struct OpticalBounds
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   FWORD		leftSide;

+ 3 - 3
thirdparty/harfbuzz/src/hb-aat-layout.cc

@@ -229,7 +229,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
  *
  * <note>Note: does not examine the `GSUB` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -300,7 +300,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
  *
  * <note>Note: does not examine the `GPOS` table.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */
@@ -333,7 +333,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
  * Tests whether the specified face includes any tracking information
  * in the `trak` table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.3.0
  */

+ 4 - 2
thirdparty/harfbuzz/src/hb-aat-map.hh

@@ -52,8 +52,9 @@ struct hb_aat_map_builder_t
   public:
 
   HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
-				    const hb_segment_properties_t *props_ HB_UNUSED) :
-				      face (face_) {}
+				    const hb_segment_properties_t props_) :
+				      face (face_),
+				      props (props_) {}
 
   HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
 
@@ -87,6 +88,7 @@ struct hb_aat_map_builder_t
 
   public:
   hb_face_t *face;
+  hb_segment_properties_t props;
 
   public:
   hb_sorted_vector_t<feature_info_t> features;

+ 11 - 10
thirdparty/harfbuzz/src/hb-algs.hh

@@ -109,15 +109,16 @@ struct BEInt<Type, 2>
   struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
   constexpr operator Type () const
   {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
     defined(__BYTE_ORDER) && \
     (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+    return __builtin_bswap16 (((packed_uint16_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
+    return ((packed_uint16_t *) v)->v;
 #endif
 #else
     return (v[0] <<  8)
@@ -153,15 +154,16 @@ struct BEInt<Type, 4>
 
   struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
   constexpr operator Type () const {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
+    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
     defined(__BYTE_ORDER) && \
     (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap32 (((packed_uint32_t *) this)->v);
+    return __builtin_bswap32 (((packed_uint32_t *) v)->v);
 #else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint32_t *) this)->v;
+    return ((packed_uint32_t *) v)->v;
 #endif
 #else
     return (v[0] << 24)
@@ -525,7 +527,6 @@ struct hb_pair_t
   T1 first;
   T2 second;
 };
-#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
 template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
 hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
 
@@ -551,14 +552,14 @@ struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a <= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a <= b ? a : b)
 }
 HB_FUNCOBJ (hb_min);
 struct
 {
   template <typename T, typename T2> constexpr auto
   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
-  (a >= b ? std::forward<T> (a) : std::forward<T2> (b))
+  (a >= b ? a : b)
 }
 HB_FUNCOBJ (hb_max);
 struct
@@ -972,7 +973,7 @@ void hb_qsort(void *base, size_t nel, size_t width,
               [void *arg]);
 */
 
-#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp))
 
 /* swap a and b */
 /* a and b must not be equal! */

+ 6 - 8
thirdparty/harfbuzz/src/hb-array.hh

@@ -100,10 +100,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
    * it's best if we can just compare arrayZ, though comparing contents is still fast,
    * but also would require that Type has operator==.  As such, we optimize this operator
-   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
-   * assume we're only compared to .end(). */
+   * for range-based for loop and just compare arrayZ and length. */
   bool operator != (const hb_array_t& o) const
-  { return arrayZ != o.arrayZ; }
+  { return this->arrayZ != o.arrayZ || this->length != o.length; }
 
   /* Extra operators.
    */
@@ -220,11 +219,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
     if (end < start + 2)
       return;
 
-    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
-      Type temp = arrayZ[rhs];
-      arrayZ[rhs] = arrayZ[lhs];
-      arrayZ[lhs] = temp;
-    }
+    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
+      hb_swap (arrayZ[rhs], arrayZ[lhs]);
   }
 
   hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
@@ -328,6 +324,8 @@ struct hb_sorted_array_t :
   { hb_array_t<Type> (*this) = o; return *this; }
 
   /* Iterator implementation. */
+
+  /* See comment in hb_array_of::operator != */
   bool operator != (const hb_sorted_array_t& o) const
   { return this->arrayZ != o.arrayZ || this->length != o.length; }
 

+ 13 - 0
thirdparty/harfbuzz/src/hb-atomic.hh

@@ -111,6 +111,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 
 
+#ifndef _hb_compiler_memory_r_barrier
+/* This we always use std::atomic for; and should never be disabled...
+ * except that MSVC gives me an internal compiler error on it. */
+#if !defined(_MSC_VER)
+#include <atomic>
+#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
+#else
+#define _hb_compiler_memory_r_barrier() do {} while (0)
+#endif
+#endif
+
+
+
 #ifndef _hb_memory_r_barrier
 #define _hb_memory_r_barrier()			_hb_memory_barrier ()
 #endif

+ 1 - 1
thirdparty/harfbuzz/src/hb-bit-page.hh

@@ -55,7 +55,7 @@ struct hb_bit_page_t
 
   void add (hb_codepoint_t g) { elt (g) |= mask (g); }
   void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-  void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+  void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
   bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
   void add_range (hb_codepoint_t a, hb_codepoint_t b)

+ 12 - 5
thirdparty/harfbuzz/src/hb-bit-set.hh

@@ -465,12 +465,10 @@ struct hb_bit_set_t
   }
   public:
 
-  template <typename Op>
-  void process (const Op& op, const hb_bit_set_t &other)
+  void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
+		 bool passthru_left, bool passthru_right,
+		 const hb_bit_set_t &other)
   {
-    const bool passthru_left = op (1, 0);
-    const bool passthru_right = op (0, 1);
-
     if (unlikely (!successful)) return;
 
     dirty ();
@@ -590,6 +588,15 @@ struct hb_bit_set_t
     assert (!count);
     resize (newCount);
   }
+  template <typename Op>
+  static hb_bit_page_t::vector_t
+  op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
+  { return Op{} (a, b); }
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_t &other)
+  {
+    process_ (op_<Op>, op (1, 0), op (0, 1), other);
+  }
 
   void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
   void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }

+ 5 - 7
thirdparty/harfbuzz/src/hb-blob.cc

@@ -99,7 +99,7 @@ hb_blob_create (const char        *data,
  * is zero. This is in contrast to hb_blob_create(), which returns the singleton
  * empty blob (as returned by hb_blob_get_empty()) if @length is zero.
  *
- * Return value: New blob, or %NULL if failed.  Destroy with hb_blob_destroy().
+ * Return value: New blob, or `NULL` if failed.  Destroy with hb_blob_destroy().
  *
  * Since: 2.8.2
  **/
@@ -263,8 +263,6 @@ hb_blob_destroy (hb_blob_t *blob)
 {
   if (!hb_object_destroy (blob)) return;
 
-  blob->fini_shallow ();
-
   hb_free (blob);
 }
 
@@ -278,7 +276,7 @@ hb_blob_destroy (hb_blob_t *blob)
  *
  * Attaches a user-data key/data pair to the specified blob.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -335,7 +333,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
  *
  * Tests whether a blob is immutable.
  *
- * Return value: %true if @blob is immutable, %false otherwise
+ * Return value: `true` if @blob is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -394,7 +392,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
  * fails.
  *
  * Returns: (transfer none) (array length=length): Writable blob data,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 0.9.2
  **/
@@ -620,7 +618,7 @@ hb_blob_create_from_file (const char *file_name)
  * specified binary font file.
  *
  * Returns: An #hb_blob_t pointer with the content of the file,
- * or %NULL if failed.
+ * or `NULL` if failed.
  *
  * Since: 2.8.2
  **/

+ 6 - 6
thirdparty/harfbuzz/src/hb-blob.hh

@@ -38,7 +38,7 @@
 
 struct hb_blob_t
 {
-  void fini_shallow () { destroy_user_data (); }
+  ~hb_blob_t () { destroy_user_data (); }
 
   void destroy_user_data ()
   {
@@ -61,12 +61,12 @@ struct hb_blob_t
   public:
   hb_object_header_t header;
 
-  const char *data;
-  unsigned int length;
-  hb_memory_mode_t mode;
+  const char *data = nullptr;
+  unsigned int length = 0;
+  hb_memory_mode_t mode = (hb_memory_mode_t) 0;
 
-  void *user_data;
-  hb_destroy_func_t destroy;
+  void *user_data = nullptr;
+  hb_destroy_func_t destroy = nullptr;
 };
 
 

+ 248 - 183
thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh

@@ -32,15 +32,16 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-json.hh"
+#line 33 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
 	0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
 	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
 	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
 	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
-	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
+	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 
+	9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 
+	34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, 
+	9u, 123u, 0u, 0u, 0
 };
 
 static const char _deserialize_json_key_spans[] = {
@@ -48,9 +49,10 @@ static const char _deserialize_json_key_spans[] = {
 	10, 117, 117, 117, 1, 50, 49, 10, 
 	117, 117, 1, 1, 50, 49, 117, 117, 
 	2, 1, 50, 49, 10, 117, 117, 1, 
-	50, 49, 10, 117, 117, 1, 50, 49, 
-	59, 117, 59, 117, 117, 1, 50, 49, 
-	117, 85, 115, 0
+	50, 49, 10, 117, 117, 1, 1, 50, 
+	49, 117, 117, 1, 50, 49, 59, 117, 
+	59, 117, 117, 1, 50, 49, 117, 85, 
+	115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
@@ -58,9 +60,10 @@ static const short _deserialize_json_index_offsets[] = {
 	271, 282, 400, 518, 636, 638, 689, 739, 
 	750, 868, 986, 988, 990, 1041, 1091, 1209, 
 	1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, 
-	1682, 1733, 1783, 1794, 1912, 2030, 2032, 2083, 
-	2133, 2193, 2311, 2371, 2489, 2607, 2609, 2660, 
-	2710, 2828, 2914, 3030
+	1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, 
+	2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, 
+	2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, 
+	3255, 3371
 };
 
 static const char _deserialize_json_indicies[] = {
@@ -82,28 +85,28 @@ static const char _deserialize_json_indicies[] = {
 	3, 3, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 3, 1, 4, 1, 
-	5, 1, 6, 7, 1, 1, 8, 1, 
+	5, 1, 6, 7, 1, 8, 9, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 9, 1, 10, 11, 
-	1, 12, 1, 12, 12, 12, 12, 12, 
+	1, 1, 1, 1, 10, 1, 11, 12, 
+	1, 13, 1, 13, 13, 13, 13, 13, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 12, 1, 1, 1, 1, 1, 
+	1, 1, 13, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 13, 1, 13, 13, 
-	13, 13, 13, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 14, 1, 14, 14, 
+	14, 14, 14, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 13, 1, 1, 
+	1, 1, 1, 1, 1, 14, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 14, 1, 1, 15, 16, 16, 
-	16, 16, 16, 16, 16, 16, 16, 1, 
-	17, 18, 18, 18, 18, 18, 18, 18, 
-	18, 18, 1, 19, 19, 19, 19, 19, 
+	1, 1, 15, 1, 1, 16, 17, 17, 
+	17, 17, 17, 17, 17, 17, 17, 1, 
+	18, 19, 19, 19, 19, 19, 19, 19, 
+	19, 19, 1, 20, 20, 20, 20, 20, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 19, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 20, 1, 
+	1, 1, 20, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 21, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -113,11 +116,11 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 21, 
-	1, 22, 22, 22, 22, 22, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 22, 
+	1, 23, 23, 23, 23, 23, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	22, 1, 1, 1, 1, 1, 1, 1, 
+	23, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 3, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -128,41 +131,58 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 23, 1, 19, 
-	19, 19, 19, 19, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 24, 1, 20, 
+	20, 20, 20, 20, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 20, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 21, 1, 1, 1, 19, 19, 
+	19, 19, 19, 19, 19, 19, 19, 19, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 22, 1, 25, 1, 25, 
+	25, 25, 25, 25, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 25, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 19, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 20, 1, 1, 1, 18, 18, 
-	18, 18, 18, 18, 18, 18, 18, 18, 
+	26, 1, 26, 26, 26, 26, 26, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 26, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 27, 1, 
+	1, 28, 29, 29, 29, 29, 29, 29, 
+	29, 29, 29, 1, 30, 31, 31, 31, 
+	31, 31, 31, 31, 31, 31, 1, 32, 
+	32, 32, 32, 32, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 32, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 33, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 21, 1, 24, 1, 24, 
-	24, 24, 24, 24, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 24, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	25, 1, 25, 25, 25, 25, 25, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 34, 1, 32, 32, 32, 
+	32, 32, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 25, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 26, 1, 
-	1, 27, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 1, 29, 30, 30, 30, 
-	30, 30, 30, 30, 30, 30, 1, 31, 
-	31, 31, 31, 31, 1, 1, 1, 1, 
+	1, 1, 1, 1, 32, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 31, 1, 
+	33, 1, 1, 1, 31, 31, 31, 31, 
+	31, 31, 31, 31, 31, 31, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 32, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -170,41 +190,41 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 34, 1, 35, 1, 36, 1, 36, 
+	36, 36, 36, 36, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 36, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 33, 1, 31, 31, 31, 
-	31, 31, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 31, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	32, 1, 1, 1, 30, 30, 30, 30, 
-	30, 30, 30, 30, 30, 30, 1, 1, 
+	37, 1, 37, 37, 37, 37, 37, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 37, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 38, 39, 39, 39, 39, 39, 39, 
+	39, 39, 39, 1, 40, 40, 40, 40, 
+	40, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 40, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 41, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 33, 1, 34, 1, 35, 1, 35, 
-	35, 35, 35, 35, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 35, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	36, 1, 36, 36, 36, 36, 36, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 36, 1, 1, 1, 1, 1, 1, 
+	42, 1, 40, 40, 40, 40, 40, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 37, 38, 38, 38, 38, 38, 38, 
-	38, 38, 38, 1, 39, 39, 39, 39, 
-	39, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 39, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 40, 
+	1, 40, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 41, 1, 1, 
+	1, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -212,137 +232,130 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 42, 1, 
+	44, 45, 1, 46, 1, 46, 46, 46, 
+	46, 46, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	41, 1, 39, 39, 39, 39, 39, 1, 
+	1, 1, 1, 1, 1, 1, 47, 1, 
+	47, 47, 47, 47, 47, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 47, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 39, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 40, 1, 1, 
-	1, 42, 42, 42, 42, 42, 42, 42, 
-	42, 42, 42, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 48, 1, 1, 49, 
+	50, 50, 50, 50, 50, 50, 50, 50, 
+	50, 1, 51, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 1, 53, 53, 53, 
+	53, 53, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 53, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	54, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 41, 1, 
-	43, 44, 1, 45, 1, 45, 45, 45, 
-	45, 45, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 45, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 46, 1, 
-	46, 46, 46, 46, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 46, 
+	1, 55, 1, 53, 53, 53, 53, 53, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 47, 1, 1, 48, 
-	49, 49, 49, 49, 49, 49, 49, 49, 
-	49, 1, 50, 51, 51, 51, 51, 51, 
-	51, 51, 51, 51, 1, 52, 52, 52, 
-	52, 52, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 52, 1, 1, 1, 
+	1, 1, 53, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 54, 1, 
+	1, 1, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	53, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 55, 
+	1, 56, 1, 56, 56, 56, 56, 56, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 56, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 54, 1, 52, 52, 52, 52, 52, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 57, 1, 57, 57, 
+	57, 57, 57, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 52, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 53, 1, 
-	1, 1, 51, 51, 51, 51, 51, 51, 
-	51, 51, 51, 51, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 57, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 58, 1, 1, 59, 60, 60, 
+	60, 60, 60, 60, 60, 60, 60, 1, 
+	61, 62, 62, 62, 62, 62, 62, 62, 
+	62, 62, 1, 63, 63, 63, 63, 63, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 63, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 64, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 54, 
-	1, 55, 1, 55, 55, 55, 55, 55, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 55, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 56, 1, 56, 56, 
-	56, 56, 56, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 56, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 65, 
+	1, 63, 63, 63, 63, 63, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 57, 1, 1, 58, 59, 59, 
-	59, 59, 59, 59, 59, 59, 59, 1, 
-	60, 61, 61, 61, 61, 61, 61, 61, 
-	61, 61, 1, 62, 62, 62, 62, 62, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	63, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 64, 1, 1, 1, 
+	62, 62, 62, 62, 62, 62, 62, 62, 
+	62, 62, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 62, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 63, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 65, 1, 66, 
+	1, 67, 1, 67, 67, 67, 67, 67, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 67, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 64, 
-	1, 62, 62, 62, 62, 62, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 68, 1, 68, 68, 
+	68, 68, 68, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	62, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 63, 1, 1, 1, 
-	61, 61, 61, 61, 61, 61, 61, 61, 
-	61, 61, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 68, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 69, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 1, 
+	71, 71, 71, 71, 71, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 71, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 72, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 64, 1, 65, 
-	1, 65, 65, 65, 65, 65, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	65, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 66, 1, 66, 66, 66, 66, 
-	66, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 66, 1, 67, 1, 1, 
+	1, 1, 1, 1, 73, 1, 71, 71, 
+	71, 71, 71, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 68, 69, 69, 69, 69, 
-	69, 69, 69, 69, 69, 1, 71, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 70, 
-	72, 70, 73, 73, 73, 73, 73, 1, 
+	1, 1, 1, 1, 1, 71, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 72, 1, 1, 1, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 73, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 74, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -350,21 +363,33 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 73, 1, 75, 1, 75, 75, 
+	75, 75, 75, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 75, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 75, 1, 
-	70, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 76, 
+	1, 76, 76, 76, 76, 76, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	76, 1, 77, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	78, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 1, 81, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 82, 80, 83, 
+	83, 83, 83, 83, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 83, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 70, 1, 76, 76, 76, 76, 
-	76, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 84, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 76, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 77, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -373,67 +398,85 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 85, 1, 80, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	78, 1, 76, 76, 76, 76, 76, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 76, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 77, 1, 1, 
-	1, 79, 79, 79, 79, 79, 79, 79, 
-	79, 79, 79, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 80, 
+	1, 86, 86, 86, 86, 86, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	86, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 87, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 78, 1, 
-	80, 1, 80, 80, 80, 80, 80, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 80, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 88, 1, 86, 
+	86, 86, 86, 86, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 81, 1, 81, 81, 81, 
-	81, 81, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 86, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 81, 1, 1, 1, 
+	1, 1, 87, 1, 1, 1, 89, 89, 
+	89, 89, 89, 89, 89, 89, 89, 89, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 82, 83, 83, 83, 
-	83, 83, 83, 83, 83, 83, 1, 76, 
-	76, 76, 76, 76, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 76, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 77, 1, 1, 1, 84, 84, 
-	84, 84, 84, 84, 84, 84, 84, 84, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 88, 1, 90, 1, 90, 
+	90, 90, 90, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 90, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 78, 1, 85, 85, 85, 
-	85, 85, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 85, 1, 1, 1, 
+	91, 1, 91, 91, 91, 91, 91, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 91, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 92, 93, 93, 93, 93, 93, 93, 
+	93, 93, 93, 1, 86, 86, 86, 86, 
 	86, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 86, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 87, 
+	1, 1, 1, 94, 94, 94, 94, 94, 
+	94, 94, 94, 94, 94, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	88, 1, 95, 95, 95, 95, 95, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 95, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 96, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 87, 1, 0, 0, 0, 0, 0, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 0, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 97, 1, 
+	0, 0, 0, 0, 0, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 0, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -442,46 +485,52 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 2, 1, 1, 
-	0
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 2, 1, 1, 0
 };
 
 static const char _deserialize_json_trans_targs[] = {
 	1, 0, 2, 2, 3, 4, 18, 24, 
-	37, 45, 5, 12, 6, 7, 8, 9, 
-	11, 9, 11, 10, 2, 49, 10, 49, 
-	13, 14, 15, 16, 17, 16, 17, 10, 
-	2, 49, 19, 20, 21, 22, 23, 10, 
-	2, 49, 23, 25, 31, 26, 27, 28, 
-	29, 30, 29, 30, 10, 2, 49, 32, 
-	33, 34, 35, 36, 35, 36, 10, 2, 
-	49, 38, 39, 40, 43, 44, 40, 41, 
-	42, 10, 2, 49, 10, 2, 49, 44, 
-	46, 47, 43, 48, 48, 49, 50, 51
+	37, 43, 51, 5, 12, 6, 7, 8, 
+	9, 11, 9, 11, 10, 2, 55, 10, 
+	55, 13, 14, 15, 16, 17, 16, 17, 
+	10, 2, 55, 19, 20, 21, 22, 23, 
+	10, 2, 55, 23, 25, 31, 26, 27, 
+	28, 29, 30, 29, 30, 10, 2, 55, 
+	32, 33, 34, 35, 36, 35, 36, 10, 
+	2, 55, 38, 39, 40, 41, 42, 10, 
+	2, 55, 42, 44, 45, 46, 49, 50, 
+	46, 47, 48, 10, 2, 55, 10, 2, 
+	55, 50, 52, 53, 49, 54, 54, 55, 
+	56, 57
 };
 
 static const char _deserialize_json_trans_actions[] = {
 	0, 0, 1, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 2, 2, 
-	2, 0, 0, 3, 3, 4, 0, 5, 
-	0, 0, 2, 2, 2, 0, 0, 6, 
-	6, 7, 0, 0, 0, 2, 2, 8, 
-	8, 9, 0, 0, 0, 0, 0, 2, 
-	2, 2, 0, 0, 10, 10, 11, 0, 
-	0, 2, 2, 2, 0, 0, 12, 12, 
-	13, 0, 0, 2, 14, 14, 0, 15, 
-	0, 16, 16, 17, 18, 18, 19, 15, 
-	0, 0, 20, 20, 21, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 2, 
+	2, 2, 0, 0, 3, 3, 4, 0, 
+	5, 0, 0, 2, 2, 2, 0, 0, 
+	6, 6, 7, 0, 0, 0, 2, 2, 
+	8, 8, 9, 0, 0, 0, 0, 0, 
+	2, 2, 2, 0, 0, 10, 10, 11, 
+	0, 0, 2, 2, 2, 0, 0, 12, 
+	12, 13, 0, 0, 0, 2, 2, 14, 
+	14, 15, 0, 0, 0, 2, 16, 16, 
+	0, 17, 0, 18, 18, 19, 20, 20, 
+	21, 17, 0, 0, 22, 22, 23, 0, 
+	0, 0
 };
 
 static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 49;
+static const int deserialize_json_first_final = 55;
 static const int deserialize_json_error = 0;
 
 static const int deserialize_json_en_main = 1;
 
 
-#line 108 "hb-buffer-deserialize-json.rl"
+#line 111 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
@@ -508,12 +557,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 512 "hb-buffer-deserialize-json.hh"
+#line 554 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
-#line 517 "hb-buffer-deserialize-json.hh"
+#line 557 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
 	int _trans;
@@ -561,25 +610,25 @@ _resume:
 	tok = p;
 }
 	break;
-	case 15:
+	case 17:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 21:
+	case 23:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 16:
+	case 18:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
+					tok+1, p - tok - 2, /* Skip "" */
 					&info.codepoint))
 	  return false;
 }
 	break;
-	case 18:
+	case 20:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
@@ -604,6 +653,10 @@ _resume:
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
 	case 14:
+#line 72 "hb-buffer-deserialize-json.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+	break;
+	case 16:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -611,7 +664,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 20:
+	case 22:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
@@ -619,12 +672,12 @@ _resume:
 #line 56 "hb-buffer-deserialize-json.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 17:
+	case 19:
 #line 58 "hb-buffer-deserialize-json.rl"
 	{
 	/* TODO Unescape \" and \\ if found. */
 	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
+					tok+1, p - tok - 2, /* Skip "" */
 					&info.codepoint))
 	  return false;
 }
@@ -637,7 +690,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
@@ -709,7 +762,19 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-#line 713 "hb-buffer-deserialize-json.hh"
+	case 15:
+#line 72 "hb-buffer-deserialize-json.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-json.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 735 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -721,7 +786,7 @@ _again:
 	_out: {}
 	}
 
-#line 136 "hb-buffer-deserialize-json.rl"
+#line 139 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;

+ 390 - 182
thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh

@@ -32,29 +32,32 @@
 #include "hb.hh"
 
 
-#line 36 "hb-buffer-deserialize-text.hh"
+#line 33 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
 	0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, 
-	48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 
-	43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 9u, 124u, 
+	48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 
+	44u, 57u, 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 
 	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 0
+	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
+	9u, 124u, 9u, 124u, 9u, 124u, 0
 };
 
 static const char _deserialize_text_key_spans[] = {
 	0, 83, 1, 1, 55, 77, 10, 13, 
-	10, 10, 13, 10, 1, 13, 10, 14, 
-	82, 13, 10, 116, 116, 0, 77, 116, 
+	10, 10, 10, 13, 10, 1, 13, 10, 
+	14, 82, 13, 10, 116, 116, 0, 77, 
+	116, 116, 116, 116, 116, 116, 116, 116, 
 	116, 116, 116, 116, 116, 116, 116, 116, 
-	116, 116, 116, 116, 116
+	116, 116, 116
 };
 
 static const short _deserialize_text_index_offsets[] = {
 	0, 0, 84, 86, 88, 144, 222, 233, 
-	247, 258, 269, 283, 294, 296, 310, 321, 
-	336, 419, 433, 444, 561, 678, 679, 757, 
-	874, 991, 1108, 1225, 1342, 1459, 1576, 1693, 
-	1810, 1927, 2044, 2161, 2278
+	247, 258, 269, 280, 294, 305, 307, 321, 
+	332, 347, 430, 444, 455, 572, 689, 690, 
+	768, 885, 1002, 1119, 1236, 1353, 1470, 1587, 
+	1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523, 
+	2640, 2757, 2874
 };
 
 static const char _deserialize_text_indicies[] = {
@@ -91,50 +94,52 @@ static const char _deserialize_text_indicies[] = {
 	12, 12, 12, 12, 12, 12, 12, 1, 
 	13, 14, 14, 14, 14, 14, 14, 14, 
 	14, 14, 1, 15, 16, 16, 16, 16, 
-	16, 16, 16, 16, 16, 1, 17, 1, 
-	1, 18, 19, 19, 19, 19, 19, 19, 
-	19, 19, 19, 1, 20, 21, 21, 21, 
+	16, 16, 16, 16, 16, 1, 17, 18, 
+	18, 18, 18, 18, 18, 18, 18, 18, 
+	1, 19, 1, 1, 20, 21, 21, 21, 
 	21, 21, 21, 21, 21, 21, 1, 22, 
-	1, 23, 1, 1, 24, 25, 25, 25, 
-	25, 25, 25, 25, 25, 25, 1, 26, 
+	23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 1, 24, 1, 25, 1, 1, 26, 
 	27, 27, 27, 27, 27, 27, 27, 27, 
-	27, 1, 22, 1, 1, 1, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 21, 
-	1, 28, 28, 1, 1, 1, 1, 1, 
+	27, 1, 28, 29, 29, 29, 29, 29, 
+	29, 29, 29, 29, 1, 24, 1, 1, 
+	1, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 1, 30, 30, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 28, 1, 1, 28, 1, 
+	1, 1, 1, 1, 1, 1, 30, 1, 
+	1, 30, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 30, 30, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 28, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 30, 1, 31, 
+	1, 1, 32, 33, 33, 33, 33, 33, 
+	33, 33, 33, 33, 1, 34, 35, 35, 
+	35, 35, 35, 35, 35, 35, 35, 1, 
+	36, 36, 36, 36, 36, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 28, 1, 29, 1, 1, 30, 
-	31, 31, 31, 31, 31, 31, 31, 31, 
-	31, 1, 32, 33, 33, 33, 33, 33, 
-	33, 33, 33, 33, 1, 34, 34, 34, 
-	34, 34, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 36, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 34, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 37, 
+	37, 37, 37, 37, 37, 37, 37, 37, 
+	37, 1, 1, 1, 38, 39, 1, 1, 
+	37, 37, 37, 37, 37, 37, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 1, 1, 
-	1, 36, 37, 1, 1, 35, 35, 35, 
-	35, 35, 35, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 35, 35, 35, 
-	35, 35, 35, 1, 1, 1, 1, 1, 
+	37, 37, 37, 37, 37, 37, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	38, 1, 39, 39, 39, 39, 39, 1, 
+	1, 1, 1, 40, 1, 41, 41, 41, 
+	41, 41, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 41, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 39, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 40, 
+	1, 1, 42, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -142,24 +147,23 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 41, 1, 1, 
-	7, 7, 7, 7, 7, 1, 1, 1, 
+	43, 1, 1, 7, 7, 7, 7, 7, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 7, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 7, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 4, 1, 42, 42, 
-	42, 42, 42, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 4, 
+	1, 44, 44, 44, 44, 44, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 42, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	44, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 43, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 45, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -167,68 +171,83 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 44, 1, 42, 42, 42, 42, 42, 
+	1, 1, 1, 1, 46, 1, 44, 44, 
+	44, 44, 44, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 44, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 42, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 47, 47, 47, 
+	47, 47, 47, 47, 47, 47, 47, 1, 
+	1, 1, 1, 45, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 45, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 1, 1, 1, 1, 
-	43, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 44, 1, 
-	47, 47, 47, 47, 47, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 47, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 48, 1, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 49, 46, 46, 50, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 51, 52, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 53, 46, 54, 54, 54, 
-	54, 54, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 54, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 55, 
-	1, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 56, 28, 28, 57, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	58, 59, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 28, 28, 28, 28, 
-	60, 28, 61, 61, 61, 61, 61, 1, 
+	1, 46, 1, 49, 49, 49, 49, 49, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 49, 48, 48, 50, 48, 48, 
+	48, 48, 48, 48, 48, 51, 1, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 52, 
+	48, 48, 53, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 54, 55, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 56, 48, 
+	57, 57, 57, 57, 57, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 57, 
+	30, 30, 58, 30, 30, 30, 30, 30, 
+	30, 30, 59, 1, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 60, 30, 30, 61, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 62, 63, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 64, 30, 57, 57, 57, 
+	57, 57, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 57, 30, 30, 58, 
+	30, 30, 30, 30, 30, 30, 30, 59, 
+	1, 30, 30, 30, 65, 66, 66, 66, 
+	66, 66, 66, 66, 66, 66, 30, 30, 
+	30, 60, 30, 30, 61, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	62, 63, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	64, 30, 67, 67, 67, 67, 67, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 61, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 62, 1, 1, 
+	1, 67, 1, 1, 68, 1, 1, 1, 
+	1, 1, 1, 1, 1, 69, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 63, 1, 
+	1, 1, 1, 1, 1, 1, 70, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 64, 1, 65, 
-	65, 65, 65, 65, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 71, 1, 72, 
+	72, 72, 72, 72, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 65, 1, 
+	1, 1, 1, 1, 1, 1, 72, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -236,172 +255,238 @@ static const char _deserialize_text_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 40, 1, 1, 1, 1, 
+	1, 1, 1, 42, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 66, 1, 67, 67, 67, 67, 
-	67, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 67, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 48, 1, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	49, 46, 46, 50, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 51, 
-	52, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 46, 
-	46, 46, 46, 46, 46, 46, 46, 53, 
-	46, 68, 68, 68, 68, 68, 1, 1, 
+	1, 1, 73, 1, 74, 74, 74, 74, 
+	74, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 74, 48, 48, 50, 48, 
+	48, 48, 48, 48, 48, 48, 51, 1, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	52, 48, 48, 53, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 54, 
+	55, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 48, 48, 48, 48, 56, 
+	48, 75, 75, 75, 75, 75, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	68, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 69, 1, 1, 1, 1, 
+	75, 1, 1, 76, 1, 1, 1, 1, 
+	1, 1, 1, 77, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	70, 1, 1, 1, 1, 1, 1, 1, 
+	78, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 43, 1, 1, 
+	1, 1, 1, 1, 1, 45, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 71, 1, 72, 72, 
-	72, 72, 72, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 79, 1, 80, 80, 
+	80, 80, 80, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 72, 1, 1, 
+	1, 1, 1, 1, 1, 80, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	73, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 74, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 81, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 75, 1, 72, 72, 72, 72, 72, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 82, 1, 80, 80, 80, 80, 80, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 72, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 73, 1, 1, 
-	1, 1, 27, 27, 27, 27, 27, 27, 
-	27, 27, 27, 27, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 80, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 74, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 81, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 75, 1, 
-	68, 68, 68, 68, 68, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 68, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 69, 1, 1, 1, 1, 76, 
-	76, 76, 76, 76, 76, 76, 76, 76, 
-	76, 1, 1, 1, 1, 1, 1, 70, 
+	1, 1, 1, 1, 1, 1, 82, 1, 
+	84, 84, 84, 84, 84, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 84, 
+	1, 1, 85, 1, 1, 1, 1, 1, 
+	1, 1, 86, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 43, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 71, 1, 77, 77, 77, 
-	77, 77, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 87, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 88, 1, 84, 84, 84, 
+	84, 84, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 84, 1, 1, 85, 
+	1, 1, 1, 1, 1, 1, 1, 86, 
+	1, 1, 1, 1, 29, 29, 29, 29, 
+	29, 29, 29, 29, 29, 29, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 77, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 87, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	88, 1, 75, 75, 75, 75, 75, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 75, 1, 1, 76, 1, 1, 1, 
+	1, 1, 1, 1, 77, 1, 1, 1, 
+	1, 89, 89, 89, 89, 89, 89, 89, 
+	89, 89, 89, 1, 1, 1, 1, 1, 
 	1, 78, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 45, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	79, 1, 77, 77, 77, 77, 77, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 77, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 79, 1, 90, 
+	90, 90, 90, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 33, 33, 33, 33, 33, 33, 33, 
-	33, 33, 33, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 90, 1, 
+	1, 91, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 78, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 79, 1, 61, 
-	61, 61, 61, 61, 1, 1, 1, 1, 
+	1, 1, 1, 92, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 61, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 62, 1, 1, 1, 14, 14, 
-	14, 14, 14, 14, 14, 14, 14, 14, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 93, 1, 90, 90, 90, 90, 
+	90, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 90, 1, 1, 91, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 35, 35, 35, 35, 35, 
+	35, 35, 35, 35, 35, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 63, 1, 1, 1, 1, 
+	92, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 93, 
+	1, 67, 67, 67, 67, 67, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 64, 1, 0
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	67, 1, 1, 68, 1, 1, 1, 1, 
+	1, 1, 1, 1, 69, 1, 1, 1, 
+	14, 14, 14, 14, 14, 14, 14, 14, 
+	14, 14, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 70, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 71, 1, 94, 94, 
+	94, 94, 94, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 94, 30, 30, 
+	58, 30, 30, 30, 30, 30, 30, 30, 
+	59, 1, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 60, 30, 30, 61, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 62, 95, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 96, 30, 94, 94, 94, 94, 94, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 94, 30, 30, 58, 30, 30, 
+	30, 30, 30, 30, 30, 59, 1, 30, 
+	30, 30, 97, 97, 97, 97, 97, 97, 
+	97, 97, 97, 97, 30, 30, 30, 60, 
+	30, 30, 61, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 62, 95, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 96, 30, 
+	0
 };
 
 static const char _deserialize_text_trans_targs[] = {
-	1, 0, 2, 25, 3, 4, 19, 5, 
-	23, 24, 8, 27, 36, 27, 36, 30, 
-	33, 11, 12, 15, 12, 15, 13, 14, 
-	31, 32, 31, 32, 26, 18, 34, 35, 
-	34, 35, 20, 19, 6, 21, 22, 20, 
-	21, 22, 20, 21, 22, 24, 26, 26, 
-	7, 9, 10, 16, 21, 29, 26, 7, 
-	9, 10, 16, 21, 29, 28, 17, 21, 
-	29, 28, 29, 29, 28, 7, 10, 29, 
-	28, 7, 21, 29, 33, 28, 21, 29
+	1, 0, 2, 26, 3, 4, 20, 5, 
+	24, 25, 8, 29, 40, 29, 40, 32, 
+	37, 33, 34, 12, 13, 16, 13, 16, 
+	14, 15, 35, 36, 35, 36, 27, 19, 
+	38, 39, 38, 39, 21, 20, 6, 22, 
+	23, 21, 22, 23, 21, 22, 23, 25, 
+	27, 27, 28, 7, 9, 11, 17, 22, 
+	31, 27, 28, 7, 9, 11, 17, 22, 
+	31, 41, 42, 30, 10, 18, 22, 31, 
+	30, 31, 31, 30, 10, 7, 11, 31, 
+	30, 22, 31, 34, 30, 10, 7, 22, 
+	31, 37, 30, 10, 22, 31, 27, 22, 
+	31, 42
 };
 
 static const char _deserialize_text_trans_actions[] = {
 	0, 0, 0, 0, 1, 0, 2, 0, 
 	2, 2, 3, 4, 4, 5, 5, 4, 
-	4, 3, 3, 3, 0, 0, 6, 3, 
-	4, 4, 5, 5, 5, 3, 4, 4, 
-	5, 5, 7, 8, 9, 7, 7, 0, 
-	0, 0, 10, 10, 10, 8, 12, 13, 
-	14, 14, 14, 15, 11, 11, 17, 18, 
-	18, 18, 0, 16, 16, 19, 20, 19, 
-	19, 0, 0, 13, 10, 21, 21, 10, 
-	22, 23, 22, 22, 5, 24, 24, 24
+	4, 4, 4, 3, 3, 3, 0, 0, 
+	6, 3, 4, 4, 5, 5, 5, 3, 
+	4, 4, 5, 5, 7, 8, 9, 7, 
+	7, 0, 0, 0, 10, 10, 10, 8, 
+	12, 13, 14, 15, 15, 15, 16, 11, 
+	11, 18, 19, 20, 20, 20, 0, 17, 
+	17, 4, 4, 21, 22, 22, 21, 21, 
+	0, 0, 13, 10, 23, 23, 23, 10, 
+	24, 24, 24, 5, 25, 26, 26, 25, 
+	25, 5, 27, 28, 27, 27, 30, 29, 
+	29, 5
 };
 
 static const char _deserialize_text_eof_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 7, 0, 0, 0, 10, 
-	10, 11, 16, 19, 0, 11, 10, 22, 
-	22, 10, 24, 24, 19
+	0, 0, 0, 0, 7, 0, 0, 0, 
+	10, 10, 11, 17, 17, 21, 0, 11, 
+	10, 24, 24, 25, 25, 10, 27, 27, 
+	21, 29, 29
 };
 
 static const int deserialize_text_start = 1;
-static const int deserialize_text_first_final = 19;
+static const int deserialize_text_first_final = 20;
 static const int deserialize_text_error = 0;
 
 static const int deserialize_text_en_main = 1;
 
 
-#line 114 "hb-buffer-deserialize-text.rl"
+#line 117 "hb-buffer-deserialize-text.rl"
 
 
 static hb_bool_t
@@ -424,12 +509,12 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer,
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   
-#line 428 "hb-buffer-deserialize-text.hh"
+#line 506 "hb-buffer-deserialize-text.hh"
 	{
 	cs = deserialize_text_start;
 	}
 
-#line 433 "hb-buffer-deserialize-text.hh"
+#line 509 "hb-buffer-deserialize-text.hh"
 	{
 	int _slen;
 	int _trans;
@@ -475,7 +560,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 18:
+	case 20:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -489,7 +574,7 @@ _resume:
 #line 66 "hb-buffer-deserialize-text.rl"
 	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
 	break;
-	case 21:
+	case 23:
 #line 68 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
@@ -497,15 +582,19 @@ _resume:
 #line 69 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
-	case 23:
+	case 26:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
-	case 20:
+	case 22:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
-	case 15:
+	case 28:
+#line 72 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+	break;
+	case 16:
 #line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
@@ -532,7 +621,7 @@ _resume:
 #line 56 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
 	break;
-	case 16:
+	case 17:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -549,6 +638,18 @@ _resume:
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
+	break;
+	case 19:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 55 "hb-buffer-deserialize-text.rl"
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
 	case 7:
 #line 66 "hb-buffer-deserialize-text.rl"
@@ -574,7 +675,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 22:
+	case 25:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -586,7 +687,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -598,7 +699,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-	case 24:
+	case 27:
 #line 72 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -608,6 +709,18 @@ _resume:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 24:
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
 }
 	break;
 	case 12:
@@ -623,7 +736,7 @@ _resume:
 #line 55 "hb-buffer-deserialize-text.rl"
 	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 	break;
-	case 14:
+	case 15:
 #line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
@@ -642,7 +755,7 @@ _resume:
 	  return false;
 }
 	break;
-	case 17:
+	case 18:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -660,6 +773,26 @@ _resume:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 29:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
 }
 	break;
 	case 11:
@@ -680,6 +813,49 @@ _resume:
 					&info.codepoint))
 	  return false;
 }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 14:
+#line 38 "hb-buffer-deserialize-text.rl"
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text.rl"
+	{
+	tok = p;
+}
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 55 "hb-buffer-deserialize-text.rl"
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 30:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 55 "hb-buffer-deserialize-text.rl"
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
@@ -718,7 +894,7 @@ _resume:
 	*end_ptr = p;
 }
 	break;
-#line 722 "hb-buffer-deserialize-text.hh"
+#line 826 "hb-buffer-deserialize-text.hh"
 	}
 
 _again:
@@ -730,7 +906,7 @@ _again:
 	if ( p == eof )
 	{
 	switch ( _deserialize_text_eof_actions[cs] ) {
-	case 16:
+	case 17:
 #line 58 "hb-buffer-deserialize-text.rl"
 	{
 	/* TODO Unescape delimiters. */
@@ -772,7 +948,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 22:
+	case 25:
 #line 70 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -784,7 +960,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 19:
+	case 21:
 #line 71 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -796,7 +972,7 @@ _again:
 	*end_ptr = p;
 }
 	break;
-	case 24:
+	case 27:
 #line 72 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
@@ -806,6 +982,38 @@ _again:
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
+}
+	break;
+	case 24:
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 29:
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 73 "hb-buffer-deserialize-text.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
 }
 	break;
 	case 11:
@@ -835,14 +1043,14 @@ _again:
 	*end_ptr = p;
 }
 	break;
-#line 839 "hb-buffer-deserialize-text.hh"
+#line 953 "hb-buffer-deserialize-text.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 138 "hb-buffer-deserialize-text.rl"
+#line 141 "hb-buffer-deserialize-text.rl"
 
 
   *end_ptr = p;

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

@@ -56,7 +56,7 @@ hb_buffer_serialize_list_formats ()
 /**
  * hb_buffer_serialize_format_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  *
  * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
  * @str is a valid buffer serialization format, use
@@ -78,11 +78,11 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
  * hb_buffer_serialize_format_to_string:
  * @format: an #hb_buffer_serialize_format_t to convert.
  *
- * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * Converts @format to the string corresponding it, or `NULL` if it is not a valid
  * #hb_buffer_serialize_format_t.
  *
  * Return value: (transfer none):
- * A %NULL terminated string corresponding to @format. Should not be freed.
+ * A `NULL` terminated string corresponding to @format. Should not be freed.
  *
  * Since: 0.9.7
  **/
@@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, an empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
  *       write serialized buffer into.
  * @buf_size: the size of @buf.
- * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf.
+ * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
- *        read glyph names and extents. If %NULL, an empty font will be used.
+ *        read glyph names and extents. If `NULL`, an empty font will be used.
  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
  *         to serialize.
@@ -727,7 +727,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * hb_buffer_deserialize_glyphs:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @font: (nullable): font for getting glyph IDs
@@ -736,7 +736,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -800,7 +800,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * hb_buffer_deserialize_unicode:
  * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len): string to deserialize
- * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
  * @end_ptr: (out) (optional): output pointer to the character after last
  *                               consumed one.
  * @format: the #hb_buffer_serialize_format_t of the input @buf
@@ -808,7 +808,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  *
- * Return value: %true if @buf is not fully consumed, %false otherwise.
+ * Return value: `true` if @buf is not fully consumed, `false` otherwise.
  *
  * Since: 2.7.3
  **/

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

@@ -51,7 +51,7 @@
  * Checks the equality of two #hb_segment_properties_t's.
  *
  * Return value:
- * %true if all properties of @a equal those of @b, %false otherwise.
+ * `true` if all properties of @a equal those of @b, `false` otherwise.
  *
  * Since: 0.9.7
  **/
@@ -643,9 +643,9 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
  * Return value: (transfer full):
  * A newly allocated #hb_buffer_t with a reference count of 1. The initial
  * reference count should be released with hb_buffer_destroy() when you are done
- * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
  * be allocated, a special #hb_buffer_t object will be returned on which
- * hb_buffer_allocation_successful() returns %false.
+ * hb_buffer_allocation_successful() returns `false`.
  *
  * Since: 0.9.2
  **/
@@ -775,7 +775,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
  *
  * Attaches a user-data key/data pair to the specified buffer. 
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1278,7 +1278,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer)
  * Pre allocates memory for @buffer to fit at least @size number of items.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise
+ * `true` if @buffer memory allocation succeeded, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1295,7 +1295,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
  * Check if allocating memory for the buffer succeeded.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1340,7 +1340,7 @@ hb_buffer_add (hb_buffer_t    *buffer,
  * end.
  *
  * Return value:
- * %true if @buffer memory allocation succeeded, %false otherwise.
+ * `true` if @buffer memory allocation succeeded, `false` otherwise.
  *
  * Since: 0.9.2
  **/
@@ -1426,7 +1426,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  * If buffer did not have positions before, the positions will be
  * initialized to zeros, unless this function is called from
  * within a buffer message callback (see hb_buffer_set_message_func()),
- * in which case %NULL is returned.
+ * in which case `NULL` is returned.
  *
  * Return value: (transfer none) (array length=length):
  * The @buffer glyph position array.
@@ -1461,7 +1461,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
  * and cleared of position data when hb_buffer_clear_contents() is called.
  *
  * Return value:
- * %true if the @buffer has position array, %false otherwise.
+ * `true` if the @buffer has position array, `false` otherwise.
  *
  * Since: 2.7.3
  **/
@@ -1645,10 +1645,10 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
  *               characters to append.
- * @text_length: The length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: The offset of the first character to add to the @buffer.
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1671,10 +1671,10 @@ hb_buffer_add_utf8 (hb_buffer_t  *buffer,
  * hb_buffer_add_utf16:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-16 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1697,10 +1697,10 @@ hb_buffer_add_utf16 (hb_buffer_t    *buffer,
  * hb_buffer_add_utf32:
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length): An array of UTF-32 characters to append
- * @text_length: The length of the @text, or -1 if it is %NULL terminated
+ * @text_length: The length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: The offset of the first character to add to the @buffer
  * @item_length: The number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * See hb_buffer_add_codepoints().
  *
@@ -1724,10 +1724,10 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
  * @buffer: An #hb_buffer_t
  * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
  *               characters to append
- * @text_length: the length of the @text, or -1 if it is %NULL terminated
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated
  * @item_offset: the offset of the first character to add to the @buffer
  * @item_length: the number of characters to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated)
+ *               end of @text (assuming it is `NULL` terminated)
  *
  * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
  * Unicode code points that can fit in 8-bit strings.
@@ -1750,10 +1750,10 @@ hb_buffer_add_latin1 (hb_buffer_t   *buffer,
  * hb_buffer_add_codepoints:
  * @buffer: a #hb_buffer_t to append characters to.
  * @text: (array length=text_length): an array of Unicode code points to append.
- * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @text_length: the length of the @text, or -1 if it is `NULL` terminated.
  * @item_offset: the offset of the first code point to add to the @buffer.
  * @item_length: the number of code points to add to the @buffer, or -1 for the
- *               end of @text (assuming it is %NULL terminated).
+ *               end of @text (assuming it is `NULL` terminated).
  *
  * Appends characters from @text array to @buffer. The @item_offset is the
  * position of the first character from @text that will be appended, and

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

@@ -755,16 +755,16 @@ hb_buffer_diff (hb_buffer_t *buffer,
  * hb_buffer_message_func_t:
  * @buffer: An #hb_buffer_t to work upon
  * @font: The #hb_font_t the @buffer is shaped with
- * @message: %NULL-terminated message passed to the function
+ * @message: `NULL`-terminated message passed to the function
  * @user_data: User data pointer passed by the caller
  *
  * A callback method for #hb_buffer_t. The method gets called with the
  * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
  * message describing what step of the shaping process will be performed.
- * Returning %false from this method will skip this shaping step and move to
+ * Returning `false` from this method will skip this shaping step and move to
  * the next one.
  *
- * Return value: %true to perform the shaping step, %false to skip it.
+ * Return value: `true` to perform the shaping step, `false` to skip it.
  *
  * Since: 1.1.3
  */

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

@@ -57,6 +57,7 @@ struct call_context_t
 
 /* call stack */
 const unsigned int kMaxCallLimit = 10;
+const unsigned int kMaxOps = 10000;
 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 
 template <typename SUBRS>
@@ -881,7 +882,13 @@ struct cs_interpreter_t : interpreter_t<ENV>
   {
     SUPER::env.set_endchar (false);
 
+    unsigned max_ops = kMaxOps;
     for (;;) {
+      if (unlikely (!--max_ops))
+      {
+	SUPER::env.set_error ();
+	break;
+      }
       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
       if (unlikely (SUPER::env.in_error ()))
 	return false;

+ 45 - 13
thirdparty/harfbuzz/src/hb-common.cc

@@ -108,7 +108,7 @@ _hb_options_init ()
 /**
  * hb_tag_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string into an #hb_tag_t. Valid tags
  * are four characters. Shorter input strings will be
@@ -170,7 +170,7 @@ static const char direction_strings[][4] = {
 /**
  * hb_direction_from_string:
  * @str: (array length=len) (element-type uint8_t): String to convert
- * @len: Length of @str, or -1 if it is %NULL-terminated
+ * @len: Length of @str, or -1 if it is `NULL`-terminated
  *
  * Converts a string to an #hb_direction_t.
  *
@@ -357,7 +357,7 @@ retry:
  * hb_language_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing
  *       a BCP 47 language tag
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts @str representing a BCP 47 language tag to the corresponding
  * #hb_language_t.
@@ -396,7 +396,7 @@ hb_language_from_string (const char *str, int len)
  * Converts an #hb_language_t to a string.
  *
  * Return value: (transfer none):
- * A %NULL-terminated string representing the @language. Must not be freed by
+ * A `NULL`-terminated string representing the @language. Must not be freed by
  * the caller.
  *
  * Since: 0.9.2
@@ -441,6 +441,38 @@ hb_language_get_default ()
   return language;
 }
 
+/**
+ * hb_language_matches:
+ * @language: The #hb_language_t to work on
+ * @specific: Another #hb_language_t
+ *
+ * Check whether a second language tag is the same or a more
+ * specific version of the provided language tag.  For example,
+ * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR".
+ *
+ * Return value: `true` if languages match, `false` otherwise.
+ *
+ * Since: 5.0.0
+ **/
+hb_bool_t
+hb_language_matches (hb_language_t language,
+		     hb_language_t specific)
+{
+  if (language == specific) return true;
+  if (!language || !specific) return false;
+
+  const char *l = language->s;
+  const char *s = specific->s;
+  unsigned ll = strlen (l);
+  unsigned sl = strlen (s);
+
+  if (ll > sl)
+    return false;
+
+  return strncmp (l, s, ll) == 0 &&
+	 (s[ll] == '\0' || s[ll] == '-');
+}
+
 
 /* hb_script_t */
 
@@ -498,7 +530,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
  * hb_script_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing an
  *       ISO 15924 tag.
- * @len: length of the @str, or -1 if it is %NULL-terminated.
+ * @len: length of the @str, or -1 if it is `NULL`-terminated.
  *
  * Converts a string @str representing an ISO 15924 script tag to a
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
@@ -693,8 +725,8 @@ hb_version_string ()
  * Tests the library version against a minimum value,
  * as three integer components.
  *
- * Return value: %true if the library is equal to or greater than
- * the test value, %false otherwise
+ * Return value: `true` if the library is equal to or greater than
+ * the test value, `false` otherwise
  *
  * Since: 0.9.30
  **/
@@ -881,7 +913,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
 /**
  * hb_feature_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @feature: (out): the #hb_feature_t to initialize with the parsed values
  *
  * Parses a string into a #hb_feature_t.
@@ -923,7 +955,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
  * </informaltable>
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 0.9.5
  **/
@@ -954,7 +986,7 @@ hb_feature_from_string (const char *str, int len,
  * @buf: (array length=size) (out): output string
  * @size: the allocated size of @buf
  *
- * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * Converts a #hb_feature_t into a `NULL`-terminated string in the format
  * understood by hb_feature_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *
@@ -1022,7 +1054,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
 /**
  * hb_variation_from_string:
  * @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is %NULL terminated
+ * @len: length of @str, or -1 if string is `NULL` terminated
  * @variation: (out): the #hb_variation_t to initialize with the parsed values
  *
  * Parses a string into a #hb_variation_t.
@@ -1035,7 +1067,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
  * number. For example `wght=500`, or `slnt=-7.5`.
  *
  * Return value:
- * %true if @str is successfully parsed, %false otherwise
+ * `true` if @str is successfully parsed, `false` otherwise
  *
  * Since: 1.4.2
  */
@@ -1107,7 +1139,7 @@ get_C_locale ()
  * @buf: (array length=size) (out): output string
  * @size: the allocated size of @buf
  *
- * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * Converts an #hb_variation_t into a `NULL`-terminated string in the format
  * understood by hb_variation_from_string(). The client in responsible for
  * allocating big enough size for @buf, 128 bytes is more than enough.
  *

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

@@ -326,6 +326,9 @@ hb_language_to_string (hb_language_t language);
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
+HB_EXTERN hb_bool_t
+hb_language_matches (hb_language_t language,
+		     hb_language_t specific);
 
 /**
  * hb_script_t:

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

@@ -98,6 +98,11 @@
 
 /* Closure of options. */
 
+#ifdef HB_NO_BORING_EXPANSION
+#define HB_NO_BEYOND_64K
+#define HB_NO_VARIATIONS2
+#endif
+
 #ifdef HB_DISABLE_DEPRECATED
 #define HB_IF_NOT_DEPRECATED(x)
 #else

+ 10 - 2
thirdparty/harfbuzz/src/hb-cplusplus.hh

@@ -166,8 +166,14 @@ HB_DEFINE_VTABLE (unicode_funcs);
 
 } // namespace hb
 
+/* Workaround for GCC < 7, see:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+ * https://stackoverflow.com/a/25594741 */
+namespace std {
+
+
 template<typename T>
-struct std::hash<hb::shared_ptr<T>>
+struct hash<hb::shared_ptr<T>>
 {
     std::size_t operator()(const hb::shared_ptr<T>& v) const noexcept
     {
@@ -177,7 +183,7 @@ struct std::hash<hb::shared_ptr<T>>
 };
 
 template<typename T>
-struct std::hash<hb::unique_ptr<T>>
+struct hash<hb::unique_ptr<T>>
 {
     std::size_t operator()(const hb::unique_ptr<T>& v) const noexcept
     {
@@ -187,6 +193,8 @@ struct std::hash<hb::unique_ptr<T>>
 };
 
 
+} // namespace std
+
 #endif /* __cplusplus */
 
 #endif /* HB_CPLUSPLUS_HH */

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

@@ -93,7 +93,7 @@ HB_BEGIN_DECLS
  * This method should retrieve the glyph ID for a specified Unicode code point
  * font, with an optional variation selector.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * Deprecated: 1.2.3
  *
  **/

+ 34 - 2
thirdparty/harfbuzz/src/hb-directwrite.cc

@@ -43,6 +43,14 @@
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
+
 /*
  * DirectWrite font stream helpers
  */
@@ -137,6 +145,7 @@ public:
 
 struct hb_directwrite_face_data_t
 {
+  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   DWriteFontFileStream *fontFileStream;
@@ -158,12 +167,33 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
     return nullptr; \
   } HB_STMT_END
 
+  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
+  if (unlikely (!data->dwrite_dll))
+    FAIL ("Cannot find DWrite.DLL");
+
+  t_DWriteCreateFactory p_DWriteCreateFactory;
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+  p_DWriteCreateFactory = (t_DWriteCreateFactory)
+			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+  if (unlikely (!p_DWriteCreateFactory))
+    FAIL ("Cannot find DWriteCreateFactory().");
+
   HRESULT hr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
-  hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-			    (IUnknown**) &dwriteFactory);
+  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+			      (IUnknown**) &dwriteFactory);
 
   if (unlikely (hr != S_OK))
     FAIL ("Failed to run DWriteCreateFactory().");
@@ -227,6 +257,8 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
+  if (data->dwrite_dll)
+    FreeLibrary (data->dwrite_dll);
   if (data)
     delete data;
 }

+ 6 - 2
thirdparty/harfbuzz/src/hb-draw.cc

@@ -120,6 +120,7 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t	 *dfuncs,		\
     if (dfuncs->destroy)						\
       dfuncs->destroy->name = nullptr;					\
   }									\
+  return;                                                                \
                                                                          \
 fail:                                                                    \
   if (destroy)                                                           \
@@ -137,7 +138,7 @@ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
  * Return value: (transfer full):
  * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
  * reference count should be released with hb_draw_funcs_destroy when you are
- * done using the #hb_draw_funcs_t. This function never returns %NULL. If
+ * done using the #hb_draw_funcs_t. This function never returns `NULL`. If
  * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
  * be returned.
  *
@@ -208,6 +209,9 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
 #undef HB_DRAW_FUNC_IMPLEMENT
   }
 
+  hb_free (dfuncs->destroy);
+  hb_free (dfuncs->user_data);
+
   hb_free (dfuncs);
 }
 
@@ -234,7 +238,7 @@ hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
  *
  * Checks whether @dfuncs is immutable.
  *
- * Return value: %true if @dfuncs is immutable, %false otherwise
+ * Return value: `true` if @dfuncs is immutable, `false` otherwise
  *
  * Since: 4.0.0
  **/

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

@@ -315,7 +315,7 @@ hb_face_destroy (hb_face_t *face)
  *
  * Attaches a user-data key/data pair to the given face object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -371,7 +371,7 @@ hb_face_make_immutable (hb_face_t *face)
  *
  * Tests whether the given face object is immutable.
  *
- * Return value: %true is @face is immutable, %false otherwise
+ * Return value: `true` is @face is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/

+ 25 - 20
thirdparty/harfbuzz/src/hb-font.cc

@@ -754,7 +754,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
  *
  * Attaches a user-data key/data pair to the specified font-functions structure.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -811,7 +811,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
  *
  * Tests whether a font-functions structure is immutable.
  *
- * Return value: %true if @ffuncs is immutable, %false otherwise
+ * Return value: `true` if @ffuncs is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -903,7 +903,7 @@ hb_font_t::has_func (unsigned int i)
  * Fetches the extents for a specified font, for horizontal
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -922,7 +922,7 @@ hb_font_get_h_extents (hb_font_t         *font,
  * Fetches the extents for a specified font, for vertical
  * text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.1.3
  **/
@@ -946,7 +946,7 @@ hb_font_get_v_extents (hb_font_t         *font,
  * If @variation_selector is 0, calls hb_font_get_nominal_glyph();
  * otherwise calls hb_font_get_variation_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -974,7 +974,7 @@ hb_font_get_glyph (hb_font_t      *font,
  * for code points modified by variation selectors. For variation-selector
  * support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -1026,7 +1026,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
  * by the specified variation-selector code point, in the specified
  * font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 1.2.3
  **/
@@ -1136,7 +1136,7 @@ hb_font_get_glyph_v_advances (hb_font_t*            font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for horizontal text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1159,7 +1159,7 @@ hb_font_get_glyph_h_origin (hb_font_t      *font,
  * Fetches the (X,Y) coordinates of the origin for a glyph ID
  * in the specified font, for vertical text segments.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1232,7 +1232,7 @@ hb_font_get_glyph_v_kerning (hb_font_t      *font,
  * Fetches the #hb_glyph_extents_t data for a glyph ID
  * in the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1255,7 +1255,7 @@ hb_font_get_glyph_extents (hb_font_t          *font,
  * Fetches the (x,y) coordinates of a specified contour-point index
  * in the specified glyph, within the specified font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1278,7 +1278,7 @@ hb_font_get_glyph_contour_point (hb_font_t      *font,
  *
  * Fetches the glyph-name string for a glyph ID in the specified @font.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1302,7 +1302,7 @@ hb_font_get_glyph_name (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the name string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1537,7 +1537,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t      *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1566,7 +1566,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t          *font,
  * Calls the appropriate direction-specific variant (horizontal
  * or vertical) depending on the value of @direction.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1617,7 +1617,7 @@ hb_font_glyph_to_string (hb_font_t      *font,
  *
  * <note>Note: @len == -1 means the string is null-terminated.</note>
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1675,6 +1675,7 @@ _hb_font_create (hb_face_t *face)
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
+
   if (!(font = hb_object_create<hb_font_t> ()))
     return hb_font_get_empty ();
 
@@ -1866,7 +1867,7 @@ hb_font_destroy (hb_font_t *font)
  *
  * Attaches a user-data key/data pair to the specified font object.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1928,7 +1929,7 @@ hb_font_make_immutable (hb_font_t *font)
  *
  * Tests whether a font object is immutable.
  *
- * Return value: %true if @font is immutable, %false otherwise
+ * Return value: `true` if @font is immutable, `false` otherwise
  *
  * Since: 0.9.2
  **/
@@ -1948,7 +1949,7 @@ hb_font_is_immutable (hb_font_t *font)
  *
  * Return value: serial number
  *
- * Since: 4.4.0.
+ * Since: 4.4.0
  **/
 unsigned int
 hb_font_get_serial (hb_font_t *font)
@@ -1964,7 +1965,7 @@ hb_font_get_serial (hb_font_t *font)
  * This has the effect of increasing the serial as returned
  * by hb_font_get_serial(), which invalidates internal caches.
  *
- * Since: 4.4.0.
+ * Since: 4.4.0
  **/
 void
 hb_font_changed (hb_font_t *font)
@@ -2386,6 +2387,10 @@ hb_font_set_variations (hb_font_t            *font,
     return;
   }
 
+  /* Initialize design coords to default from fvar. */
+  for (unsigned int i = 0; i < coords_length; i++)
+    design_coords[i] = axes[i].get_default ();
+
   for (unsigned int i = 0; i < variations_length; i++)
   {
     const auto tag = variations[i].tag;

+ 7 - 7
thirdparty/harfbuzz/src/hb-font.h

@@ -198,7 +198,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
  * This method should retrieve the nominal glyph ID for a specified Unicode code
  * point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -221,7 +221,7 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
  * followed by a specified Variation Selector code point. Glyph IDs must be
  * returned in a #hb_codepoint_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
@@ -362,7 +362,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
  * origin for a glyph. Each coordinate must be returned in an #hb_position_t
  * output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -434,7 +434,7 @@ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
  * This method should retrieve the extents for a specified glyph. Extents must be 
  * returned in an #hb_glyph_extents output parameter.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  * 
  **/
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -458,7 +458,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
  * specified contour point in a glyph. Each coordinate must be returned as
  * an #hb_position_t output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
@@ -481,7 +481,7 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
  * This method should retrieve the glyph name that corresponds to a
  * glyph ID. The name should be returned in a string output parameter.
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
@@ -503,7 +503,7 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
  * This method should retrieve the glyph ID that corresponds to a glyph-name
  * string. 
  * 
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  **/
 typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,

+ 103 - 44
thirdparty/harfbuzz/src/hb-ft.cc

@@ -136,32 +136,56 @@ _hb_ft_font_destroy (void *data)
 /* hb_font changed, update FT_Face. */
 static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
 {
+  float x_mult = 1.f, y_mult = 1.f;
 
-  FT_Set_Char_Size (ft_face,
-		    abs (font->x_scale), abs (font->y_scale),
-		    0, 0);
+  if (font->x_scale < 0) x_mult = -x_mult;
+  if (font->y_scale < 0) y_mult = -y_mult;
+
+  if (FT_Set_Char_Size (ft_face,
+			abs (font->x_scale), abs (font->y_scale),
+			0, 0
 #if 0
 		    font->x_ppem * 72 * 64 / font->x_scale,
-		    font->y_ppem * 72 * 64 / font->y_scale);
+		    font->y_ppem * 72 * 64 / font->y_scale
+#endif
+     ) && ft_face->num_fixed_sizes)
+  {
+#ifdef HAVE_FT_GET_TRANSFORM
+    /* Bitmap font, eg. bitmap color emoji. */
+    /* TODO Pick largest size? */
+    int x_scale  = ft_face->available_sizes[0].x_ppem;
+    int y_scale = ft_face->available_sizes[0].y_ppem;
+    FT_Set_Char_Size (ft_face,
+		      x_scale, y_scale,
+		      0, 0);
+
+    /* This contains the sign that was previously in x_mult/y_mult. */
+    x_mult = (float) font->x_scale / x_scale;
+    y_mult = (float) font->y_scale / y_scale;
 #endif
-  if (font->x_scale < 0 || font->y_scale < 0)
+  }
+  else
+  { /* Shrug */ }
+
+
+  if (x_mult != 1.f || y_mult != 1.f)
   {
-    FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
-			  0, font->y_scale < 0 ? -1 : +1};
+    FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
+			  0, (int) roundf (y_mult * (1<<16))};
     FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
   unsigned int num_coords;
-  const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
+  const float *coords = hb_font_get_var_coords_design (font, &num_coords);
   if (num_coords)
   {
     FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
     if (ft_coords)
     {
       for (unsigned int i = 0; i < num_coords; i++)
-	ft_coords[i] = coords[i] * 4;
-      FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
+	  ft_coords[i] = coords[i] * 65536.f;
+      FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
       hb_free (ft_coords);
     }
   }
@@ -241,7 +265,7 @@ hb_ft_font_get_load_flags (hb_font_t *font)
  * Fetches the FT_Face associated with the specified #hb_font_t
  * font object.
  *
- * Return value: (nullable): the FT_Face found or %NULL
+ * Return value: (nullable): the FT_Face found or `NULL`
  *
  * Since: 0.9.2
  **/
@@ -263,7 +287,7 @@ hb_ft_font_get_face (hb_font_t *font)
  * Gets the FT_Face associated with @font, This face will be kept around until
  * you call hb_ft_font_unlock_face().
  *
- * Return value: (nullable): the FT_Face associated with @font or %NULL
+ * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
  * Since: 2.6.5
  **/
 FT_Face
@@ -280,7 +304,7 @@ hb_ft_font_lock_face (hb_font_t *font)
 }
 
 /**
- * hb_ft_font_unlock_face:
+ * hb_ft_font_unlock_face: (skip)
  * @font: #hb_font_t to work upon
  *
  * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
@@ -404,7 +428,13 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
   int load_flags = ft_font->load_flags;
-  int mult = font->x_scale < 0 ? -1 : +1;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float mult = matrix.xx / 65536.f;
+#else
+  float mult = font->x_scale < 0 ? -1 : +1;
+#endif
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -420,7 +450,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
       ft_font->advance_cache.set (glyph, v);
     }
 
-    *first_advance = (v * mult + (1<<9)) >> 10;
+    *first_advance = (int) (v * mult + (1<<9)) >> 10;
     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
@@ -436,12 +466,18 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Fixed v;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
     return 0;
 
-  if (font->y_scale < 0)
-    v = -v;
+  v = (int) (y_mult * v);
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
@@ -462,6 +498,15 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float x_mult = matrix.xx / 65536.f;
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float x_mult = font->x_scale < 0 ? -1 : +1;
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
@@ -471,10 +516,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 
-  if (font->x_scale < 0)
-    *x = -*x;
-  if (font->y_scale < 0)
-    *y = -*y;
+  *x = (hb_position_t) (x_mult * *x);
+  *y = (hb_position_t) (y_mult * *y);
 
   return true;
 }
@@ -510,24 +553,24 @@ hb_ft_get_glyph_extents (hb_font_t *font,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float x_mult = matrix.xx / 65536.f;
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float x_mult = font->x_scale < 0 ? -1 : +1;
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
-  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
-  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
-  extents->width = ft_face->glyph->metrics.width;
-  extents->height = -ft_face->glyph->metrics.height;
-  if (font->x_scale < 0)
-  {
-    extents->x_bearing = -extents->x_bearing;
-    extents->width = -extents->width;
-  }
-  if (font->y_scale < 0)
-  {
-    extents->y_bearing = -extents->y_bearing;
-    extents->height = -extents->height;
-  }
+  extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX);
+  extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY);
+  extents->width  = (hb_position_t) (x_mult *  ft_face->glyph->metrics.width);
+  extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height);
+
   return true;
 }
 
@@ -620,16 +663,32 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
+#ifdef HAVE_FT_GET_TRANSFORM
+  FT_Matrix matrix;
+  FT_Get_Transform (ft_face, &matrix, nullptr);
+  float y_mult = matrix.yy / 65536.f;
+#else
+  float y_mult = font->y_scale < 0 ? -1 : +1;
+#endif
 
-  metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
-  metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
-  metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
-  if (font->y_scale < 0)
+  if (ft_face->units_per_EM != 0)
+  {
+    metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
+    metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
+    metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
+  }
+  else
   {
-    metrics->ascender = -metrics->ascender;
-    metrics->descender = -metrics->descender;
-    metrics->line_gap = -metrics->line_gap;
+    /* Bitmap-only font, eg. color bitmap font. */
+    metrics->ascender = ft_face->size->metrics.ascender;
+    metrics->descender = ft_face->size->metrics.descender;
+    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
   }
+
+  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
+  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
+  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
+
   return true;
 }
 
@@ -684,8 +743,6 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
   hb_lock_t lock (ft_font->lock);
   FT_Face ft_face = ft_font->ft_face;
 
-  _hb_ft_hb_font_check_changed (font, ft_font);
-
   if (unlikely (FT_Load_Glyph (ft_face, glyph,
 			       FT_LOAD_NO_BITMAP | ft_font->load_flags)))
     return;
@@ -1028,6 +1085,8 @@ hb_ft_font_changed (hb_font_t *font)
 #endif
   }
 #endif
+
+  _hb_ft_hb_font_check_changed (font, ft_font);
 }
 
 /**

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

@@ -158,7 +158,7 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
 }
 
 /**
- * hb_graphite2_face_get_gr_face:
+ * hb_graphite2_face_get_gr_face: (skip)
  * @face: @hb_face_t to query
  *
  * Fetches the Graphite2 gr_face corresponding to the specified
@@ -195,10 +195,10 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
 
 #ifndef HB_DISABLE_DEPRECATED
 /**
- * hb_graphite2_font_get_gr_font:
+ * hb_graphite2_font_get_gr_font: (skip)
  * @font: An #hb_font_t
  *
- * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ * Always returns `NULL`. Use hb_graphite2_face_get_gr_face() instead.
  *
  * Return value: (nullable): Graphite2 font associated with @font.
  *
@@ -223,7 +223,7 @@ struct hb_graphite2_cluster_t {
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
-  unsigned int advance;
+  int advance;
 };
 
 hb_bool_t

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

@@ -253,6 +253,8 @@ struct hb_is_iterator_of
 };
 #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
 #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+#define hb_is_sorted_iterator_of(Iter, Item) (hb_is_iterator_of<Iter, Item>::value && Iter::is_sorted_iterator)
+#define hb_is_sorted_iterator(Iter) hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
 
 /* hb_is_iterable() */
 

+ 5 - 9
thirdparty/harfbuzz/src/hb-map.cc

@@ -56,8 +56,6 @@ hb_map_create ()
   if (!(map = hb_object_create<hb_map_t> ()))
     return hb_map_get_empty ();
 
-  map->init_shallow ();
-
   return map;
 }
 
@@ -107,8 +105,6 @@ hb_map_destroy (hb_map_t *map)
 {
   if (!hb_object_destroy (map)) return;
 
-  map->fini_shallow ();
-
   hb_free (map);
 }
 
@@ -122,7 +118,7 @@ hb_map_destroy (hb_map_t *map)
  *
  * Attaches a user-data key/data pair to the specified map.
  *
- * Return value: %true if success, %false otherwise
+ * Return value: `true` if success, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -162,7 +158,7 @@ hb_map_get_user_data (hb_map_t           *map,
  *
  * Tests whether memory allocation for a set was successful.
  *
- * Return value: %true if allocation succeeded, %false otherwise
+ * Return value: `true` if allocation succeeded, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -251,7 +247,7 @@ hb_map_del (hb_map_t       *map,
  *
  * Tests whether @key is an element of @map.
  *
- * Return value: %true if @key is found in @map, %false otherwise
+ * Return value: `true` if @key is found in @map, `false` otherwise
  *
  * Since: 1.7.7
  **/
@@ -283,7 +279,7 @@ hb_map_clear (hb_map_t *map)
  *
  * Tests whether @map is empty (contains no elements).
  *
- * Return value: %true if @map is empty
+ * Return value: `true` if @map is empty
  *
  * Since: 1.7.7
  **/
@@ -317,7 +313,7 @@ hb_map_get_population (const hb_map_t *map)
  * Tests whether @map and @other are equal (contain the same
  * elements).
  *
- * Return value: %true if the two maps are equal, %false otherwise.
+ * Return value: `true` if the two maps are equal, `false` otherwise.
  *
  * Since: 4.3.0
  **/

+ 53 - 19
thirdparty/harfbuzz/src/hb-map.hh

@@ -124,21 +124,20 @@ struct hb_hashmap_t
     hb_swap (a.prime, b.prime);
     hb_swap (a.items, b.items);
   }
-  void init_shallow ()
+  void init ()
   {
+    hb_object_init (this);
+
     successful = true;
     population = occupancy = 0;
     mask = 0;
     prime = 0;
     items = nullptr;
   }
-  void init ()
-  {
-    hb_object_init (this);
-    init_shallow ();
-  }
-  void fini_shallow ()
+  void fini ()
   {
+    hb_object_fini (this);
+
     if (likely (items)) {
       unsigned size = mask + 1;
       for (unsigned i = 0; i < size; i++)
@@ -148,11 +147,6 @@ struct hb_hashmap_t
     }
     population = occupancy = 0;
   }
-  void fini ()
-  {
-    hb_object_fini (this);
-    fini_shallow ();
-  }
 
   void reset ()
   {
@@ -219,13 +213,11 @@ struct hb_hashmap_t
   /* Has interface. */
   typedef const V& value_t;
   value_t operator [] (K k) const { return get (k); }
-  bool has (K key, const V **vp = nullptr) const
+  template <typename VV=V>
+  bool has (K key, VV **vp = nullptr) const
   {
     if (unlikely (!items))
-    {
-      if (vp) *vp = &item_t::default_value ();
       return false;
-    }
     unsigned int i = bucket_for (key);
     if (items[i].is_real () && items[i] == key)
     {
@@ -233,10 +225,7 @@ struct hb_hashmap_t
       return true;
     }
     else
-    {
-      if (vp) *vp = &item_t::default_value ();
       return false;
-    }
   }
   /* Projection. */
   V operator () (K k) const { return get (k); }
@@ -301,6 +290,12 @@ struct hb_hashmap_t
     | hb_map (&item_t::key)
     | hb_map (hb_ridentity)
   )
+  auto keys_ref () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::key)
+  )
   auto values () const HB_AUTO_RETURN
   (
     + hb_array (items, mask ? mask + 1 : 0)
@@ -308,6 +303,12 @@ struct hb_hashmap_t
     | hb_map (&item_t::value)
     | hb_map (hb_ridentity)
   )
+  auto values_ref () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::value)
+  )
 
   /* Sink interface. */
   hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
@@ -443,4 +444,37 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
   hb_map_t (const Iterable &o) : hashmap (o) {}
 };
 
+template <typename K, typename V>
+static inline
+hb_hashmap_t<K, V>* hb_hashmap_create ()
+{
+  using hashmap = hb_hashmap_t<K, V>;
+  hashmap* map;
+  if (!(map = hb_object_create<hashmap> ()))
+    return nullptr;
+
+  return map;
+}
+
+template <typename K, typename V>
+static inline
+void hb_hashmap_destroy (hb_hashmap_t<K, V>* map)
+{
+  if (!hb_object_destroy (map))
+    return;
+
+  hb_free (map);
+}
+
+namespace hb {
+
+template <typename K, typename V>
+struct vtable<hb_hashmap_t<K, V>>
+{
+  static constexpr auto destroy = hb_hashmap_destroy<K,V>;
+};
+
+}
+
+
 #endif /* HB_MAP_HH */

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

@@ -188,7 +188,7 @@ template <> struct hb_int_max<signed long long>		: hb_integral_constant<signed l
 template <> struct hb_int_max<unsigned long long>	: hb_integral_constant<unsigned long long,	ULLONG_MAX>	{};
 #define hb_int_max(T) hb_int_max<T>::value
 
-#if defined(__GNUC__) && __GNUC__ < 5
+#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
 #define hb_is_trivially_copyable(T) __has_trivial_copy(T)
 #define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T)
 #define hb_is_trivially_constructible(T) __has_trivial_constructor(T)

+ 30 - 1
thirdparty/harfbuzz/src/hb-null.hh

@@ -39,6 +39,24 @@
 
 #define HB_NULL_POOL_SIZE 448
 
+template <typename T, typename>
+struct _hb_has_min_size : hb_false_type {};
+template <typename T>
+struct _hb_has_min_size<T, hb_void_t<decltype (T::min_size)>>
+	: hb_true_type {};
+template <typename T>
+using hb_has_min_size = _hb_has_min_size<T, void>;
+#define hb_has_min_size(T) hb_has_min_size<T>::value
+
+template <typename T, typename>
+struct _hb_has_null_size : hb_false_type {};
+template <typename T>
+struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>>
+	: hb_true_type {};
+template <typename T>
+using hb_has_null_size = _hb_has_null_size<T, void>;
+#define hb_has_null_size(T) hb_has_null_size<T>::value
+
 /* Use SFINAE to sniff whether T has min_size; in which case return the larger
  * of sizeof(T) and T::null_size, otherwise return sizeof(T).
  *
@@ -117,8 +135,19 @@ struct NullHelper
 	}; \
 	namespace Namespace { \
 	static_assert (true, "") /* Require semicolon after. */
+#define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \
+	} /* Close namespace. */ \
+	extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \
+	template <typename Spec> \
+	struct Null<Namespace::Type<Spec>> { \
+	  static Namespace::Type<Spec> const & get_null () { \
+	    return *reinterpret_cast<const Namespace::Type<Spec> *> (_hb_Null_##Namespace##_##Type); \
+	  } \
+	}; \
+	namespace Namespace { \
+	static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-	const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]
+	const unsigned char _hb_Null_##Namespace##_##Type[sizeof (_hb_Null_##Namespace##_##Type)]
 
 /* Specializations for arbitrary-content Null objects expressed as struct initializer. */
 #define DECLARE_NULL_INSTANCE(Type) \

+ 4 - 4
thirdparty/harfbuzz/src/hb-number-parser.hh

@@ -31,7 +31,7 @@
 #include "hb.hh"
 
 
-#line 35 "hb-number-parser.hh"
+#line 32 "hb-number-parser.hh"
 static const unsigned char _double_parser_trans_keys[] = {
 	0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 
 	46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
 
   int cs;
   
-#line 139 "hb-number-parser.hh"
+#line 132 "hb-number-parser.hh"
 	{
 	cs = double_parser_start;
 	}
 
-#line 144 "hb-number-parser.hh"
+#line 135 "hb-number-parser.hh"
 	{
 	int _slen;
 	int _trans;
@@ -198,7 +198,7 @@ _resume:
 	  exp_overflow = true;
 }
 	break;
-#line 202 "hb-number-parser.hh"
+#line 187 "hb-number-parser.hh"
 	}
 
 _again:

+ 7 - 1
thirdparty/harfbuzz/src/hb-object.hh

@@ -222,8 +222,11 @@ static inline Type *hb_object_create ()
   if (unlikely (!obj))
     return obj;
 
+  new (obj) Type;
+
   hb_object_init (obj);
   hb_object_trace (obj, HB_FUNC);
+
   return obj;
 }
 template <typename Type>
@@ -269,6 +272,9 @@ static inline bool hb_object_destroy (Type *obj)
     return false;
 
   hb_object_fini (obj);
+
+  obj->~Type ();
+
   return true;
 }
 template <typename Type>
@@ -280,7 +286,7 @@ static inline void hb_object_fini (Type *obj)
   {
     user_data->fini ();
     hb_free (user_data);
-    user_data = nullptr;
+    obj->header.user_data.set_relaxed (nullptr);
   }
 }
 template <typename Type>

+ 37 - 10
thirdparty/harfbuzz/src/hb-open-type.hh

@@ -105,7 +105,7 @@ struct IntType
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
   protected:
   BEInt<Type, Size> v;
@@ -170,7 +170,7 @@ struct LONGDATETIME
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
   protected:
   HBINT32 major;
@@ -196,6 +196,10 @@ struct HBGlyphID16 : HBUINT16
 {
   HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
+struct HBGlyphID24 : HBUINT24
+{
+  HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
@@ -300,6 +304,10 @@ struct _hb_has_null<Type, true>
 template <typename Type, typename OffsetType, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
+  // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
+  static_assert (has_null == false ||
+		 (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
+
   HB_DELETE_COPY_ASSIGN (OffsetTo);
   OffsetTo () = default;
 
@@ -450,14 +458,16 @@ struct UnsizedArrayOf
   {
     unsigned int i = (unsigned int) i_;
     const Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return *p;
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     Type *p = &arrayZ[i];
-    if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return *p;
   }
 
@@ -550,14 +560,16 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
   {
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
-    if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return this+*p;
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
-    if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */
+    if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
+    _hb_compiler_memory_r_barrier ();
     return this+*p;
   }
 
@@ -608,12 +620,14 @@ struct ArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
 
@@ -729,6 +743,7 @@ struct ArrayOf
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
@@ -738,26 +753,28 @@ template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUI
 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
-template <typename Type>
-struct List16OfOffset16To : Array16OfOffset16To<Type>
+template <typename Type, typename OffsetType>
+struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
 {
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
   const Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= this->len)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return this+this->arrayZ[i];
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
+    struct List16OfOffsetTo *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
@@ -769,10 +786,13 @@ struct List16OfOffset16To : Array16OfOffset16To<Type>
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (Array16OfOffset16To<Type>::sanitize (c, this, std::forward<Ts> (ds)...));
+    return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
   }
 };
 
+template <typename Type>
+using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
+
 /* An array starting at second element. */
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
@@ -785,12 +805,14 @@ struct HeadlessArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= lenP1 || !i)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i-1];
   }
   unsigned int get_size () const
@@ -869,12 +891,14 @@ struct ArrayOfM1
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i > lenM1)) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return arrayZ[i];
   }
   unsigned int get_size () const
@@ -961,6 +985,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
 };
 
 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
 
 /*
@@ -1053,12 +1078,14 @@ struct VarSizedBinSearchArrayOf
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Null (Type);
+    _hb_compiler_memory_r_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= get_length ())) return Crap (Type);
+    _hb_compiler_memory_r_barrier ();
     return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
   }
   unsigned int get_length () const

+ 4 - 1
thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh

@@ -145,7 +145,7 @@ struct BaseGlyphRecord
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   public:
@@ -524,6 +524,7 @@ struct PaintSweepGradient
 };
 
 struct Paint;
+
 // Paint a non-COLR glyph, filled as indicated by paint.
 struct PaintGlyph
 {
@@ -1152,6 +1153,8 @@ struct Paint
   Variable<PaintSkewAroundCenter>		paintformat31;
   PaintComposite				paintformat32;
   } u;
+  public:
+  DEFINE_SIZE_MIN (2);
 };
 
 struct BaseGlyphPaintRecord

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

@@ -61,7 +61,7 @@
  *
  * Tests whether a face includes a `CPAL` color-palette table.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
@@ -192,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t     *face,
  *
  * Tests whether a face includes any `COLR` color layers.
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */
@@ -239,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
  *
  * Tests whether a face includes any `SVG` glyph images.
  *
- * Return value: %true if data found, %false otherwise.
+ * Return value: `true` if data found, `false` otherwise.
  *
  * Since: 2.1.0
  */
@@ -279,7 +279,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
  *
  * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
  *
- * Return value: %true if data found, %false otherwise
+ * Return value: `true` if data found, `false` otherwise
  *
  * Since: 2.1.0
  */

+ 4 - 0
thirdparty/harfbuzz/src/hb-ot-color.h

@@ -102,6 +102,10 @@ hb_ot_color_has_layers (hb_face_t *face);
  *
  * Pairs of glyph and color index.
  *
+ * A color index of 0xFFFF does not refer to a palette
+ * color, but indicates that the foreground color should
+ * be used.
+ *
  * Since: 2.1.0
  **/
 typedef struct hb_ot_color_layer_t {

+ 26 - 14
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -151,7 +151,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
 #ifndef HB_NO_VAR
-  const OT::HVARVVAR &HVAR = *hmtx.var_table;
+  const OT::HVAR &HVAR = *hmtx.var_table;
   const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
   OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
 
@@ -190,7 +190,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
   {
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, varStore_cache));
+      *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -211,7 +211,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
 	v = cv;
       else
       {
-        v = hmtx.get_advance (*first_glyph, font, varStore_cache);
+        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
 	ot_font->advance_cache->set (*first_glyph, v);
       }
       *first_advance = font->em_scale_x (v);
@@ -242,7 +242,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
   if (vmtx.has_data ())
   {
 #ifndef HB_NO_VAR
-    const OT::HVARVVAR &VVAR = *vmtx.var_table;
+    const OT::VVAR &VVAR = *vmtx.var_table;
     const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
     OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
 #else
@@ -251,7 +251,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
 
     for (unsigned int i = 0; i < count; i++)
     {
-      *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, varStore_cache));
+      *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache));
       first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
@@ -293,17 +293,28 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
   const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
-    *y = font->em_scale_y (VORG.get_y_origin (glyph));
+    float delta = 0;
+
+#ifndef HB_NO_VAR
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+    const OT::VVAR &VVAR = *vmtx.var_table;
+    if (font->num_coords)
+      VVAR.get_vorg_delta_unscaled (glyph,
+				    font->coords, font->num_coords,
+				    &delta);
+#endif
+
+    *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta);
     return true;
   }
 
   hb_glyph_extents_t extents = {0};
   if (ot_face->glyf->get_extents (font, glyph, &extents))
   {
-    if (ot_face->vmtx->has_data ())
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
+    int tsb = 0;
+    if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb))
     {
-      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;
     }
@@ -503,16 +514,17 @@ hb_ot_font_set_funcs (hb_font_t *font)
 }
 
 #ifndef HB_NO_VAR
-int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
+					     int *lsb)
 {
-  return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
+  return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
 }
 
 unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
 {
-  return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+  return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
 }
 #endif
 

+ 47 - 33
thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh

@@ -43,11 +43,11 @@
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
-HB_INTERNAL int
-_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+HB_INTERNAL bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
 
 HB_INTERNAL unsigned
-_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
 
 
 namespace OT {
@@ -62,7 +62,7 @@ struct LongMetric
 };
 
 
-template <typename T, typename H>
+template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
 struct hmtxvmtx
 {
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
@@ -135,9 +135,9 @@ struct hmtxvmtx
       auto& plan = c->plan;
       num_long_metrics = plan->num_output_glyphs ();
       hb_codepoint_t old_gid = 0;
-      unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
+      unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0;
       while (num_long_metrics > 1 &&
-	     last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
+	     last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0))
       {
 	num_long_metrics--;
       }
@@ -150,7 +150,9 @@ struct hmtxvmtx
 		hb_codepoint_t old_gid;
 		if (!c->plan->old_gid_for_new_gid (_, &old_gid))
 		  return hb_pair (0u, 0);
-		return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+		int lsb = 0;
+		(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
+		return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
 	      })
     ;
 
@@ -173,7 +175,7 @@ struct hmtxvmtx
     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);
+      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
 
       default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
 
@@ -221,36 +223,46 @@ struct hmtxvmtx
 
     bool has_data () const { return (bool) num_bearings; }
 
-    int get_side_bearing (hb_codepoint_t glyph) const
+    bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
+						   int *lsb) const
     {
       if (glyph < num_long_metrics)
-	return table->longMetricZ[glyph].sb;
+      {
+	*lsb = table->longMetricZ[glyph].sb;
+	return true;
+      }
 
       if (unlikely (glyph >= num_bearings))
-	return 0;
+	return false;
 
       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
-      return bearings[glyph - num_long_metrics];
+      *lsb = bearings[glyph - num_long_metrics];
+      return true;
     }
 
-    int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+    bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
+						hb_codepoint_t glyph,
+						int *lsb) const
     {
-      int side_bearing = get_side_bearing (glyph);
+      if (!font->num_coords)
+	return get_leading_bearing_without_var_unscaled (glyph, lsb);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_bearings) || !font->num_coords)
-	return side_bearing;
-
-      if (var_table.get_length ())
-	return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords);
+      float delta;
+      if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
+	  get_leading_bearing_without_var_unscaled (glyph, lsb))
+      {
+	*lsb += roundf (delta);
+	return true;
+      }
 
-      return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
 #else
-      return side_bearing;
+      return false;
 #endif
     }
 
-    unsigned int get_advance (hb_codepoint_t glyph) const
+    unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
     {
       /* OpenType case. */
       if (glyph < num_bearings)
@@ -262,7 +274,7 @@ struct hmtxvmtx
       if (unlikely (!num_advances))
 	return default_advance;
 
-#ifdef HB_NO_BORING_EXPANSION
+#ifdef HB_NO_BEYOND_64K
       return 0;
 #endif
 
@@ -275,7 +287,7 @@ struct hmtxvmtx
       /* TODO Optimize */
 
       if (num_bearings == num_advances)
-        return get_advance (num_bearings - 1);
+        return get_advance_without_var_unscaled (num_bearings - 1);
 
       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
       const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
@@ -283,20 +295,22 @@ struct hmtxvmtx
       return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
     }
 
-    unsigned int get_advance (hb_codepoint_t  glyph,
-			      hb_font_t      *font,
-			      VariationStore::cache_t *store_cache = nullptr) const
+    unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
+					    hb_font_t      *font,
+					    VariationStore::cache_t *store_cache = nullptr) const
     {
-      unsigned int advance = get_advance (glyph);
+      unsigned int advance = get_advance_without_var_unscaled (glyph);
 
 #ifndef HB_NO_VAR
       if (unlikely (glyph >= num_bearings) || !font->num_coords)
 	return advance;
 
       if (var_table.get_length ())
-	return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?!
+	return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
+									font->coords, font->num_coords,
+									store_cache)); // TODO Optimize?!
 
-      return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
 #else
       return advance;
 #endif
@@ -313,7 +327,7 @@ struct hmtxvmtx
 
     public:
     hb_blob_ptr_t<hmtxvmtx> table;
-    hb_blob_ptr_t<HVARVVAR> var_table;
+    hb_blob_ptr_t<V> var_table;
   };
 
   protected:
@@ -346,12 +360,12 @@ struct hmtxvmtx
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };
 
-struct hmtx : hmtxvmtx<hmtx, hhea> {
+struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
   static constexpr bool is_horizontal = true;
 };
-struct vmtx : hmtxvmtx<vmtx, vhea> {
+struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
   static constexpr bool is_horizontal = false;

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

@@ -49,7 +49,7 @@ struct BaseCoordFormat1
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this)));
+    return_trace (c->check_struct (this));
   }
 
   protected:

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 444 - 470
thirdparty/harfbuzz/src/hb-ot-layout-common.hh


+ 272 - 104
thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh

@@ -510,6 +510,101 @@ struct MarkGlyphSets
  */
 
 
+template <typename Types>
+struct GDEFVersion1_2
+{
+  friend struct GDEF;
+
+  protected:
+  FixedVersion<>version;		/* Version of the GDEF table--currently
+					 * 0x00010003u */
+  typename Types::template OffsetTo<ClassDef>
+		glyphClassDef;		/* Offset to class definition table
+					 * for glyph type--from beginning of
+					 * GDEF header (may be Null) */
+  typename Types::template OffsetTo<AttachList>
+		attachList;		/* Offset to list of glyphs with
+					 * attachment points--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<LigCaretList>
+		ligCaretList;		/* Offset to list of positioning points
+					 * for ligature carets--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<ClassDef>
+		markAttachClassDef;	/* Offset to class definition table for
+					 * mark attachment type--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<MarkGlyphSets>
+		markGlyphSetsDef;	/* Offset to the table of mark set
+					 * definitions--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010002. */
+  Offset32To<VariationStore>
+		varStore;		/* Offset to the table of Item Variation
+					 * Store--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010003. */
+  public:
+  DEFINE_SIZE_MIN (4 + 4 * Types::size);
+
+  unsigned int get_size () const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  glyphClassDef.sanitize (c, this) &&
+		  attachList.sanitize (c, this) &&
+		  ligCaretList.sanitize (c, this) &&
+		  markAttachClassDef.sanitize (c, this) &&
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+
+    bool subset_markglyphsetsdef = false;
+    if (version.to_int () >= 0x00010002u)
+    {
+      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+    }
+
+    bool subset_varstore = false;
+    if (version.to_int () >= 0x00010003u)
+    {
+      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
+    }
+
+    if (subset_varstore)
+    {
+      out->version.minor = 3;
+    } else if (subset_markglyphsetsdef) {
+      out->version.minor = 2;
+    } else  {
+      out->version.minor = 0;
+    }
+
+    return_trace (subset_glyphclassdef || subset_attachlist ||
+		  subset_ligcaretlist || subset_markattachclassdef ||
+		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+		  (out->version.to_int () >= 0x00010003u && subset_varstore));
+  }
+};
+
 struct GDEF
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
@@ -522,42 +617,190 @@ struct GDEF
     ComponentGlyph	= 4
   };
 
-  bool has_data () const { return version.to_int (); }
-  bool has_glyph_classes () const { return glyphClassDef != 0; }
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset (c);
+#endif
+    default: return false;
+    }
+  }
+
+  bool has_glyph_classes () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.glyphClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.glyphClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_glyph_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.glyphClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.glyphClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.attachList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.attachList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const AttachList &get_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.attachList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.attachList;
+#endif
+    default: return Null(AttachList);
+    }
+  }
+  bool has_lig_carets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.ligCaretList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.ligCaretList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const LigCaretList &get_lig_caret_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.ligCaretList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.ligCaretList;
+#endif
+    default: return Null(LigCaretList);
+    }
+  }
+  bool has_mark_attachment_types () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.markAttachClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markAttachClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_mark_attach_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.markAttachClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markAttachClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markGlyphSetsDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const MarkGlyphSets &get_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markGlyphSetsDef;
+#endif
+    default: return Null(MarkGlyphSets);
+    }
+  }
+  bool has_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.varStore != 0;
+#endif
+    default: return false;
+    }
+  }
+  const VariationStore &get_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.varStore;
+#endif
+    default: return Null(VariationStore);
+    }
+  }
+
+
+  bool has_data () const { return u.version.to_int (); }
   unsigned int get_glyph_class (hb_codepoint_t glyph) const
-  { return (this+glyphClassDef).get_class (glyph); }
+  { return get_glyph_class_def ().get_class (glyph); }
   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
-  { (this+glyphClassDef).collect_class (glyphs, klass); }
+  { get_glyph_class_def ().collect_class (glyphs, klass); }
 
-  bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
-  { return (this+markAttachClassDef).get_class (glyph); }
+  { return get_mark_attach_class_def ().get_class (glyph); }
 
-  bool has_attach_points () const { return attachList != 0; }
   unsigned int get_attach_points (hb_codepoint_t glyph_id,
 				  unsigned int start_offset,
 				  unsigned int *point_count /* IN/OUT */,
 				  unsigned int *point_array /* OUT */) const
-  { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
+  { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
 
-  bool has_lig_carets () const { return ligCaretList != 0; }
   unsigned int get_lig_carets (hb_font_t *font,
 			       hb_direction_t direction,
 			       hb_codepoint_t glyph_id,
 			       unsigned int start_offset,
 			       unsigned int *caret_count /* IN/OUT */,
 			       hb_position_t *caret_array /* OUT */) const
-  { return (this+ligCaretList).get_lig_carets (font,
-					       direction, glyph_id, get_var_store(),
-					       start_offset, caret_count, caret_array); }
+  { return get_lig_caret_list ().get_lig_carets (font,
+						 direction, glyph_id, get_var_store(),
+						 start_offset, caret_count, caret_array); }
 
-  bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
   bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
-  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
-
-  bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
-  const VariationStore &get_var_store () const
-  { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
+  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
 
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
@@ -599,20 +842,13 @@ struct GDEF
     hb_blob_ptr_t<GDEF> table;
   };
 
-  unsigned int get_size () const
-  {
-    return min_size +
-	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
-	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
-  }
-
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
-  { (this+ligCaretList).collect_variation_indices (c); }
+  { get_lig_caret_list ().collect_variation_indices (c); }
 
   void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
 				       hb_map_t *layout_variation_idx_map /* OUT */) const
   {
-    if (version.to_int () < 0x00010003u || !varStore) return;
+    if (!has_var_store ()) return;
     if (layout_variation_indices->is_empty ()) return;
 
     unsigned new_major = 0, new_minor = 0;
@@ -620,7 +856,7 @@ struct GDEF
     for (unsigned idx : layout_variation_indices->iter ())
     {
       uint16_t major = idx >> 16;
-      if (major >= (this+varStore).get_sub_table_count ()) break;
+      if (major >= get_var_store ().get_sub_table_count ()) break;
       if (major != last_major)
       {
 	new_minor = 0;
@@ -634,84 +870,16 @@ struct GDEF
     }
   }
 
-  bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-
-    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
-    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
-    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
-    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
-    bool subset_markglyphsetsdef = true;
-    if (version.to_int () >= 0x00010002u)
-    {
-      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
-      if (!subset_markglyphsetsdef &&
-	  version.to_int () == 0x00010002u)
-	out->version.minor = 0;
-    }
-
-    bool subset_varstore = true;
-    if (version.to_int () >= 0x00010003u)
-    {
-      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
-      if (!subset_varstore && version.to_int () == 0x00010003u)
-	out->version.minor = 2;
-    }
-
-    return_trace (subset_glyphclassdef || subset_attachlist ||
-		  subset_ligcaretlist || subset_markattachclassdef ||
-		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
-		  (out->version.to_int () >= 0x00010003u && subset_varstore));
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (version.sanitize (c) &&
-		  likely (version.major == 1) &&
-		  glyphClassDef.sanitize (c, this) &&
-		  attachList.sanitize (c, this) &&
-		  ligCaretList.sanitize (c, this) &&
-		  markAttachClassDef.sanitize (c, this) &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
-		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
-  }
-
   protected:
-  FixedVersion<>version;		/* Version of the GDEF table--currently
-					 * 0x00010003u */
-  Offset16To<ClassDef>
-		glyphClassDef;		/* Offset to class definition table
-					 * for glyph type--from beginning of
-					 * GDEF header (may be Null) */
-  Offset16To<AttachList>
-		attachList;		/* Offset to list of glyphs with
-					 * attachment points--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<LigCaretList>
-		ligCaretList;		/* Offset to list of positioning points
-					 * for ligature carets--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<ClassDef>
-		markAttachClassDef;	/* Offset to class definition table for
-					 * mark attachment type--from beginning
-					 * of GDEF header (may be Null) */
-  Offset16To<MarkGlyphSets>
-		markGlyphSetsDef;	/* Offset to the table of mark set
-					 * definitions--from beginning of GDEF
-					 * header (may be NULL).  Introduced
-					 * in version 0x00010002. */
-  Offset32To<VariationStore>
-		varStore;		/* Offset to the table of Item Variation
-					 * Store--from beginning of GDEF
-					 * header (may be NULL).  Introduced
-					 * in version 0x00010003. */
+  union {
+  FixedVersion<>		version;	/* Version identifier */
+  GDEFVersion1_2<SmallTypes>	version1;
+#ifndef HB_NO_BEYOND_64K
+  GDEFVersion1_2<MediumTypes>	version2;
+#endif
+  } u;
   public:
-  DEFINE_SIZE_MIN (12);
+  DEFINE_SIZE_MIN (4);
 };
 
 struct GDEF_accelerator_t : GDEF::accelerator_t {

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно