Przeglądaj źródła

HarfBuzz: Update to version 4.0.0

bruvzg 3 lat temu
rodzic
commit
9b0fbfa06d
51 zmienionych plików z 2554 dodań i 534 usunięć
  1. 1 0
      modules/text_server_adv/SCsub
  2. 1 1
      thirdparty/README.md
  3. 1 1
      thirdparty/harfbuzz/src/hb-algs.hh
  4. 422 0
      thirdparty/harfbuzz/src/hb-buffer-verify.cc
  5. 1 1
      thirdparty/harfbuzz/src/hb-buffer.cc
  6. 41 23
      thirdparty/harfbuzz/src/hb-buffer.h
  7. 18 0
      thirdparty/harfbuzz/src/hb-buffer.hh
  8. 1 1
      thirdparty/harfbuzz/src/hb-common.cc
  9. 16 0
      thirdparty/harfbuzz/src/hb-common.h
  10. 2 0
      thirdparty/harfbuzz/src/hb-config.hh
  11. 226 150
      thirdparty/harfbuzz/src/hb-draw.cc
  12. 256 29
      thirdparty/harfbuzz/src/hb-draw.h
  13. 169 77
      thirdparty/harfbuzz/src/hb-draw.hh
  14. 159 4
      thirdparty/harfbuzz/src/hb-font.cc
  15. 40 5
      thirdparty/harfbuzz/src/hb-font.h
  16. 15 1
      thirdparty/harfbuzz/src/hb-font.hh
  17. 82 0
      thirdparty/harfbuzz/src/hb-ft.cc
  18. 1 0
      thirdparty/harfbuzz/src/hb-gobject-structs.cc
  19. 4 0
      thirdparty/harfbuzz/src/hb-gobject-structs.h
  20. 10 4
      thirdparty/harfbuzz/src/hb-machinery.hh
  21. 16 18
      thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
  22. 1 3
      thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
  23. 10 12
      thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
  24. 1 3
      thirdparty/harfbuzz/src/hb-ot-cff2-table.hh
  25. 15 0
      thirdparty/harfbuzz/src/hb-ot-deprecated.h
  26. 12 1
      thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
  27. 3 0
      thirdparty/harfbuzz/src/hb-ot-face.hh
  28. 21 0
      thirdparty/harfbuzz/src/hb-ot-font.cc
  29. 27 28
      thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
  30. 90 69
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  31. 300 1
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  32. 15 47
      thirdparty/harfbuzz/src/hb-ot-layout.h
  33. 78 0
      thirdparty/harfbuzz/src/hb-ot-math-table.hh
  34. 45 0
      thirdparty/harfbuzz/src/hb-ot-math.cc
  35. 31 5
      thirdparty/harfbuzz/src/hb-ot-math.h
  36. 139 0
      thirdparty/harfbuzz/src/hb-ot-metrics.cc
  37. 5 0
      thirdparty/harfbuzz/src/hb-ot-metrics.h
  38. 1 1
      thirdparty/harfbuzz/src/hb-ot-name.cc
  39. 5 0
      thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
  40. 3 1
      thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
  41. 3 3
      thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc
  42. 3 0
      thirdparty/harfbuzz/src/hb-ot-tag.cc
  43. 18 0
      thirdparty/harfbuzz/src/hb-shape.cc
  44. 31 6
      thirdparty/harfbuzz/src/hb-static.cc
  45. 3 4
      thirdparty/harfbuzz/src/hb-style.cc
  46. 3 1
      thirdparty/harfbuzz/src/hb-style.h
  47. 131 12
      thirdparty/harfbuzz/src/hb-subset-plan.cc
  48. 0 9
      thirdparty/harfbuzz/src/hb-subset-plan.hh
  49. 29 8
      thirdparty/harfbuzz/src/hb-subset.cc
  50. 45 1
      thirdparty/harfbuzz/src/hb-subset.h
  51. 4 4
      thirdparty/harfbuzz/src/hb-version.h

+ 1 - 0
modules/text_server_adv/SCsub

@@ -49,6 +49,7 @@ if env["builtin_harfbuzz"]:
         "src/hb-aat-map.cc",
         "src/hb-blob.cc",
         "src/hb-buffer-serialize.cc",
+        "src/hb-buffer-verify.cc",
         "src/hb-buffer.cc",
         "src/hb-common.cc",
         #'src/hb-coretext.cc',

+ 1 - 1
thirdparty/README.md

@@ -206,7 +206,7 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 3.3.2 (ac46c3248e8b0316235943175c4d4a11c24dd4a9, 2022)
+- Version: 4.0.0 (8d1b000a3edc90c12267b836b4ef3f81c0e53edc, 2022)
 - License: MIT
 
 Files extracted from upstream source:

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

@@ -498,7 +498,7 @@ struct hb_pair_t
 
   template <typename Q1, typename Q2,
 	    hb_enable_if (hb_is_convertible (T1, Q1) &&
-			  hb_is_convertible (T2, T2))>
+			  hb_is_convertible (T2, Q2))>
   operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
 
   hb_pair_t<T1, T2> reverse () const

+ 422 - 0
thirdparty/harfbuzz/src/hb-buffer-verify.cc

@@ -0,0 +1,422 @@
+/*
+ * Copyright © 2022  Behdad Esfahbod
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_BUFFER_VERIFY
+
+#include "hb-buffer.hh"
+
+
+#define BUFFER_VERIFY_ERROR "buffer verify error: "
+static inline void
+buffer_verify_error (hb_buffer_t *buffer,
+		     hb_font_t *font,
+		     const char *fmt,
+		     ...) HB_PRINTF_FUNC(3, 4);
+
+static inline void
+buffer_verify_error (hb_buffer_t *buffer,
+		     hb_font_t *font,
+		     const char *fmt,
+		     ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  if (buffer->messaging ())
+  {
+    buffer->message_impl (font, fmt, ap);
+  }
+  else
+  {
+    fprintf (stderr, "harfbuzz ");
+    vfprintf (stderr, fmt, ap);
+    fprintf (stderr, "\n");
+  }
+  va_end (ap);
+}
+
+static bool
+buffer_verify_monotone (hb_buffer_t *buffer,
+			hb_font_t   *font)
+{
+  /* Check that clusters are monotone. */
+  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
+      buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  {
+    bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+    unsigned int num_glyphs;
+    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (info[i-1].cluster != info[i].cluster &&
+	  (info[i-1].cluster < info[i].cluster) != is_forward)
+      {
+	buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
+	return false;
+      }
+  }
+
+  return true;
+}
+
+static bool
+buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
+			       hb_buffer_t  *text_buffer,
+			       hb_font_t          *font,
+			       const hb_feature_t *features,
+			       unsigned int        num_features,
+			       const char * const *shapers)
+{
+  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  {
+    /* Cannot perform this check without monotone clusters. */
+    return true;
+  }
+
+  /* Check that breaking up shaping at safe-to-break is indeed safe. */
+
+  hb_buffer_t *fragment = hb_buffer_create_similar (buffer);
+  hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
+  hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
+
+  unsigned int num_glyphs;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+  unsigned int num_chars;
+  hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+  /* Chop text and shape fragments. */
+  bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+  unsigned int start = 0;
+  unsigned int text_start = forward ? 0 : num_chars;
+  unsigned int text_end = text_start;
+  for (unsigned int end = 1; end < num_glyphs + 1; end++)
+  {
+    if (end < num_glyphs &&
+	(info[end].cluster == info[end-1].cluster ||
+	 info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
+	continue;
+
+    /* Shape segment corresponding to glyphs start..end. */
+    if (end == num_glyphs)
+    {
+      if (forward)
+	text_end = num_chars;
+      else
+	text_start = 0;
+    }
+    else
+    {
+      if (forward)
+      {
+	unsigned int cluster = info[end].cluster;
+	while (text_end < num_chars && text[text_end].cluster < cluster)
+	  text_end++;
+      }
+      else
+      {
+	unsigned int cluster = info[end - 1].cluster;
+	while (text_start && text[text_start - 1].cluster >= cluster)
+	  text_start--;
+      }
+    }
+    assert (text_start < text_end);
+
+    if (0)
+      printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+    hb_buffer_clear_contents (fragment);
+
+    hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
+    if (0 < text_start)
+      flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+    if (text_end < num_chars)
+      flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+    hb_buffer_set_flags (fragment, flags);
+
+    hb_buffer_append (fragment, text_buffer, text_start, text_end);
+    if (!hb_shape_full (font, fragment, features, num_features, shapers))
+    {
+      buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
+      hb_buffer_destroy (reconstruction);
+      hb_buffer_destroy (fragment);
+      return false;
+    }
+    hb_buffer_append (reconstruction, fragment, 0, -1);
+
+    start = end;
+    if (forward)
+      text_start = text_end;
+    else
+      text_end = text_start;
+  }
+
+  bool ret = true;
+  hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+  if (diff)
+  {
+    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+    ret = false;
+
+    /* Return the reconstructed result instead so it can be inspected. */
+    hb_buffer_set_length (buffer, 0);
+    hb_buffer_append (buffer, reconstruction, 0, -1);
+  }
+
+  hb_buffer_destroy (reconstruction);
+  hb_buffer_destroy (fragment);
+
+  return ret;
+}
+
+static bool
+buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
+				hb_buffer_t        *text_buffer,
+				hb_font_t          *font,
+				const hb_feature_t *features,
+				unsigned int        num_features,
+				const char * const *shapers)
+{
+  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+  {
+    /* Cannot perform this check without monotone clusters. */
+    return true;
+  }
+
+  /* Check that shuffling up text before shaping at safe-to-concat points
+   * is indeed safe. */
+
+  /* This is what we do:
+   *
+   * 1. We shape text once. Then segment the text at all the safe-to-concat
+   *    points;
+   *
+   * 2. Then we create two buffers, one containing all the even segments and
+   *    one all the odd segments.
+   *
+   * 3. Because all these segments were safe-to-concat at both ends, we
+   *    expect that concatenating them and shaping should NOT change the
+   *    shaping results of each segment.  As such, we expect that after
+   *    shaping the two buffers, we still get cluster boundaries at the
+   *    segment boundaries, and that those all are safe-to-concat points.
+   *    Moreover, that there are NOT any safe-to-concat points within the
+   *    segments.
+   *
+   * 4. Finally, we reconstruct the shaping results of the original text by
+   *    simply interleaving the shaping results of the segments from the two
+   *    buffers, and assert that the total shaping results is the same as
+   *    the one from original buffer in step 1.
+   */
+
+  hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer),
+			     hb_buffer_create_similar (buffer)};
+  hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer);
+  hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY);
+  hb_segment_properties_t props;
+  hb_buffer_get_segment_properties (buffer, &props);
+  hb_buffer_set_segment_properties (fragments[0], &props);
+  hb_buffer_set_segment_properties (fragments[1], &props);
+  hb_buffer_set_segment_properties (reconstruction, &props);
+
+  unsigned num_glyphs;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+  unsigned num_chars;
+  hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+  bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+  if (!forward)
+    hb_buffer_reverse (buffer);
+
+  /*
+   * Split text into segments and collect into to fragment streams.
+   */
+  {
+    unsigned fragment_idx = 0;
+    unsigned start = 0;
+    unsigned text_start = 0;
+    unsigned text_end = 0;
+    for (unsigned end = 1; end < num_glyphs + 1; end++)
+    {
+      if (end < num_glyphs &&
+	  (info[end].cluster == info[end-1].cluster ||
+	   info[end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
+	  continue;
+
+      /* Accumulate segment corresponding to glyphs start..end. */
+      if (end == num_glyphs)
+	text_end = num_chars;
+      else
+      {
+	unsigned cluster = info[end].cluster;
+	while (text_end < num_chars && text[text_end].cluster < cluster)
+	  text_end++;
+      }
+      assert (text_start < text_end);
+
+      if (0)
+	printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+#if 0
+      hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
+      if (0 < text_start)
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+      if (text_end < num_chars)
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+      hb_buffer_set_flags (fragment, flags);
+#endif
+
+      hb_buffer_append (fragments[fragment_idx], text_buffer, text_start, text_end);
+
+      start = end;
+      text_start = text_end;
+      fragment_idx = 1 - fragment_idx;
+    }
+  }
+
+  bool ret = true;
+  hb_buffer_diff_flags_t diff;
+
+  /*
+   * Shape the two fragment streams.
+   */
+  if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
+  {
+    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
+    ret = false;
+    goto out;
+  }
+  if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
+  {
+    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
+    ret = false;
+    goto out;
+  }
+
+  if (!forward)
+  {
+    hb_buffer_reverse (fragments[0]);
+    hb_buffer_reverse (fragments[1]);
+  }
+
+  /*
+   * Reconstruct results.
+   */
+  {
+    unsigned fragment_idx = 0;
+    unsigned fragment_start[2] {0, 0};
+    unsigned fragment_num_glyphs[2];
+    hb_glyph_info_t *fragment_info[2];
+    for (unsigned i = 0; i < 2; i++)
+      fragment_info[i] = hb_buffer_get_glyph_infos (fragments[i], &fragment_num_glyphs[i]);
+    while (fragment_start[0] < fragment_num_glyphs[0] ||
+	   fragment_start[1] < fragment_num_glyphs[1])
+    {
+      unsigned fragment_end = fragment_start[fragment_idx] + 1;
+      while (fragment_end < fragment_num_glyphs[fragment_idx] &&
+	     (fragment_info[fragment_idx][fragment_end].cluster == fragment_info[fragment_idx][fragment_end - 1].cluster ||
+	      fragment_info[fragment_idx][fragment_end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT))
+	fragment_end++;
+
+      hb_buffer_append (reconstruction, fragments[fragment_idx], fragment_start[fragment_idx], fragment_end);
+
+      fragment_start[fragment_idx] = fragment_end;
+      fragment_idx = 1 - fragment_idx;
+    }
+  }
+
+  if (!forward)
+  {
+    hb_buffer_reverse (buffer);
+    hb_buffer_reverse (reconstruction);
+  }
+
+  /*
+   * Diff results.
+   */
+  diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+  if (diff)
+  {
+    buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+    ret = false;
+
+    /* Return the reconstructed result instead so it can be inspected. */
+    hb_buffer_set_length (buffer, 0);
+    hb_buffer_append (buffer, reconstruction, 0, -1);
+  }
+
+
+out:
+  hb_buffer_destroy (reconstruction);
+  hb_buffer_destroy (fragments[0]);
+  hb_buffer_destroy (fragments[1]);
+
+  return ret;
+}
+
+bool
+hb_buffer_t::verify (hb_buffer_t        *text_buffer,
+		     hb_font_t          *font,
+		     const hb_feature_t *features,
+		     unsigned int        num_features,
+		     const char * const *shapers)
+{
+  bool ret = true;
+  if (!buffer_verify_monotone (this, font))
+    ret = false;
+  if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers))
+    ret = false;
+  if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 &&
+      !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers))
+    ret = false;
+  if (!ret)
+  {
+    unsigned len = text_buffer->len;
+    hb_vector_t<char> bytes;
+    if (likely (bytes.resize (len * 10 + 16)))
+    {
+      hb_buffer_serialize_unicode (text_buffer,
+				   0, len,
+				   bytes.arrayZ, bytes.length,
+				   &len,
+				   HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+				   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS);
+      buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ);
+    }
+  }
+  return ret;
+}
+
+
+#endif

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

