Browse Source

Merge pull request #63899 from bruvzg/hb_510

HarfBuzz: Update to version 5.1.0, use new FLAG_SAFE_TO_INSERT_TATWEEL flag to improve justification.
Rémi Verschelde 3 years ago
parent
commit
fdceece7f8
57 changed files with 2001 additions and 3240 deletions
  1. 3 0
      doc/classes/TextServer.xml
  2. 18 2
      modules/text_server_adv/text_server_adv.cpp
  3. 1 0
      servers/text_server.cpp
  4. 1 0
      servers/text_server.h
  5. 1 1
      thirdparty/README.md
  6. 14 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
  7. 19 4
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
  8. 13 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
  9. 16 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
  10. 2 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
  11. 17 5
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
  12. 14 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
  13. 15 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
  14. 50 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
  15. 16 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
  16. 61 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
  17. 27 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
  18. 15 0
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
  19. 12 0
      thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
  20. 80 0
      thirdparty/harfbuzz/src/graph/coverage-graph.hh
  21. 136 4
      thirdparty/harfbuzz/src/graph/graph.hh
  22. 71 0
      thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
  23. 67 0
      thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
  24. 351 0
      thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
  25. 299 0
      thirdparty/harfbuzz/src/graph/pairpos-graph.hh
  26. 1 1
      thirdparty/harfbuzz/src/hb-blob.cc
  27. 1 1
      thirdparty/harfbuzz/src/hb-blob.h
  28. 40 3
      thirdparty/harfbuzz/src/hb-buffer.cc
  29. 20 5
      thirdparty/harfbuzz/src/hb-buffer.h
  30. 13 5
      thirdparty/harfbuzz/src/hb-buffer.hh
  31. 22 1
      thirdparty/harfbuzz/src/hb-cplusplus.hh
  32. 5 0
      thirdparty/harfbuzz/src/hb-debug.hh
  33. 1 1
      thirdparty/harfbuzz/src/hb-face.cc
  34. 1 1
      thirdparty/harfbuzz/src/hb-face.h
  35. 3 3
      thirdparty/harfbuzz/src/hb-font.cc
  36. 3 3
      thirdparty/harfbuzz/src/hb-font.h
  37. 2 1
      thirdparty/harfbuzz/src/hb-ft.cc
  38. 1 1
      thirdparty/harfbuzz/src/hb-map.cc
  39. 1 1
      thirdparty/harfbuzz/src/hb-map.h
  40. 4 4
      thirdparty/harfbuzz/src/hb-number-parser.hh
  41. 1 5
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  42. 24 0
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  43. 26 3
      thirdparty/harfbuzz/src/hb-ot-shape.cc
  44. 2 2
      thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
  45. 260 238
      thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
  46. 158 3
      thirdparty/harfbuzz/src/hb-repacker.hh
  47. 1 1
      thirdparty/harfbuzz/src/hb-set.cc
  48. 1 1
      thirdparty/harfbuzz/src/hb-set.h
  49. 2 2
      thirdparty/harfbuzz/src/hb-shape-plan.cc
  50. 2 2
      thirdparty/harfbuzz/src/hb-shape-plan.h
  51. 11 2
      thirdparty/harfbuzz/src/hb-subset-repacker.cc
  52. 2 1
      thirdparty/harfbuzz/src/hb-subset-repacker.h
  53. 40 2894
      thirdparty/harfbuzz/src/hb-ucd-table.hh
  54. 27 32
      thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
  55. 2 2
      thirdparty/harfbuzz/src/hb-unicode.cc
  56. 2 2
      thirdparty/harfbuzz/src/hb-unicode.h
  57. 3 3
      thirdparty/harfbuzz/src/hb-version.h

+ 3 - 0
doc/classes/TextServer.xml

@@ -1679,6 +1679,9 @@
 		<constant name="GRAPHEME_IS_CONNECTED" value="1024" enum="GraphemeFlag" is_bitfield="true">
 			Grapheme is connected to the previous grapheme. Breaking line before this grapheme is not safe.
 		</constant>
+		<constant name="GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL" value="2048" enum="GraphemeFlag" is_bitfield="true">
+			It is safe to insert a U+0640 before this grapheme for elongation.
+		</constant>
 		<constant name="HINTING_NONE" value="0" enum="Hinting">
 			Disables font hinting (smoother but less crisp).
 		</constant>

+ 18 - 2
modules/text_server_adv/text_server_adv.cpp

@@ -4718,6 +4718,11 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
 							if (sd_glyphs[i].font_rid != RID()) {
 								Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
 								if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
+#if HB_VERSION_ATLEAST(5, 1, 0)
+									if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {
+										continue;
+									}
+#endif
 									gl.start = sd_glyphs[i].start;
 									gl.end = sd_glyphs[i].end;
 									gl.repeat = 0;
@@ -4908,11 +4913,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
 
 	hb_buffer_clear_contents(p_sd->hb_buffer);
 	hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
+	int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);
 	if (p_sd->preserve_control) {
-		hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+		flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
 	} else {
-		hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+		flags |= HB_BUFFER_FLAG_DEFAULT;
 	}
+#if HB_VERSION_ATLEAST(5, 1, 0)
+	flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+#endif
+	hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);
 	hb_buffer_set_script(p_sd->hb_buffer, p_script);
 
 	if (p_sd->spans[p_span].language.is_empty()) {
@@ -4980,6 +4990,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
 				gl.flags |= GRAPHEME_IS_CONNECTED;
 			}
 
+#if HB_VERSION_ATLEAST(5, 1, 0)
+			if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {
+				gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;
+			}
+#endif
+
 			gl.index = glyph_info[i].codepoint;
 			if (gl.index != 0) {
 				_ensure_glyph(fd, fss, gl.index);

+ 1 - 0
servers/text_server.cpp

@@ -521,6 +521,7 @@ void TextServer::_bind_methods() {
 	BIND_BITFIELD_FLAG(GRAPHEME_IS_PUNCTUATION);
 	BIND_BITFIELD_FLAG(GRAPHEME_IS_UNDERSCORE);
 	BIND_BITFIELD_FLAG(GRAPHEME_IS_CONNECTED);
+	BIND_BITFIELD_FLAG(GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL);
 
 	/* Hinting */
 	BIND_ENUM_CONSTANT(HINTING_NONE);

+ 1 - 0
servers/text_server.h

@@ -116,6 +116,7 @@ public:
 		GRAPHEME_IS_PUNCTUATION = 1 << 8, // Punctuation, except underscore (can be used as word break, but not line break or justifiction).
 		GRAPHEME_IS_UNDERSCORE = 1 << 9, // Underscore (can be used as word break).
 		GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme.
+		GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL = 1 << 11, // It is safe to insert a U+0640 before this grapheme for elongation.
 	};
 
 	enum Hinting {

+ 1 - 1
thirdparty/README.md

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

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

@@ -140,6 +140,13 @@ struct CursivePosFormat1
     unsigned int i = skippy_iter.idx;
     unsigned int j = buffer->idx;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "cursive attaching glyph at %d to glyph at %d",
+			  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);
@@ -231,6 +238,13 @@ struct CursivePosFormat1
 	pos[parent].x_offset = 0;
     }
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "cursive attached glyph at %d to glyph at %d",
+			  i, j);
+    }
+
     buffer->idx++;
     return_trace (true);
   }

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

@@ -39,6 +39,13 @@ struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Cove
     mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "attaching mark glyph at %d to glyph at %d",
+			  c->buffer->idx, glyph_pos);
+    }
+
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = roundf (base_x - mark_x);
     o.y_offset = roundf (base_y - mark_y);
@@ -46,6 +53,13 @@ struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Cove
     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "attached mark glyph at %d to glyph at %d",
+			  c->buffer->idx, glyph_pos);
+    }
+
     buffer->idx++;
     return_trace (true);
   }
@@ -83,10 +97,11 @@ struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Cove
   }
 };
 
-static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
-                                                 const MarkArray &mark_array,
-                                                 const hb_set_t  &glyphset,
-                                                 hb_map_t*        klass_mapping /* INOUT */)
+HB_INTERNAL inline
+void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
+                                          const MarkArray &mark_array,
+                                          const hb_set_t  &glyphset,
+                                          hb_map_t*        klass_mapping /* INOUT */)
 {
   hb_set_t orig_classes;
 

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

@@ -217,10 +217,23 @@ struct PairPosFormat2_4
     }
     bail:
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "kerning glyphs at %d,%d",
+			  c->buffer->idx, skippy_iter.idx);
+    }
 
     applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
     applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "kerned glyphs at %d,%d",
+			  c->buffer->idx, skippy_iter.idx);
+    }
+
     success:
     if (applied_first || applied_second)
       buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);

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

@@ -109,12 +109,28 @@ struct PairSet
                                                 record_size);
     if (record)
     {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "kerning glyphs at %d,%d",
+			    c->buffer->idx, pos);
+      }
+
       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 (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "kerned glyphs at %d,%d",
+			    c->buffer->idx, pos);
+      }
+
       if (applied_first || applied_second)
         buffer->unsafe_to_break (buffer->idx, pos + 1);
       if (len2)
         pos++;
+
       buffer->idx = pos;
       return_trace (true);
     }

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

@@ -1,6 +1,8 @@
 #ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
 #define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
 
+#include "ValueFormat.hh"
+
 namespace OT {
 namespace Layout {
 namespace GPOS_impl {

+ 17 - 5
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh

@@ -39,12 +39,10 @@ struct SinglePosFormat1
   {
     if (!valueFormat.has_device ()) return;
 
-    auto it =
-    + hb_iter (this+coverage)
-    | hb_filter (c->glyph_set)
-    ;
+    hb_set_t intersection;
+    (this+coverage).intersect_set (*c->glyph_set, intersection);
+    if (!intersection) return;
 
-    if (!it) return;
     valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
   }
 
@@ -62,8 +60,22 @@ struct SinglePosFormat1
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "positioning glyph at %d",
+			  c->buffer->idx);
+    }
+
     valueFormat.apply_value (c, this, values, buffer->cur_pos());
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "positioned glyph at %d",
+			  c->buffer->idx);
+    }
+
     buffer->idx++;
     return_trace (true);
   }

+ 14 - 0
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh

@@ -70,10 +70,24 @@ struct SinglePosFormat2
 
     if (likely (index >= valueCount)) return_trace (false);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "positioning glyph at %d",
+			  c->buffer->idx);
+    }
+
     valueFormat.apply_value (c, this,
                              &values[index * valueFormat.get_len ()],
                              buffer->cur_pos());
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "positioned glyph at %d",
+			  c->buffer->idx);
+    }
+
     buffer->idx++;
     return_trace (true);
   }

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

@@ -57,8 +57,23 @@ struct AlternateSet
 
     if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "replacing glyph at %d (alternate substitution)",
+			  c->buffer->idx);
+    }
+
     c->replace_glyph (alternates[alt_index - 1]);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "replaced glyph at %d (alternate substitution)",
+			  c->buffer->idx - 1);
+    }
+
     return_trace (true);
   }
 

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

@@ -64,7 +64,24 @@ struct Ligature
      * as a "ligated" substitution. */
     if (unlikely (count == 1))
     {
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->sync_so_far ();
+	c->buffer->message (c->font,
+			    "replacing glyph at %d (ligature substitution)",
+			    c->buffer->idx);
+      }
+
       c->replace_glyph (ligGlyph);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "replaced glyph at %d (ligature substitution)",
+			    c->buffer->idx - 1);
+      }
+
       return_trace (true);
     }
 
@@ -85,6 +102,31 @@ struct Ligature
       return_trace (false);
     }
 
+    unsigned pos = 0;
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      unsigned delta = c->buffer->sync_so_far ();
+
+      pos = c->buffer->idx;
+
+      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+      char *p = buf;
+
+      match_end += delta;
+      for (unsigned i = 0; i < count; i++)
+      {
+	match_positions[i] += delta;
+	if (i)
+	  *p++ = ',';
+	sprintf (p, "%u", match_positions[i]);
+	p += strlen(p);
+      }
+
+      c->buffer->message (c->font,
+			  "ligating glyphs at %s",
+			  buf);
+    }
+
     ligate_input (c,
                   count,
                   match_positions,
@@ -92,6 +134,14 @@ struct Ligature
                   ligGlyph,
                   total_component_count);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "ligated glyph at %d",
+			  pos);
+    }
+
     return_trace (true);
   }
 

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

@@ -131,7 +131,23 @@ struct ReverseChainSingleSubstFormat1
                          c->buffer->idx + 1, &end_index))
     {
       c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "replacing glyph at %d (reverse chaining substitution)",
+			    c->buffer->idx);
+      }
+
       c->replace_glyph_inplace (substitute[index]);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "replaced glyph at %d (reverse chaining substitution)",
+			    c->buffer->idx);
+      }
+
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
        * calls us through a Context lookup. */

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

@@ -40,17 +40,58 @@ struct Sequence
      * as a "multiplied" substitution. */
     if (unlikely (count == 1))
     {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->sync_so_far ();
+	c->buffer->message (c->font,
+			    "replacing glyph at %d (multiple substitution)",
+			    c->buffer->idx);
+      }
+
       c->replace_glyph (substitute.arrayZ[0]);
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->message (c->font,
+			    "replaced glyph at %d (multiple subtitution)",
+			    c->buffer->idx - 1);
+      }
+
       return_trace (true);
     }
     /* Spec disallows this, but Uniscribe allows it.
      * https://github.com/harfbuzz/harfbuzz/issues/253 */
     else if (unlikely (count == 0))
     {
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->sync_so_far ();
+	c->buffer->message (c->font,
+			    "deleting glyph at %d (multiple substitution)",
+			    c->buffer->idx);
+      }
+
       c->buffer->delete_glyph ();
+
+      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+      {
+	c->buffer->sync_so_far ();
+	c->buffer->message (c->font,
+			    "deleted glyph at %d (multiple substitution)",
+			    c->buffer->idx);
+      }
+
       return_trace (true);
     }
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "multiplying glyph at %d",
+			  c->buffer->idx);
+    }
+
     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
                          HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
@@ -65,6 +106,26 @@ struct Sequence
     }
     c->buffer->skip_glyph ();
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+
+      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+      char *p = buf;
+
+      for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
+      {
+	if (buf < p)
+	  *p++ = ',';
+	sprintf (p, "%u", i);
+	p += strlen(p);
+      }
+
+      c->buffer->message (c->font,
+			  "multiplied glyphs at %s",
+			  buf);
+    }
+
     return_trace (true);
   }
 

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