@@ -1789,7 +1789,7 @@ hb_buffer_add_codepoints (hb_buffer_t          *buffer,
  **/
 HB_EXTERN void
 hb_buffer_append (hb_buffer_t *buffer,
-		  hb_buffer_t *source,
+		  const hb_buffer_t *source,
 		  unsigned int start,
 		  unsigned int end)
 {

+ 41 - 23
thirdparty/harfbuzz/src/hb-buffer.h

@@ -137,7 +137,11 @@ typedef struct hb_glyph_info_t {
  * 				   clusters.
  * 				   The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will
  * 				   always imply this flag.
- * 				   Since: 3.3.0
+ *				   To use this flag, you must enable the buffer flag
+ *				   @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during
+ *				   shaping, otherwise the buffer flag will not be
+ *				   reliably produced.
+ * 				   Since: 4.0.0
  * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
  *
  * Flags for #hb_glyph_info_t.
@@ -356,7 +360,19 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
  * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
  *                      flag indicating that a dotted circle should
  *                      not be inserted in the rendering of incorrect
- *                      character sequences (such at <0905 093E>). Since: 2.4
+ *                      character sequences (such at <0905 093E>). Since: 2.4.0
+ * @HB_BUFFER_FLAG_VERIFY:
+ *                      flag indicating that the hb_shape() call and its variants
+ *                      should perform various verification processes on the results
+ *                      of the shaping operation on the buffer.  If the verification
+ *                      fails, then either a buffer message is sent, if a message
+ *                      handler is installed on the buffer, or a message is written
+ *                      to standard error.  In either case, the shaping result might
+ *                      be modified to show the failed output. Since: 3.4.0
+ * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT:
+ *                      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
  *
  * Flags for #hb_buffer_t.
  *
@@ -368,7 +384,9 @@ typedef enum { /*< flags >*/
   HB_BUFFER_FLAG_EOT				= 0x00000002u, /* End-of-text */
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u,
   HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES	= 0x00000008u,
-  HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE	= 0x00000010u
+  HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE	= 0x00000010u,
+  HB_BUFFER_FLAG_VERIFY				= 0x00000020u,
+  HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT	= 0x00000040u
 } hb_buffer_flags_t;
 
 HB_EXTERN void
@@ -522,7 +540,7 @@ hb_buffer_add_codepoints (hb_buffer_t          *buffer,
 
 HB_EXTERN void
 hb_buffer_append (hb_buffer_t *buffer,
-		  hb_buffer_t *source,
+		  const hb_buffer_t *source,
 		  unsigned int start,
 		  unsigned int end);
 
@@ -619,24 +637,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
 
 HB_EXTERN unsigned int
 hb_buffer_serialize_unicode (hb_buffer_t *buffer,
-					unsigned int start,
-					unsigned int end,
-					char *buf,
-					unsigned int buf_size,
-					unsigned int *buf_consumed,
-					hb_buffer_serialize_format_t format,
-					hb_buffer_serialize_flags_t flags);
+			     unsigned int start,
+			     unsigned int end,
+			     char *buf,
+			     unsigned int buf_size,
+			     unsigned int *buf_consumed,
+			     hb_buffer_serialize_format_t format,
+			     hb_buffer_serialize_flags_t flags);
 
 HB_EXTERN unsigned int
 hb_buffer_serialize (hb_buffer_t *buffer,
-					unsigned int start,
-					unsigned int end,
-					char *buf,
-					unsigned int buf_size,
-					unsigned int *buf_consumed,
-					hb_font_t *font,
-					hb_buffer_serialize_format_t format,
-					hb_buffer_serialize_flags_t flags);
+		     unsigned int start,
+		     unsigned int end,
+		     char *buf,
+		     unsigned int buf_size,
+		     unsigned int *buf_consumed,
+		     hb_font_t *font,
+		     hb_buffer_serialize_format_t format,
+		     hb_buffer_serialize_flags_t flags);
 
 HB_EXTERN hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
@@ -648,10 +666,10 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 
 HB_EXTERN hb_bool_t
 hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
-            const char *buf,
-            int buf_len,
-            const char **end_ptr,
-            hb_buffer_serialize_format_t format);
+			       const char *buf,
+			       int buf_len,
+			       const char **end_ptr,
+			       hb_buffer_serialize_format_t format);
 
 
 

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

@@ -212,6 +212,20 @@ struct hb_buffer_t
   HB_INTERNAL void enter ();
   HB_INTERNAL void leave ();
 
+#ifndef HB_NO_BUFFER_VERIFY
+  HB_INTERNAL
+#endif
+  bool verify (hb_buffer_t        *text_buffer,
+	       hb_font_t          *font,
+	       const hb_feature_t *features,
+	       unsigned int        num_features,
+	       const char * const *shapers)
+#ifndef HB_NO_BUFFER_VERIFY
+  ;
+#else
+  { return true; }
+#endif
+
   unsigned int backtrack_len () const { return have_output ? out_len : idx; }
   unsigned int lookahead_len () const { return len - idx; }
   uint8_t next_serial () { return ++serial ? serial : ++serial; }
@@ -446,6 +460,8 @@ struct hb_buffer_t
   }
   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
   {
+    if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
+      return;
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
 		      start, end,
 		      true);
@@ -458,6 +474,8 @@ struct hb_buffer_t
   }
   void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
   {
+    if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
+      return;
     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
 		      start, end,
 		      false, true);

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

@@ -1065,7 +1065,7 @@ hb_variation_from_string (const char *str, int len,
 static inline void free_static_C_locale ();
 
 static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
-							     hb_C_locale_lazy_loader_t>
+							   hb_C_locale_lazy_loader_t>
 {
   static hb_locale_t create ()
   {

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

@@ -130,6 +130,16 @@ typedef union _hb_var_int_t {
   int8_t i8[4];
 } hb_var_int_t;
 
+typedef union _hb_var_num_t {
+  float f;
+  uint32_t u32;
+  int32_t i32;
+  uint16_t u16[2];
+  int16_t i16[2];
+  uint8_t u8[4];
+  int8_t i8[4];
+} hb_var_num_t;
+
 
 /* hb_tag_t */
 
@@ -481,6 +491,7 @@ hb_language_get_default (void);
  * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
  * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
  * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
+ * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
  * @HB_SCRIPT_INVALID: No script set
  *
  * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -697,6 +708,11 @@ typedef enum
   HB_SCRIPT_TOTO			= HB_TAG ('T','o','t','o'), /*14.0*/
   HB_SCRIPT_VITHKUQI			= HB_TAG ('V','i','t','h'), /*14.0*/
 
+  /*
+   * Since 3.4.0
+   */
+  HB_SCRIPT_MATH			= HB_TAG ('Z','m','t','h'),
+
   /* No script set. */
   HB_SCRIPT_INVALID			= HB_TAG_NONE,
 

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

@@ -55,6 +55,7 @@
 #define HB_NO_ATEXIT
 #define HB_NO_BUFFER_MESSAGE
 #define HB_NO_BUFFER_SERIALIZE
+#define HB_NO_BUFFER_VERIFY
 #define HB_NO_BITMAP
 #define HB_NO_CFF
 #define HB_NO_COLOR
@@ -84,6 +85,7 @@
 #ifdef HB_MINI
 #define HB_NO_AAT
 #define HB_NO_LEGACY
+#define HB_NO_BORING_EXPANSION
 #endif
 
 #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)

+ 226 - 150
thirdparty/harfbuzz/src/hb-draw.cc

@@ -25,237 +25,313 @@
 #include "hb.hh"
 
 #ifndef HB_NO_DRAW
-#ifdef HB_EXPERIMENTAL_API
 
 #include "hb-draw.hh"
-#include "hb-ot.h"
-#include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
-#include "hb-ot-cff2-table.hh"
 
 /**
- * hb_draw_funcs_set_move_to_func:
- * @funcs: draw functions object
- * @move_to: move-to callback
+ * SECTION:hb-draw
+ * @title: hb-draw
+ * @short_description: Glyph drawing
+ * @include: hb.h
  *
- * Sets move-to callback to the draw functions object.
- *
- * Since: EXPERIMENTAL
+ * Functions for drawing (extracting) glyph shapes.
  **/
-void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
-				hb_draw_move_to_func_t  move_to)
+
+static void
+hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+		     hb_draw_state_t *st HB_UNUSED,
+		     float to_x HB_UNUSED, float to_y HB_UNUSED,
+		     void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+		     hb_draw_state_t *st HB_UNUSED,
+		     float to_x HB_UNUSED, float to_y HB_UNUSED,
+		     void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data,
+			  hb_draw_state_t *st,
+			  float control_x, float control_y,
+			  float to_x, float to_y,
+			  void *user_data HB_UNUSED)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->move_to = move_to;
+  dfuncs->emit_cubic_to (draw_data, *st,
+			 (st->current_x + 2.f * control_x) / 3.f,
+			 (st->current_y + 2.f * control_y) / 3.f,
+			 (to_x + 2.f * control_x) / 3.f,
+			 (to_y + 2.f * control_y) / 3.f,
+			 to_x, to_y);
+}
+
+static void
+hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+		      hb_draw_state_t *st HB_UNUSED,
+		      float control1_x HB_UNUSED, float control1_y HB_UNUSED,
+		      float control2_x HB_UNUSED, float control2_y HB_UNUSED,
+		      float to_x HB_UNUSED, float to_y HB_UNUSED,
+		      void *user_data HB_UNUSED) {}
+
+static void
+hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
+			hb_draw_state_t *st HB_UNUSED,
+			void *user_data HB_UNUSED) {}
+
+
+#define HB_DRAW_FUNC_IMPLEMENT(name)						\
+										\
+void										\
+hb_draw_funcs_set_##name##_func (hb_draw_funcs_t	 *dfuncs,		\
+				 hb_draw_##name##_func_t  func,			\
+				 void			 *user_data,		\
+				 hb_destroy_func_t	  destroy)		\
+{										\
+  if (hb_object_is_immutable (dfuncs))						\
+    return;									\
+										\
+  if (dfuncs->destroy.name)							\
+    dfuncs->destroy.name (dfuncs->user_data.name);				\
+										\
+  if (func) {									\
+    dfuncs->func.name = func;							\
+    dfuncs->user_data.name = user_data;						\
+    dfuncs->destroy.name = destroy;						\
+  } else {									\
+    dfuncs->func.name = hb_draw_##name##_nil;					\
+    dfuncs->user_data.name = nullptr;						\
+    dfuncs->destroy.name = nullptr;						\
+  }										\
 }
 
+HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+
 /**
- * hb_draw_funcs_set_line_to_func:
- * @funcs: draw functions object
- * @line_to: line-to callback
+ * hb_draw_funcs_create: (Xconstructor)
+ *
+ * Creates a new draw callbacks object.
  *
- * Sets line-to callback to the draw functions object.
+ * Return value: (transfer full):
+ * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
+ * reference count should be released with hb_draw_funcs_destroy when you are
+ * done using the #hb_draw_funcs_t. This function never returns %NULL. If
+ * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
+ * be returned.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
-				hb_draw_line_to_func_t  line_to)
+hb_draw_funcs_t *
+hb_draw_funcs_create ()
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->line_to = line_to;
+  hb_draw_funcs_t *dfuncs;
+  if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ())))
+    return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+
+  dfuncs->func =  Null (hb_draw_funcs_t).func;
+
+  return dfuncs;
 }
 
+DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
+{
+  HB_OBJECT_HEADER_STATIC,
+
+  {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil,
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  }
+};
+
+
 /**
- * hb_draw_funcs_set_quadratic_to_func:
- * @funcs: draw functions object
- * @move_to: quadratic-to callback
+ * hb_draw_funcs_reference: (skip)
+ * @dfuncs: draw functions
+ *
+ * Increases the reference count on @dfuncs by one. This prevents @buffer from
+ * being destroyed until a matching call to hb_draw_funcs_destroy() is made.
  *
- * Sets quadratic-to callback to the draw functions object.
+ * Return value: (transfer full):
+ * The referenced #hb_draw_funcs_t.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
-				     hb_draw_quadratic_to_func_t  quadratic_to)
+hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->quadratic_to = quadratic_to;
-  funcs->is_quadratic_to_set = true;
+  return hb_object_reference (dfuncs);
 }
 
 /**
- * hb_draw_funcs_set_cubic_to_func:
- * @funcs: draw functions
- * @cubic_to: cubic-to callback
+ * hb_draw_funcs_destroy: (skip)
+ * @dfuncs: draw functions
  *
- * Sets cubic-to callback to the draw functions object.
+ * Deallocate the @dfuncs.
+ * Decreases the reference count on @dfuncs by one. If the result is zero, then
+ * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference().
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
-				 hb_draw_cubic_to_func_t  cubic_to)
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->cubic_to = cubic_to;
+  if (!hb_object_destroy (dfuncs)) return;
+
+#define HB_DRAW_FUNC_IMPLEMENT(name) \
+  if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name);
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+
+
+  hb_free (dfuncs);
 }
 
 /**
- * hb_draw_funcs_set_close_path_func:
- * @funcs: draw functions object
- * @close_path: close-path callback
+ * hb_draw_funcs_make_immutable:
+ * @dfuncs: draw functions
  *
- * Sets close-path callback to the draw functions object.
+ * Makes @dfuncs object immutable.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
-				   hb_draw_close_path_func_t  close_path)
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
 {
-  if (unlikely (hb_object_is_immutable (funcs))) return;
-  funcs->close_path = close_path;
-}
-
-static void
-_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
-
-static void
-_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
-		   hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-		   void *user_data HB_UNUSED) {}
-
-static void
-_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
-	       hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
-	       hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
-	       void *user_data HB_UNUSED) {}
+  if (hb_object_is_immutable (dfuncs))
+    return;
 
-static void
-_close_path_nil (void *user_data HB_UNUSED) {}
+  hb_object_make_immutable (dfuncs);
+}
 
 /**
- * hb_draw_funcs_create:
+ * hb_draw_funcs_is_immutable:
+ * @dfuncs: draw functions
  *
- * Creates a new draw callbacks object.
+ * Checks whether @dfuncs is immutable.
+ *
+ * Return value: %true if @dfuncs is immutable, %false otherwise
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_draw_funcs_t *
-hb_draw_funcs_create ()
+hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs)
 {
-  hb_draw_funcs_t *funcs;
-  if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
-    return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
-
-  funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
-  funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
-  funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
-  funcs->is_quadratic_to_set = false;
-  funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
-  funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
-  return funcs;
+  return hb_object_is_immutable (dfuncs);
 }
 
+
 /**
- * hb_draw_funcs_reference:
- * @funcs: draw functions
+ * hb_draw_move_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Add to callbacks object refcount.
+ * Perform a "move-to" draw operation.
  *
- * Returns: The same object.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
+void
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		 hb_draw_state_t *st,
+		 float to_x, float to_y)
 {
-  return hb_object_reference (funcs);
+  dfuncs->move_to (draw_data, *st,
+		   to_x, to_y);
 }
 
 /**
- * hb_draw_funcs_destroy:
- * @funcs: draw functions
+ * hb_draw_line_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Decreases refcount of callbacks object and deletes the object if it reaches
- * to zero.
+ * Perform a "line-to" draw operation.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		 hb_draw_state_t *st,
+		 float to_x, float to_y)
 {
-  if (!hb_object_destroy (funcs)) return;
-
-  hb_free (funcs);
+  dfuncs->line_to (draw_data, *st,
+		   to_x, to_y);
 }
 
 /**
- * hb_draw_funcs_make_immutable:
- * @funcs: draw functions
+ * hb_draw_quadratic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Makes funcs object immutable.
+ * Perform a "quadratic-to" draw operation.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
 void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		      hb_draw_state_t *st,
+		      float control_x, float control_y,
+		      float to_x, float to_y)
 {
-  if (hb_object_is_immutable (funcs))
-    return;
-
-  hb_object_make_immutable (funcs);
+  dfuncs->quadratic_to (draw_data, *st,
+			control_x, control_y,
+			to_x, to_y);
 }
 
 /**
- * hb_draw_funcs_is_immutable:
- * @funcs: draw functions
+ * hb_draw_cubic_to:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
  *
- * Checks whether funcs is immutable.
+ * Perform a "cubic-to" draw operation.
  *
- * Returns: If is immutable.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
+void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		  hb_draw_state_t *st,
+		  float control1_x, float control1_y,
+		  float control2_x, float control2_y,
+		  float to_x, float to_y)
 {
-  return hb_object_is_immutable (funcs);
+  dfuncs->cubic_to (draw_data, *st,
+		    control1_x, control1_y,
+		    control2_x, control2_y,
+		    to_x, to_y);
 }
 
 /**
- * hb_font_draw_glyph:
- * @font: a font object
- * @glyph: a glyph id
- * @funcs: draw callbacks object
- * @user_data: parameter you like be passed to the callbacks when are called
+ * hb_draw_close_path:
+ * @dfuncs: draw functions
+ * @draw_data: associated draw data passed by the caller
+ * @st: current draw state
  *
- * Draw a glyph.
+ * Perform a "close-path" draw operation.
  *
- * Returns: Whether the font had the glyph and the operation completed successfully.
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
-hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
-		    const hb_draw_funcs_t *funcs,
-		    void *user_data)
+void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+		    hb_draw_state_t *st)
 {
-  if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
-		glyph >= font->face->get_num_glyphs ()))
-    return false;
-
-  draw_helper_t draw_helper (funcs, user_data);
-  if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
-#ifndef HB_NO_CFF
-  if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
-  if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
-#endif
-
-  return false;
+  dfuncs->close_path (draw_data, *st);
 }
 
-#endif
+
 #endif

+ 256 - 29
thirdparty/harfbuzz/src/hb-draw.h

@@ -33,65 +33,292 @@
 
 HB_BEGIN_DECLS
 
-#ifdef HB_EXPERIMENTAL_API
-typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
-typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
-					     hb_position_t to_x, hb_position_t to_y,
-					     void *user_data);
-typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
-					 hb_position_t control2_x, hb_position_t control2_y,
-					 hb_position_t to_x, hb_position_t to_y,
-					 void *user_data);
-typedef void (*hb_draw_close_path_func_t) (void *user_data);
+
+/**
+ * hb_draw_state_t
+ * @path_open: Whether there is an open path
+ * @path_start_x: X component of the start of current path
+ * @path_start_y: Y component of the start of current path
+ * @current_x: X component of current point
+ * @current_y: Y component of current point
+ *
+ * Current drawing state.
+ *
+ * Since: 4.0.0
+ **/
+typedef struct hb_draw_state_t {
+  hb_bool_t path_open;
+
+  float path_start_x;
+  float path_start_y;
+
+  float current_x;
+  float current_y;
+
+  /*< private >*/
+  hb_var_num_t   reserved1;
+  hb_var_num_t   reserved2;
+  hb_var_num_t   reserved3;
+  hb_var_num_t   reserved4;
+  hb_var_num_t   reserved5;
+  hb_var_num_t   reserved6;
+  hb_var_num_t   reserved7;
+} hb_draw_state_t;
+
+/**
+ * HB_DRAW_STATE_DEFAULT:
+ *
+ * The default #hb_draw_state_t at the start of glyph drawing.
+ */
+#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}}
+
 
 /**
  * hb_draw_funcs_t:
  *
  * Glyph draw callbacks.
  *
- * _move_to, _line_to and _cubic_to calls are necessary to be defined but we
- * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
+ * #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and
+ * #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate
+ * #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the
+ * callback isn't defined.
  *
- * Since: EXPERIMENTAL
+ * Since: 4.0.0
  **/
+
 typedef struct hb_draw_funcs_t hb_draw_funcs_t;
 
+
+/**
+ * hb_draw_move_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+					hb_draw_state_t *st,
+					float to_x, float to_y,
+					void *user_data);
+
+/**
+ * hb_draw_line_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+					hb_draw_state_t *st,
+					float to_x, float to_y,
+					void *user_data);
+
+/**
+ * hb_draw_quadratic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @control_x: X component of control point
+ * @control_y: Y component of control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+					     hb_draw_state_t *st,
+					     float control_x, float control_y,
+					     float to_x, float to_y,
+					     void *user_data);
+
+/**
+ * hb_draw_cubic_to_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @control1_x: X component of first control point
+ * @control1_y: Y component of first control point
+ * @control2_x: X component of second control point
+ * @control2_y: Y component of second control point
+ * @to_x: X component of target point
+ * @to_y: Y component of target point
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+					 hb_draw_state_t *st,
+					 float control1_x, float control1_y,
+					 float control2_x, float control2_y,
+					 float to_x, float to_y,
+					 void *user_data);
+
+/**
+ * hb_draw_close_path_func_t:
+ * @dfuncs: draw functions object
+ * @draw_data: The data accompanying the draw functions
+ * @st: current draw state
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
+ * operation.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data,
+					   hb_draw_state_t *st,
+					   void *user_data);
+
+/**
+ * hb_draw_funcs_set_move_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): move-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets move-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
-				hb_draw_move_to_func_t  move_to);
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *dfuncs,
+				hb_draw_move_to_func_t  func,
+				void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_line_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): line-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets line-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
-				hb_draw_line_to_func_t  line_to);
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *dfuncs,
+				hb_draw_line_to_func_t  func,
+				void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_quadratic_to_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets quadratic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
-				     hb_draw_quadratic_to_func_t  quadratic_to);
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *dfuncs,
+				     hb_draw_quadratic_to_func_t  func,
+				     void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_cubic_to_func:
+ * @dfuncs: draw functions
+ * @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets cubic-to callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
-				 hb_draw_cubic_to_func_t  cubic_to);
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *dfuncs,
+				 hb_draw_cubic_to_func_t  func,
+				 void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_draw_funcs_set_close_path_func:
+ * @dfuncs: draw functions object
+ * @func: (closure user_data) (destroy destroy) (scope notified): close-path callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets close-path callback to the draw functions object.
+ *
+ * Since: 4.0.0
+ **/
 HB_EXTERN void
-hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
-				   hb_draw_close_path_func_t  close_path);
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *dfuncs,
+				   hb_draw_close_path_func_t  func,
+				   void *user_data, hb_destroy_func_t destroy);
+
 
 HB_EXTERN hb_draw_funcs_t *
 hb_draw_funcs_create (void);
 
 HB_EXTERN hb_draw_funcs_t *
-hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
+hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
 
 HB_EXTERN void
-hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
+hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
 
 HB_EXTERN void
-hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
 
 HB_EXTERN hb_bool_t
-hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
-#endif
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs);
+
+
+HB_EXTERN void
+hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		 hb_draw_state_t *st,
+		 float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		 hb_draw_state_t *st,
+		 float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		      hb_draw_state_t *st,
+		      float control_x, float control_y,
+		      float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
+		  hb_draw_state_t *st,
+		  float control1_x, float control1_y,
+		  float control2_x, float control2_y,
+		  float to_x, float to_y);
+
+HB_EXTERN void
+hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
+		    hb_draw_state_t *st);
+
 
 HB_END_DECLS
 

+ 169 - 77
thirdparty/harfbuzz/src/hb-draw.hh

@@ -27,113 +27,205 @@
 
 #include "hb.hh"
 
-#ifdef HB_EXPERIMENTAL_API
-struct hb_draw_funcs_t
-{
-  hb_object_header_t header;
 
-  hb_draw_move_to_func_t move_to;
-  hb_draw_line_to_func_t line_to;
-  hb_draw_quadratic_to_func_t quadratic_to;
-  bool is_quadratic_to_set;
-  hb_draw_cubic_to_func_t cubic_to;
-  hb_draw_close_path_func_t close_path;
-};
+/*
+ * hb_draw_funcs_t
+ */
+
+#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_DRAW_FUNC_IMPLEMENT (move_to) \
+  HB_DRAW_FUNC_IMPLEMENT (line_to) \
+  HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \
+  HB_DRAW_FUNC_IMPLEMENT (cubic_to) \
+  HB_DRAW_FUNC_IMPLEMENT (close_path) \
+  /* ^--- Add new callbacks here */
 