@@ -45,6 +45,18 @@ struct SingleSubstFormat1_3
     hb_set_t intersection;
     (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
 
+    /* In degenerate fuzzer-found fonts, but not real fonts,
+     * this table can keep adding new glyphs in each round of closure.
+     * Refuse to close-over, if it maps glyph range to overlapping range. */
+    hb_codepoint_t min_before = intersection.get_min ();
+    hb_codepoint_t max_before = intersection.get_max ();
+    hb_codepoint_t min_after = (min_before + d) & mask;
+    hb_codepoint_t max_after = (max_before + d) & mask;
+    if ((this+coverage).get_population () >= max_before - min_before &&
+	((min_before <= min_after && min_after <= max_before) ||
+	 (min_before <= max_after && max_after <= max_before)))
+      return;
+
     + hb_iter (intersection)
     | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     | hb_sink (c->output)
@@ -82,8 +94,23 @@ struct SingleSubstFormat1_3
 
     glyph_id = (glyph_id + d) & mask;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "replacing glyph at %d (single substitution)",
+			  c->buffer->idx);
+    }
+
     c->replace_glyph (glyph_id);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "replaced glyph at %d (single substitution)",
+			  c->buffer->idx - 1);
+    }
+
     return_trace (true);
   }
 

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

@@ -68,8 +68,23 @@ struct SingleSubstFormat2_4
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "replacing glyph at %d (single substitution)",
+			  c->buffer->idx);
+    }
+
     c->replace_glyph (substitute[index]);
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      c->buffer->message (c->font,
+			  "replaced glyph at %d (single substitution)",
+			  c->buffer->idx - 1);
+    }
+
     return_trace (true);
   }
 

+ 12 - 0
thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh

@@ -26,7 +26,9 @@ struct CompositeGlyphRecord
     OVERLAP_COMPOUND		= 0x0400,
     SCALED_COMPONENT_OFFSET	= 0x0800,
     UNSCALED_COMPONENT_OFFSET	= 0x1000,
+#ifndef HB_NO_BEYOND_64K
     GID_IS_24BIT		= 0x2000
+#endif
   };
 
   public:
@@ -34,7 +36,9 @@ struct CompositeGlyphRecord
   {
     unsigned int size = min_size;
     /* glyphIndex is 24bit instead of 16bit */
+#ifndef HB_NO_BEYOND_64K
     if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
+#endif
     /* arg1 and 2 are int16 */
     if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
     /* arg1 and 2 are int8 */
@@ -64,9 +68,11 @@ struct CompositeGlyphRecord
   void get_anchor_points (unsigned int &point1, unsigned int &point2) const
   {
     const auto *p = &StructAfter<const HBUINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
     if (flags & GID_IS_24BIT)
       p += HBGlyphID24::static_size;
     else
+#endif
       p += HBGlyphID16::static_size;
     if (flags & ARG_1_AND_2_ARE_WORDS)
     {
@@ -109,9 +115,11 @@ struct CompositeGlyphRecord
     matrix[1] = matrix[2] = 0.f;
 
     const auto *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
     if (flags & GID_IS_24BIT)
       p += HBGlyphID24::static_size;
     else
+#endif
       p += HBGlyphID16::static_size;
     int tx, ty;
     if (flags & ARG_1_AND_2_ARE_WORDS)
@@ -158,16 +166,20 @@ struct CompositeGlyphRecord
   public:
   hb_codepoint_t get_gid () const
   {
+#ifndef HB_NO_BEYOND_64K
     if (flags & GID_IS_24BIT)
       return StructAfter<const HBGlyphID24> (flags);
     else
+#endif
       return StructAfter<const HBGlyphID16> (flags);
   }
   void set_gid (hb_codepoint_t gid)
   {
+#ifndef HB_NO_BEYOND_64K
     if (flags & GID_IS_24BIT)
       StructAfter<HBGlyphID24> (flags) = gid;
     else
+#endif
       /* TODO assert? */
       StructAfter<HBGlyphID16> (flags) = gid;
   }

+ 80 - 0
thirdparty/harfbuzz/src/graph/coverage-graph.hh

@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../OT/Layout/Common/Coverage.hh"
+
+#ifndef GRAPH_COVERAGE_GRAPH_HH
+#define GRAPH_COVERAGE_GRAPH_HH
+
+namespace graph {
+
+struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
+  }
+};
+
+struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+    return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+  }
+};
+
+struct Coverage : public OT::Layout::Common::Coverage
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
+    switch (u.format)
+    {
+    case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
+    case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+    // Not currently supported
+    case 3:
+    case 4:
+#endif
+    default: return false;
+    }
+  }
+};
+
+
+}
+
+#endif  // GRAPH_COVERAGE_GRAPH_HH

+ 136 - 4
thirdparty/harfbuzz/src/graph/graph.hh

@@ -24,6 +24,10 @@
  * Google Author(s): Garret Rieger
  */
 
+#include "../hb-set.hh"
+#include "../hb-priority-queue.hh"
+#include "../hb-serialize.hh"
+
 #ifndef GRAPH_GRAPH_HH
 #define GRAPH_GRAPH_HH
 
@@ -76,6 +80,22 @@ struct graph_t
       }
     }
 
+    void remove_real_link (unsigned child_index, const void* offset)
+    {
+      for (unsigned i = 0; i < obj.real_links.length; i++)
+      {
+        auto& link = obj.real_links[i];
+        if (link.objidx != child_index)
+          continue;
+
+        if ((obj.head + link.position) != offset)
+          continue;
+
+        obj.real_links.remove (i);
+        return;
+      }
+    }
+
     void remap_parents (const hb_vector_t<unsigned>& id_map)
     {
       for (unsigned i = 0; i < parents.length; i++)
@@ -107,6 +127,10 @@ struct graph_t
       return priority >= 3;
     }
 
+    size_t table_size () const {
+      return obj.tail - obj.head;
+    }
+
     int64_t modified_distance (unsigned order) const
     {
       // TODO(garretrieger): once priority is high enough, should try
@@ -199,11 +223,22 @@ struct graph_t
     return vertices_.length - 1;
   }
 
-  const hb_serialize_context_t::object_t& object(unsigned i) const
+  const hb_serialize_context_t::object_t& object (unsigned i) const
   {
     return vertices_[i].obj;
   }
 
+  /*
+   * Generates a new topological sorting of graph ordered by the shortest
+   * distance to each node if positions are marked as invalid.
+   */
+  void sort_shortest_distance_if_needed ()
+  {
+    if (!positions_invalid) return;
+    sort_shortest_distance ();
+  }
+
+
   /*
    * Generates a new topological sorting of graph ordered by the shortest
    * distance to each node.
@@ -256,12 +291,12 @@ struct graph_t
 
     check_success (!queue.in_error ());
     check_success (!sorted_graph.in_error ());
-    if (!check_success (new_id == -1))
-      print_orphaned_nodes ();
 
     remap_all_obj_indices (id_map, &sorted_graph);
-
     hb_swap (vertices_, sorted_graph);
+
+    if (!check_success (new_id == -1))
+      print_orphaned_nodes ();
   }
 
   /*
@@ -310,6 +345,22 @@ struct graph_t
     }
   }
 
+  unsigned index_for_offset(unsigned node_idx, const void* offset) const
+  {
+    const auto& node = object (node_idx);
+    if (offset < node.head || offset >= node.tail) return -1;
+
+    for (const auto& link : node.real_links)
+    {
+      if (offset != node.head + link.position)
+        continue;
+      return link.objidx;
+    }
+
+    return -1;
+  }
+
+
   /*
    * 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
@@ -317,6 +368,8 @@ struct graph_t
    */
   bool assign_spaces ()
   {
+    update_parents ();
+
     hb_set_t visited;
     hb_set_t roots;
     find_space_roots (visited, roots);
@@ -458,6 +511,21 @@ struct graph_t
       find_subgraph (link.objidx, subgraph);
   }
 
+  size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
+  {
+    if (subgraph.has (node_idx)) return 0;
+    subgraph.add (node_idx);
+
+    const auto& o = vertices_[node_idx].obj;
+    size_t size = o.tail - o.head;
+    if (max_depth == 0)
+      return size;
+
+    for (const auto& link : o.all_links ())
+      size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
+    return size;
+  }
+
   /*
    * Finds the topmost children of 32bit offsets in the subgraph starting
    * at node_idx. Found indices are placed into 'found'.
@@ -474,6 +542,37 @@ struct graph_t
     }
   }
 
+  /*
+   * Moves the child of old_parent_idx pointed to by old_offset to a new
+   * vertex at the new_offset.
+   */
+  template<typename O>
+  void move_child (unsigned old_parent_idx,
+                   const O* old_offset,
+                   unsigned new_parent_idx,
+                   const O* new_offset)
+  {
+    distance_invalid = true;
+    positions_invalid = true;
+
+    auto& old_v = vertices_[old_parent_idx];
+    auto& new_v = vertices_[new_parent_idx];
+
+    unsigned child_id = index_for_offset (old_parent_idx,
+                                          old_offset);
+
+    auto* new_link = new_v.obj.real_links.push ();
+    new_link->width = O::static_size;
+    new_link->objidx = child_id;
+    new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
+
+    auto& child = vertices_[child_id];
+    child.parents.push (new_parent_idx);
+
+    old_v.remove_real_link (child_id, old_offset);
+    child.remove_parent (old_parent_idx);
+  }
+
   /*
    * 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
@@ -581,6 +680,39 @@ struct graph_t
     return true;
   }
 
+
+  /*
+   * Adds a new node to the graph, not connected to anything.
+   */
+  unsigned new_node (char* head, char* tail)
+  {
+    positions_invalid = true;
+    distance_invalid = true;
+
+    auto* clone = vertices_.push ();
+    if (vertices_.in_error ()) {
+      return -1;
+    }
+
+    clone->obj.head = head;
+    clone->obj.tail = tail;
+    clone->distance = 0;
+    clone->space = 0;
+
+    unsigned clone_idx = vertices_.length - 2;
+
+    // The last object is the root of the graph, so swap back the root to the end.
+    // The root's obj idx does change, however since it's root nothing else refers to it.
+    // all other obj idx's will be unaffected.
+    hb_swap (vertices_[vertices_.length - 2], *clone);
+
+    // Since the root moved, update the parents arrays of all children on the root.
+    for (const auto& l : root ().obj.all_links ())
+      vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+
+    return clone_idx;
+  }
+
   /*
    * Raises the sorting priority of all children.
    */

+ 71 - 0
thirdparty/harfbuzz/src/graph/gsubgpos-context.cc

@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "gsubgpos-graph.hh"
+
+namespace graph {
+
+gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
+                                                    graph_t& graph_)
+    : table_tag (table_tag_),
+      graph (graph_),
+      lookup_list_index (0),
+      lookups (),
+      buffers ()
+{
+  if (table_tag_ != HB_OT_TAG_GPOS
+      &&  table_tag_ != HB_OT_TAG_GSUB)
+    return;
+
+  GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_);
+  if (gstar) {
+    gstar->find_lookups (graph, lookups);
+    lookup_list_index = gstar->get_lookup_list_index (graph_);
+  }
+}
+
+unsigned gsubgpos_graph_context_t::create_node (unsigned size)
+{
+  char* buffer = (char*) hb_calloc (1, size);
+  if (!buffer)
+    return -1;
+
+  buffers.push (buffer);
+
+  return graph.new_node (buffer, buffer + size);
+}
+
+unsigned gsubgpos_graph_context_t::num_non_ext_subtables ()  {
+  unsigned count = 0;
+  for (auto l : lookups.values ())
+  {
+    if (l->is_extension (table_tag)) continue;
+    count += l->number_of_subtables ();
+  }
+  return count;
+}
+
+}

+ 67 - 0
thirdparty/harfbuzz/src/graph/gsubgpos-context.hh

@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+
+#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
+#define GRAPH_GSUBGPOS_CONTEXT_HH
+
+namespace graph {
+
+struct Lookup;
+
+struct gsubgpos_graph_context_t
+{
+  hb_tag_t table_tag;
+  graph_t& graph;
+  unsigned lookup_list_index;
+  hb_hashmap_t<unsigned, graph::Lookup*> lookups;
+  hb_vector_t<char*> buffers;
+
+  HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
+                                        graph_t& graph_);
+
+  ~gsubgpos_graph_context_t ()
+  {
+    for (char* b : buffers)
+      hb_free (b);
+  }
+
+  HB_INTERNAL unsigned create_node (unsigned size);
+
+  void add_buffer (char* buffer)
+  {
+    buffers.push (buffer);
+  }
+
+ private:
+  HB_INTERNAL unsigned num_non_ext_subtables ();
+};
+
+}
+
+#endif  // GRAPH_GSUBGPOS_CONTEXT

+ 351 - 0
thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh

@@ -0,0 +1,351 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+#include "../OT/Layout/GSUB/ExtensionSubst.hh"
+#include "gsubgpos-context.hh"
+#include "pairpos-graph.hh"
+
+#ifndef GRAPH_GSUBGPOS_GRAPH_HH
+#define GRAPH_GSUBGPOS_GRAPH_HH
+
+namespace graph {
+
+struct Lookup;
+
+template<typename T>
+struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
+{
+  void reset(unsigned type)
+  {
+    this->format = 1;
+    this->extensionLookupType = type;
+    this->extensionOffset = 0;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    return vertex_len >= OT::ExtensionFormat1<T>::static_size;
+  }
+
+  unsigned get_lookup_type () const
+  {
+    return this->extensionLookupType;
+  }
+
+  unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
+  {
+    return graph.index_for_offset (this_index, &this->extensionOffset);
+  }
+};
+
+struct Lookup : public OT::Lookup
+{
+  unsigned number_of_subtables () const
+  {
+    return subTable.len;
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::Lookup::min_size) return false;
+    return vertex_len >= this->get_size ();
+  }
+
+  bool is_extension (hb_tag_t table_tag) const
+  {
+    return lookupType == extension_type (table_tag);
+  }
+
+  bool make_extension (gsubgpos_graph_context_t& c,
+                       unsigned this_index)
+  {
+    unsigned type = lookupType;
+    unsigned ext_type = extension_type (c.table_tag);
+    if (!ext_type || is_extension (c.table_tag))
+    {
+      // NOOP
+      return true;
+    }
+
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "Promoting lookup type %u (obj %u) to extension.",
+               type,
+               this_index);
+
+    for (unsigned i = 0; i < subTable.len; i++)
+    {
+      unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      if (!make_subtable_extension (c,
+                                    this_index,
+                                    subtable_index))
+        return false;
+    }
+
+    lookupType = ext_type;
+    return true;
+  }
+
+  bool split_subtables_if_needed (gsubgpos_graph_context_t& c,
+                                  unsigned this_index)
+  {
+    unsigned type = lookupType;
+    bool is_ext = is_extension (c.table_tag);
+
+    if (c.table_tag != HB_OT_TAG_GPOS)
+      return true;
+
+    if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+      return true;
+
+    hb_vector_t<unsigned> all_new_subtables;
+    for (unsigned i = 0; i < subTable.len; i++)
+    {
+      unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      if (is_ext) {
+        unsigned ext_subtable_index = subtable_index;
+        ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+            (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
+            c.graph.object (ext_subtable_index).head;
+        if (!extension->sanitize (c.graph.vertices_[ext_subtable_index]))
+          continue;
+
+        subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
+        type = extension->get_lookup_type ();
+        if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+          continue;
+      }
+
+      PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head;
+      if (!pairPos->sanitize (c.graph.vertices_[subtable_index])) continue;
+
+      hb_vector_t<unsigned> new_sub_tables = pairPos->split_subtables (c, subtable_index);
+      if (new_sub_tables.in_error ()) return false;
+      + new_sub_tables.iter() | hb_sink (all_new_subtables);
+    }
+
+    if (all_new_subtables)
+      add_sub_tables (c, this_index, type, all_new_subtables);
+
+    return true;
+  }
+
+  void add_sub_tables (gsubgpos_graph_context_t& c,
+                       unsigned this_index,
+                       unsigned type,
+                       hb_vector_t<unsigned>& subtable_indices)
+  {
+    bool is_ext = is_extension (c.table_tag);
+    auto& v = c.graph.vertices_[this_index];
+
+    size_t new_size = v.table_size ()
+                      + subtable_indices.length * OT::Offset16::static_size;
+    char* buffer = (char*) hb_calloc (1, new_size);
+    c.add_buffer (buffer);
+    memcpy (buffer, v.obj.head, v.table_size());
+
+    v.obj.head = buffer;
+    v.obj.tail = buffer + new_size;
+
+    Lookup* new_lookup = (Lookup*) buffer;
+
+    new_lookup->subTable.len = subTable.len + subtable_indices.length;
+    unsigned offset_index = subTable.len;
+    for (unsigned subtable_id : subtable_indices)
+    {
+      if (is_ext)
+      {
+        unsigned ext_id = create_extension_subtable (c, subtable_id, type);
+        c.graph.vertices_[subtable_id].parents.push (ext_id);
+        subtable_id = ext_id;
+      }
+
+      auto* link = v.obj.real_links.push ();
+      link->width = 2;
+      link->objidx = subtable_id;
+      link->position = (char*) &new_lookup->subTable[offset_index++] -
+                       (char*) new_lookup;
+      c.graph.vertices_[subtable_id].parents.push (this_index);
+    }
+
+    // The head location of the lookup has changed, invalidating the lookups map entry
+    // in the context. Update the map.
+    c.lookups.set (this_index, new_lookup);
+  }
+
+  unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
+                                      unsigned subtable_index,
+                                      unsigned type)
+  {
+    unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
+
+    unsigned ext_index = c.create_node (extension_size);
+    if (ext_index == (unsigned) -1)
+      return -1;
+
+    auto& ext_vertex = c.graph.vertices_[ext_index];
+    ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+        (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
+    extension->reset (type);
+
+    // Make extension point at the subtable.
+    auto* l = ext_vertex.obj.real_links.push ();
+
+    l->width = 4;
+    l->objidx = subtable_index;
+    l->position = 4;
+
+    return ext_index;
+  }
+
+  bool make_subtable_extension (gsubgpos_graph_context_t& c,
+                                unsigned lookup_index,
+                                unsigned subtable_index)
+  {
+    unsigned type = lookupType;
+
+    unsigned ext_index = create_extension_subtable(c, subtable_index, type);
+    if (ext_index == (unsigned) -1)
+      return false;
+
+    auto& lookup_vertex = c.graph.vertices_[lookup_index];
+    for (auto& l : lookup_vertex.obj.real_links.writer ())
+    {
+      if (l.objidx == subtable_index)
+        // Change lookup to point at the extension.
+        l.objidx = ext_index;
+    }
+
+    // Make extension point at the subtable.
+    auto& ext_vertex = c.graph.vertices_[ext_index];
+    auto& subtable_vertex = c.graph.vertices_[subtable_index];
+    ext_vertex.parents.push (lookup_index);
+    subtable_vertex.remap_parent (lookup_index, ext_index);
+
+    return true;
+  }
+
+ private:
+  unsigned extension_type (hb_tag_t table_tag) const
+  {
+    switch (table_tag)
+    {
+    case HB_OT_TAG_GPOS: return 9;
+    case HB_OT_TAG_GSUB: return 7;
+    default: return 0;
+    }
+  }
+};
+
+template <typename T>
+struct LookupList : public OT::LookupList<T>
+{
+  bool sanitize (const graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < OT::LookupList<T>::min_size) return false;
+    return vertex_len >= OT::LookupList<T>::item_size * this->len;
+  }
+};
+
+struct GSTAR : public OT::GSUBGPOS
+{
+  static GSTAR* graph_to_gstar (graph_t& graph)
+  {
+    const auto& r = graph.root ();
+
+    GSTAR* gstar = (GSTAR*) r.obj.head;
+    if (!gstar->sanitize (r))
+      return nullptr;
+
+    return gstar;
+  }
+
+  const void* get_lookup_list_field_offset () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_lookup_list_offset ();
+#ifndef HB_NO_BORING_EXPANSION
+    case 2: return u.version2.get_lookup_list_offset ();
+#endif
+    default: return 0;
+    }
+  }
+
+  bool sanitize (const graph_t::vertex_t& vertex)
+  {
+    int64_t len = vertex.obj.tail - vertex.obj.head;
+    if (len < OT::GSUBGPOS::min_size) return false;
+    return len >= get_size ();
+  }
+
+  void find_lookups (graph_t& graph,
+                     hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+  {
+    switch (u.version.major) {
+      case 1: find_lookups<SmallTypes> (graph, lookups); break;
+#ifndef HB_NO_BORING_EXPANSION
+      case 2: find_lookups<MediumTypes> (graph, lookups); break;
+#endif
+    }
+  }
+
+  unsigned get_lookup_list_index (graph_t& graph)
+  {
+    return graph.index_for_offset (graph.root_idx (),
+                                   get_lookup_list_field_offset());
+  }
+
+  template<typename Types>
+  void find_lookups (graph_t& graph,
+                     hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+  {
+    unsigned lookup_list_idx = get_lookup_list_index (graph);
+
+    const LookupList<Types>* lookupList =
+        (const LookupList<Types>*) graph.object (lookup_list_idx).head;
+    if (!lookupList->sanitize (graph.vertices_[lookup_list_idx]))
+      return;
+
+    for (unsigned i = 0; i < lookupList->len; i++)
+    {
+      unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
+      Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
+      if (!lookup->sanitize (graph.vertices_[lookup_idx])) continue;
+      lookups.set (lookup_idx, lookup);
+    }
+  }
+};
+
+
+
+
+}
+
+#endif  /* GRAPH_GSUBGPOS_GRAPH_HH */

+ 299 - 0
thirdparty/harfbuzz/src/graph/pairpos-graph.hh

@@ -0,0 +1,299 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_PAIRPOS_GRAPH_HH
+#define GRAPH_PAIRPOS_GRAPH_HH
+
+#include "coverage-graph.hh"
+#include "../OT/Layout/GPOS/PairPos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+    if (vertex_len < min_size) return false;
+
+    return vertex_len >=
+        min_size + pairSet.get_size () - pairSet.len.get_size();
+  }
+
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  {
+    hb_set_t visited;
+
+    const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+    const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+                               + coverage_size;
+
+    unsigned accumulated = base_size;
+    hb_vector_t<unsigned> split_points;
+    for (unsigned i = 0; i < pairSet.len; i++)
+    {
+      unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
+      accumulated += c.graph.find_subgraph_size (pair_set_index, visited);
+      accumulated += SmallTypes::size; // for PairSet offset.
+
+      // TODO(garretrieger): don't count the size of the largest pairset against the limit, since
+      //                     it will be packed last in the order and does not contribute to
+      //                     the 64kb limit.
+
+      if (accumulated > (1 << 16))
+      {
+        split_points.push (i);
+        accumulated = base_size;
+        visited.clear (); // Pretend node sharing isn't allowed between splits.
+      }
+    }
+
+    return do_split (c, this_index, split_points);
+  }
+
+ private:
+
+  // Split this PairPos into two or more PairPos's. split_points defines
+  // the indices (first index to include in the new table) to split at.
+  // Returns the object id's of the newly created PairPos subtables.
+  hb_vector_t<unsigned> do_split (gsubgpos_graph_context_t& c,
+                                  unsigned this_index,
+                                  const hb_vector_t<unsigned> split_points)
+  {
+    hb_vector_t<unsigned> new_objects;
+    if (!split_points)
+      return new_objects;
+
+    for (unsigned i = 0; i < split_points.length; i++)
+    {
+      unsigned start = split_points[i];
+      unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : pairSet.len;
+      unsigned id = clone_range (c, this_index, start, end);
+
+      if (id == (unsigned) -1)
+      {
+        new_objects.reset ();
+        new_objects.allocated = -1; // mark error
+        return new_objects;
+      }
+      new_objects.push (id);
+    }
+
+    if (!shrink (c, this_index, split_points[0]))
+    {
+      new_objects.reset ();
+      new_objects.allocated = -1; // mark error
+    }
+
+    return new_objects;
+  }
+
+  bool shrink (gsubgpos_graph_context_t& c,
+               unsigned this_index,
+               unsigned count)
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Shrinking PairPosFormat1 (%u) to [0, %u).",
+               this_index,
+               count);
+    unsigned old_count = pairSet.len;
+    if (count >= old_count)
+      return true;
+
+    pairSet.len = count;
+    c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
+
+    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+    auto& coverage_v = c.graph.vertices_[coverage_id];
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    if (!coverage_table->sanitize (coverage_v))
+      return false;
+
+    auto new_coverage =
+        + hb_zip (coverage_table->iter (), hb_range ())
+        | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+          return p.second < count;
+        })
+        | hb_map_retains_sorting (hb_first)
+        ;
+
+    return make_coverage (c, new_coverage, coverage_id, coverage_size);
+  }
+
+  // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
+  // Returns object id of the new object.
+  unsigned clone_range (gsubgpos_graph_context_t& c,
+                        unsigned this_index,
+                        unsigned start, unsigned end) const
+  {
+    DEBUG_MSG (SUBSET_REPACK, nullptr,
+               "  Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+    unsigned num_pair_sets = end - start;
+    unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+                          + num_pair_sets * SmallTypes::size;
+
+    unsigned pair_pos_prime_id = c.create_node (prime_size);
+    if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+    PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
+    pair_pos_prime->format = this->format;
+    pair_pos_prime->valueFormat[0] = this->valueFormat[0];
+    pair_pos_prime->valueFormat[1] = this->valueFormat[1];
+    pair_pos_prime->pairSet.len = num_pair_sets;
+
+    for (unsigned i = start; i < end; i++)
+    {
+      c.graph.move_child<> (this_index,
+                            &pairSet[i],
+                            pair_pos_prime_id,
+                            &pair_pos_prime->pairSet[i - start]);
+    }
+
+    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+    unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+    auto& coverage_v = c.graph.vertices_[coverage_id];
+    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+    if (!coverage_table->sanitize (coverage_v))
+      return false;
+
+    auto new_coverage =
+        + hb_zip (coverage_table->iter (), hb_range ())
+        | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+          return p.second >= start && p.second < end;
+        })
+        | hb_map_retains_sorting (hb_first)
+        ;
+
+    unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
+    auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
+    if (!make_coverage (c, new_coverage, coverage_prime_id, coverage_size))
+      return -1;
+
+    auto* coverage_link = c.graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
+    coverage_link->width = SmallTypes::size;
+    coverage_link->objidx = coverage_prime_id;
+    coverage_link->position = 2;
+    coverage_prime_vertex.parents.push (pair_pos_prime_id);
+
+    return pair_pos_prime_id;
+  }
+
+  template<typename It>
+  bool make_coverage (gsubgpos_graph_context_t& c,
+                      It glyphs,
+                      unsigned dest_obj,
+                      unsigned max_size) const
+  {
+    char* buffer = (char*) hb_calloc (1, max_size);
+    hb_serialize_context_t serializer (buffer, max_size);
+    Coverage_serialize (&serializer, glyphs);
+    serializer.end_serialize ();
+    if (serializer.in_error ())
+    {
+      hb_free (buffer);
+      return false;
+    }
+
+    hb_bytes_t coverage_copy = serializer.copy_bytes ();
+    c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+    auto& obj = c.graph.vertices_[dest_obj].obj;
+    obj.head = (char *) coverage_copy.arrayZ;
+    obj.tail = obj.head + coverage_copy.length;
+
+    hb_free (buffer);
+    return true;
+  }
+
+  unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+  {
+    return c.graph.index_for_offset (this_index, &pairSet[i]);
+  }
+};
+
+struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
+{
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    // TODO(garretrieger): implement me!
+    return true;
+  }
+
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  {
+    // TODO(garretrieger): implement me!
+    return hb_vector_t<unsigned> ();
+  }
+};
+
+struct PairPos : public OT::Layout::GPOS_impl::PairPos
+{
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  {
+    switch (u.format) {
+    case 1:
+      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
+    case 2:
+      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: HB_FALLTHROUGH;
+    case 4: HB_FALLTHROUGH;
+      // Don't split 24bit PairPos's.
+#endif
+    default:
+      return hb_vector_t<unsigned> ();
+    }
+  }
+
+  bool sanitize (graph_t::vertex_t& vertex) const
+  {
+    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+    if (vertex_len < u.format.get_size ()) return false;
+
+    switch (u.format) {
+    case 1:
+      return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
+    case 2:
+      return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+    case 3: HB_FALLTHROUGH;
+    case 4: HB_FALLTHROUGH;
+#endif
+    default:
+      // We don't handle format 3 and 4 here.
+      return false;
+    }
+  }
+};
+
+}
+
+#endif  // GRAPH_PAIRPOS_GRAPH_HH

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

@@ -303,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t          *blob,
  * Since: 0.9.2
  **/
 void *