-struct draw_helper_t
+struct hb_draw_funcs_t
 {
-  draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
-  {
-    funcs = funcs_;
-    user_data = user_data_;
-    path_open = false;
-    path_start_x = current_x = path_start_y = current_y = 0;
-  }
-  ~draw_helper_t () { end_path (); }
+  hb_object_header_t header;
 
-  void move_to (hb_position_t x, hb_position_t y)
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } func;
+
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) void *name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } user_data;
+
+  struct {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  } destroy;
+
+  void emit_move_to (void *draw_data, hb_draw_state_t &st,
+		     float to_x, float to_y)
+  { func.move_to (this, draw_data, &st,
+		  to_x, to_y,
+		  user_data.move_to); }
+  void emit_line_to (void *draw_data, hb_draw_state_t &st,
+		     float to_x, float to_y)
+  { func.line_to (this, draw_data, &st,
+		  to_x, to_y,
+		  user_data.line_to); }
+  void emit_quadratic_to (void *draw_data, hb_draw_state_t &st,
+			  float control_x, float control_y,
+			  float to_x, float to_y)
+  { func.quadratic_to (this, draw_data, &st,
+		       control_x, control_y,
+		       to_x, to_y,
+		       user_data.quadratic_to); }
+  void emit_cubic_to (void *draw_data, hb_draw_state_t &st,
+		      float control1_x, float control1_y,
+		      float control2_x, float control2_y,
+		      float to_x, float to_y)
+  { func.cubic_to (this, draw_data, &st,
+		   control1_x, control1_y,
+		   control2_x, control2_y,
+		   to_x, to_y,
+		   user_data.cubic_to); }
+  void emit_close_path (void *draw_data, hb_draw_state_t &st)
+  { func.close_path (this, draw_data, &st,
+		     user_data.close_path); }
+
+
+  void move_to (void *draw_data, hb_draw_state_t &st,
+		float to_x, float to_y)
   {
-    if (path_open) end_path ();
-    current_x = path_start_x = x;
-    current_y = path_start_y = y;
+    if (st.path_open) close_path (draw_data, st);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
-  void line_to (hb_position_t x, hb_position_t y)
+  void line_to (void *draw_data, hb_draw_state_t &st,
+		float to_x, float to_y)
   {
-    if (equal_to_current (x, y)) return;
-    if (!path_open) start_path ();
-    funcs->line_to (x, y, user_data);
-    current_x = x;
-    current_y = y;
+    if (!st.path_open) start_path (draw_data, st);
+    emit_line_to (draw_data, st, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
   void
-  quadratic_to (hb_position_t control_x, hb_position_t control_y,
-		hb_position_t to_x, hb_position_t to_y)
+  quadratic_to (void *draw_data, hb_draw_state_t &st,
+		float control_x, float control_y,
+		float to_x, float to_y)
   {
-    if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
-      return;
-    if (!path_open) start_path ();
-    if (funcs->is_quadratic_to_set)
-      funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
-    else
-      funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
-		       roundf ((current_y + 2.f * control_y) / 3.f),
-		       roundf ((to_x + 2.f * control_x) / 3.f),
-		       roundf ((to_y + 2.f * control_y) / 3.f),
-		       to_x, to_y, user_data);
-    current_x = to_x;
-    current_y = to_y;
+    if (!st.path_open) start_path (draw_data, st);
+    emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
   void
-  cubic_to (hb_position_t control1_x, hb_position_t control1_y,
-	    hb_position_t control2_x, hb_position_t control2_y,
-	    hb_position_t to_x, hb_position_t to_y)
+  cubic_to (void *draw_data, hb_draw_state_t &st,
+	    float control1_x, float control1_y,
+	    float control2_x, float control2_y,
+	    float to_x, float to_y)
   {
-    if (equal_to_current (control1_x, control1_y) &&
-	equal_to_current (control2_x, control2_y) &&
-	equal_to_current (to_x, to_y))
-      return;
-    if (!path_open) start_path ();
-    funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
-    current_x = to_x;
-    current_y = to_y;
+    if (!st.path_open) start_path (draw_data, st);
+    emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
+    st.current_x = to_x;
+    st.current_y = to_y;
   }
 
-  void end_path ()
+  void
+  close_path (void *draw_data, hb_draw_state_t &st)
   {
-    if (path_open)
+    if (st.path_open)
     {
-      if ((path_start_x != current_x) || (path_start_y != current_y))
-	funcs->line_to (path_start_x, path_start_y, user_data);
-      funcs->close_path (user_data);
+      if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
+	emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
+      emit_close_path (draw_data, st);
     }
-    path_open = false;
-    path_start_x = current_x = path_start_y = current_y = 0;
+    st.path_open = false;
+    st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0;
   }
 
   protected:
-  bool equal_to_current (hb_position_t x, hb_position_t y)
-  { return current_x == x && current_y == y; }
 
-  void start_path ()
+  void start_path (void *draw_data, hb_draw_state_t &st)
   {
-    if (path_open) end_path ();
-    path_open = true;
-    funcs->move_to (path_start_x, path_start_y, user_data);
+    assert (!st.path_open);
+    emit_move_to (draw_data, st, st.current_x, st.current_y);
+    st.path_open = true;
+    st.path_start_x = st.current_x;
+    st.path_start_y = st.current_y;
   }
+};
+DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
 
-  hb_position_t path_start_x;
-  hb_position_t path_start_y;
+struct hb_draw_session_t
+{
+  hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
+    : slant {slant_}, not_slanted {slant == 0.f},
+      funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
+  {}
 
-  hb_position_t current_x;
-  hb_position_t current_y;
+  ~hb_draw_session_t () { close_path (); }
 
-  bool path_open;
-  const hb_draw_funcs_t *funcs;
-  void *user_data;
+  void move_to (float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->move_to (draw_data, st,
+		      to_x, to_y);
+    else
+      funcs->move_to (draw_data, st,
+		      to_x + to_y * slant, to_y);
+  }
+  void line_to (float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->line_to (draw_data, st,
+		      to_x, to_y);
+    else
+      funcs->line_to (draw_data, st,
+		      to_x + to_y * slant, to_y);
+  }
+  void
+  quadratic_to (float control_x, float control_y,
+		float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->quadratic_to (draw_data, st,
+			   control_x, control_y,
+			   to_x, to_y);
+    else
+      funcs->quadratic_to (draw_data, st,
+			   control_x + control_y * slant, control_y,
+			   to_x + to_y * slant, to_y);
+  }
+  void
+  cubic_to (float control1_x, float control1_y,
+	    float control2_x, float control2_y,
+	    float to_x, float to_y)
+  {
+    if (likely (not_slanted))
+      funcs->cubic_to (draw_data, st,
+		       control1_x, control1_y,
+		       control2_x, control2_y,
+		       to_x, to_y);
+    else
+      funcs->cubic_to (draw_data, st,
+		       control1_x + control1_y * slant, control1_y,
+		       control2_x + control2_y * slant, control2_y,
+		       to_x + to_y * slant, to_y);
+  }
+  void close_path ()
+  {
+    funcs->close_path (draw_data, st);
+  }
+
+  protected:
+  float slant;
+  bool not_slanted;
+  hb_draw_funcs_t *funcs;
+  void *draw_data;
+  hb_draw_state_t st;
 };
-#endif
 
 #endif /* HB_DRAW_HH */

+ 159 - 4
thirdparty/harfbuzz/src/hb-font.cc

@@ -29,6 +29,7 @@
 #include "hb.hh"
 
 #include "hb-font.hh"
+#include "hb-draw.hh"
 #include "hb-machinery.hh"
 
 #include "hb-ot.h"
@@ -501,6 +502,136 @@ hb_font_get_glyph_from_name_default (hb_font_t      *font,
   return font->parent->get_glyph_from_name (name, len, glyph);
 }
 
+static void
+hb_font_get_glyph_shape_nil (hb_font_t       *font HB_UNUSED,
+			     void            *font_data HB_UNUSED,
+			     hb_codepoint_t   glyph,
+			     hb_draw_funcs_t *draw_funcs,
+			     void            *draw_data,
+			     void            *user_data HB_UNUSED)
+{
+}
+
+
+typedef struct hb_font_get_glyph_shape_default_adaptor_t {
+  hb_draw_funcs_t *draw_funcs;
+  void		  *draw_data;
+  float		   x_scale;
+  float		   y_scale;
+} hb_font_get_glyph_shape_default_adaptor_t;
+
+static void
+hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
+			 void *draw_data,
+			 hb_draw_state_t *st,
+			 float to_x, float to_y,
+			 void *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+
+  adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st,
+				     x_scale * to_x, y_scale * to_y);
+}
+
+static void
+hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+			 hb_draw_state_t *st,
+			 float to_x, float to_y,
+			 void *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+
+  st->current_x *= x_scale;
+  st->current_y *= y_scale;
+
+  adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st,
+				     x_scale * to_x, y_scale * to_y);
+}
+
+static void
+hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+			      hb_draw_state_t *st,
+			      float control_x, float control_y,
+			      float to_x, float to_y,
+			      void *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+
+  st->current_x *= x_scale;
+  st->current_y *= y_scale;
+
+  adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st,
+					  x_scale * control_x, y_scale * control_y,
+					  x_scale * to_x, y_scale * to_y);
+}
+
+static void
+hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+			  hb_draw_state_t *st,
+			  float control1_x, float control1_y,
+			  float control2_x, float control2_y,
+			  float to_x, float to_y,
+			  void *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+  float x_scale = adaptor->x_scale;
+  float y_scale = adaptor->y_scale;
+
+  st->current_x *= x_scale;
+  st->current_y *= y_scale;
+
+  adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st,
+				      x_scale * control1_x, y_scale * control1_y,
+				      x_scale * control2_x, y_scale * control2_y,
+				      x_scale * to_x, y_scale * to_y);
+}
+
+static void
+hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
+			    hb_draw_state_t *st,
+			    void *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+
+  adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
+}
+
+static const hb_draw_funcs_t _hb_draw_funcs_default = {
+  HB_OBJECT_HEADER_STATIC,
+
+  {
+#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default,
+    HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_DRAW_FUNC_IMPLEMENT
+  }
+};
+
+static void
+hb_font_get_glyph_shape_default (hb_font_t       *font,
+				 void            *font_data HB_UNUSED,
+				 hb_codepoint_t   glyph,
+				 hb_draw_funcs_t *draw_funcs,
+				 void            *draw_data,
+				 void            *user_data HB_UNUSED)
+{
+  hb_font_get_glyph_shape_default_adaptor_t adaptor = {
+    draw_funcs,
+    draw_data,
+    (float) font->x_scale / (float) font->parent->x_scale,
+    (float) font->y_scale / (float) font->parent->y_scale
+  };
+
+  font->parent->get_glyph_shape (glyph,
+				 const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
+				 &adaptor);
+}
+
 DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
 {
   HB_OBJECT_HEADER_STATIC,
@@ -1168,6 +1299,26 @@ hb_font_get_glyph_from_name (hb_font_t      *font,
   return font->get_glyph_from_name (name, len, glyph);
 }
 
+/**
+ * hb_font_get_glyph_shape:
+ * @font: #hb_font_t to work upon
+ * @glyph: : The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Fetches the glyph shape that corresponds to a glyph in the specified @font.
+ * The shape is returned by way of calls to the callsbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_font_get_glyph_shape (hb_font_t *font,
+			 hb_codepoint_t glyph,
+			 hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+  font->get_glyph_shape (glyph, dfuncs, draw_data);
+}
 
 /* A bit higher-level, and with fallback */
 
@@ -1190,7 +1341,7 @@ hb_font_get_extents_for_direction (hb_font_t         *font,
 				   hb_direction_t     direction,
 				   hb_font_extents_t *extents)
 {
-  return font->get_extents_for_direction (direction, extents);
+  font->get_extents_for_direction (direction, extents);
 }
 /**
  * hb_font_get_glyph_advance_for_direction:
@@ -1215,7 +1366,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t      *font,
 					 hb_position_t  *x,
 					 hb_position_t  *y)
 {
-  return font->get_glyph_advance_for_direction (glyph, direction, x, y);
+  font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 /**
  * hb_font_get_glyph_advances_for_direction:
@@ -2044,12 +2195,16 @@ hb_font_get_ptem (hb_font_t *font)
  * @slant: synthetic slant value.
  *
  * Sets the "synthetic slant" of a font.  By default is zero.
- * Synthetic slant is the graphical skew that the renderer
- * applies to the font at rendering time.
+ * Synthetic slant is the graphical skew applied to the font
+ * at rendering time.
  *
  * HarfBuzz needs to know this value to adjust shaping results,
  * metrics, and style values to match the slanted rendering.
  *
+ * <note>Note: The glyph shape fetched via the
+ * hb_font_get_glyph_shape() is slanted to reflect this value
+ * as well.</note>
+ *
  * <note>Note: The slant value is a ratio.  For example, a
  * 20% slant would be represented as a 0.2 value.</note>
  *

+ 40 - 5
thirdparty/harfbuzz/src/hb-font.h

@@ -511,6 +511,25 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
 							 hb_codepoint_t *glyph,
 							 void *user_data);
 
+/**
+ * hb_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ *
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+						hb_codepoint_t glyph,
+						hb_draw_funcs_t *draw_funcs, void *draw_data,
+						void *user_data);
+
 
 /* func setters */
 
@@ -770,6 +789,22 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_from_name_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t.
+ *
+ * Since: 4.0.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+				    hb_font_get_glyph_shape_func_t func,
+				    void *user_data, hb_destroy_func_t destroy);
+
 /* func dispatch */
 
 HB_EXTERN hb_bool_t
@@ -850,6 +885,11 @@ hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph);
 
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+			 hb_codepoint_t glyph,
+			 hb_draw_funcs_t *dfuncs, void *draw_data);
+
 
 /* high-level funcs, with fallback */
 
@@ -1056,11 +1096,6 @@ HB_EXTERN void
 hb_font_set_var_named_instance (hb_font_t *font,
 				unsigned instance_index);
 
-#ifdef HB_EXPERIMENTAL_API
-HB_EXTERN hb_bool_t
-hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
-		    const hb_draw_funcs_t *funcs, void *user_data);
-#endif
 
 HB_END_DECLS
 

+ 15 - 1
thirdparty/harfbuzz/src/hb-font.hh

@@ -57,6 +57,7 @@
   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
   HB_FONT_FUNC_IMPLEMENT (glyph_name) \
   HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_shape) \
   /* ^--- Add new callbacks here */
 
 struct hb_font_funcs_t
@@ -140,6 +141,8 @@ struct hb_font_t
   hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
   float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
   float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
+  float em_fscalef_x (float v) { return em_fscalef (v, x_scale); }
+  float em_fscalef_y (float v) { return em_fscalef (v, y_scale); }
   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
   { return em_mult (v, dir_mult (direction)); }
 
@@ -373,6 +376,15 @@ struct hb_font_t
 					 klass->user_data.glyph_from_name);
   }
 
+  void get_glyph_shape (hb_codepoint_t glyph,
+			hb_draw_funcs_t *draw_funcs, void *draw_data)
+  {
+    klass->get.f.glyph_shape (this, user_data,
+			      glyph,
+			      draw_funcs, draw_data,
+			      klass->user_data.glyph_shape);
+  }
+
 
   /* A bit higher-level, and with fallback */
 
@@ -625,7 +637,9 @@ struct hb_font_t
   hb_position_t em_mult (int16_t v, int64_t mult)
   { return (hb_position_t) ((v * mult + 32768) >> 16); }
   hb_position_t em_scalef (float v, int scale)
-  { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
+  { return (hb_position_t) roundf (em_fscalef (v, scale)); }
+  float em_fscalef (float v, int scale)
+  { return v * scale / face->get_upem (); }
   float em_fscale (int16_t v, int scale)
   { return (float) v * scale / face->get_upem (); }
 };

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

@@ -33,12 +33,14 @@
 
 #include "hb-ft.h"
 
+#include "hb-draw.hh"
 #include "hb-font.hh"
 #include "hb-machinery.hh"
 #include "hb-cache.hh"
 
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
+#include FT_OUTLINE_H
 #include FT_TRUETYPE_TABLES_H
 
 
@@ -565,6 +567,82 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
   return true;
 }
 
+#ifndef HB_NO_DRAW
+
+static int
+_hb_ft_move_to (const FT_Vector *to,
+		hb_draw_session_t *drawing)
+{
+  drawing->move_to (to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_line_to (const FT_Vector *to,
+		hb_draw_session_t *drawing)
+{
+  drawing->line_to (to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_conic_to (const FT_Vector *control,
+		 const FT_Vector *to,
+		 hb_draw_session_t *drawing)
+{
+  drawing->quadratic_to (control->x, control->y,
+			 to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static int
+_hb_ft_cubic_to (const FT_Vector *control1,
+		 const FT_Vector *control2,
+		 const FT_Vector *to,
+		 hb_draw_session_t *drawing)
+{
+  drawing->cubic_to (control1->x, control1->y,
+		     control2->x, control2->y,
+		     to->x, to->y);
+  return FT_Err_Ok;
+}
+
+static void
+hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
+		       void *font_data,
+		       hb_codepoint_t glyph,
+		       hb_draw_funcs_t *draw_funcs, void *draw_data,
+		       void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  hb_lock_t lock (ft_font->lock);
+  FT_Face ft_face = ft_font->ft_face;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph,
+			       FT_LOAD_NO_BITMAP | ft_font->load_flags)))
+    return;
+
+  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+    return;
+
+  const FT_Outline_Funcs outline_funcs = {
+    (FT_Outline_MoveToFunc) _hb_ft_move_to,
+    (FT_Outline_LineToFunc) _hb_ft_line_to,
+    (FT_Outline_ConicToFunc) _hb_ft_conic_to,
+    (FT_Outline_CubicToFunc) _hb_ft_cubic_to,
+    0, /* shift */
+    0, /* delta */
+  };
+
+  hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
+
+  FT_Outline_Decompose (&ft_face->glyph->outline,
+			&outline_funcs,
+			&draw_session);
+}
+#endif
+
+
 static inline void free_static_ft_funcs ();
 
 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
@@ -596,6 +674,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr);
+#endif
+
     hb_font_funcs_make_immutable (funcs);
 
     hb_atexit (free_static_ft_funcs);

+ 1 - 0
thirdparty/harfbuzz/src/hb-gobject-structs.cc

@@ -90,6 +90,7 @@ hb_gobject_##name##_get_type () \
 
 HB_DEFINE_OBJECT_TYPE (buffer)
 HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (draw_funcs)
 HB_DEFINE_OBJECT_TYPE (face)
 HB_DEFINE_OBJECT_TYPE (font)
 HB_DEFINE_OBJECT_TYPE (font_funcs)

+ 4 - 0
thirdparty/harfbuzz/src/hb-gobject-structs.h

@@ -48,6 +48,10 @@ HB_EXTERN GType
 hb_gobject_buffer_get_type (void);
 #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
 
+HB_EXTERN GType
+hb_gobject_draw_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ())
+
 HB_EXTERN GType
 hb_gobject_face_get_type (void);
 #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())

+ 10 - 4
thirdparty/harfbuzz/src/hb-machinery.hh

@@ -194,7 +194,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   }
 
   const Returned * operator -> () const { return get (); }
-  const Returned & operator * () const  { return *get (); }
+  template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))>
+  const U & operator * () const  { return *get (); }
   explicit operator bool () const
   { return get_stored () != Funcs::get_null (); }
   template <typename C> operator const C * () const { return get (); }
@@ -272,14 +273,19 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
 						hb_face_lazy_loader_t<T, WheresFace>,
 						hb_face_t, WheresFace> {};
 
-template <typename T, unsigned int WheresFace>
+template <typename T, unsigned int WheresFace, bool core=false>
 struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
-						 hb_table_lazy_loader_t<T, WheresFace>,
+						 hb_table_lazy_loader_t<T, WheresFace, core>,
 						 hb_face_t, WheresFace,
 						 hb_blob_t>
 {
   static hb_blob_t *create (hb_face_t *face)
-  { return hb_sanitize_context_t ().reference_table<T> (face); }
+  {
+    auto c = hb_sanitize_context_t ();
+    if (core)
+      c.set_num_glyphs (0); // So we don't recurse ad infinitum...
+    return c.reference_table<T> (face);
+  }
   static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
 
   static const hb_blob_t *get_null ()

+ 16 - 18
thirdparty/harfbuzz/src/hb-ot-cff1-table.cc

@@ -442,13 +442,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
   return true;
 }
 
-#ifdef HB_EXPERIMENTAL_API
 struct cff1_path_param_t
 {
   cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
-		     draw_helper_t &draw_helper_, point_t *delta_)
+		     hb_draw_session_t &draw_session_, point_t *delta_)
   {
-    draw_helper = &draw_helper_;
+    draw_session = &draw_session_;
     cff = cff_;
     font = font_;
     delta = delta_;
@@ -458,14 +457,14 @@ struct cff1_path_param_t
   {
     point_t point = p;
     if (delta) point.move (*delta);
-    draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+    draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
   }
 
   void line_to (const point_t &p)
   {
     point_t point = p;
     if (delta) point.move (*delta);
-    draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+    draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
   }
 
   void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
@@ -477,15 +476,15 @@ struct cff1_path_param_t
       point2.move (*delta);
       point3.move (*delta);
     }
-    draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
-			   font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
-			   font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
+    draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
+			   font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
+			   font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
   }
 
-  void end_path () { draw_helper->end_path (); }
+  void end_path () { draw_session->close_path (); }
 
   hb_font_t *font;
-  draw_helper_t *draw_helper;
+  hb_draw_session_t *draw_session;
   point_t *delta;
 
   const OT::cff1::accelerator_t *cff;
@@ -513,7 +512,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int
 };
 
 static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
-		       draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
+		       hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
 
 struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
 {
@@ -530,14 +529,14 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa
     hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
 
     if (unlikely (!(!env.in_seac && base && accent
-		    && _get_path (param.cff, param.font, base, *param.draw_helper, true)
-		    && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
+		    && _get_path (param.cff, param.font, base, *param.draw_session, true)
+		    && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
       env.set_error ();
   }
 };
 
 bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
-		draw_helper_t &draw_helper, bool in_seac, point_t *delta)
+		hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
 {
   if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
 
@@ -546,7 +545,7 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
   const byte_str_t str = (*cff->charStrings)[glyph];
   interp.env.init (str, *cff, fd);
   interp.env.set_in_seac (in_seac);
-  cff1_path_param_t param (cff, font, draw_helper, delta);
+  cff1_path_param_t param (cff, font, draw_session, delta);
   if (unlikely (!interp.interpret (param))) return false;
 
   /* Let's end the path specially since it is called inside seac also */
@@ -555,16 +554,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
   return true;
 }
 
-bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
   return true;
 #endif
 
-  return _get_path (this, font, glyph, draw_helper);
+  return _get_path (this, font, glyph, draw_session);
 }
-#endif
 
 struct get_seac_param_t
 {

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

@@ -1347,9 +1347,7 @@ struct cff1
 
     HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
     HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
-#ifdef HB_EXPERIMENTAL_API
-    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
 
     private:
     struct gname_t

+ 10 - 12
thirdparty/harfbuzz/src/hb-ot-cff2-table.cc

@@ -143,30 +143,29 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
   return true;
 }
 
-#ifdef HB_EXPERIMENTAL_API
 struct cff2_path_param_t
 {
-  cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+  cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
   {
-    draw_helper = &draw_helper_;
+    draw_session = &draw_session_;
     font = font_;
   }
 
   void move_to (const point_t &p)
-  { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+  { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
 
   void line_to (const point_t &p)
-  { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+  { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); }
 
   void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
   {
-    draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
-			   font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
-			   font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
+    draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()),
+			   font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()),
+			   font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ()));
   }
 
   protected:
-  draw_helper_t *draw_helper;
+  hb_draw_session_t *draw_session;
   hb_font_t *font;
 };
 
@@ -193,7 +192,7 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int
 
 struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
 
-bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
 {
 #ifdef HB_NO_OT_FONT_CFF
   /* XXX Remove check when this code moves to .hh file. */
@@ -206,10 +205,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d
   cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
   const byte_str_t str = (*charStrings)[glyph];
   interp.env.init (str, *this, fd, font->coords, font->num_coords);
-  cff2_path_param_t param (font, draw_helper);
+  cff2_path_param_t param (font, draw_session);
   if (unlikely (!interp.interpret (param))) return false;
   return true;
 }
-#endif
 
 #endif

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

@@ -515,9 +515,7 @@ struct cff2
     HB_INTERNAL bool get_extents (hb_font_t *font,
 				  hb_codepoint_t glyph,
 				  hb_glyph_extents_t *extents) const;
-#ifdef HB_EXPERIMENTAL_API
-    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
-#endif
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
   };
 
   typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;

+ 15 - 0
thirdparty/harfbuzz/src/hb-ot-deprecated.h

@@ -50,6 +50,21 @@ HB_BEGIN_DECLS
  */
 #define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
 
+/* https://github.com/harfbuzz/harfbuzz/pull/3417 */
+/**
+ * HB_OT_MATH_SCRIPT:
+ *
+ * Use #HB_SCRIPT_MATH or #HB_OT_TAG_MATH_SCRIPT instead.
+ *
+ * <note>Previous versions of this documentation recommended passing
+ * #HB_OT_MATH_SCRIPT to hb_buffer_set_script() to enable math shaping, but this
+ * usage is no longer supported. Use #HB_SCRIPT_MATH instead.</note>
+ *
+ * Since: 1.3.3
+ * Deprecated: 3.4.0
+ */
+#define HB_OT_MATH_SCRIPT HB_OT_TAG_MATH_SCRIPT
+
 
 /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
 HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t

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

@@ -32,6 +32,11 @@
 #define HB_OT_FACE_TABLE_LIST_HH
 #endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
 
+#ifndef HB_OT_CORE_TABLE
+#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_CORE_TABLE_UNDEF
+#endif
+
 #ifndef HB_OT_ACCELERATOR
 #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
 #define _HB_OT_ACCELERATOR_UNDEF
@@ -46,7 +51,8 @@
 
 
 /* OpenType fundamentals. */
-HB_OT_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, maxp)
 #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
 HB_OT_ACCELERATOR (OT, cmap)
 #endif
@@ -74,6 +80,7 @@ HB_OT_TABLE (OT, VORG)
 #endif
 
 /* TrueType outlines. */
+HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs
 HB_OT_ACCELERATOR (OT, glyf)
 
 /* CFF outlines. */
@@ -138,3 +145,7 @@ HB_OT_TABLE (OT, MATH)
 #ifdef _HB_OT_ACCELERATOR_UNDEF
 #undef HB_OT_ACCELERATOR
 #endif
+
+#ifdef _HB_OT_CORE_TABLE_UNDEF
+#undef HB_OT_CORE_TABLE
+#endif

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

@@ -63,10 +63,13 @@ struct hb_ot_face_t
   hb_face_t *face; /* MUST be JUST before the lazy loaders. */
 #define HB_OT_TABLE(Namespace, Type) \
   hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
+#define HB_OT_CORE_TABLE(Namespace, Type) \
+  hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type;
 #define HB_OT_ACCELERATOR(Namespace, Type) \
   hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
 #include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
+#undef HB_OT_CORE_TABLE
 #undef HB_OT_TABLE
 };
 

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

@@ -257,6 +257,23 @@ hb_ot_get_font_v_extents (hb_font_t *font,
 }
 #endif
 
+#ifndef HB_NO_DRAW
+static void
+hb_ot_get_glyph_shape (hb_font_t *font,
+		       void *font_data HB_UNUSED,
+		       hb_codepoint_t glyph,
+		       hb_draw_funcs_t *draw_funcs, void *draw_data,
+		       void *user_data)
+{
+  hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
+  if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
+#ifndef HB_NO_CFF
+  if (font->face->table.cff1->get_path (font, glyph, draw_session)) return;
+  if (font->face->table.cff2->get_path (font, glyph, draw_session)) return;
+#endif
+}
+#endif
+
 static inline void free_static_ot_funcs ();
 
 static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
@@ -279,6 +296,10 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
 #endif
 
+#ifndef HB_NO_DRAW
+    hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr);
+#endif
+
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
 

+ 27 - 28
thirdparty/harfbuzz/src/hb-ot-glyf-table.hh

@@ -936,7 +936,7 @@ struct glyf
 	return;
       short_offset = 0 == head.indexToLocFormat;
 
-      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
+      loca_table = face->table.loca.get_blob (); // Needs no destruct!
       glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
 #ifndef HB_NO_VAR
       gvar = face->table.gvar;
@@ -951,7 +951,6 @@ struct glyf
     }
     ~accelerator_t ()
     {
-      loca_table.destroy ();
       glyf_table.destroy ();
     }
 
@@ -1152,11 +1151,10 @@ struct glyf
       return operation_count;
     }
 
-#ifdef HB_EXPERIMENTAL_API
     struct path_builder_t
     {
       hb_font_t *font;
-      draw_helper_t *draw_helper;
+      hb_draw_session_t *draw_session;
 
       struct optional_point_t
       {
@@ -1171,10 +1169,10 @@ struct glyf
 	{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
       } first_oncurve, first_offcurve, last_offcurve;
 
-      path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+      path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
       {
 	font = font_;
-	draw_helper = &draw_helper_;
+	draw_session = &draw_session_;
 	first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
       }
 
@@ -1184,10 +1182,6 @@ struct glyf
 	 * https://stackoverflow.com/a/20772557 */
       void consume_point (const contour_point_t &point)
       {
-	/* Skip empty contours */
-	if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
-	  return;
-
 	bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
 	optional_point_t p (point.x, point.y);
 	if (!first_oncurve.has_data)
@@ -1195,7 +1189,7 @@ struct glyf
 	  if (is_on_curve)
 	  {
 	    first_oncurve = p;
-	    draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+	    draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
 	  }
 	  else
 	  {
@@ -1204,7 +1198,7 @@ struct glyf
 	      optional_point_t mid = first_offcurve.lerp (p, .5f);
 	      first_oncurve = mid;
 	      last_offcurve = p;
-	      draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+	      draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
 	    }
 	    else
 	      first_offcurve = p;
@@ -1216,22 +1210,22 @@ struct glyf
 	  {
 	    if (is_on_curve)
 	    {
-	      draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-					 font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+	      draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
+					 font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
 	      last_offcurve = optional_point_t ();
 	    }
 	    else
 	    {
 	      optional_point_t mid = last_offcurve.lerp (p, .5f);
-	      draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-					 font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+	      draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
+					 font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
 	      last_offcurve = p;
 	    }
 	  }
 	  else
 	  {
 	    if (is_on_curve)
-	      draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+	      draw_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y));
 	    else
 	      last_offcurve = p;
 	  }
@@ -1242,24 +1236,30 @@ struct glyf
 	  if (first_offcurve.has_data && last_offcurve.has_data)
 	  {
 	    optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
-	    draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-				       font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+	    draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
+				       font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y));
 	    last_offcurve = optional_point_t ();
 	    /* now check the rest */
 	  }
 
 	  if (first_offcurve.has_data && first_oncurve.has_data)
-	    draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
-				       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+	    draw_session->quadratic_to (font->em_fscalef_x (first_offcurve.x), font->em_fscalef_y (first_offcurve.y),
+				       font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
 	  else if (last_offcurve.has_data && first_oncurve.has_data)
-	    draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
-				       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+	    draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y),
+				       font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
 	  else if (first_oncurve.has_data)
-	    draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+	    draw_session->line_to (font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y));
+	  else if (first_offcurve.has_data)
+	  {
+	    float x = font->em_fscalef_x (first_offcurve.x), y = font->em_fscalef_x (first_offcurve.y);
+	    draw_session->move_to (x, y);
+	    draw_session->quadratic_to (x, y, x, y);
+	  }
 
 	  /* Getting ready for the next contour */
 	  first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
-	  draw_helper->end_path ();
+	  draw_session->close_path ();
 	}
       }
       void points_end () {}
@@ -1269,9 +1269,8 @@ struct glyf
     };
 
     bool
-    get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const
-    { return get_points (font, gid, path_builder_t (font, draw_helper)); }
-#endif
+    get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
+    { return get_points (font, gid, path_builder_t (font, draw_session)); }
 
 #ifndef HB_NO_VAR
     const gvar_accelerator_t *gvar;

+ 90 - 69
thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh

@@ -28,6 +28,7 @@
 #define HB_OT_HMTX_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-maxp-table.hh"
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-var-hvar-table.hh"
 #include "hb-ot-metrics.hh"
@@ -98,12 +99,12 @@ struct hmtxvmtx
 	   hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
 		  Iterator it,