-hb_blob_get_user_data (hb_blob_t          *blob,
+hb_blob_get_user_data (const hb_blob_t    *blob,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (blob, key);

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

@@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t          *blob,
 
 
 HB_EXTERN void *
-hb_blob_get_user_data (hb_blob_t          *blob,
+hb_blob_get_user_data (const hb_blob_t    *blob,
 		       hb_user_data_key_t *key);
 
 

+ 40 - 3
thirdparty/harfbuzz/src/hb-buffer.cc

@@ -387,9 +387,11 @@ hb_buffer_t::clear_positions ()
   hb_memset (pos, 0, sizeof (pos[0]) * len);
 }
 
-void
+bool
 hb_buffer_t::sync ()
 {
+  bool ret = false;
+
   assert (have_output);
 
   assert (idx <= len);
@@ -403,12 +405,39 @@ hb_buffer_t::sync ()
     info = out_info;
   }
   len = out_len;
+  ret = true;
 
 reset:
   have_output = false;
   out_len = 0;
   out_info = info;
   idx = 0;
+
+  return ret;
+}
+
+int
+hb_buffer_t::sync_so_far ()
+{
+  bool had_output = have_output;
+  unsigned out_i = out_len;
+  unsigned i = idx;
+  unsigned old_idx = idx;
+
+  if (sync ())
+    idx = out_i;
+  else
+    idx = i;
+
+  if (had_output)
+  {
+    have_output = true;
+    out_len = idx;
+  }
+
+  assert (idx <= len);
+
+  return idx - old_idx;
 }
 
 bool
@@ -802,7 +831,7 @@ hb_buffer_set_user_data (hb_buffer_t        *buffer,
  * Since: 0.9.2
  **/
 void *
-hb_buffer_get_user_data (hb_buffer_t        *buffer,
+hb_buffer_get_user_data (const hb_buffer_t  *buffer,
 			 hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (buffer, key);
@@ -2090,8 +2119,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
 bool
 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
 {
+  assert (!have_output || (out_info == info && out_len == idx));
+
+  message_depth++;
+
   char buf[100];
   vsnprintf (buf, sizeof (buf), fmt, ap);
-  return (bool) this->message_func (this, font, buf, this->message_data);
+  bool ret = (bool) this->message_func (this, font, buf, this->message_data);
+
+  message_depth--;
+
+  return ret;
 }
 #endif

+ 20 - 5
thirdparty/harfbuzz/src/hb-buffer.h

@@ -142,6 +142,15 @@ typedef struct hb_glyph_info_t {
  *				   shaping, otherwise the buffer flag will not be
  *				   reliably produced.
  * 				   Since: 4.0.0
+ * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
+				   Mongolian, Syriac, etc.), this flag signifies
+				   that it is safe to insert a U+0640 TATWEEL
+				   character *before* this cluster for elongation.
+				   This flag does not determine the
+				   script-specific elongation places, but only
+				   when it is safe to do the elongation without
+				   interrupting text shaping.
+				   Since: 5.1.0
  * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
  *
  * Flags for #hb_glyph_info_t.
@@ -149,10 +158,11 @@ typedef struct hb_glyph_info_t {
  * Since: 1.5.0
  */
 typedef enum { /*< flags >*/
-  HB_GLYPH_FLAG_UNSAFE_TO_BREAK		= 0x00000001,
-  HB_GLYPH_FLAG_UNSAFE_TO_CONCAT	= 0x00000002,
+  HB_GLYPH_FLAG_UNSAFE_TO_BREAK			= 0x00000001,
+  HB_GLYPH_FLAG_UNSAFE_TO_CONCAT		= 0x00000002,
+  HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL		= 0x00000004,
 
-  HB_GLYPH_FLAG_DEFINED			= 0x00000003 /* OR of all defined flags */
+  HB_GLYPH_FLAG_DEFINED				= 0x00000007 /* OR of all defined flags */
 } hb_glyph_flags_t;
 
 HB_EXTERN hb_glyph_flags_t
@@ -266,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t        *buffer,
 			 hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_buffer_get_user_data (hb_buffer_t        *buffer,
+hb_buffer_get_user_data (const hb_buffer_t  *buffer,
 			 hb_user_data_key_t *key);
 
 
@@ -373,6 +383,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
  *                      flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
  *                      glyph-flag should be produced by the shaper. By default
  *                      it will not be produced since it incurs a cost. Since: 4.0.0
+ * @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL:
+ *                      flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+ *                      glyph-flag should be produced by the shaper. By default
+ *                      it will not be produced. Since: 5.1.0
  * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
  *
  * Flags for #hb_buffer_t.
@@ -388,8 +402,9 @@ typedef enum { /*< flags >*/
   HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE	= 0x00000010u,
   HB_BUFFER_FLAG_VERIFY				= 0x00000020u,
   HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT	= 0x00000040u,
+  HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL	= 0x00000080u,
 
-  HB_BUFFER_FLAG_DEFINED			= 0x0000007Fu
+  HB_BUFFER_FLAG_DEFINED			= 0x000000FFu
 } hb_buffer_flags_t;
 
 HB_EXTERN void

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

@@ -288,7 +288,8 @@ struct hb_buffer_t
 
   HB_INTERNAL void guess_segment_properties ();
 
-  HB_INTERNAL void sync ();
+  HB_INTERNAL bool sync ();
+  HB_INTERNAL int sync_so_far ();
   HB_INTERNAL void clear_output ();
   HB_INTERNAL void clear_positions ();
 
@@ -461,6 +462,17 @@ struct hb_buffer_t
 		      start, end,
 		      true);
   }
+  void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
+  {
+    if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
+    {
+      unsafe_to_break (start, end);
+      return;
+    }
+    _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
+		      start, end,
+		      true);
+  }
   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
   {
     if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
@@ -555,15 +567,11 @@ struct hb_buffer_t
     if (likely (!messaging ()))
       return true;
 
-    message_depth++;
-
     va_list ap;
     va_start (ap, fmt);
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
 
-    message_depth--;
-
     return ret;
 #endif
   }

+ 22 - 1
thirdparty/harfbuzz/src/hb-cplusplus.hh

@@ -130,7 +130,7 @@ template <typename T,
 				       void *,
 				       hb_destroy_func_t,
 				       hb_bool_t),
-	  void * (*_get_user_data) (T *,
+	  void * (*_get_user_data) (const T *,
 				    hb_user_data_key_t *)>
 struct vtable_t
 {
@@ -164,6 +164,27 @@ HB_DEFINE_VTABLE (unicode_funcs);
 #undef HB_DEFINE_VTABLE
 
 
+#ifdef HB_SUBSET_H
+
+#define HB_DEFINE_VTABLE(name) \
+	template<> \
+	struct vtable<hb_##name##_t> \
+	     : vtable_t<hb_##name##_t, \
+			nullptr, \
+			&hb_##name##_reference, \
+			&hb_##name##_destroy, \
+			&hb_##name##_set_user_data, \
+			&hb_##name##_get_user_data> {}
+
+
+HB_DEFINE_VTABLE (subset_input);
+HB_DEFINE_VTABLE (subset_plan);
+
+#undef HB_DEFINE_VTABLE
+
+#endif
+
+
 } // namespace hb
 
 /* Workaround for GCC < 7, see:

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

@@ -460,4 +460,9 @@ struct hb_no_trace_t {
 #endif
 
 
+#ifndef HB_BUFFER_MESSAGE_MORE
+#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
+#endif
+
+
 #endif /* HB_DEBUG_HH */

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

@@ -342,7 +342,7 @@ hb_face_set_user_data (hb_face_t          *face,
  * Since: 0.9.2
  **/
 void *
-hb_face_get_user_data (hb_face_t          *face,
+hb_face_get_user_data (const hb_face_t    *face,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (face, key);

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

@@ -96,7 +96,7 @@ hb_face_set_user_data (hb_face_t          *face,
 		       hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_face_get_user_data (hb_face_t          *face,
+hb_face_get_user_data (const hb_face_t    *face,
 		       hb_user_data_key_t *key);
 
 HB_EXTERN void

+ 3 - 3
thirdparty/harfbuzz/src/hb-font.cc

@@ -781,8 +781,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
  * Since: 0.9.2
  **/
 void *
-hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
-			     hb_user_data_key_t *key)
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+			     hb_user_data_key_t    *key)
 {
   return hb_object_get_user_data (ffuncs, key);
 }
@@ -1897,7 +1897,7 @@ hb_font_set_user_data (hb_font_t          *font,
  * Since: 0.9.2
  **/
 void *
-hb_font_get_user_data (hb_font_t          *font,
+hb_font_get_user_data (const hb_font_t    *font,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (font, key);

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

@@ -86,8 +86,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
 
 
 HB_EXTERN void *
-hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
-			     hb_user_data_key_t *key);
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+			     hb_user_data_key_t    *key);
 
 
 HB_EXTERN void
@@ -993,7 +993,7 @@ hb_font_set_user_data (hb_font_t          *font,
 
 
 HB_EXTERN void *
-hb_font_get_user_data (hb_font_t          *font,
+hb_font_get_user_data (const hb_font_t    *font,
 		       hb_user_data_key_t *key);
 
 HB_EXTERN void

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

@@ -1086,7 +1086,8 @@ hb_ft_font_changed (hb_font_t *font)
   }
 #endif
 
-  _hb_ft_hb_font_check_changed (font, ft_font);
+  ft_font->advance_cache.clear ();
+  ft_font->cached_serial = font->serial;
 }
 
 /**

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

@@ -145,7 +145,7 @@ hb_map_set_user_data (hb_map_t           *map,
  * Since: 1.7.7
  **/
 void *
-hb_map_get_user_data (hb_map_t           *map,
+hb_map_get_user_data (const hb_map_t     *map,
 		      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (map, key);

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

@@ -74,7 +74,7 @@ hb_map_set_user_data (hb_map_t           *map,
 		      hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_map_get_user_data (hb_map_t           *map,
+hb_map_get_user_data (const hb_map_t     *map,
 		      hb_user_data_key_t *key);
 
 

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

@@ -31,7 +31,7 @@
 #include "hb.hh"
 
 
-#line 32 "hb-number-parser.hh"
+#line 35 "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 132 "hb-number-parser.hh"
+#line 139 "hb-number-parser.hh"
 	{
 	cs = double_parser_start;
 	}
 
-#line 135 "hb-number-parser.hh"
+#line 144 "hb-number-parser.hh"
 	{
 	int _slen;
 	int _trans;
@@ -198,7 +198,7 @@ _resume:
 	  exp_overflow = true;
 }
 	break;
-#line 187 "hb-number-parser.hh"
+#line 202 "hb-number-parser.hh"
 	}
 
 _again:

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

@@ -72,10 +72,6 @@ using OT::Layout::MediumTypes;
 #define HB_MAX_LANGSYS_FEATURE_COUNT 50000
 #endif
 
-#ifndef HB_MAX_FEATURES
-#define HB_MAX_FEATURES 750
-#endif
-
 #ifndef HB_MAX_FEATURE_INDICES
 #define HB_MAX_FEATURE_INDICES	1500
 #endif
@@ -1337,7 +1333,7 @@ struct Lookup
     return_trace (true);
   }
 
-  private:
+  protected:
   HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
   HBUINT16	lookupFlag;		/* Lookup qualifiers */
   Array16Of<Offset16>

+ 24 - 0
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh

@@ -1602,9 +1602,28 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
     if (unlikely (buffer->max_ops <= 0))
       break;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      if (buffer->have_output)
+        c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "recursing to lookup %u at %d",
+			  (unsigned) lookupRecord[i].lookupListIndex,
+			  buffer->idx);
+    }
+
     if (!c->recurse (lookupRecord[i].lookupListIndex))
       continue;
 
+    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+    {
+      if (buffer->have_output)
+        c->buffer->sync_so_far ();
+      c->buffer->message (c->font,
+			  "recursed to lookup %u",
+			  (unsigned) lookupRecord[i].lookupListIndex);
+    }
+
     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
     int delta = new_len - orig_len;
 
@@ -4010,6 +4029,11 @@ struct GSUBGPOSVersion1_2
 	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
   }
 
+  const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
+  {
+    return &lookupList;
+  }
+
   template <typename TLookup>
   bool sanitize (hb_sanitize_context_t *c) const
   {

+ 26 - 3
thirdparty/harfbuzz/src/hb-ot-shape.cc

@@ -1141,6 +1141,18 @@ hb_propagate_flags (hb_buffer_t *buffer)
   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
     return;
 
+  /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
+   *
+   * - If the places that the Arabic shaper marked as SAFE_TO_INSERT_TATWEEL,
+   *   are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
+   * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
+   *
+   * We couldn't make this interaction earlier. It has to be done here.
+   */
+  bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+
+  bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
+
   hb_glyph_info_t *info = buffer->info;
 
   foreach_cluster (buffer, start, end)
@@ -1148,9 +1160,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
     unsigned int mask = 0;
     for (unsigned int i = start; i < end; i++)
       mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
-    if (mask)
-      for (unsigned int i = start; i < end; i++)
-	info[i].mask |= mask;
+
+    if (flip_tatweel)
+    {
+      if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+	mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
+      if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
+	mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+    }
+
+    if (clear_concat)
+	mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+
+    for (unsigned int i = start; i < end; i++)
+      info[i].mask = mask;
   }
 }
 

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

@@ -331,7 +331,7 @@ arabic_joining (hb_buffer_t *buffer)
     if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
-      buffer->unsafe_to_break (prev, i + 1);
+      buffer->safe_to_insert_tatweel (prev, i + 1);
     }
     else
     {
@@ -365,7 +365,7 @@ arabic_joining (hb_buffer_t *buffer)
     if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
-      buffer->unsafe_to_break (prev, buffer->len);
+      buffer->safe_to_insert_tatweel (prev, buffer->len);
     }
     else if (2 <= state && state <= 5) /* States that have a possible prev_action. */
     {

+ 260 - 238
thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh

@@ -90,263 +90,264 @@
 #pragma GCC diagnostic pop
 
 static const uint8_t
-hb_use_u8[1842] =
+hb_use_u8[3083] =
 {
-      0,    1,    2,    3,    3,    3,    3,    3,    3,    3,    4,    3,    3,    3,    3,    5,
-      6,    7,    3,    8,    3,    3,    9,    3,   10,    3,    3,   11,    3,   12,   13,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-      3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-     14,    0,    0,    1,    1,    2,    1,    1,    3,    4,    5,    6,    7,    8,    9,   10,
-      1,   11,   12,    1,    1,    1,    1,    1,    1,   13,   14,   15,   16,   17,   18,   19,
-      1,    1,   20,    1,    1,    1,    1,   21,    1,    1,    1,    1,    1,    1,    1,   22,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   23,   24,   25,   26,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-     27,   28,    1,    1,    1,    1,    1,   29,    1,    1,    1,    1,   30,   31,    1,   32,
-     33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,    1,   46,   47,
-     48,    1,   49,   49,   49,   49,   50,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   51,   52,    1,    1,
-      1,   53,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   49,   54,    1,
-      1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,   55,    1,
-      1,    1,    1,   56,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-      1,    1,    1,   57,   58,    1,    1,    1,    1,    1,    1,   59,    1,    1,    1,    1,
-      1,    1,   60,   61,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,   60,
-     60,   60,    O,    O,    O,    O,    O,   GB,    O,    O,    B,    B,    B,    B,    B,    B,
-      O,    O,   GB,    O,    O,    O,    O,   WJ,    O,    O,    O,    O,FMPst,FMPst,    O,    O,
-      O,   GB,    O,    O,    O,  CGJ,    B,    O,    O,    O,    O,    O,    B,    B,    B,    B,
-      B,VMAbv,VMAbv,VMAbv,VMAbv,VMAbv,    O,    O,    B,    O,    O,VMAbv,    O,    O,    B,CMBlw,
-  CMBlw,CMBlw,VMAbv,VMAbv,VMAbv,VMPst,    B,    B, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw,
-   VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst,    H, VPre, VPst,    O,VMAbv,
-  VMBlw,    O,    O, VAbv, VBlw, VBlw,    B,    B, VBlw, VBlw,   GB,VMAbv,VMPst,VMPst,    O,    B,
-      B,    B,    B,    O,    O,    B,    B,    O,    B,    B,    B,    O,    B,    O, VBlw,    O,
-      O, VPre, VPre,    O,    O, VPre, VPre,    H,    O,    O,    O,    O,    O, VPst,    B,    B,
-      O,    B,    B,    O,FMAbv,    O,    O,VMAbv,VMAbv,VMPst,    B,    B,    B,    O,    O,    O,
-      O,    B,    O,    B,    B,    O,CMBlw,    O, VPst, VPre, VPst, VBlw, VBlw,    O,    O,    O,
-      O, VAbv, VAbv,    O,    O, VAbv, VAbv,    H,    O,    O,    O,VMBlw,    O,    O,VMAbv,CMAbv,
-     GB,   GB,    O, MBlw,    O,    O, VBlw, VAbv,    O, VAbv, VAbv, VAbv,    O, VPst, VPst,    H,
-      O,    O,    O,    B,VMAbv,VMAbv,VMAbv,CMAbv,CMAbv,CMAbv,    O,VMAbv,VMPst,VMPst,CMBlw,    B,
-   VPst, VAbv,    O, VAbv, VAbv, VAbv,    O,    B,    O,    O,    O,    O,VMAbv,    O,    O,    O,
-   VPst, VPst, VAbv, VPst, VPst,    O,    O,    O, VPre, VPre, VPre,    O, VPre, VPre,VMAbv,VMPst,
-  VMPst,VMPst,VMAbv,    B,    B,    B,CMBlw,    B, VAbv, VAbv, VPst,    O, VAbv, VAbv, VAbv,    O,
-   VAbv, VAbv,    O, VAbv, VBlw,    O,    B,VMAbv,VMPst,VMPst,    O, VPst, VPst,    O,    O,   CS,
-     CS,    O,VMAbv,VMAbv,VMPst,VMPst,    B,    B,    B, VAbv, VAbv,    B, VPst, VPst, VPst, VPst,
-   VPst, VBlw, VBlw,    O, VPre, VPre, VPre,    H,    R,    O,    O,    O,  HVM,    O, VPst, VPst,
-   VAbv, VAbv, VBlw,    O, VBlw,    O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, VBlw, VBlw,
-      O,    O,    O, FBlw,    O, FBlw,    O,CMAbv,    O,    O,    O,    O, VPst, VPre,    O,CMBlw,
-   VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,VMAbv,    O, VBlw, VAbv,
-  VMAbv,VMAbv, VBlw,    O,VMAbv,VMAbv,    B,  SUB,  SUB,  SUB,  SUB,  SUB,  SUB,  SUB,    O,  SUB,
-    SUB,  SUB,  SUB,    O,    O,    O,    O,    O, FBlw,    O,    B,    B,    B, VPst, VPst, VAbv,
-   VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv, VAbv,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw,
-   MBlw,    B,    B,    B,    O,   GB,    O,    O,   GB,    O,    B,    B, VPst, VPst, VBlw, VBlw,
-      B,    B,    B,    B, MBlw, MBlw, MBlw,    B, VPst,VMPst,VMPst,    B,    B, VPst, VPst,VMPst,
-  VMPst,VMPst,VMPst,VMPst,    B,    B,    B, VAbv, VAbv, VAbv, VAbv,    B,    B,    B,    B,    B,
-   MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMPst,VMPst,VMPst,VMPst,VMBlw,    B,VMPst,    B,    B,
-  VMPst,VMPst, VPst, VAbv,    O,    O,    B,    B, VAbv, VBlw, VBlw, VPst,    O,    O, VPst,    O,
-      O,    O,    B,    O, VAbv, VBlw,  CGJ,  CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw,
-   VPre, VPre, VPre, VPre, VPre, VPre, VPre, VPre,VMAbv,VMPst, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,
-  FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    O,    O,    O,    O,    B,  CGJ,  CGJ,  CGJ,
-     WJ,  CGJ,   GB,   GB,   GB,   GB,   GB,CMAbv,CMAbv,    B,    B,CMBlw,    B,    O,   GB,    B,
-      B,    B, VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv,  SUB,  SUB,  SUB, FPst, FPst,
-  VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw,VMAbv,FMBlw,VMPst,VMPst,    O,    O, VAbv, VPre,
-   VPst, VAbv,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,  SUB,  SUB,  SUB,    O,   Sk, VPst,
-   VAbv, VPst, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, VPre, VPre, VPre, VAbv,VMAbv,VMAbv,
-   VAbv,VMAbv,VMAbv,    O,    O,VMBlw,VMAbv,VMAbv,VMAbv, FAbv,VMPst,    B,    B,    B,CMAbv, VPst,
-   VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, VPre, VPre, VAbv, VAbv,    H,    B,
-      B,    B,    O,    O,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,VMAbv, FAbv,
-  VMPst,    B, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst,   IS,  SUB,  SUB,    B,    B,    B,    B,
-  CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv, FAbv, FAbv,CMBlw,CMBlw,  SUB,  SUB,
-   VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv,VMPre,VMPre,
-  FMAbv,CMBlw,VMAbv,VMAbv,VMAbv,    O,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMAbv,VMAbv,VMAbv,VMPst,
-  VMBlw,VMBlw,VMBlw,    O,    O,    O,VMAbv,   CS,   CS,VMPst,VMAbv,VMAbv,   GB,    O,    O,    O,
-      O,FMAbv,    O,    O,    O,   WJ, ZWNJ,  CGJ,   WJ,   WJ,    O,    O,   WJ,   WJ,   WJ,   WJ,
-     WJ,    O,   WJ,   WJ,   WJ,   WJ,FMPst,    O,    O,    O,VMAbv,    O,    O,    O,    O,    O,
-      O,    H,    B,    B, VAbv,    B,    B,    B,    H,    B, VPst, VBlw, VAbv, VPst, VBlw,    O,
-      O,    O, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst,    H,VMAbv,    O,    O,VMAbv,VMAbv,
-      B,    B,    O,    O,    B, VAbv,    B,    B, VAbv, VAbv, VAbv, VAbv, VAbv,VMBlw,VMBlw,VMBlw,
-      O,    O,    B,    B,    B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv, FAbv, FAbv,
-   FPst, VPst,VMAbv,VMAbv, FAbv,VMPst,    B,    B,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O,
-      O,    O,    B, VAbv,    O,    B,    B,VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre, VPre, VAbv,
-   VBlw, MPst, MPre, MAbv, MBlw,    O,    B,    B,    B, FAbv, FAbv, FPst,    O,    O,   GB,   GB,
-     GB,    O,    O,    O,    B,VMPst,VMAbv,VMPst,    B,    B, VAbv,    B, VAbv, VAbv, VBlw,    B,
-      B, VAbv,    B,    B, VAbv,VMAbv,    B,VMAbv,    B,    O,    B,    B,    B, VPre, VBlw, VAbv,
-   VPre, VPst,    O,VMPst,   IS,    O, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst,    O,VMPst, VBlw,
-      O,    O,  CGJ,  CGJ,  CGJ,  CGJ,   WJ,    O,    O,    O,    B, VBlw, VBlw, VBlw, VPst,VMBlw,
-  VMBlw,VMAbv,CMBlw,CMBlw,CMBlw,    O,    O,    O,    O,   IS,    B,CMBlw,CMBlw,    O,VMAbv,VMAbv,
-  VMAbv,CMAbv,    B,    B,    O, VAbv, VAbv,    O,    O,    O,    B,    B,VMBlw,VMBlw,VMBlw,    B,
-      B,    B,    B,    B,CMBlw,CMBlw,CMBlw,CMBlw,    O,    O,VMPst,VMAbv,VMPst,   CS,   CS,    B,
-      B,    B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,    H,    O,    O,    O,
-      N,    N,    N,    N,    N,    N,    N,    N,    B,    B, VAbv,    B,    B, VAbv, VAbv,    B,
-      O,    O,    O,    O,    O,   HN,VMAbv,VMAbv,VMPst,    B, VPst, VPre, VPst, VBlw, VBlw, VAbv,
-   VAbv, VPst, VPst,    H,CMBlw,    O,    O,    O, VBlw,    O,VMAbv,VMAbv,VMAbv,    B, VPre, VBlw,
-   VAbv, VAbv, VBlw, VAbv, VAbv,   IS,CMAbv,    O,    B,    B,    B, VPst, VPst,    B,    B,    B,
-      B,CMBlw, VPre, VPst, VBlw, VBlw,    H,    B,    R,    R,    O,FMBlw,CMBlw, VAbv, VBlw,    O,
-   VPre,VMAbv,VMAbv,    H,CMAbv,CMAbv, VAbv,CMBlw, VBlw,    O,    B,    B,    O,CMBlw,CMBlw,    B,
-   VPst, VPst, VPst,    O,    O, VPre,    O,    O,VMAbv,VMAbv,    B, VPst, VPre, VPst, VPst, VPst,
-      H,VMAbv,VMAbv,VMPst,CMBlw,    B,    O,    O,FMAbv,    B,   CS,   CS,    O,    O, VBlw, VPre,
-   VAbv, VPre, VPre, VPst, VPre,VMAbv,VMAbv,VMAbv,    H,CMBlw,VMAbv,VMAbv,VMPst,    H,CMBlw,    O,
-      O,    O, VPst,VMAbv,VMPst,    H,VMPst, VAbv, VPre, VPst, VAbv, VAbv,    H,CMBlw,    O, MBlw,
-   MPre, MAbv, VBlw, VBlw, VPre, VAbv, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,VMAbv,VMPst,    H,
-  CMBlw,    O, VPst, VPre,    O, VPre, VPre,    O,    O,VMAbv,VMAbv, VPst,   IS,    R, MPst,    R,
-   MPst,CMBlw,    O,    O, VAbv, VAbv, VPst, VPst,VMPst,VMPst,    H,    B,    O,    O, VPre,    O,
-      O,    O,    B, VAbv, VBlw, VBlw, VAbv, VAbv, VBlw,    B,    B,    B,    B,FMBlw, VBlw,VMAbv,
-  VMAbv,VMAbv,VMAbv,VMPst,    R, MBlw, MBlw, MBlw, MBlw,   GB,    O,   GB,    O,   IS, VAbv, VAbv,
-   VAbv, VPst,    R,    R,    R,    R,    R,    R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
-  VMAbv,VMPst,CMAbv,   IS,    O,    O, VBlw, VBlw, VBlw,    O,    O,    O,  SUB,  SUB, VBlw, VPre,
-   VBlw, VAbv, VPst,VMAbv,VMAbv,    O, VAbv, VAbv, VBlw,    O,    O,    O, VAbv,    O, VAbv, VAbv,
-      O, VAbv,VMAbv,VMAbv,CMBlw, VAbv, VBlw,   IS,    R, MBlw, VPst, VPst, VPst,    O, VPst,VMAbv,
-  VMPst,   IS,    B,    B,   GB, VAbv, VBlw, VPre, VPst,    O,    H,    H,    H,    H,    H,    H,
-      H,    B,    O,    O,    O,CMBlw,    O, VBlw, VBlw, VBlw,    O,    O,    O,VMBlw,VMBlw,VMBlw,
-  VMBlw,    O,    O,CMBlw,CMBlw,    O,    B,    B,VMAbv,    O,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,
-  CMAbv,    B,
+     16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
+     14,    0,    1,    2,    2,    2,    2,    3,    2,    2,    2,    2,    2,    4,    2,    2,
+      5,    6,    2,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,    2,    2,   17,
+     18,   19,   20,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   21,
+     22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,    2,   33,    2,    2,    2,
+      2,   34,   35,    2,    2,    2,    2,    2,    2,    2,    2,    2,   36,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   37,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,   38,   39,   40,   41,   42,   43,    2,   44,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   45,   46,    2,
+     47,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,   48,   49,    2,    2,    2,
+      2,    2,    2,    2,    2,   50,   51,    2,   52,    2,    2,   53,    2,    2,   54,   55,
+     56,   57,   58,   59,   60,   61,   62,   63,    2,   64,   65,    2,   66,   67,   68,   69,
+      2,   70,    2,   71,   72,   73,   74,    2,    2,   75,   76,   77,   78,    2,   79,    2,
+      2,   80,   80,   80,   80,   80,   80,   80,   80,   81,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   82,   83,    2,    2,    2,    2,    2,    2,    2,   84,
+     85,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   80,   80,   80,   86,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,   87,   88,    2,    2,    2,    2,    2,
+      2,    2,    2,   89,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,   90,    2,    2,   91,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,   92,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,   93,   93,   94,   95,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+     93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,   93,
+     93,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      0,    2,    2,    2,    2,    2,    0,    0,    0,    3,    0,    0,    0,    0,    0,    4,
+      0,    0,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    0,    0,    6,    7,    0,    0,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    8,    9,    9,    9,    9,    0,    0,    0,    7,   10,
+      0,    2,    2,    2,    2,   11,   12,    0,    0,    9,   13,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,   14,   15,   16,   17,   18,   19,   20,   14,   21,   22,
+     23,   10,   24,   25,   18,    2,    2,    2,    2,    2,   18,    0,    2,    2,    2,    2,
+      2,    0,    2,    2,    2,    2,    2,    2,    2,   26,   27,   28,    2,    2,    2,    7,
+     28,    7,   28,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    7,    2,    2,
+      2,    7,    7,    0,    2,    2,    0,   15,   16,   17,   18,   29,   30,   31,   30,   32,
+      0,    0,    0,    0,   33,    0,    0,    2,   28,    2,    0,    0,    0,    0,    0,    7,
+     34,   10,   13,   28,    2,    2,    7,    0,   28,    7,    2,   28,    7,    2,    0,   35,
+     16,   17,   29,    0,   25,   36,   25,   37,    0,   38,    0,    0,    0,   28,    2,    7,
+      7,    0,    0,    0,    2,    2,    2,    2,    2,   39,   40,   41,    0,    0,    0,    0,
+      0,   10,   13,   28,    2,    2,    2,    2,   28,    2,   28,    2,    2,    2,    2,    2,
+      2,    7,    2,   28,    2,    2,    0,   15,   16,   17,   18,   19,   25,   20,   33,   22,
+      0,    0,    0,    0,    0,   28,    9,   39,   42,   10,   27,   28,    2,    2,    2,    7,
+     28,    7,    2,   28,    2,    2,    0,   15,   43,    0,    0,   25,   20,    0,    0,    2,
+     28,   28,    0,    0,    0,    0,    0,    0,    0,    0,   44,   28,    2,    2,    7,    0,
+      2,    7,    2,    2,    0,   28,    7,    7,    2,    0,   28,    7,    0,    2,    7,    0,
+      2,    2,    2,    2,    2,    2,    0,    0,   21,   14,   45,    0,   46,   31,   46,   32,
+      0,    0,    0,    0,   33,    0,    0,    0,    0,   13,   27,   47,    2,    2,    2,    7,
+      2,    7,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    0,   15,
+     20,   14,   21,   45,   20,   36,   20,   37,    0,    0,    0,   25,   29,    2,    7,    0,
+      0,    8,   27,   28,    2,    2,    2,    7,    2,    2,    2,   28,    2,    2,    0,   15,
+     43,    0,    0,   33,   45,    0,    0,    0,    7,   48,   49,    0,    0,    0,    0,    0,
+      0,    9,   27,    2,    2,    2,    2,    7,    2,    2,    2,    2,    2,    2,   50,   51,
+     21,   21,   17,   29,   46,   31,   46,   32,   52,    0,    0,    0,   33,    0,    0,    0,
+     28,   10,   27,   28,    2,    2,    2,    2,    2,    2,    2,    2,    7,    0,    2,    2,
+      2,    2,   28,    2,    2,    2,    2,   28,    0,    2,    2,    2,    7,    0,   53,    0,
+     33,   21,   20,   29,   29,   16,   46,   46,   23,    0,   21,    0,    0,    0,    0,    0,
+      0,    2,    0,    2,    7,    0,    0,    0,    0,    0,    0,    0,    0,   18,    0,    0,
+      0,    2,    2,   54,   54,   55,    0,    0,   16,    2,    2,    2,    2,   28,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    7,    0,   56,   19,   57,   20,   20,   18,   18,
+     44,   19,    9,   29,    9,    2,    2,   58,   59,   59,   59,   59,   59,   60,   59,   59,
+     59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   59,   61,
+      0,    0,    0,    0,   62,    0,    0,    0,    0,    2,    2,    2,    2,    2,   63,   43,
+     57,   64,   20,   20,   65,   66,   67,   68,   69,    2,    2,    2,    2,    2,    1,    0,
+      3,    2,    2,    2,   21,   18,    2,    2,   70,   69,   71,   72,   63,   71,   27,   27,
+      2,   50,   20,   51,    2,    2,    2,    2,    2,    2,   73,   74,   75,   27,   27,   76,
+     77,    2,    2,    2,    2,    2,   27,   43,    0,    2,   57,   78,    0,    0,    0,    0,
+     28,    2,   57,   45,    0,    0,    0,    0,    0,    2,   57,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    7,    2,    7,   57,    0,    0,    0,    0,    0,
+      0,    2,    2,   79,   43,   20,   57,   18,   46,   46,   46,   46,   13,   80,   81,   82,
+     83,   84,   85,    0,    0,    0,    0,   86,    0,    7,    0,    0,   28,    0,   87,   79,
+     88,    2,    2,    2,    2,    7,    0,    0,    0,   40,   40,   89,   90,    2,    2,    2,
+      2,    2,    2,    2,    2,   11,    7,    0,    0,   91,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,    2,    7,   20,   78,   43,   20,   92,   59,    0,
+      0,   93,   94,   93,   93,   95,   96,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+      0,    2,    2,    7,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    0,
+      0,    2,    2,    2,    2,   27,    0,    0,    0,    2,    2,    2,    2,    2,    7,    0,
+      0,    2,    2,    2,   50,   97,   43,    0,    0,    2,    2,   98,   99,  100,  101,   59,
+     61,  102,   14,   43,   20,   57,   19,   78,   46,   46,   74,    9,    9,    9,  103,   44,
+     38,    9,  104,   72,    2,    2,    2,    2,    2,    2,    2,  105,   20,   18,   18,   20,
+     46,   46,   20,  106,    2,    2,    2,    7,    0,    0,    0,    0,    0,    0,  107,  108,
+    109,  109,  109,    0,    0,    0,    0,    0,    0,  104,   72,    2,    2,    2,    2,    2,
+      2,   58,   59,   57,   23,   20,  110,   59,    2,    2,    2,    2,  105,   20,   21,   43,
+     43,  100,   12,    0,    0,    0,    0,    0,    0,    2,    2,   59,   16,   46,   21,  111,
+    100,  100,  100,  112,  113,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   28,
+      2,    9,   44,  114,  114,  114,    9,  114,  114,   13,  114,  114,  114,   24,    0,   38,
+      0,    0,    0,  115,  116,    9,    3,    0,    0,    0,    0,    0,    0,    0,  117,    0,
+      0,    0,    0,    0,    0,    0,    4,  118,  119,   40,   40,    3,    0,    0,    0,    0,
+      0,    0,    0,    0,    0,    0,  119,  119,  120,  119,  119,  119,  119,  119,  119,  119,
+    119,    0,    0,  121,    0,    0,    0,    0,    0,    0,    5,  121,    0,    0,    0,    0,
+      0,   44,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    7,
+      0,    2,    2,    2,    2,    0,    0,    0,   28,    0,    0,    0,    0,    0,    0,    0,
+    122,    2,   51,    2,  106,    2,    8,    2,    2,    2,   63,   17,   14,    0,    0,   29,
+      0,    2,    2,    0,    0,    0,    0,    0,    0,   27,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,  123,   21,   21,   21,   21,   21,   21,   21,  124,    0,    0,    0,    0,
+      0,    9,    9,    9,    9,    9,    9,    9,    9,    9,    2,    0,    0,    0,    0,    0,
+     50,    2,    2,    2,   20,   20,  125,  114,    0,    2,    2,    2,  126,   18,   57,   18,
+    111,  100,  127,    0,    0,    0,    0,    0,    0,    9,  128,    2,    2,    2,    2,    2,
+      2,    2,  129,   21,   20,   18,   46,  130,  131,  132,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,   50,   28,    2,    2,    2,    2,    2,    2,    2,    2,    8,   20,   57,
+     97,   74,  133,  134,  135,    0,    0,    0,    0,    2,  136,    2,    2,    2,    2,  137,
+      0,   28,    2,   40,    3,    0,   77,   13,    2,   51,   20,  138,   50,   51,    2,    2,
+    103,    8,    7,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,  139,   19,
+     23,    0,    0,  140,  141,    0,    0,    0,    0,    2,   63,   43,   21,   78,   45,  142,
+      0,   79,   79,   79,   79,   79,   79,   79,   79,    0,    0,    0,    0,    0,    0,    0,
+      4,  119,  119,  119,  119,  120,    0,    0,    0,    2,    2,    2,    2,    2,    7,    2,
+      2,    2,    7,    2,   28,    2,    2,    2,    2,    2,   28,    2,    2,    2,   28,    7,
+      0,  126,   18,   25,   29,    0,    0,  143,  144,    2,    2,   28,    2,   28,    2,    2,
+      2,    2,    2,    2,    0,   12,   35,    0,  145,    2,    2,   11,   35,    0,   28,    2,
+      2,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   28,    2,    2,
+      7,    2,    2,    9,   39,    0,    0,    0,    0,    2,    2,    2,    2,    2,   25,   36,
+      0,    2,    2,    2,  114,  114,  114,  114,  114,  146,    2,    7,    0,    0,    0,    0,
+      0,    2,   12,   12,    0,    0,    0,    0,    0,    7,    2,    2,    7,    2,    2,    2,
+      2,   28,    2,    7,    0,   28,    2,    0,    0,  147,  148,  149,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,   20,   20,   18,   18,   18,   20,   20,  132,    0,    0,    0,
+      0,    0,  150,  150,  150,  150,  150,  150,  150,  150,  150,  150,    2,    2,    2,    2,
+      2,   51,   50,   51,    0,    0,    0,    0,  151,    9,   72,    2,    2,    2,    2,    2,
+      2,   16,   17,   19,   14,   22,   35,    0,    0,    0,   29,    0,    0,    0,    0,    0,
+      0,    9,   47,    2,    2,    2,    2,    2,    2,    2,    2,    2,  126,   18,   20,  152,
+     20,   19,  153,  154,    2,    2,    2,    2,    2,    0,    0,   63,  155,    0,    0,    0,
+      0,    2,   11,    0,    0,    0,    0,    0,    0,    2,   63,   23,   18,   18,   18,   20,
+     20,  106,  156,    0,    0,  157,  158,   29,  159,   28,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   21,   17,   20,   20,  160,   42,    0,    0,    0,
+     44,    2,    2,    2,    7,    7,    2,    2,   28,    2,    2,    2,    2,    2,    2,    2,
+     28,    2,    2,    2,    2,    2,    2,    2,    8,   16,   17,   19,   20,  161,   29,    0,
+      0,    9,    9,   28,    2,    2,    2,    7,   28,    7,    2,   28,    2,    2,   56,   15,
+     21,   14,   21,   45,   30,   31,   30,   32,    0,    0,    0,    0,   33,    0,    0,    0,
+      2,    2,   21,    0,    9,    9,    9,   44,    0,    9,    9,   44,    0,    0,    0,    0,
+      0,    2,    2,   63,   23,   18,   18,   18,   20,   21,  124,   13,   15,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    0,    0,  162,  163,    0,    0,    0,    0,    0,    0,
+      0,   16,   17,   18,   18,   64,   97,   23,  159,    9,  164,    7,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    2,    2,   63,   23,   18,   18,    0,   46,   46,    9,
+    165,   35,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2,    2,   18,
+      0,   21,   17,   18,   18,   19,   14,   80,  165,   36,    0,    0,    0,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    8,  166,   23,   18,   20,   20,  164,    7,    0,    0,
+      0,    2,    2,    2,    2,    2,    7,   41,  134,   21,   20,   18,   74,   19,   20,    0,
+      0,    2,    2,    2,    7,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,   16,
+     17,   18,   19,   20,  103,  165,   35,    0,    0,    2,    2,    2,    7,   28,    0,    2,
+      2,    2,    2,   28,    7,    2,    2,    2,    2,   21,   21,   16,   30,   31,   10,  167,
+    168,  169,  170,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    0,    2,    2,
+      2,   63,   23,   18,   18,    0,   20,   21,   27,  106,    0,   31,    0,    0,    0,    0,
+      0,   50,   18,   20,   20,   20,  138,    2,    2,    2,  171,  172,    9,   13,  173,   70,
+    174,    0,    0,    1,  145,    0,    0,    0,    0,   50,   18,   20,   14,   17,   18,    2,
+      2,    2,    2,  156,  156,  156,  175,  175,  175,  175,  175,  175,   13,  176,    0,   28,
+      0,   20,   18,   18,   29,   20,   20,    9,  165,    0,   59,   59,   59,   59,   59,   59,
+     59,   64,   19,   80,   44,    0,    0,    0,    0,    2,    2,    2,    7,    2,   28,    2,
+      2,   50,   20,   20,   29,    0,   36,   20,   25,    9,  158,  177,  173,    0,    0,    0,
+      0,    2,    2,    2,   28,    7,    2,    2,    2,    2,    2,    2,    2,    2,   21,   21,
+     45,   20,   33,   80,   66,    0,    0,    0,    0,    2,  178,   64,   45,    0,    0,    0,
+      0,  179,  179,  179,  106,    7,    0,    0,    0,    9,    9,    9,   44,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    7,    0,   56,  180,   18,   18,   18,   18,   18,   18,
+     18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,    0,    0,    0,
+     38,  114,   24,    0,    0,    0,    0,    0,    0,    0,    0,    7,    0,    0,    0,    0,
+      0,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   56,
+     35,    0,    4,  119,  119,  119,  120,    0,    0,    9,    9,    9,   47,    2,    2,    2,
+      0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
+     44,    2,    2,    2,    2,    2,    2,    9,    9,    2,    2,   42,   42,   42,   90,    0,
+      0,    O,    O,    O,   GB,    B,    B,   GB,    O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,
+      O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
+      B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre,
+   VPst,VMBlw,    O,    O, VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,    O,    O, VPre, VPre,
+      O, VPre,    H,    O, VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,    H,    O,VMBlw,VMAbv,
+  CMAbv,   GB,   GB,    O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,    O, VPre, VPre,VMAbv,
+      B,    O,   CS,   CS,    O,    B, VAbv, VAbv,    B,    R,    O,  HVM,    O,    O, FBlw,    O,
+  CMAbv,    O,CMBlw, VAbv, VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,    O, FBlw,    O,    B,
+   VPst, VBlw, VPre,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,
+  VMPst,VMPst,    B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,
+    CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,
+    CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst,
+   FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,
+  VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw,
+   FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,   CS,VMPst,    O,FMAbv, ZWNJ,  CGJ,   WJ,
+     WJ,   WJ,    O,FMPst,    O,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst,
+   VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,
+      O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,
+  VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,
+     HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,    O,FMBlw,CMBlw, VAbv, VPre,
+  VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv,
+   VPst,   IS,    R, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,   GB, FBlw,
+   FBlw,CMAbv,   IS, VBlw,   IS,   GB, VAbv,    H,    H,    O, VBlw,
 };
 static const uint16_t
-hb_use_u16[2056] =
+hb_use_u16[768] =
 {
     0,  0,  1,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  5,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  9, 10, 11,
-    0,  0,  0,  0,  9, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   13,  9,  9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 17, 25,
-   26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35,  0, 17, 36,
-   37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46, 30,  0,
-   47, 48, 21, 49, 50, 51, 17,  0, 52, 48, 21, 53, 50, 54, 17, 55,
-   56, 48,  9, 57, 58, 59, 17,  0, 60, 61,  9, 62, 63, 64, 30, 65,
-   66, 67,  9, 68, 69,  9, 70, 71, 72, 73, 74, 75, 76,  0,  0,  0,
-    9,  9, 77, 78, 79, 80, 81, 82, 83, 84,  0,  0,  0,  0,  0,  0,
-    9, 85,  9, 86,  9, 87, 88, 89,  9,  9,  9, 90, 91, 92,  2,  0,
-   93,  0,  9,  9,  9,  9,  9, 94, 95,  9, 96,  0,  0,  0,  0,  0,
-   97, 98, 99,100, 30,  9,101,102,  9,  9,103,  9,104,105,  0,  0,
-    9,106,  9,  9,  9,107,108,109,  2,  2,  0,  0,  0,  0,  0,  0,
-  110,  9,  9,111,112,  2,113,114,115,  9,116,  9,  9,  9,117,118,
-    9,  9,119,120,121,  0,  0,  0,  0,  0,  0,  0,  0,122,123,124,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,125,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,
+    0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  8,  9, 10, 11,
+    0,  0,  0,  0,  9, 12,  0,  0, 13,  9,  9, 14, 15, 16, 17, 18,
+   19, 20, 21, 22, 23, 24, 17, 25, 26, 20, 21, 27, 28, 29, 30, 31,
+   32, 33, 21, 34, 35,  0, 17, 36, 37, 20, 21, 38, 23, 39, 17, 40,
+   41, 42, 43, 44, 45, 46, 30,  0, 47, 48, 21, 49, 50, 51, 17,  0,
+   52, 48, 21, 53, 50, 54, 17, 55, 56, 48,  9, 57, 58, 59, 17,  0,
+   60, 61,  9, 62, 63, 64, 30, 65, 66, 67,  9, 68, 69,  9, 70, 71,
+   72, 73, 74, 75, 76,  0,  0,  0,  9,  9, 77, 78, 79, 80, 81, 82,
+   83, 84,  0,  0,  0,  0,  0,  0,  9, 85,  9, 86,  9, 87, 88, 89,
+    9,  9,  9, 90, 91, 92,  2,  0, 93,  0,  9,  9,  9,  9,  9, 94,
+   95,  9, 96,  0,  0,  0,  0,  0, 97, 98, 99,100, 30,  9,101,102,
+    9,  9,103,  9,104,105,  0,  0,  9,106,  9,  9,  9,107,108,109,
+    2,  2,  0,  0,  0,  0,  0,  0,110,  9,  9,111,112,  2,113,114,
+  115,  9,116,  9,  9,  9,117,118,  9,  9,119,120,121,  0,  0,  0,
+    0,  0,  0,  0,  0,122,123,124,  0,  0,  0,  0,  0,  0,  0,125,
   126,127,128,  0,  0,  0,129,130,131,  0,  0,  0,  0,  0,  0,132,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,133,  0,  0,  0,
-    0,  0,  0,  9,  9,  9,134,135,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,133,  0,  0,  0,  0,  0,  0,  9,  9,  9,134,135,
   136,  9,137,  0,  9,  9,  9,138,139,  9,  9,140,141,  2,142,143,
     9,  9,144,  9,145,146,  0,  0,147,  9,  9,148,149,  2,150, 98,
     9,  9,151,152,153,  2,  9,154,  9,  9,  9,155,156,  0,157,158,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,159,  2,
-  160,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,161,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,
+    0,  0,  0,  0,  9,  9,159,  2,160,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,161,  0,  0,  0,  0,  0,  0,  0,162,
     0,  0,  0,  0,  0,  0,  0,163,163,164, 33,165,  0,  0,  0,  0,
   166,167,  9,168, 94,  0,  0,  0,  0,  0,  0,  0, 69,  9,169,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  9,170,171,  0,  0,  0,  0,  0,
-    9,  9,172,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  9,  9,173,170,  0,  0,  0,  0,
-    0,  0,  0,  9,174,175,  0,  9,176,  0,  0,177,178,  0,  0,  0,
-  179,  9,  9,180,181,182,183,184,185,  9,  9,186,187,  0,  0,  0,
-  188,  9,189,190,191,  9,  9,192,185,  9,  9,193,194,105,195,102,
-    9, 33,196,197,  0,  0,  0,  0,198,199, 94,  9,  9,200,201,  2,
-  202, 20, 21,203,204,205,206,207,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,170,171,  0,  0,  0,  0,  0,  9,  9,172,  2,  0,  0,  0,  0,
+    9,  9,173,170,  0,  0,  0,  0,  0,  0,  0,  9,174,175,  0,  9,
+  176,  0,  0,177,178,  0,  0,  0,179,  9,  9,180,181,182,183,184,
+  185,  9,  9,186,187,  0,  0,  0,188,  9,189,190,191,  9,  9,192,
+  185,  9,  9,193,194,105,195,102,  9, 33,196,197,  0,  0,  0,  0,
+  198,199, 94,  9,  9,200,201,  2,202, 20, 21,203,204,205,206,207,
     9,  9,  9,208,209,210,211,  0,195,  9,  9,212,213,  2,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  9,  9,214,215,216,217,  0,  0,
-    9,  9,  9,218,219,  2,  0,  0,  9,  9,220,221,  2,  0,  0,  0,
-    9,222,223,103,224,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    9,  9,225,226,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  227,228,  9,229,230,  2,  0,  0,  0,  0,231,  9,  9,232,233,  0,
-  234,  9,  9,235,236,237,  9,  9,238,239,  0,  0,  0,  0,  0,  0,
-   21,  9,214,240,  7,  9, 70, 18,  9,241, 73,242,  0,  0,  0,  0,
-  243,  9,  9,244,245,  2,246,  9,247,248,  2,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,249,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9, 98,250,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-    9,  9,  9,251,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  9,214,215,216,217,  0,  0,  9,  9,  9,218,219,  2,  0,  0,
+    9,  9,220,221,  2,  0,  0,  0,  9,222,223,103,224,  0,  0,  0,
+    9,  9,225,226,  0,  0,  0,  0,227,228,  9,229,230,  2,  0,  0,
+    0,  0,231,  9,  9,232,233,  0,234,  9,  9,235,236,237,  9,  9,
+  238,239,  0,  0,  0,  0,  0,  0, 21,  9,214,240,  7,  9, 70, 18,
+    9,241, 73,242,  0,  0,  0,  0,243,  9,  9,244,245,  2,246,  9,
+  247,248,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,249,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 98,250,  0,  0,  0,  0,
+    0,  0,  0,  0,  2,  0,  0,  0,  9,  9,  9,251,  0,  0,  0,  0,
     9,  9,  9,  9,252,253,254,254,255,256,  0,  0,  0,  0,257,  0,
-    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,258,  0,  0,
-    9,  9,  9,  9,  9,  9,105, 70, 94,259,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,260,  0,  0,  0,  0,  0,  0,  0,  0,
-    9,  9, 70,261,262,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  9,263,  0,  9,  9,264,  2,
-    9,  9,  9,  9,265,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
+    9,  9,  9,  9,  9,258,  0,  0,  9,  9,  9,  9,  9,  9,105, 70,
+   94,259,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,260,
+    9,  9, 70,261,262,  0,  0,  0,  0,  9,263,  0,  9,  9,264,  2,
+    9,  9,  9,  9,265,  2,  0,  0,129,129,129,129,129,129,129,129,
   160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
-    0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  3,  0,  4,  0,  0,  5,
-    6,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,
-    0,  0, 10,  2,  2,  2,  2,  2,  2,  2, 11, 12, 12,  0, 13, 14,
-    2,  2, 15,  0, 16,  2,  2,  2,  2,  2, 17, 18, 19, 20, 21, 22,
-   23, 24,  2,  2, 25, 10,  2,  2, 10,  2,  2,  2, 26, 27,  2, 28,
-   28,  2,  2,  2,  2,  2, 29,  2, 30, 10,  3, 18, 19, 31, 32, 33,
-    0, 34,  0, 35,  3,  0,  0, 36, 37, 27, 38, 39, 29, 40,  3, 41,
-   42, 43, 44, 45, 46,  0, 27, 30,  0, 10,  2,  2, 47, 48,  0,  0,
-   37, 27,  2, 35, 35,  2,  2,  2, 29, 27,  3, 18, 19, 49, 50, 51,
-    0,  0, 52, 53, 54, 27,  2, 28, 29, 27,  3, 55,  0, 56,  0, 35,
-   57,  0,  0,  0, 58, 27, 38, 10, 29,  3, 40, 29, 39,  9, 38, 10,
-    2,  2,  3, 59, 60, 61, 62, 33,  0, 34,  0,  0, 63, 64,  2, 29,
-   29,  2,  2,  2,  2,  2,  3, 65, 21, 66, 67, 45,  0, 68, 38,  0,
-   69, 27,  2, 29,  2, 27,  3, 55,  0, 70,  0, 13, 71,  0,  0,  0,
-   72,  2,  2, 29,  2,  2, 73, 74, 75, 76, 62, 77,  0, 34,  0, 39,
-   54, 27,  2,  2,  2, 38, 10,  2, 35,  2,  2, 57,  2, 38, 78, 34,
-   79, 80, 81, 82, 59,  0,  0,  0,  3, 38,  0,  0,  0,  0, 83,  0,
-    2, 84, 85, 86,  2,  2, 27,  2,  2,  2,  2,  9, 87, 88, 89, 90,
-   91, 92,  2, 93, 94, 94, 95, 94, 94, 94, 94, 94, 94, 94, 94, 96,
-    0, 97,  0,  0,  2,  2, 98, 99,100,101,102,103,  2,  2,104,105,
-    2,106,107,108,109,110,111,112,113,114,  2,  2,115,116,117,118,
-    2,  2,119,120,121,122,  0, 39,121,123,  0,  0,121,  0,  0,  0,
-    2,  2,  2, 29,124,  0,  0,  0,  2,125,126,127,128,129,130,131,
-  132,  0,  0,133,  9, 39,134,135,  2,  2,  9,  0,136,137,  2,  2,
-    2,  2,138,  0,139,  2,  2,  2,  2,  2,  2, 38,140,141,142,  0,
-  143,144,145,  0,  2,  2,  2,  3,  2,  9,  0,  0,  2,  2,  2,  0,
-    2,  2,146,  0,  2,  2, 38,  0,  2, 73,147,  0,  2,148,149,150,
-  151,141,152,153,154, 12,155,156,157,158,  2,  2,  2,159,160,161,
-  162,163,  2,  9,  0,  0,164,165,166,  0,  0,  0,167,  2,  2,  2,
-   93,168,169,170,  2,171,172,173,174,  0,  0,  0,  2,175,176,177,
-  178,179,  0,  0,  2,  2,  3, 27,180,181,182,181,183,181,184, 46,
-    0,185,186,  0,  0,  0,187,  0,  0,  0,188,189,136,  4,  0,  0,
-    0,  0,190,191,192,192,192,192,  0,193,  0,  0,  6,193,  0,  0,
-  194,  0,  0,  0,  0,  0,  0,  9,  2,  2,  0, 39,  0,  0,  0,195,
-  196,197, 11,  2, 98,198,  0,199,  2,  0,  0,  0,112,  2,  2,  2,
-    2,200,201,201,201,202,  0,  0, 12, 12, 12, 12,203,  0,  0,204,
-    2,205,206,207,  2,208,209,210,211,  0,  0,  0,212,  2,  2,  2,
-  213, 79,127,214,215,  0,  0,  0,  2,216,  2,  2,  2,  2,217,218,
-  219,220,  0,  0,221,  2,  2,222, 27,223,224,225,226,227,114,228,
-  229,  0,  0,  0,  2,  2,230,231,  0,232,  0,  0, 98,233,234,235,
-  236,236,236,236,  0,  0,  0,188,192,192,237,  0,  2,  2, 38,  2,
-   38, 35,  2,  2, 35,  2, 35,  9,238, 68,  0,239,  2, 27, 27,  2,
-    2,  3,240,241,  2,242, 39,  2,  3,  0,  0,  0,  0,  0, 27, 38,
-    2,243,  0,  0,  2,  2,244,245,  2,246,181,181,247,  9,  0,  0,
-  248,249,  0,  0, 29, 38,  2,  2, 27,  9, 27,  0,250,251,  2,  2,
-    2,  2,252,160,253,254,  0,  0,255,256,256,256,256,257,  2,  2,
-  258,259,  0,260,261,  2,  2,  2,262,263,264,  0,265,  0,  0,  0,
-  266,  2,  2,  2,  2,208,253,267,268,269,  2,  2,  0,270,  0,  0,
-  271,  0,  0,  0, 98,272,160,252,273,  0,274,275, 27,  2,  2,  2,
-    2,  2,  2, 75,252,276,  0, 58,  2, 38, 29, 35,  2,  2,  2, 35,
-    2,  2,  2, 11,262, 20,277,  0, 12, 27,  2, 28, 29, 27,278,279,
-   21,280, 32, 33,  0, 34,  0, 10,106,281, 12,194, 12,194,  0,  0,
-    2,282,160,253,283,284,  0,  0,  2,  2,  3,285,286,  0,  0,  0,
-  262,160,287,288,289,  9,  0,  0,  2,  2,  2, 98,272, 83,128,290,
-  291,  0,  0,  0,  0,  0,  2, 83, 75,160,263,292,245,  0,  0,  0,
-    2,  2, 11,293,253,294,  9,  0,  2,  2, 38,295, 79,296, 20,  0,
-    2, 38,  0,  0,  2,  2,  2,262,297,298,299,  0,  2, 38, 57,  2,
-    2, 40,  2,  2,201,300,301,302,303,  0,  0,  0,  2,  2, 10,  2,
-  282,160,304,305,306,307,  0,  0,308,252,309,  2,310,311,312,313,
-    0,314,  0,  0,308,315, 19,  2,  2,316,317,318,318,319,320, 57,
-   89,321,252,290,322, 94, 94, 94,323,324,  0,  0,  2, 38, 35,  2,
-  113,325,326,327,328,329,  0,  0,  2, 35, 29,  2,  2,  2,106,330,
-   50,331,  0,  0,332,333,  0,  0,334,335,  9,  0, 12,180,  0,  0,
-    2,  2, 38,336,337,160,160,160,160,160,160,160,160,160,  0,338,
-  339,  0,  0,  0,  0,  9,  0,  0,  2,  3,  0,  0,  2,  2,  3,340,
-  188,192,191,  0, 12,266,  2,  3,  2,  2,  3, 10,  2,  2,  2,341,
-    2,  2,  2, 12,  2,342,343,  0,
 };
 
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
 static inline uint_fast8_t
 hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[466+(((hb_use_u16[992+(((hb_use_u16[((hb_use_u8[226+(((hb_use_u8[u>>2>>2>>4>>4])<<4)+((u>>2>>2>>4)&15u))])<<4)+((u>>2>>2)&15u)])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:O;
+  return u<921600u?hb_use_u8[2721+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
 }
 
 #undef B
@@ -392,5 +393,26 @@ hb_use_get_category (unsigned u)
 #undef VMPre
 
 
+#ifdef HB_USE_TABLE_MAIN
+int main (int argc, char **argv)
+{
+  if (argc != 2)
+  {
+    for (unsigned u = 0; u < 0x10FFFFu; u++)
+      printf ("U+%04X %d\n", u, hb_use_get_category (u));
+    return 0;
+  }
+
+  hb_codepoint_t u;
+  sscanf (argv[1], "%x", &u);
+
+  printf ("%d\n", hb_use_get_category (u));
+
+  return 0;
+}
+
+#endif
+
+
 #endif /* HB_OT_SHAPER_USE_TABLE_HH */
 /* == End of generated table == */

+ 158 - 3
thirdparty/harfbuzz/src/hb-repacker.hh

@@ -29,10 +29,9 @@
 
 #include "hb-open-type.hh"
 #include "hb-map.hh"
-#include "hb-priority-queue.hh"
-#include "hb-serialize.hh"
 #include "hb-vector.hh"
 #include "graph/graph.hh"
+#include "graph/gsubgpos-graph.hh"
 #include "graph/serialize.hh"
 
 using graph::graph_t;
@@ -42,6 +41,143 @@ using graph::graph_t;
  * docs/repacker.md
  */
 
+struct lookup_size_t
+{
+  unsigned lookup_index;
+  size_t size;
+  unsigned num_subtables;
+
+  static int cmp (const void* a, const void* b)
+  {
+    return cmp ((const lookup_size_t*) a,
+                (const lookup_size_t*) b);
+  }
+
+  static int cmp (const lookup_size_t* a, const lookup_size_t* b)
+  {
+    double subtables_per_byte_a = (double) a->num_subtables / (double) a->size;
+    double subtables_per_byte_b = (double) b->num_subtables / (double) b->size;
+    if (subtables_per_byte_a == subtables_per_byte_b) {
+      return b->lookup_index - a->lookup_index;
+    }
+
+    double cmp = subtables_per_byte_b - subtables_per_byte_a;
+    if (cmp < 0) return -1;
+    if (cmp > 0) return 1;
+    return 0;
+  }
+};
+
+static inline
+bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+  // For each lookup this will check the size of subtables and split them as needed
+  // so that no subtable is at risk of overflowing. (where we support splitting for
+  // that subtable type).
+  //
+  // TODO(grieger): de-dup newly added nodes as necessary. Probably just want a full de-dup
+  //                pass after this processing is done. Not super necessary as splits are
+  //                only done where overflow is likely, so de-dup probably will get undone
+  //                later anyways.
+  for (unsigned lookup_index : ext_context.lookups.keys ())
+  {
+    graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+    if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
+      return false;
+  }
+
+  return true;
+}
+
+/*
+ * Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
+ * to extension lookups.
+ */
+static inline
+bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+  // Simple Algorithm (v1, current):
+  // 1. Calculate how many bytes each non-extension lookup consumes.
+  // 2. Select up to 64k of those to remain as non-extension (greedy, highest subtables per byte first)
+  // 3. Promote the rest.
+  //
+  // Advanced Algorithm (v2, not implemented):
+  // 1. Perform connected component analysis using lookups as roots.
+  // 2. Compute size of each connected component.
+  // 3. Select up to 64k worth of connected components to remain as non-extensions.
+  //    (greedy, highest subtables per byte first)
+  // 4. Promote the rest.
+
+  // TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
+  // TODO(garretrieger): also support extension promotion during iterative resolution phase, then
+  //                     we can use a less conservative threshold here.
+  // TODO(grieger): skip this for the 24 bit case.
+  if (!ext_context.lookups) return true;
+
+  hb_vector_t<lookup_size_t> lookup_sizes;
+  lookup_sizes.alloc (ext_context.lookups.get_population ());
+
+  for (unsigned lookup_index : ext_context.lookups.keys ())
+  {
+    const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+    hb_set_t visited;
+    lookup_sizes.push (lookup_size_t {
+        lookup_index,
+        ext_context.graph.find_subgraph_size (lookup_index, visited),
+        lookup->number_of_subtables (),
+      });
+  }
+
+  lookup_sizes.qsort ();
+
+  size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
+  size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
+  size_t l3_l4_size = 0; // Lookups + SubTables
+  size_t l4_plus_size = 0; // SubTables + their descendants
+
+  // Start by assuming all lookups are using extension subtables, this size will be removed later
+  // if it's decided to not make a lookup extension.
+  for (auto p : lookup_sizes)
+  {
+    unsigned subtables_size = p.num_subtables * 8;
+    l3_l4_size += subtables_size;
+    l4_plus_size += subtables_size;
+  }
+
+  bool layers_full = false;
+  for (auto p : lookup_sizes)
+  {
+    const graph::Lookup* lookup = ext_context.lookups.get(p.lookup_index);
+    if (lookup->is_extension (ext_context.table_tag))
+      // already an extension so size is counted by the loop above.
+      continue;
+
+    if (!layers_full)
+    {
+      size_t lookup_size = ext_context.graph.vertices_[p.lookup_index].table_size ();
+      hb_set_t visited;
+      size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
+      size_t remaining_size = p.size - subtables_size - lookup_size;
+
+      l2_l3_size   += lookup_size;
+      l3_l4_size   += lookup_size + subtables_size;
+      l3_l4_size   -= p.num_subtables * 8;
+      l4_plus_size += subtables_size + remaining_size;
+
+      if (l2_l3_size < (1 << 16)
+          && l3_l4_size < (1 << 16)
+          && l4_plus_size < (1 << 16)) continue; // this lookup fits within all layers groups
+
+      layers_full = true;
+    }
+
+    if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index))
+      return false;
+  }
+
+  return true;
+}
+
 static inline
 bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
                                graph_t& sorted_graph)
@@ -157,7 +293,8 @@ template<typename T>
 inline hb_blob_t*
 hb_resolve_overflows (const T& packed,
                       hb_tag_t table_tag,
-                      unsigned max_rounds = 20) {
+                      unsigned max_rounds = 20,
+                      bool recalculate_extensions = false) {
   graph_t sorted_graph (packed);
   sorted_graph.sort_shortest_distance ();
 
@@ -167,13 +304,31 @@ hb_resolve_overflows (const T& packed,
     return graph::serialize (sorted_graph);
   }
 
+  graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
   if ((table_tag == HB_OT_TAG_GPOS
        ||  table_tag == HB_OT_TAG_GSUB)
       && will_overflow)
   {
+    if (recalculate_extensions)
+    {
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
+      if (!_presplit_subtables_if_needed (ext_context)) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
+        return nullptr;
+      }
+
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
+      if (!_promote_extensions_if_needed (ext_context)) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
+        return nullptr;
+      }
+    }
+
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
     if (sorted_graph.assign_spaces ())
       sorted_graph.sort_shortest_distance ();
+    else
+      sorted_graph.sort_shortest_distance_if_needed ();
   }
 
   unsigned round = 0;

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

@@ -145,7 +145,7 @@ hb_set_set_user_data (hb_set_t           *set,
  * Since: 0.9.2
  **/
 void *
-hb_set_get_user_data (hb_set_t           *set,
+hb_set_get_user_data (const hb_set_t     *set,
 		      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (set, key);

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

@@ -77,7 +77,7 @@ hb_set_set_user_data (hb_set_t           *set,
 		      hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_set_get_user_data (hb_set_t           *set,
+hb_set_get_user_data (const hb_set_t     *set,
 		      hb_user_data_key_t *key);
 
 

+ 2 - 2
thirdparty/harfbuzz/src/hb-shape-plan.cc

@@ -358,8 +358,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
  * Since: 0.9.7
  **/
 void *
-hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
-			     hb_user_data_key_t *key)
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+			     hb_user_data_key_t    *key)
 {
   return hb_object_get_user_data (shape_plan, key);
 }

+ 2 - 2
thirdparty/harfbuzz/src/hb-shape-plan.h

@@ -102,8 +102,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
 			     hb_bool_t           replace);
 
 HB_EXTERN void *
-hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
-			     hb_user_data_key_t *key);
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+			     hb_user_data_key_t    *key);
 
 
 HB_EXTERN hb_bool_t

+ 11 - 2
thirdparty/harfbuzz/src/hb-subset-repacker.cc

@@ -25,18 +25,24 @@
 #include "hb-repacker.hh"
 
 #ifdef HB_EXPERIMENTAL_API
+
 /**
  * hb_subset_repack_or_fail:
+ * @table_tag: tag of the table being packed, needed to allow table specific optimizations.
  * @hb_objects: raw array of struct hb_object_t, which provides
  * object graph info
  * @num_hb_objs: number of hb_object_t in the hb_objects array.
  *
  * Given the input object graph info, repack a table to eliminate
  * offset overflows. A nullptr is returned if the repacking attempt fails.
+ * Table specific optimizations (eg. extension promotion in GSUB/GPOS) may be performed.
+ * Passing HB_TAG_NONE will disable table specific optimizations.
  *
  * Since: EXPERIMENTAL
  **/
-hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_objs)
+hb_blob_t* hb_subset_repack_or_fail (hb_tag_t table_tag,
+                                     hb_object_t* hb_objects,
+                                     unsigned num_hb_objs)
 {
   hb_vector_t<const hb_object_t *> packed;
   packed.alloc (num_hb_objs + 1);
@@ -44,6 +50,9 @@ hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_ob
   for (unsigned i = 0 ; i < num_hb_objs ; i++)
     packed.push (&(hb_objects[i]));
 
-  return hb_resolve_overflows (packed, HB_OT_TAG_GSUB);
+  return hb_resolve_overflows (packed,
+                               table_tag,
+                               20,
+                               true);
 }
 #endif

+ 2 - 1
thirdparty/harfbuzz/src/hb-subset-repacker.h

@@ -70,7 +70,8 @@ struct hb_object_t
 typedef struct hb_object_t hb_object_t;
 
 HB_EXTERN hb_blob_t*
-hb_subset_repack_or_fail (hb_object_t* hb_objects,
+hb_subset_repack_or_fail (hb_tag_t table_tag,
+                          hb_object_t* hb_objects,
                           unsigned num_hb_objs);
 
 #endif

File diff suppressed because it is too large
+ 40 - 2894
thirdparty/harfbuzz/src/hb-ucd-table.hh


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

@@ -24,42 +24,37 @@
 #include "hb-unicode.hh"
 
 static const uint8_t
-_hb_emoji_u8[544] =
+_hb_emoji_u8[464] =
 {
    16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
-    0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    2,  3,  0,  0,  4,  0,  5,  0,  0,  0,  0,  0,  6,  0,  7,  8,
-    0,  0,  0,  9,  0,  0, 10, 11, 12, 13, 14, 13, 15, 16, 17,  0,
-    0,  0,  0,  0, 18,  0,  0,  0,  0,  0,  0,  0, 19, 20,  0,  0,
-   21,  0,  0,  0,  0,  0,  0,  0,  0,  0, 22,  0,  0,  0,  0,  0,
-   13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
-   13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13,  0, 33,  0, 34,
-   35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13,  0,  0,  0,  0,
-   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66,  0,  0,
-    0,  0,  0,  0,  0,  0,  0, 16,  0,  2,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,  0,  6,  0,  0,
-    0,  0,  0, 12,  0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
-    0,128,  0,  0,  0,254, 15,  7,  4,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0, 12, 64,  0,  1,  0,  0,  0,  0,  0,  0,120,
-  191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
-   63,  0,255,255,255,255,255,255, 63,255, 87, 32,  2,  1, 24,  0,
-  144, 80,184,  0,248,  0,  0,  0,  0,  0,224,  0,  2,  0,  1,128,
-    0,  0,  0,  0,  0,  0, 48,  0,224,  0,  0, 24,  0,  0,  0,  0,
-    0,  0, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1, 32,
-    0,  0,128,  2,  0,  0,  0,  0,  0,224,  0,  0,  0,128,  0,  0,
-    0,  0,  0,  0,  0,240,  3,192,  0, 64,254,  7,  0,224,255,255,
-  255,255,255,255, 63,  0,  0,  0,254,255,  0,  4,  0,128,252,247,
-    0,254,255,255,255,255,255,255,255,255,255,255,255,255,255,  7,
-  255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
-  255,255,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,255,
-    0,  0,224,255,255,255,255,255,  0,240,  0,  0,  0,  0,  0,  0,
-    0,255,  0,252,  0,  0,  0,  0,  0,255,  0,  0,  0,192,255,255,
-    0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
+    0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  0,  3,  4,  0,  0,  5,  6,  0,  7,  0,  8,  9, 10, 11, 12,
+    0,  0, 13,  0,  0,  0, 14,  0, 15,  0,  0,  0,  0, 16,  0,  0,
+   17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
+   26, 27, 28, 17, 17, 17,  0,  0, 17, 17, 17, 17, 17, 17, 17, 29,
+    0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  3,  0,  0,  4,  0,  0,
+    5,  6,  0,  0,  7,  8,  0,  0,  8,  0,  9, 10,  0,  0, 11,  0,
+    0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
+   22, 23,  0,  0,  0, 24,  0,  0, 25,  0, 26,  0,  0, 27,  0,  0,
+   28,  0,  0,  0, 16, 16, 16, 16, 29,  9,  0, 30, 31, 32, 16, 33,
+   34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40,  0,
+    0,  0,  0, 41,  0,  0, 42, 16, 43,  0, 44,  0, 45, 46, 16, 16,
+   47, 48, 49, 16, 16, 16, 16, 38,  0,  0,  0,  0,  0, 66,  0,  0,
+    0,  0,  0, 16,  0,  2,  0,  0,  4,  0,  0,  2,  0,  0,240,  3,
+    0,  6,  0,  0,  0,  0,  0, 12,  0,  1,  0,  0,  0,128,  0,  0,
+    0,254, 15,  7,  4,  0,  0,  0,  0, 12, 64,  0,  1,  0,  0,  0,
+    0,  0,  0,120,191,255,247,255,255,255,255,255, 63,  0,255,255,
+   63,255, 87, 32,  2,  1, 24,  0,144, 80,184,  0,248,  0,  0,  0,
+    0,  0,224,  0,  2,  0,  1,128,  0,  0, 48,  0,224,  0,  0, 24,
+    0,  0, 33,  0,  0,  0,  1, 32,  0,  0,128,  2,  0,224,  0,  0,
+    0,240,  3,192,  0, 64,254,  7,  0,224,255,255, 63,  0,  0,  0,
+  254,255,  0,  4,  0,128,252,247,  0,254,255,255,255,255,255,  7,
+  255,255,255, 63,192,255,255,255,255,255,  0,  0,  0,  0,240,255,
+    0,  0,224,255,  0,240,  0,  0,  0,255,  0,252,  0,255,  0,  0,
+    0,192,255,255,  0,240,255,255,255,255,255,247,191,255,255,255,
 };
 
 static inline unsigned
@@ -75,7 +70,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
 static inline uint_fast8_t
 _hb_emoji_is_Extended_Pictographic (unsigned u)
 {
-  return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+  return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
 }
 
 

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

@@ -308,8 +308,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
  * Since: 0.9.2
  **/
 void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-				hb_user_data_key_t *key)
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+				hb_user_data_key_t       *key)
 {
   return hb_object_get_user_data (ufuncs, key);
 }

+ 2 - 2
thirdparty/harfbuzz/src/hb-unicode.h

@@ -317,8 +317,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
 
 
 HB_EXTERN void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-				hb_user_data_key_t *key);
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+				hb_user_data_key_t       *key);
 
 
 HB_EXTERN void

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

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

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