-		  unsigned num_advances)
+		  unsigned num_long_metrics)
   {
     unsigned idx = 0;
     for (auto _ : it)
     {
-      if (idx < num_advances)
+      if (idx < num_long_metrics)
       {
 	LongMetric lm;
 	lm.advance = _.first;
@@ -128,7 +129,19 @@ struct hmtxvmtx
     if (unlikely (!table_prime)) return_trace (false);
 
     accelerator_t _mtx (c->plan->source);
-    unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
+    unsigned num_long_metrics;
+    {
+      /* Determine num_long_metrics to encode. */
+      auto& plan = c->plan;
+      num_long_metrics = plan->num_output_glyphs ();
+      hb_codepoint_t old_gid = 0;
+      unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
+      while (num_long_metrics > 1 &&
+	     last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
+      {
+	num_long_metrics--;
+      }
+    }
 
     auto it =
     + hb_range (c->plan->num_output_glyphs ())
@@ -141,13 +154,13 @@ struct hmtxvmtx
 	      })
     ;
 
-    table_prime->serialize (c->serializer, it, num_advances);
+    table_prime->serialize (c->serializer, it, num_long_metrics);
 
     if (unlikely (c->serializer->in_error ()))
       return_trace (false);
 
     // Amend header num hmetrics
-    if (unlikely (!subset_update_header (c->plan, num_advances)))
+    if (unlikely (!subset_update_header (c->plan, num_long_metrics)))
       return_trace (false);
 
     return_trace (true);
@@ -160,35 +173,46 @@ struct hmtxvmtx
     accelerator_t (hb_face_t *face,
 		   unsigned int default_advance_ = 0)
     {
+      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+
       default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
 
-      num_advances = T::is_horizontal ?
-		     face->table.hhea->numberOfLongMetrics :
+      /* Populate count variables and sort them out as we go */
+
+      unsigned int len = table.get_length ();
+      if (len & 1)
+        len--;
+
+      num_long_metrics = T::is_horizontal ?
+			 face->table.hhea->numberOfLongMetrics :
 #ifndef HB_NO_VERTICAL
-		     face->table.vhea->numberOfLongMetrics
+			 face->table.vhea->numberOfLongMetrics
 #else
-		     0
+			 0
 #endif
-		     ;
+			 ;
+      if (unlikely (num_long_metrics * 4 > len))
+	num_long_metrics = len / 4;
+      len -= num_long_metrics * 4;
 
-      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+      num_bearings = face->table.maxp->get_num_glyphs ();
 
-      /* Cap num_metrics() and num_advances() based on table length. */
-      unsigned int len = table.get_length ();
-      if (unlikely (num_advances * 4 > len))
-	num_advances = len / 4;
-      num_metrics = num_advances + (len - 4 * num_advances) / 2;
+      if (unlikely (num_bearings < num_long_metrics))
+        num_bearings = num_long_metrics;
+      if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
+        num_bearings = num_long_metrics + len / 2;
+      len -= (num_bearings - num_long_metrics) * 2;
 
-      /* We MUST set num_metrics to zero if num_advances is zero.
+      /* We MUST set num_bearings to zero if num_long_metrics is zero.
        * Our get_advance() depends on that. */
-      if (unlikely (!num_advances))
-      {
-	num_metrics = num_advances = 0;
-	table.destroy ();
-	table = hb_blob_get_empty ();
-      }
+      if (unlikely (!num_long_metrics))
+	num_bearings = num_long_metrics = 0;
 
-      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+      num_advances = num_bearings + len / 2;
+      num_glyphs = face->get_num_glyphs ();
+      if (num_glyphs < num_advances)
+        num_glyphs = num_advances;
     }
     ~accelerator_t ()
     {
@@ -198,14 +222,14 @@ struct hmtxvmtx
 
     int get_side_bearing (hb_codepoint_t glyph) const
     {
-      if (glyph < num_advances)
+      if (glyph < num_long_metrics)
 	return table->longMetricZ[glyph].sb;
 
-      if (unlikely (glyph >= num_metrics))
+      if (unlikely (glyph >= num_bearings))
 	return 0;
 
-      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
-      return bearings[glyph - num_advances];
+      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+      return bearings[glyph - num_long_metrics];
     }
 
     int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
@@ -213,7 +237,7 @@ struct hmtxvmtx
       int side_bearing = get_side_bearing (glyph);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+      if (unlikely (glyph >= num_bearings) || !font->num_coords)
 	return side_bearing;
 
       if (var_table.get_length ())
@@ -227,18 +251,35 @@ struct hmtxvmtx
 
     unsigned int get_advance (hb_codepoint_t glyph) const
     {
-      if (unlikely (glyph >= num_metrics))
-      {
-	/* If num_metrics is zero, it means we don't have the metrics table
-	 * for this direction: return default advance.  Otherwise, it means that the
-	 * glyph index is out of bound: return zero. */
-	if (num_metrics)
-	  return 0;
-	else
-	  return default_advance;
-      }
+      /* OpenType case. */
+      if (glyph < num_bearings)
+	return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
+
+      /* If num_advances is zero, it means we don't have the metrics table
+       * for this direction: return default advance.  Otherwise, there's a
+       * well-defined answer. */
+      if (unlikely (!num_advances))
+	return default_advance;
 
-      return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
+#ifdef HB_NO_BORING_EXPANSION
+      return 0;
+#endif
+
+      if (unlikely (glyph >= num_glyphs))
+        return 0;
+
+      /* num_bearings <= glyph < num_glyphs;
+       * num_bearings <= num_advances */
+
+      /* TODO Optimize */
+
+      if (num_bearings == num_advances)
+        return get_advance (num_bearings - 1);
+
+      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+      const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
+
+      return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
     }
 
     unsigned int get_advance (hb_codepoint_t  glyph,
@@ -247,7 +288,7 @@ struct hmtxvmtx
       unsigned int advance = get_advance (glyph);
 
 #ifndef HB_NO_VAR
-      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+      if (unlikely (glyph >= num_bearings) || !font->num_coords)
 	return advance;
 
       if (var_table.get_length ())
@@ -259,35 +300,13 @@ struct hmtxvmtx
 #endif
     }
 
-    unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
-    {
-      unsigned int num_advances = plan->num_output_glyphs ();
-      unsigned int last_advance = _advance_for_new_gid (plan,
-							num_advances - 1);
-      while (num_advances > 1 &&
-	     last_advance == _advance_for_new_gid (plan,
-						   num_advances - 2))
-      {
-	num_advances--;
-      }
-
-      return num_advances;
-    }
-
-    private:
-    unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
-				       hb_codepoint_t new_gid) const
-    {
-      hb_codepoint_t old_gid;
-      if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
-	return 0;
-
-      return get_advance (old_gid);
-    }
-
     protected:
-    unsigned int num_metrics;
-    unsigned int num_advances;
+    // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
+    unsigned num_long_metrics;
+    unsigned num_bearings;
+    unsigned num_advances;
+    unsigned num_glyphs;
+
     unsigned int default_advance;
 
     private:
@@ -319,6 +338,8 @@ struct hmtxvmtx
 				 * the end. This allows a monospaced
 				 * font to vary the side bearing
 				 * values for each glyph. */
+/*UnsizedArrayOf<UFWORD>advancesX;*/
+				/* TODO Document. */
   public:
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };

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

@@ -361,6 +361,13 @@ hb_ot_layout_get_attach_points (hb_face_t      *face,
  * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
  * table of the font. The list returned will begin at the offset provided.
  *
+ * Note that a ligature that is formed from n characters will have n-1
+ * caret positions. The first character is not represented in the array,
+ * since its caret position is the glyph position.
+ *
+ * The positions returned by this function are 'unshaped', and will have to
+ * be fixed up for kerning that may be applied to the ligature glyph.
+ *
  * Return value: Total number of ligature caret positions for @glyph.
  *
  **/
@@ -1959,6 +1966,77 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
 }
 
 #ifndef HB_NO_BASE
+/**
+ * hb_ot_layout_get_horizontal_baseline_tag_for_script:
+ * @script: a script tag.
+ *
+ * Fetches the dominant horizontal baseline tag used by @script.
+ *
+ * Return value: dominant baseline tag for the @script.
+ *
+ * Since: 4.0.0
+ **/
+hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)
+{
+  /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */
+  switch ((int) script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_BENGALI:
+    case HB_SCRIPT_DEVANAGARI:
+    case HB_SCRIPT_GUJARATI:
+    case HB_SCRIPT_GURMUKHI:
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_LIMBU:
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_SYLOTI_NAGRI:
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_PHAGS_PA:
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_MEETEI_MAYEK:
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_SHARADA:
+    case HB_SCRIPT_TAKRI:
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MODI:
+    case HB_SCRIPT_SIDDHAM:
+    case HB_SCRIPT_TIRHUTA:
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_MARCHEN:
+    case HB_SCRIPT_NEWA:
+    /* Unicode-10.0 additions */
+    case HB_SCRIPT_SOYOMBO:
+    case HB_SCRIPT_ZANABAZAR_SQUARE:
+    /* Unicode-11.0 additions */
+    case HB_SCRIPT_DOGRA:
+    case HB_SCRIPT_GUNJALA_GONDI:
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_NANDINAGARI:
+      return HB_OT_LAYOUT_BASELINE_TAG_HANGING;
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+    case HB_SCRIPT_HAN:
+    case HB_SCRIPT_HIRAGANA:
+    case HB_SCRIPT_KATAKANA:
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_BOPOMOFO:
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_TANGUT:
+    /* Unicode-10.0 additions */
+    case HB_SCRIPT_NUSHU:
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_KHITAN_SMALL_SCRIPT:
+      return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT;
+
+    default:
+      return HB_OT_LAYOUT_BASELINE_TAG_ROMAN;
+  }
+}
+
 /**
  * hb_ot_layout_get_baseline:
  * @font: a font
@@ -1966,7 +2044,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
  * @direction: text direction.
  * @script_tag:  script tag.
  * @language_tag: language tag, currently unused.
- * @coord: (out): baseline value if found.
+ * @coord: (out) (nullable): baseline value if found.
  *
  * Fetches a baseline value from the face.
  *
@@ -1989,6 +2067,227 @@ hb_ot_layout_get_baseline (hb_font_t                   *font,
 
   return result;
 }
+
+/**
+ * hb_ot_layout_get_baseline_with_fallback:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script_tag:  script tag.
+ * @language_tag: language tag, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
+					 hb_ot_layout_baseline_tag_t  baseline_tag,
+					 hb_direction_t               direction,
+					 hb_tag_t                     script_tag,
+					 hb_tag_t                     language_tag,
+					 hb_position_t               *coord /* OUT */)
+{
+  if (hb_ot_layout_get_baseline (font,
+                                 baseline_tag,
+                                 direction,
+                                 script_tag,
+                                 language_tag,
+                                 coord))
+    return;
+
+  /* Synthesize missing baselines.
+   * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts
+   */
+  switch (baseline_tag)
+  {
+  case HB_OT_LAYOUT_BASELINE_TAG_ROMAN:
+    *coord = 0; // FIXME origin ?
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_MATH:
+    {
+      hb_codepoint_t glyph;
+      hb_glyph_extents_t extents;
+      if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
+          (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||
+           hb_font_get_nominal_glyph (font, '-', &glyph)) &&
+          hb_font_get_glyph_extents (font, glyph, &extents))
+      {
+        *coord = extents.y_bearing + extents.height / 2;
+      }
+      else
+      {
+        hb_position_t x_height = 0;
+        hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);
+        *coord = x_height / 2;
+      }
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT:
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT:
+    {
+      hb_position_t embox_top, embox_bottom;
+
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &embox_top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &embox_bottom);
+
+      if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)
+        *coord = embox_top + (embox_bottom - embox_top) / 10;
+      else
+        *coord = embox_bottom + (embox_top - embox_bottom) / 10;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:
+    if (hb_ot_layout_get_baseline (font,
+                                   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                   direction,
+                                   script_tag,
+                                   language_tag,
+                                   coord))
+      *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+    else
+    {
+      hb_font_extents_t font_extents;
+      hb_font_get_extents_for_direction (font, direction, &font_extents);
+      *coord = font_extents.ascender;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:
+    if (hb_ot_layout_get_baseline (font,
+                                   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                   direction,
+                                   script_tag,
+                                   language_tag,
+                                   coord))
+      *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;
+    else
+    {
+      hb_font_extents_t font_extents;
+      hb_font_get_extents_for_direction (font, direction, &font_extents);
+      *coord = font_extents.descender;
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_HANGING:
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    {
+      hb_codepoint_t ch;
+      hb_codepoint_t glyph;
+      hb_glyph_extents_t extents;
+
+      /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */
+      switch ((int) script_tag)
+      {
+      /* Unicode-1.1 additions */
+      case HB_SCRIPT_BENGALI:          ch = 0x0995u; break;
+      case HB_SCRIPT_DEVANAGARI:       ch = 0x0915u; break;
+      case HB_SCRIPT_GUJARATI:         ch = 0x0a95u; break;
+      case HB_SCRIPT_GURMUKHI:         ch = 0x0a15u; break;
+      /* Unicode-2.0 additions */
+      case HB_SCRIPT_TIBETAN:          ch = 0x0f40u; break;
+      /* Unicode-4.0 additions */
+      case HB_SCRIPT_LIMBU:            ch = 0x1901u; break;
+      /* Unicode-4.1 additions */
+      case HB_SCRIPT_SYLOTI_NAGRI:     ch = 0xa807u; break;
+      /* Unicode-5.0 additions */
+      case HB_SCRIPT_PHAGS_PA:         ch = 0xa840u; break;
+      /* Unicode-5.2 additions */
+      case HB_SCRIPT_MEETEI_MAYEK:     ch = 0xabc0u; break;
+      /* Unicode-6.1 additions */
+      case HB_SCRIPT_SHARADA:          ch = 0x11191u; break;
+      case HB_SCRIPT_TAKRI:            ch = 0x1168cu; break;
+      /* Unicode-7.0 additions */
+      case HB_SCRIPT_MODI:             ch = 0x1160eu;break;
+      case HB_SCRIPT_SIDDHAM:          ch = 0x11590u; break;
+      case HB_SCRIPT_TIRHUTA:          ch = 0x1148fu; break;
+      /* Unicode-9.0 additions */
+      case HB_SCRIPT_MARCHEN:          ch = 0x11c72u; break;
+      case HB_SCRIPT_NEWA:             ch = 0x1140eu; break;
+      /* Unicode-10.0 additions */
+      case HB_SCRIPT_SOYOMBO:          ch = 0x11a5cu; break;
+      case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break;
+      /* Unicode-11.0 additions */
+      case HB_SCRIPT_DOGRA:            ch = 0x1180au; break;
+      case HB_SCRIPT_GUNJALA_GONDI:    ch = 0x11d6cu; break;
+      /* Unicode-12.0 additions */
+      case HB_SCRIPT_NANDINAGARI:      ch = 0x119b0u; break;
+      default:                         ch = 0;        break;
+      }
+
+      if (ch &&
+          hb_font_get_nominal_glyph (font, ch, &glyph) &&
+          hb_font_get_glyph_extents (font, glyph, &extents))
+        *coord = extents.y_bearing;
+      else
+        *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin
+    }
+    else
+      *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL:
+    {
+      hb_position_t top, bottom;
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &bottom);
+      *coord = (top + bottom) / 2;
+
+    }
+    break;
+
+  case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL:
+    {
+      hb_position_t top, bottom;
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &top);
+      hb_ot_layout_get_baseline_with_fallback (font,
+                                               HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,
+                                               direction,
+                                               script_tag,
+                                               language_tag,
+                                               &bottom);
+      *coord = (top + bottom) / 2;
+
+    }
+    break;
+
+  case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE:
+  default:
+    *coord = 0;
+    break;
+  }
+}
+
 #endif
 
 

+ 15 - 47
thirdparty/harfbuzz/src/hb-ot-layout.h

@@ -332,31 +332,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_set_t     *glyphs_after,  /* OUT.  May be NULL */
 				    hb_set_t     *glyphs_output  /* OUT.  May be NULL */);
 
-#ifdef HB_NOT_IMPLEMENTED
-typedef struct
-{
-  const hb_codepoint_t *before,
-  unsigned int          before_length,
-  const hb_codepoint_t *input,
-  unsigned int          input_length,
-  const hb_codepoint_t *after,
-  unsigned int          after_length,
-} hb_ot_layout_glyph_sequence_t;
-
-typedef hb_bool_t
-(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t    *font,
-				       hb_tag_t      table_tag,
-				       unsigned int  lookup_index,
-				       const hb_ot_layout_glyph_sequence_t *sequence,
-				       void         *user_data);
-
-HB_EXTERN void
-Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
-					 hb_tag_t      table_tag,
-					 unsigned int  lookup_index,
-					 hb_ot_layout_glyph_sequence_func_t callback,
-					 void         *user_data);
-#endif
 
 /* Variations support */
 
@@ -411,19 +386,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
 					 hb_set_t       *glyphs);
 
 
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
-				unsigned int          lookup_index,
-				const hb_ot_layout_glyph_sequence_t *sequence,
-				unsigned int          out_size,
-				hb_codepoint_t       *glyphs_out,   /* OUT */
-				unsigned int         *clusters_out, /* OUT */
-				unsigned int         *out_length    /* OUT */);
-#endif
-
-
 /*
  * GPOS
  */
@@ -431,15 +393,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face);
 
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_position (hb_font_t            *font,
-			      unsigned int          lookup_index,
-			      const hb_ot_layout_glyph_sequence_t *sequence,
-			      hb_glyph_position_t  *positions /* IN / OUT */);
-#endif
-
 /* Optical 'size' feature info.  Returns true if found.
  * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
 HB_EXTERN hb_bool_t
@@ -487,9 +440,11 @@ hb_ot_layout_feature_get_characters (hb_face_t      *face,
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
  * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0
  * if the direction is horizontal or vertical, respectively.
  * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
  * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
@@ -503,14 +458,19 @@ typedef enum {
   HB_OT_LAYOUT_BASELINE_TAG_HANGING			= HB_TAG ('h','a','n','g'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT	= HB_TAG ('i','c','f','b'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT	= HB_TAG ('i','c','f','t'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL		= HB_TAG ('I','c','f','c'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT	= HB_TAG ('i','d','e','o'),
   HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT	= HB_TAG ('i','d','t','p'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL		= HB_TAG ('I','d','c','e'),
   HB_OT_LAYOUT_BASELINE_TAG_MATH			= HB_TAG ('m','a','t','h'),
 
   /*< private >*/
   _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_layout_baseline_tag_t;
 
+HB_EXTERN hb_ot_layout_baseline_tag_t
+hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script);
+
 HB_EXTERN hb_bool_t
 hb_ot_layout_get_baseline (hb_font_t                   *font,
 			   hb_ot_layout_baseline_tag_t  baseline_tag,
@@ -519,6 +479,14 @@ hb_ot_layout_get_baseline (hb_font_t                   *font,
 			   hb_tag_t                     language_tag,
 			   hb_position_t               *coord        /* OUT.  May be NULL. */);
 
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,
+					 hb_ot_layout_baseline_tag_t  baseline_tag,
+					 hb_direction_t               direction,
+					 hb_tag_t                     script_tag,
+					 hb_tag_t                     language_tag,
+					 hb_position_t               *coord        /* OUT */);
+
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */

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

@@ -369,6 +369,37 @@ struct MathKern
     return kernValue[i].get_x_value (font, this);
   }
 
+  unsigned int get_entries (unsigned int start_offset,
+			    unsigned int *entries_count, /* IN/OUT */
+			    hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+			    hb_font_t *font) const
+  {
+    const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
+    const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
+    const unsigned int entriesCount = heightCount + 1;
+
+    if (entries_count)
+    {
+      unsigned int start = hb_min (start_offset, entriesCount);
+      unsigned int end = hb_min (start + *entries_count, entriesCount);
+      *entries_count = end - start;
+
+      for (unsigned int i = 0; i < *entries_count; i++) {
+	unsigned int j = start + i;
+
+	hb_position_t max_height;
+	if (j == heightCount) {
+	  max_height = INT32_MAX;
+	} else {
+	  max_height = correctionHeight[j].get_y_value (font, this);
+	}
+
+	kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
+      }
+    }
+    return entriesCount;
+  }
+
   protected:
   HBUINT16	heightCount;
   UnsizedArrayOf<MathValueRecord>
@@ -423,6 +454,24 @@ struct MathKernInfoRecord
     return (base+mathKern[idx]).get_value (correction_height, font);
   }
 
+  unsigned int get_kernings (hb_ot_math_kern_t kern,
+			     unsigned int start_offset,
+			     unsigned int *entries_count, /* IN/OUT */
+			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+			     hb_font_t *font,
+			     const void *base) const
+  {
+    unsigned int idx = kern;
+    if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
+      if (entries_count) *entries_count = 0;
+      return 0;
+    }
+    return (base+mathKern[idx]).get_entries (start_offset,
+					     entries_count,
+					     kern_entries,
+					     font);
+  }
+
   protected:
   /* Offset to MathKern table for each corner -
    * from the beginning of MathKernInfo table.  May be NULL. */
@@ -473,6 +522,22 @@ struct MathKernInfo
     return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
   }
 
+  unsigned int get_kernings (hb_codepoint_t glyph,
+			     hb_ot_math_kern_t kern,
+			     unsigned int start_offset,
+			     unsigned int *entries_count, /* IN/OUT */
+			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+			     hb_font_t *font) const
+  {
+    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+    return mathKernInfoRecords[index].get_kernings (kern,
+						    start_offset,
+						    entries_count,
+						    kern_entries,
+						    font,
+						    this);
+  }
+
   protected:
   Offset16To<Coverage>
 		mathKernCoverage;
@@ -545,6 +610,19 @@ struct MathGlyphInfo
 			     hb_font_t *font) const
   { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
 
+  hb_position_t get_kernings (hb_codepoint_t glyph,
+			      hb_ot_math_kern_t kern,
+			      unsigned int start_offset,
+			      unsigned int *entries_count, /* IN/OUT */
+			      hb_ot_math_kern_entry_t *kern_entries, /* OUT */
+			      hb_font_t *font) const
+  { return (this+mathKernInfo).get_kernings (glyph,
+					     kern,
+					     start_offset,
+					     entries_count,
+					     kern_entries,
+					     font); }
+
   protected:
   /* Offset to MathItalicsCorrectionInfo table -
    * from the beginning of MathGlyphInfo table. */

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

@@ -184,6 +184,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
 							       font);
 }
 
+/**
+ * hb_ot_math_get_glyph_kernings:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the kernings
+ * @kern: The #hb_ot_math_kern_t from which to retrieve the kernings
+ * @start_offset: offset of the first kern entry to retrieve
+ * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return;
+ *                                     Output = the actual number of kern entries returned
+ * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned
+ *
+ * Fetches the raw MathKern (cut-in) data for the specified font, glyph index,
+ * and @kern. The corresponding list of kern values and correction heights is
+ * returned as a list of #hb_ot_math_kern_entry_t structs.
+ *
+ * See also #hb_ot_math_get_glyph_kerning, which handles selecting the
+ * appropriate kern value for a given correction height.
+ *
+ * <note>For a glyph with @n defined kern values (where @n > 0), there are only
+ * @n−1 defined correction heights, as each correction height defines a boundary
+ * past which the next kern value should be selected. Therefore, only the
+ * #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t
+ * actually comes from the font; its corresponding
+ * #hb_ot_math_kern_entry_t.max_correction_height is always set to
+ * <code>INT32_MAX</code>.</note>
+ *
+ * Return value: the total number of kern values available or zero
+ *
+ * Since: 3.4.0
+ **/
+unsigned int
+hb_ot_math_get_glyph_kernings (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_ot_math_kern_t kern,
+			       unsigned int start_offset,
+			       unsigned int *entries_count, /* IN/OUT */
+			       hb_ot_math_kern_entry_t *kern_entries /* OUT */)
+{
+  return font->face->table.MATH->get_glyph_info().get_kernings (glyph,
+								kern,
+								start_offset,
+								entries_count,
+								kern_entries,
+								font);
+}
+
 /**
  * hb_ot_math_get_glyph_variants:
  * @font: #hb_font_t to work upon

+ 31 - 5
thirdparty/harfbuzz/src/hb-ot-math.h

@@ -50,14 +50,18 @@ HB_BEGIN_DECLS
 #define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
 
 /**
- * HB_OT_MATH_SCRIPT:
+ * HB_OT_TAG_MATH_SCRIPT:
  *
- * OpenType script tag for math shaping, for use with
- * Use with hb_buffer_set_script().
+ * OpenType script tag, `math`, for features specific to math shaping.
  *
- * Since: 1.3.3
+ * <note>#HB_OT_TAG_MATH_SCRIPT is not a valid #hb_script_t and should only be
+ * used with functions that accept raw OpenType script tags, such as
+ * #hb_ot_layout_collect_features. In other cases, #HB_SCRIPT_MATH should be
+ * used instead.</note>
+ *
+ * Since: 3.4.0
  */
-#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
+#define HB_OT_TAG_MATH_SCRIPT HB_TAG('m','a','t','h')
 
 /* Types */
 
@@ -204,6 +208,20 @@ typedef enum {
   HB_OT_MATH_KERN_BOTTOM_LEFT = 3
 } hb_ot_math_kern_t;
 
+/**
+ * hb_ot_math_kern_entry_t:
+ * @max_correction_height: The maximum height at which this entry should be used
+ * @kern_value: The kern value of the entry
+ *
+ * Data type to hold math kerning (cut-in) information for a glyph.
+ *
+ * Since: 3.4.0
+ */
+typedef struct {
+  hb_position_t max_correction_height;
+  hb_position_t kern_value;
+} hb_ot_math_kern_entry_t;
+
 /**
  * hb_ot_math_glyph_variant_t:
  * @glyph: The glyph index of the variant
@@ -280,6 +298,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font,
 			      hb_ot_math_kern_t kern,
 			      hb_position_t correction_height);
 
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_kernings (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_ot_math_kern_t kern,
+			       unsigned int start_offset,
+			       unsigned int *entries_count, /* IN/OUT */
+			       hb_ot_math_kern_entry_t *kern_entries /* OUT */);
+
 HB_EXTERN unsigned int
 hb_ot_math_get_glyph_variants (hb_font_t *font,
 			       hb_codepoint_t glyph,

+ 139 - 0
thirdparty/harfbuzz/src/hb-ot-metrics.cc

@@ -238,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t           *font,
   }
 }
 
+/**
+ * hb_ot_metrics_get_position_with_fallback:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ * @position: (out) (optional): result of metrics value from the font.
+ *
+ * Fetches metrics value corresponding to @metrics_tag from @font,
+ * and synthesizes a value if it the value is missing in the font.
+ *
+ * Since: 4.0.0
+ **/
+void
+hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
+					  hb_ot_metrics_tag_t  metrics_tag,
+					  hb_position_t       *position     /* OUT */)
+{
+  hb_font_extents_t font_extents;
+  hb_codepoint_t glyph;
+  hb_glyph_extents_t extents;
+
+  if (hb_ot_metrics_get_position (font, metrics_tag, position))
+    {
+      if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE &&
+           metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) ||
+          *position != 0)
+        return;
+    }
+
+  switch (metrics_tag)
+  {
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.descender;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.ascender;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
+    *position = font_extents.line_gap;
+    break;
+
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:
+    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
+    *position = font_extents.line_gap;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:
+    *position = 1;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_X_HEIGHT:
+    if (hb_font_get_nominal_glyph (font, 'o', &glyph) &&
+        hb_font_get_glyph_extents (font, glyph, &extents))
+      *position = extents.height + 2 * extents.y_bearing;
+    else
+      *position = font->y_scale / 2;
+    break;
+
+  case HB_OT_METRICS_TAG_CAP_HEIGHT:
+    if (hb_font_get_nominal_glyph (font, 'O', &glyph) &&
+        hb_font_get_glyph_extents (font, glyph, &extents))
+      *position = extents.height + 2 * extents.y_bearing;
+    else
+      *position = font->y_scale * 2 / 3;
+    break;
+
+  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:
+  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:
+    *position = font->y_scale / 18;
+    break;
+
+  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:
+    {
+      hb_position_t ascender;
+      hb_ot_metrics_get_position_with_fallback (font,
+                                                HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+                                                &ascender);
+      *position = ascender / 2;
+    }
+    break;
+
+  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:
+    *position = - font->y_scale / 18;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:
+    *position = font->x_scale * 10 / 12;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:
+    *position = font->y_scale * 10 / 12;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:
+    *position = 0;
+    break;
+
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:
+    *position = font->y_scale / 5;
+    break;
+
+  case _HB_OT_METRICS_TAG_MAX_VALUE:
+  default:
+    *position = 0;
+    break;
+  }
+}
+
 #ifndef HB_NO_VAR
 /**
  * hb_ot_metrics_get_variation:

+ 5 - 0
thirdparty/harfbuzz/src/hb-ot-metrics.h

@@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t           *font,
 			    hb_ot_metrics_tag_t  metrics_tag,
 			    hb_position_t       *position     /* OUT.  May be NULL. */);
 
+HB_EXTERN void
+hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
+					  hb_ot_metrics_tag_t  metrics_tag,
+					  hb_position_t       *position     /* OUT */);
+
 HB_EXTERN float
 hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
 

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-name.cc

@@ -52,7 +52,7 @@
  * array is owned by the @face and should not be modified.  It can be
  * used as long as @face is alive.
  *
- * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries.
+ * Returns: (transfer none) (array length=num_entries): Array of available name entries.
  * Since: 2.1.0
  **/
 const hb_ot_name_entry_t *

+ 5 - 0
thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc

@@ -635,6 +635,11 @@ modifier_combining_marks[] =
   0x06E3u, /* ARABIC SMALL LOW SEEN */
   0x06E7u, /* ARABIC SMALL HIGH YEH */
   0x06E8u, /* ARABIC SMALL HIGH NOON */
+  0x08CAu, /* ARABIC SMALL HIGH FARSI YEH */
+  0x08CBu, /* ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW */
+  0x08CDu, /* ARABIC SMALL HIGH ZAH */
+  0x08CEu, /* ARABIC LARGE ROUND DOT ABOVE */
+  0x08CFu, /* ARABIC LARGE ROUND DOT BELOW */
   0x08D3u, /* ARABIC SMALL LOW WAW */
   0x08F3u, /* ARABIC SMALL HIGH WAW */
 };

+ 3 - 1
thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh

@@ -385,7 +385,9 @@ struct machine_index_t :
 			  typename Iter::item_t>
 {
   machine_index_t (const Iter& it) : it (it) {}
-  machine_index_t (const machine_index_t& o) : it (o.it) {}
+  machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
+								       typename Iter::item_t> (),
+					       it (o.it) {}
 
   static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
   static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;

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

@@ -497,14 +497,14 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
 #endif
 
 #ifndef HB_DISABLE_DEPRECATED
-  if (!buffer->message (font, "start fallback kern"))
-    return;
-
   if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
       !font->has_glyph_h_kerning_func () :
       !font->has_glyph_v_kerning_func ())
     return;
 
+  if (!buffer->message (font, "start fallback kern"))
+    return;
+
   bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
   if (reverse)

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

@@ -41,6 +41,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
   switch ((hb_tag_t) script)
   {
     case HB_SCRIPT_INVALID:		return HB_OT_TAG_DEFAULT_SCRIPT;
+    case HB_SCRIPT_MATH:		return HB_OT_TAG_MATH_SCRIPT;
 
     /* KATAKANA and HIRAGANA both map to 'kana' */
     case HB_SCRIPT_HIRAGANA:		return HB_TAG('k','a','n','a');
@@ -63,6 +64,8 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
 {
   if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
     return HB_SCRIPT_INVALID;
+  if (unlikely (tag == HB_OT_TAG_MATH_SCRIPT))
+    return HB_SCRIPT_MATH;
 
   /* This side of the conversion is fully algorithmic. */
 

+ 18 - 0
thirdparty/harfbuzz/src/hb-shape.cc

@@ -126,6 +126,13 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
+  hb_buffer_t *text_buffer = nullptr;
+  if (buffer->flags & HB_BUFFER_FLAG_VERIFY)
+  {
+    text_buffer = hb_buffer_create ();
+    hb_buffer_append (text_buffer, buffer, 0, -1);
+  }
+
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
 							      features, num_features,
 							      font->coords, font->num_coords,
@@ -133,6 +140,17 @@ hb_shape_full (hb_font_t          *font,
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
 
+  if (text_buffer)
+  {
+    if (res && !buffer->verify (text_buffer,
+				font,
+				features,
+				num_features,
+				shaper_list))
+      res = false;
+    hb_buffer_destroy (text_buffer);
+  }
+
   return res;
 }
 

+ 31 - 6
thirdparty/harfbuzz/src/hb-static.cc

@@ -33,6 +33,7 @@
 #include "hb-aat-layout-feat-table.hh"
 #include "hb-ot-layout-common.hh"
 #include "hb-ot-cmap-table.hh"
+#include "hb-ot-glyf-table.hh"
 #include "hb-ot-head-table.hh"
 #include "hb-ot-maxp-table.hh"
 
@@ -55,17 +56,41 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
 
 /* hb_face_t */
 
+static inline unsigned
+load_num_glyphs_from_loca (const hb_face_t *face)
+{
+  unsigned ret = 0;
+
+  unsigned indexToLocFormat = face->table.head->indexToLocFormat;
+
+  if (indexToLocFormat <= 1)
+  {
+    bool short_offset = 0 == indexToLocFormat;
+    hb_blob_t *loca_blob = face->table.loca.get_blob ();
+    ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1;
+  }
+
+  return ret;
+}
+
+static inline unsigned
+load_num_glyphs_from_maxp (const hb_face_t *face)
+{
+  return face->table.maxp->get_num_glyphs ();
+}
+
 unsigned int
 hb_face_t::load_num_glyphs () const
 {
-  hb_sanitize_context_t c = hb_sanitize_context_t ();
-  c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
-  hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
-  const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
+  unsigned ret = 0;
+
+#ifndef HB_NO_BORING_EXPANSION
+  ret = hb_max (ret, load_num_glyphs_from_loca (this));
+#endif
+
+  ret = hb_max (ret, load_num_glyphs_from_maxp (this));
 
-  unsigned int ret = maxp_table->get_num_glyphs ();
   num_glyphs.set_relaxed (ret);
-  hb_blob_destroy (maxp_blob);
   return ret;
 }
 

+ 3 - 4
thirdparty/harfbuzz/src/hb-style.cc

@@ -46,13 +46,13 @@
 static inline float
 _hb_angle_to_ratio (float a)
 {
-  return tanf (a * float (M_PI / 180.));
+  return tanf (a * float (-M_PI / 180.));
 }
 
 static inline float
 _hb_ratio_to_angle (float r)
 {
-  return atanf (r) * float (180. / M_PI);
+  return atanf (r) * float (-180. / M_PI);
 }
 
 /**
@@ -72,8 +72,7 @@ float
 hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag)
 {
   if (unlikely (style_tag == HB_STYLE_TAG_SLANT_RATIO))
-    return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE))
-	 + font->slant;
+    return _hb_angle_to_ratio (hb_style_get_value (font, HB_STYLE_TAG_SLANT_ANGLE));
 
   hb_face_t *face = font->face;
 

+ 3 - 1
thirdparty/harfbuzz/src/hb-style.h

@@ -43,8 +43,10 @@ HB_BEGIN_DECLS
  * @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values
  * must be greater than -90 and less than +90. Values can be interpreted as
  * the angle, in counter-clockwise degrees, of oblique slant from whatever the
- * designer considers to be upright for that font design.
+ * designer considers to be upright for that font design. Typical right-leaning
+ * Italic fonts have a negative slant angle (typically around -12)
  * @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio.
+ * Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2)
  * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider.
  * Non-zero. Values can be interpreted as a percentage of whatever the font
  * designer considers “normal width” for that font design.

+ 131 - 12
thirdparty/harfbuzz/src/hb-subset-plan.cc

@@ -111,7 +111,7 @@ static void _collect_layout_indices (hb_face_t		  *face,
       retain_all_features = false;
       continue;
     }
-    
+
     if (visited_features.has (tag))
       continue;
 
@@ -249,9 +249,9 @@ static void _colr_closure (hb_face_t *face,
     hb_set_t glyphset_colrv0;
     for (hb_codepoint_t gid : glyphs_colred->iter ())
       colr.closure_glyphs (gid, &glyphset_colrv0);
-    
+
     glyphs_colred->union_ (glyphset_colrv0);
-    
+
     //closure for COLRv1
     colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
@@ -458,7 +458,7 @@ _nameid_closure (hb_face_t *face,
 }
 
 /**
- * hb_subset_plan_create:
+ * hb_subset_plan_create_or_fail:
  * @face: font face to create the plan for.
  * @input: a #hb_subset_input_t input.
  *
@@ -467,17 +467,18 @@ _nameid_closure (hb_face_t *face,
  * which tables and glyphs should be retained.
  *
  * Return value: (transfer full): New subset plan. Destroy with
- * hb_subset_plan_destroy().
+ * hb_subset_plan_destroy(). If there is a failure creating the plan
+ * nullptr will be returned.
  *
- * Since: 1.7.5
+ * Since: 4.0.0
  **/
 hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t	 *face,
-		       const hb_subset_input_t *input)
+hb_subset_plan_create_or_fail (hb_face_t	 *face,
+                               const hb_subset_input_t *input)
 {
   hb_subset_plan_t *plan;
   if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
-    return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
+    return nullptr;
 
   plan->successful = true;
   plan->flags = input->flags;
@@ -514,8 +515,9 @@ hb_subset_plan_create (hb_face_t	 *face,
   plan->layout_variation_indices = hb_set_create ();
   plan->layout_variation_idx_map = hb_map_create ();
 
-  if (plan->in_error ()) {
-    return plan;
+  if (unlikely (plan->in_error ())) {
+    hb_subset_plan_destroy (plan);
+    return nullptr;
   }
 
   _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
@@ -532,6 +534,10 @@ hb_subset_plan_create (hb_face_t	 *face,
 				  plan->reverse_glyph_map,
 				  &plan->_num_output_glyphs);
 
+  if (unlikely (plan->in_error ())) {
+    hb_subset_plan_destroy (plan);
+    return nullptr;
+  }
   return plan;
 }
 
@@ -542,7 +548,7 @@ hb_subset_plan_create (hb_face_t	 *face,
  * Decreases the reference count on @plan, and if it reaches zero, destroys
  * @plan, freeing all memory.
  *
- * Since: 1.7.5
+ * Since: 4.0.0
  **/
 void
 hb_subset_plan_destroy (hb_subset_plan_t *plan)
@@ -596,3 +602,116 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
 
   hb_free (plan);
 }
+
+/**
+ * hb_subset_plan_old_to_new_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the original font to glyphs in the
+ * subset that will be produced by @plan
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->glyph_map;
+}
+
+/**
+ * hb_subset_plan_new_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between glyphs in the subset that will be produced by
+ * @plan and the glyph in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->reverse_glyph_map;
+}
+
+/**
+ * hb_subset_plan_unicode_to_old_glyph_mapping:
+ * @plan: a subsetting plan.
+ *
+ * Returns the mapping between codepoints in the original font and the
+ * associated glyph id in the original font.
+ *
+ * Return value: (transfer none):
+ * A pointer to the #hb_map_t of the mapping.
+ *
+ * Since: 4.0.0
+ **/
+const hb_map_t*
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
+{
+  return plan->codepoint_to_glyph;
+}
+
+/**
+ * hb_subset_plan_reference: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ *
+ * Increases the reference count on @plan.
+ *
+ * Return value: @plan.
+ *
+ * Since: 4.0.0
+ **/
+hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan)
+{
+  return hb_object_reference (plan);
+}
+
+/**
+ * hb_subset_plan_set_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to set
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the given subset plan object.
+ *
+ * Return value: %true if success, %false otherwise
+ *
+ * Since: 4.0.0
+ **/
+hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t   *plan,
+                              hb_user_data_key_t *key,
+                              void               *data,
+                              hb_destroy_func_t   destroy,
+                              hb_bool_t	          replace)
+{
+  return hb_object_set_user_data (plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_subset_plan_get_user_data: (skip)
+ * @plan: a #hb_subset_plan_t object.
+ * @key: The user-data key to query
+ *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified subset plan object.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 4.0.0
+ **/
+void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+                              hb_user_data_key_t     *key)
+{
+  return hb_object_get_user_data (plan, key);
+}

+ 0 - 9
thirdparty/harfbuzz/src/hb-subset-plan.hh

@@ -198,13 +198,4 @@ struct hb_subset_plan_t
   }
 };
 
-typedef struct hb_subset_plan_t hb_subset_plan_t;
-
-HB_INTERNAL hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t           *face,
-		       const hb_subset_input_t   *input);
-
-HB_INTERNAL void
-hb_subset_plan_destroy (hb_subset_plan_t *plan);
-
 #endif /* HB_SUBSET_PLAN_HH */

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

@@ -343,9 +343,33 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
 {
   if (unlikely (!input || !source)) return hb_face_get_empty ();
 
-  hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
-  if (unlikely (plan->in_error ())) {
-    hb_subset_plan_destroy (plan);
+  hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input);
+  if (unlikely (!plan)) {
+    return nullptr;
+  }
+
+  hb_face_t * result = hb_subset_plan_execute_or_fail (plan);
+  hb_subset_plan_destroy (plan);
+  return result;
+}
+
+
+/**
+ * hb_subset_plan_execute_or_fail:
+ * @plan: a subsetting plan.
+ *
+ * Executes the provided subsetting @plan.
+ *
+ * Return value:
+ * on success returns a reference to generated font subset. If the subsetting operation fails
+ * returns nullptr.
+ *
+ * Since: 4.0.0
+ **/
+hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
+{
+  if (unlikely (!plan || plan->in_error ())) {
     return nullptr;
   }
 
@@ -353,7 +377,7 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
   bool success = true;
   hb_tag_t table_tags[32];
   unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
-  while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+  while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables))
   {
     for (unsigned i = 0; i < num_tables; ++i)
     {
@@ -367,8 +391,5 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
   }
 end:
 
-  hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
-
-  hb_subset_plan_destroy (plan);
-  return result;
+  return success ? hb_face_reference (plan->dest) : nullptr;
 }

+ 45 - 1
thirdparty/harfbuzz/src/hb-subset.h

@@ -39,6 +39,15 @@ HB_BEGIN_DECLS
 
 typedef struct hb_subset_input_t hb_subset_input_t;
 
+/**
+ * hb_subset_plan_t:
+ *
+ * Contains information about how the subset operation will be executed.
+ * Such as mappings from the old glyph ids to the new ones in the subset.
+ */
+
+typedef struct hb_subset_plan_t hb_subset_plan_t;
+
 /**
  * hb_subset_flags_t:
  * @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false.
@@ -124,7 +133,7 @@ hb_subset_input_set_user_data (hb_subset_input_t  *input,
 
 HB_EXTERN void *
 hb_subset_input_get_user_data (const hb_subset_input_t *input,
-			       hb_user_data_key_t	   *key);
+			       hb_user_data_key_t      *key);
 
 HB_EXTERN hb_set_t *
 hb_subset_input_unicode_set (hb_subset_input_t *input);
@@ -145,6 +154,41 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
 HB_EXTERN hb_face_t *
 hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
 
+HB_EXTERN hb_face_t *
+hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_create_or_fail (hb_face_t                 *face,
+                               const hb_subset_input_t   *input);
+
+HB_EXTERN void
+hb_subset_plan_destroy (hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+HB_EXTERN const hb_map_t*
+hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan);
+
+
+HB_EXTERN hb_subset_plan_t *
+hb_subset_plan_reference (hb_subset_plan_t *plan);
+
+HB_EXTERN hb_bool_t
+hb_subset_plan_set_user_data (hb_subset_plan_t   *plan,
+                              hb_user_data_key_t *key,
+                              void               *data,
+                              hb_destroy_func_t   destroy,
+                              hb_bool_t	          replace);
+
+HB_EXTERN void *
+hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
+                              hb_user_data_key_t     *key);
+
+
 HB_END_DECLS
 
 #endif /* HB_SUBSET_H */

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

@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
  *
  * The major component of the library version available at compile-time.
  */
-#define HB_VERSION_MAJOR 3
+#define HB_VERSION_MAJOR 4
 /**
  * HB_VERSION_MINOR:
  *
  * The minor component of the library version available at compile-time.
  */
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 0
 /**
  * HB_VERSION_MICRO:
  *
  * The micro component of the library version available at compile-time.
  */
-#define HB_VERSION_MICRO 2
+#define HB_VERSION_MICRO 0
 
 /**
  * HB_VERSION_STRING:
  *
  * A string literal containing the library version available at compile-time.
  */
-#define HB_VERSION_STRING "3.3.2"
+#define HB_VERSION_STRING "4.0.0"
 
 /**
  * HB_VERSION_ATLEAST: