Sfoglia il codice sorgente

HarfBuzz: Update to version 5.3.1

bruvzg 2 anni fa
parent
commit
7afd76bba6
46 ha cambiato i file con 1352 aggiunte e 446 eliminazioni
  1. 1 1
      thirdparty/README.md
  2. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
  3. 18 0
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
  4. 23 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
  5. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
  6. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
  7. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
  8. 43 23
      thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
  9. 12 14
      thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
  10. 0 1
      thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
  11. 42 33
      thirdparty/harfbuzz/src/OT/glyf/glyf.hh
  12. 24 5
      thirdparty/harfbuzz/src/graph/graph.hh
  13. 6 3
      thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
  14. 13 10
      thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
  15. 35 36
      thirdparty/harfbuzz/src/graph/pairpos-graph.hh
  16. 10 10
      thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
  17. 4 4
      thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
  18. 1 0
      thirdparty/harfbuzz/src/hb-aat-layout.cc
  19. 1 0
      thirdparty/harfbuzz/src/hb-config.hh
  20. 3 3
      thirdparty/harfbuzz/src/hb-cplusplus.hh
  21. 62 14
      thirdparty/harfbuzz/src/hb-face.cc
  22. 4 0
      thirdparty/harfbuzz/src/hb-face.h
  23. 12 0
      thirdparty/harfbuzz/src/hb-meta.hh
  24. 13 16
      thirdparty/harfbuzz/src/hb-open-type.hh
  25. 7 7
      thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
  26. 2 2
      thirdparty/harfbuzz/src/hb-ot-color.cc
  27. 1 4
      thirdparty/harfbuzz/src/hb-ot-font.cc
  28. 359 110
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  29. 17 5
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  30. 72 1
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  31. 11 0
      thirdparty/harfbuzz/src/hb-ot-layout.h
  32. 1 1
      thirdparty/harfbuzz/src/hb-ot-post-table.hh
  33. 5 3
      thirdparty/harfbuzz/src/hb-ot-shape.cc
  34. 62 58
      thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
  35. 34 0
      thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
  36. 7 7
      thirdparty/harfbuzz/src/hb-ot-stat-table.hh
  37. 89 9
      thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
  38. 1 1
      thirdparty/harfbuzz/src/hb-repacker.hh
  39. 76 0
      thirdparty/harfbuzz/src/hb-subset-accelerator.hh
  40. 51 4
      thirdparty/harfbuzz/src/hb-subset-input.cc
  41. 1 0
      thirdparty/harfbuzz/src/hb-subset-input.hh
  42. 148 53
      thirdparty/harfbuzz/src/hb-subset-plan.cc
  43. 27 0
      thirdparty/harfbuzz/src/hb-subset-plan.hh
  44. 30 0
      thirdparty/harfbuzz/src/hb-subset.cc
  45. 17 0
      thirdparty/harfbuzz/src/hb-subset.h
  46. 3 3
      thirdparty/harfbuzz/src/hb-version.h

+ 1 - 1
thirdparty/README.md

@@ -214,7 +214,7 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 5.2.0 (4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde, 2022)
+- Version: 5.3.1 (970321db7bddbe8c579b73751fc655a924ea3ce6, 2022)
 - License: MIT
 
 Files extracted from upstream source:

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

@@ -39,7 +39,7 @@ struct GPOS : GSUBGPOS
 
   bool subset (hb_subset_context_t *c) const
   {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
+    hb_subset_layout_context_t l (c, tableTag);
     return GSUBGPOS::subset<PosLookup> (&l);
   }
 

+ 18 - 0
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh

@@ -80,6 +80,24 @@ struct SinglePosFormat1
     return_trace (true);
   }
 
+  bool
+  position_single (hb_font_t           *font,
+		   hb_direction_t       direction,
+		   hb_codepoint_t       gid,
+		   hb_glyph_position_t &pos) const
+  {
+    unsigned int index = (this+coverage).get_coverage  (gid);
+    if (likely (index == NOT_COVERED)) return false;
+
+    /* This is ugly... */
+    hb_buffer_t buffer;
+    buffer.props.direction = direction;
+    OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+    valueFormat.apply_value (&c, this, values, pos);
+    return true;
+  }
+
   template<typename Iterator,
       typename SrcLookup,
       hb_requires (hb_is_iterator (Iterator))>

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

@@ -68,7 +68,7 @@ struct SinglePosFormat2
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    if (likely (index >= valueCount)) return_trace (false);
+    if (unlikely (index >= valueCount)) return_trace (false);
 
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
@@ -92,6 +92,28 @@ struct SinglePosFormat2
     return_trace (true);
   }
 
+  bool
+  position_single (hb_font_t           *font,
+		   hb_direction_t       direction,
+		   hb_codepoint_t       gid,
+		   hb_glyph_position_t &pos) const
+  {
+    unsigned int index = (this+coverage).get_coverage  (gid);
+    if (likely (index == NOT_COVERED)) return false;
+    if (unlikely (index >= valueCount)) return false;
+
+    /* This is ugly... */
+    hb_buffer_t buffer;
+    buffer.props.direction = direction;
+    OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+    valueFormat.apply_value (&c, this,
+                             &values[index * valueFormat.get_len ()],
+                             pos);
+    return true;
+  }
+
+
   template<typename Iterator,
       typename SrcLookup,
       hb_requires (hb_is_iterator (Iterator))>

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

@@ -27,7 +27,7 @@ struct GSUB : GSUBGPOS
 
   bool subset (hb_subset_context_t *c) const
   {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
+    hb_subset_layout_context_t l (c, tableTag);
     return GSUBGPOS::subset<SubstLookup> (&l);
   }
 

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

@@ -118,7 +118,7 @@ struct Ligature
 	match_positions[i] += delta;
 	if (i)
 	  *p++ = ',';
-	sprintf (p, "%u", match_positions[i]);
+	snprintf (p, sizeof(buf), "%u", match_positions[i]);
 	p += strlen(p);
       }
 

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

@@ -117,7 +117,7 @@ struct Sequence
       {
 	if (buf < p)
 	  *p++ = ',';
-	sprintf (p, "%u", i);
+	snprintf (p, sizeof(buf), "%u", i);
 	p += strlen(p);
       }
 

+ 43 - 23
thirdparty/harfbuzz/src/OT/glyf/Glyph.hh

@@ -102,17 +102,19 @@ struct Glyph
                              hb_bytes_t &dest_bytes /* OUT */) const
   {
     GlyphHeader *glyph_header = nullptr;
-    if (all_points.length > 4)
+    if (type != EMPTY && all_points.length > 4)
     {
       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
       if (unlikely (!glyph_header)) return false;
     }
 
-    int xMin, xMax;
-    xMin = xMax = roundf (all_points[0].x);
-
-    int yMin, yMax;
-    yMin = yMax = roundf (all_points[0].y);
+    int xMin = 0, xMax = 0;
+    int yMin = 0, yMax = 0;
+    if (all_points.length > 4)
+    {
+      xMin = xMax = roundf (all_points[0].x);
+      yMin = yMax = roundf (all_points[0].y);
+    }
 
     for (unsigned i = 1; i < all_points.length - 4; i++)
     {
@@ -128,7 +130,7 @@ struct Glyph
 
     /*for empty glyphs: all_points only include phantom points.
      *just update metrics and then return */
-    if (all_points.length == 4)
+    if (!glyph_header)
       return true;
 
     glyph_header->numberOfContours = header->numberOfContours;
@@ -145,10 +147,17 @@ struct Glyph
                                   hb_font_t *font,
                                   const glyf_accelerator_t &glyf,
                                   hb_bytes_t &dest_start,  /* IN/OUT */
-                                  hb_bytes_t &dest_end /* OUT */) const
+                                  hb_bytes_t &dest_end /* OUT */)
   {
     contour_point_vector_t all_points, deltas;
-    get_points (font, glyf, all_points, &deltas, false);
+    if (!get_points (font, glyf, all_points, &deltas, false, false))
+      return false;
+
+    // .notdef, set type to empty so we only update metrics and don't compile bytes for
+    // it
+    if (gid == 0 &&
+        !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+      type = EMPTY;
 
     switch (type) {
     case COMPOSITE:
@@ -171,7 +180,12 @@ struct Glyph
       break;
     }
 
-    return compile_header_bytes (plan, all_points, dest_start);
+    if (!compile_header_bytes (plan, all_points, dest_start))
+    {
+      dest_end.fini ();
+      return false;
+    }
+    return true;
   }
 
 
@@ -182,6 +196,7 @@ struct Glyph
   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
 		   contour_point_vector_t &all_points /* OUT */,
 		   contour_point_vector_t *deltas = nullptr, /* OUT */
+		   bool shift_points_hori = true,
 		   bool use_my_metrics = true,
 		   bool phantom_only = false,
 		   unsigned int depth = 0) const
@@ -238,8 +253,7 @@ struct Glyph
     if (deltas != nullptr && depth == 0 && type == COMPOSITE)
     {
       if (unlikely (!deltas->resize (points.length))) return false;
-      for (unsigned i = 0 ; i < points.length; i++)
-        deltas->arrayZ[i] = points.arrayZ[i];
+      deltas->copy_vector (points);
     }
 
 #ifndef HB_NO_VAR
@@ -271,14 +285,9 @@ struct Glyph
         comp_points.reset ();
 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 				       .get_points (font, glyf_accelerator, comp_points,
-						    deltas, use_my_metrics, phantom_only, depth + 1)))
+						    deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1)))
 	  return false;
 
-	/* Copy phantom points from component if USE_MY_METRICS flag set */
-	if (use_my_metrics && item.is_use_my_metrics ())
-	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
-	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
-
 	/* Apply component transformation & translation */
 	item.transform_points (comp_points);
 
@@ -299,6 +308,11 @@ struct Glyph
 	  }
 	}
 
+	/* Copy phantom points from component if USE_MY_METRICS flag set */
+	if (use_my_metrics && item.is_use_my_metrics ())
+	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
 	all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
 
 	comp_index++;
@@ -310,7 +324,7 @@ struct Glyph
       all_points.extend (phantoms);
     }
 
-    if (depth == 0) /* Apply at top level */
+    if (depth == 0 && shift_points_hori) /* Apply at top level */
     {
       /* Undocumented rasterizer behavior:
        * Shift points horizontally by the updated left side bearing
@@ -332,10 +346,16 @@ struct Glyph
 
   hb_bytes_t get_bytes () const { return bytes; }
 
-  Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
-	 hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_),
-						      header (bytes.as<GlyphHeader> ()),
-						      gid (gid_)
+  Glyph () : bytes (),
+             header (bytes.as<GlyphHeader> ()),
+             gid (-1),
+             type(EMPTY)
+  {}
+
+  Glyph (hb_bytes_t bytes_,
+	 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
+                                                header (bytes.as<GlyphHeader> ()),
+                                                gid (gid_)
   {
     int num_contours = header->numberOfContours;
     if (unlikely (num_contours == 0)) type = EMPTY;

+ 12 - 14
thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh

@@ -271,31 +271,29 @@ struct SimpleGlyph
     }
     //convert absolute values to relative values
     unsigned num_points = all_points.length - 4;
-    hb_vector_t<hb_pair_t<int, int>> deltas;
-    deltas.resize (num_points);
-
-    for (unsigned i = 0; i < num_points; i++)
-    {
-      deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x);
-      deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y);
-    }
 
     hb_vector_t<uint8_t> flags, x_coords, y_coords;
-    flags.alloc (num_points);
-    x_coords.alloc (2*num_points);
-    y_coords.alloc (2*num_points);
+    if (unlikely (!flags.alloc (num_points))) return false;
+    if (unlikely (!x_coords.alloc (2*num_points))) return false;
+    if (unlikely (!y_coords.alloc (2*num_points))) return false;
 
     uint8_t lastflag = 0, repeat = 0;
-
+    int prev_x = 0.f, prev_y = 0.f;
+    
     for (unsigned i = 0; i < num_points; i++)
     {
       uint8_t flag = all_points[i].flag;
       flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
 
-      encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
-      encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
+      float cur_x = roundf (all_points[i].x);
+      float cur_y = roundf (all_points[i].y);
+      encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
+      encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
       if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
       encode_flag (flag, repeat, lastflag, flags);
+
+      prev_x = cur_x;
+      prev_y = cur_y;
     }
 
     unsigned len_before_instrs = 2 * header.numberOfContours + 2;

+ 0 - 1
thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh

@@ -14,7 +14,6 @@ namespace glyf_impl {
 
 struct SubsetGlyph
 {
-  hb_codepoint_t new_gid;
   hb_codepoint_t old_gid;
   Glyph source_glyph;
   hb_bytes_t dest_start;  /* region of source_glyph to copy first */

+ 42 - 33
thirdparty/harfbuzz/src/OT/glyf/glyf.hh

@@ -72,10 +72,13 @@ struct glyf
     if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
 
     hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
-    _populate_subset_glyphs (c->plan, &glyphs);
+    _populate_subset_glyphs (c->plan, glyphs);
 
     if (!c->plan->pinned_at_default)
-      _compile_subset_glyphs_with_deltas (c->plan, &glyphs);
+    {
+      if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs))
+        return_trace (false);
+    }
 
     auto padded_offsets =
     + hb_iter (glyphs)
@@ -105,9 +108,9 @@ struct glyf
 
   void
   _populate_subset_glyphs (const hb_subset_plan_t   *plan,
-			   hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
-  
-  void
+			   hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
+
+  bool
   _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
                                       hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
 
@@ -180,7 +183,7 @@ struct glyf_accelerator_t
     contour_point_vector_t all_points;
 
     bool phantom_only = !consumer.is_consuming_contour_points ();
-    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, phantom_only)))
+    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only)))
       return false;
 
     if (consumer.is_consuming_contour_points ())
@@ -374,44 +377,43 @@ struct glyf_accelerator_t
 
 inline void
 glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
-			       hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
+			       hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
 {
   OT::glyf_accelerator_t glyf (plan->source);
+  unsigned num_glyphs = plan->num_output_glyphs ();
+  if (!glyphs.resize (num_glyphs)) return;
 
-  + hb_range (plan->num_output_glyphs ())
-  | hb_map ([&] (hb_codepoint_t new_gid)
-	{
-	  glyf_impl::SubsetGlyph subset_glyph = {0};
-	  subset_glyph.new_gid = new_gid;
-
-	  /* should never fail: all old gids should be mapped */
-	  if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
-	    return subset_glyph;
-
-	  if (new_gid == 0 &&
-	      !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
-	    subset_glyph.source_glyph = glyf_impl::Glyph ();
-	  else
-	    subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
-	  if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
-	    subset_glyph.drop_hints_bytes ();
-	  else
-	    subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
-	  return subset_glyph;
-	})
-  | hb_sink (glyphs)
-  ;
+  for (auto p : plan->glyph_map->iter ())
+  {
+    unsigned new_gid = p.second;
+    glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
+    subset_glyph.old_gid = p.first;
+
+    if (unlikely (new_gid == 0 &&
+                  !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
+                  plan->pinned_at_default)
+      subset_glyph.source_glyph = glyf_impl::Glyph ();
+    else
+      subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+
+    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+      subset_glyph.drop_hints_bytes ();
+    else
+      subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+  }
 }
 
-inline void
+inline bool
 glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
                                           hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
 {
   OT::glyf_accelerator_t glyf (plan->source);
   hb_font_t *font = hb_font_create (plan->source);
+  if (unlikely (!font)) return false;
 
   hb_vector_t<hb_variation_t> vars;
-  vars.alloc (plan->user_axes_location->get_population ());
+  if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
+    return false;
 
   for (auto _ : *plan->user_axes_location)
   {
@@ -423,9 +425,16 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
 
   hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
   for (auto& subset_glyph : *glyphs)
-    const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf);
+  {
+    if (!const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf))
+    {
+      hb_font_destroy (font);
+      return false;
+    }
+  }
 
   hb_font_destroy (font);
+  return true;
 }
 
 

+ 24 - 5
thirdparty/harfbuzz/src/graph/graph.hh

@@ -70,8 +70,8 @@ struct graph_t
       {
         DEBUG_MSG (SUBSET_REPACK, nullptr,
                    "vertex [%lu] bytes != [%lu] bytes, depth = %u",
-                   table_size (),
-                   other.table_size (),
+                   (unsigned long) table_size (),
+                   (unsigned long) other.table_size (),
                    depth);
 
         auto a = as_bytes ();
@@ -495,6 +495,12 @@ struct graph_t
     return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
   }
 
+  template <typename T, typename ...Ts>
+  vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
+  {
+    return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+  }
+
   template <typename T, typename ...Ts>
   vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
   {
@@ -833,7 +839,20 @@ struct graph_t
    * parent to the clone. The copy is a shallow copy, objects
    * linked from child are not duplicated.
    */
-  bool duplicate (unsigned parent_idx, unsigned child_idx)
+  unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
+  {
+    unsigned new_idx = duplicate (parent_idx, child_idx);
+    if (new_idx == (unsigned) -1) return child_idx;
+    return new_idx;
+  }
+
+
+  /*
+   * Creates a copy of child and re-assigns the link from
+   * parent to the clone. The copy is a shallow copy, objects
+   * linked from child are not duplicated.
+   */
+  unsigned duplicate (unsigned parent_idx, unsigned child_idx)
   {
     update_parents ();
 
@@ -849,7 +868,7 @@ struct graph_t
       // to child are from parent.
       DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %d => %d",
                  parent_idx, child_idx);
-      return false;
+      return -1;
     }
 
     DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %d => %d",
@@ -869,7 +888,7 @@ struct graph_t
       reassign_link (l, parent_idx, clone_idx);
     }
 
-    return true;
+    return clone_idx;
   }
 
 

+ 6 - 3
thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh

@@ -131,8 +131,10 @@ struct Lookup : public OT::Lookup
     for (unsigned i = 0; i < subTable.len; i++)
     {
       unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      unsigned parent_index = this_index;
       if (is_ext) {
         unsigned ext_subtable_index = subtable_index;
+        parent_index = ext_subtable_index;
         ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
             (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
             c.graph.object (ext_subtable_index).head;
@@ -150,9 +152,9 @@ struct Lookup : public OT::Lookup
       switch (type)
       {
       case 2:
-        new_sub_tables = split_subtable<PairPos> (c, subtable_index); break;
+        new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
       case 4:
-        new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break;
+        new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
       default:
         break;
       }
@@ -172,13 +174,14 @@ struct Lookup : public OT::Lookup
 
   template<typename T>
   hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
+                                        unsigned parent_idx,
                                         unsigned objidx)
   {
     T* sub_table = (T*) c.graph.object (objidx).head;
     if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
       return hb_vector_t<unsigned> ();
 
-    return sub_table->split_subtables (c, objidx);
+    return sub_table->split_subtables (c, parent_idx, objidx);
   }
 
   void add_sub_tables (gsubgpos_graph_context_t& c,

+ 13 - 10
thirdparty/harfbuzz/src/graph/markbasepos-graph.hh

@@ -209,7 +209,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
     return vertex_len >= MarkBasePosFormat1::static_size;
   }
 
-  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
   {
     hb_set_t visited;
 
@@ -261,7 +263,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
     split_context_t split_context {
       c,
       this,
-      this_index,
+      c.graph.duplicate_if_shared (parent_index, this_index),
       std::move (class_to_info),
       c.graph.vertices_[mark_array_id].position_to_index_map (),
     };
@@ -365,8 +367,8 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
 
     classCount = count;
 
-    auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
-                                                        &markCoverage);
+    auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
+                                                                &markCoverage);
     if (!mark_coverage) return false;
     hb_set_t marks = sc.marks_for (0, count);
     auto new_coverage =
@@ -380,17 +382,17 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
       return false;
 
 
-    auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index,
-                                                         &baseArray,
-                                                         old_count);
+    auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index,
+                                                                 &baseArray,
+                                                                 old_count);
     if (!base_array || !base_array.table->shrink (sc.c,
                                                   base_array.index,
                                                   old_count,
                                                   count))
       return false;
 
-    auto mark_array = sc.c.graph.as_table<MarkArray> (this_index,
-                                                      &markArray);
+    auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
+                                                              &markArray);
     if (!mark_array || !mark_array.table->shrink (sc.c,
                                                   sc.mark_array_links,
                                                   mark_array.index,
@@ -469,11 +471,12 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
 struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
 {
   hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
                                          unsigned this_index)
   {
     switch (u.format) {
     case 1:
-      return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index);
+      return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
 #ifndef HB_NO_BORING_EXPANSION
     case 2: HB_FALLTHROUGH;
       // Don't split 24bit PairPos's.

+ 35 - 36
thirdparty/harfbuzz/src/graph/pairpos-graph.hh

@@ -47,7 +47,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
         min_size + pairSet.get_size () - pairSet.len.get_size();
   }
 
-  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
   {
     hb_set_t visited;
 
@@ -81,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
     split_context_t split_context {
       c,
       this,
-      this_index,
+      c.graph.duplicate_if_shared (parent_index, this_index),
     };
 
     return actuate_subtable_split<split_context_t> (split_context, split_points);
@@ -125,23 +127,19 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
     pairSet.len = count;
     c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
 
-    unsigned coverage_id = c.graph.mutable_index_for_offset (this_index, &coverage);
-    unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
-    auto& coverage_v = c.graph.vertices_[coverage_id];
-
-    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
-    if (!coverage_table || !coverage_table->sanitize (coverage_v))
-      return false;
+    auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
+    if (!coverage) return false;
 
+    unsigned coverage_size = coverage.vertex->table_size ();
     auto new_coverage =
-        + hb_zip (coverage_table->iter (), hb_range ())
+        + hb_zip (coverage.table->iter (), hb_range ())
         | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
           return p.second < count;
         })
         | hb_map_retains_sorting (hb_first)
         ;
 
-    return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size);
+    return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
   }
 
   // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
@@ -206,7 +204,9 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
         min_size + class1_count * get_class1_record_size ();
   }
 
-  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
   {
     const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
     const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
@@ -287,7 +287,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
     split_context_t split_context {
       c,
       this,
-      this_index,
+      c.graph.duplicate_if_shared (parent_index, this_index),
       class1_record_size,
       total_value_len,
       value_1_len,
@@ -508,40 +508,37 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
     graph.vertices_[split_context.this_index].obj.tail -=
         (old_count - count) * split_context.class1_record_size;
 
-    unsigned coverage_id =
-        graph.mutable_index_for_offset (split_context.this_index, &coverage);
-    unsigned class_def_1_id =
-        graph.mutable_index_for_offset (split_context.this_index, &classDef1);
-    auto& coverage_v = graph.vertices_[coverage_id];
-    auto& class_def_1_v = graph.vertices_[class_def_1_id];
-    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
-    ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
-    if (!coverage_table
-        || !coverage_table->sanitize (coverage_v)
-        || !class_def_1_table
-        || !class_def_1_table->sanitize (class_def_1_v))
-      return false;
+    auto coverage =
+        graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
+    if (!coverage) return false;
+
+    auto class_def_1 =
+        graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
+    if (!class_def_1) return false;
 
     auto klass_map =
-    + coverage_table->iter ()
+    + coverage.table->iter ()
     | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
-      return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+      return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
     })
     | hb_filter ([&] (hb_codepoint_t klass) {
       return klass < count;
     }, hb_second)
     ;
 
+    auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
     if (!Coverage::make_coverage (split_context.c,
-                                  + klass_map | hb_map_retains_sorting (hb_first),
-                                  coverage_id,
-                                  coverage_v.table_size ()))
+                                  + new_coverage,
+                                  coverage.index,
+                                  // existing ranges my not be kept, worst case size is a format 1
+                                  // coverage table.
+                                  4 + new_coverage.len() * 2))
       return false;
 
     return ClassDef::make_class_def (split_context.c,
                                      + klass_map,
-                                     class_def_1_id,
-                                     class_def_1_v.table_size ());
+                                     class_def_1.index,
+                                     class_def_1.vertex->table_size ());
   }
 
   hb_hashmap_t<unsigned, unsigned>
@@ -605,13 +602,15 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
 
 struct PairPos : public OT::Layout::GPOS_impl::PairPos
 {
-  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+                                         unsigned parent_index,
+                                         unsigned this_index)
   {
     switch (u.format) {
     case 1:
-      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
+      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
     case 2:
-      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
+      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
 #ifndef HB_NO_BORING_EXPANSION
     case 3: HB_FALLTHROUGH;
     case 4: HB_FALLTHROUGH;

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

@@ -70,9 +70,9 @@ struct DecompositionAction
 
   ActionSubrecordHeader
 		header;
-  HBFixed	lowerLimit;	/* If the distance factor is less than this value,
+  F16DOT16	lowerLimit;	/* If the distance factor is less than this value,
 				 * then the ligature is decomposed. */
-  HBFixed	upperLimit;	/* If the distance factor is greater than this value,
+  F16DOT16	upperLimit;	/* If the distance factor is greater than this value,
 				 * then the ligature is decomposed. */
   HBUINT16	order;		/* Numerical order in which this ligature will
 				 * be decomposed; you may want infrequent ligatures
@@ -118,7 +118,7 @@ struct ConditionalAddGlyphAction
   protected:
   ActionSubrecordHeader
 		header;
-  HBFixed	substThreshold; /* Distance growth factor (in ems) at which
+  F16DOT16	substThreshold; /* Distance growth factor (in ems) at which
 				 * this glyph is replaced and the growth factor
 				 * recalculated. */
   HBGlyphID16	addGlyph;	/* Glyph to be added as kashida. If this value is
@@ -146,13 +146,13 @@ struct DuctileGlyphAction
   HBUINT32	variationAxis;	/* The 4-byte tag identifying the ductile axis.
 				 * This would normally be 0x64756374 ('duct'),
 				 * but you may use any axis the font contains. */
-  HBFixed	minimumLimit;	/* The lowest value for the ductility axis that
+  F16DOT16	minimumLimit;	/* The lowest value for the ductility axis that
 				 * still yields an acceptable appearance. Normally
 				 * this will be 1.0. */
-  HBFixed	noStretchValue; /* This is the default value that corresponds to
+  F16DOT16	noStretchValue; /* This is the default value that corresponds to
 				 * no change in appearance. Normally, this will
 				 * be 1.0. */
-  HBFixed	maximumLimit;	/* The highest value for the ductility axis that
+  F16DOT16	maximumLimit;	/* The highest value for the ductility axis that
 				 * still yields an acceptable appearance. */
   public:
   DEFINE_SIZE_STATIC (22);
@@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
   };
 
   protected:
-  HBFixed	beforeGrowLimit;/* The ratio by which the advance width of the
+  F16DOT16	beforeGrowLimit;/* The ratio by which the advance width of the
 				 * glyph is permitted to grow on the left or top side. */
-  HBFixed	beforeShrinkLimit;
+  F16DOT16	beforeShrinkLimit;
 				/* The ratio by which the advance width of the
 				 * glyph is permitted to shrink on the left or top side. */
-  HBFixed	afterGrowLimit;	/* The ratio by which the advance width of the glyph
+  F16DOT16	afterGrowLimit;	/* The ratio by which the advance width of the glyph
 				 * is permitted to shrink on the left or top side. */
-  HBFixed	afterShrinkLimit;
+  F16DOT16	afterShrinkLimit;
 				/* The ratio by which the advance width of the glyph
 				 * is at most permitted to shrink on the right or
 				 * bottom side. */

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

@@ -62,7 +62,7 @@ struct TrackTableEntry
   }
 
   protected:
-  HBFixed	track;		/* Track value for this record. */
+  F16DOT16	track;		/* Track value for this record. */
   NameID	trackNameID;	/* The 'name' table index for this track.
 				 * (a short word or phrase like "loose"
 				 * or "very tight") */
@@ -82,7 +82,7 @@ struct TrackData
 			const void *base) const
   {
     unsigned int sizes = nSizes;
-    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
 
     float s0 = size_table[idx].to_float ();
     float s1 = size_table[idx + 1].to_float ();
@@ -120,7 +120,7 @@ struct TrackData
     if (!sizes) return 0.;
     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
 
-    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
     unsigned int size_index;
     for (size_index = 0; size_index < sizes - 1; size_index++)
       if (size_table[size_index].to_float () >= ptem)
@@ -141,7 +141,7 @@ struct TrackData
   protected:
   HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
   HBUINT16	nSizes;		/* Number of point sizes included in this table. */
-  NNOffset32To<UnsizedArrayOf<HBFixed>>
+  NNOffset32To<UnsizedArrayOf<F16DOT16>>
 		sizeTable;	/* Offset from start of the tracking table to
 				 * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>

+ 1 - 0
thirdparty/harfbuzz/src/hb-aat-layout.cc

@@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
   {HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING,          HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS,           (hb_aat_layout_feature_selector_t) 4},
   {HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,            HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT,              (hb_aat_layout_feature_selector_t) 7},
   {HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,            HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT,             (hb_aat_layout_feature_selector_t) 7},
+  {HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,               HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON,          HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
   {HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA,               HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON,                   HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
   {HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION,       HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS,           HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
   {HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE,              HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS,          HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},

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

@@ -71,6 +71,7 @@
 #define HB_NO_LANGUAGE_PRIVATE_SUBTAG
 #define HB_NO_LAYOUT_FEATURE_PARAMS
 #define HB_NO_LAYOUT_COLLECT_GLYPHS
+#define HB_NO_LAYOUT_RARELY_USED
 #define HB_NO_LAYOUT_UNUSED
 #define HB_NO_MATH
 #define HB_NO_META

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

@@ -69,9 +69,9 @@ struct shared_ptr
   operator T * () const { return p; }
   T& operator * () const { return *get (); }
   T* operator -> () const { return get (); }
-  operator bool () { return p; }
-  bool operator == (const shared_ptr &o) { return p == o.p; }
-  bool operator != (const shared_ptr &o) { return p != o.p; }
+  operator bool () const { return p; }
+  bool operator == (const shared_ptr &o) const { return p == o.p; }
+  bool operator != (const shared_ptr &o) const { return p != o.p; }
 
   static T* get_empty() { return v::get_empty (); }
   T* reference() { return v::reference (p); }

+ 62 - 14
thirdparty/harfbuzz/src/hb-face.cc

@@ -633,20 +633,29 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
  * face-builder: A face that has add_table().
  */
 
+struct face_table_info_t
+{
+  hb_blob_t* data;
+  unsigned order;
+};
+
 struct hb_face_builder_data_t
 {
-  hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
+  hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
 };
 
 static int compare_entries (const void* pa, const void* pb)
 {
-  const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
-  const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
+  const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
+  const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
 
   /* Order by blob size first (smallest to largest) and then table tag */
 
-  if (a.second->length != b.second->length)
-    return a.second->length < b.second->length ? -1 : +1;
+  if (a.second.order != b.second.order)
+    return a.second.order < b.second.order ? -1 : +1;
+
+  if (a.second.data->length != b.second.data->length)
+    return a.second.data->length < b.second.data->length ? -1 : +1;
 
   return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
 }
@@ -668,8 +677,8 @@ _hb_face_builder_data_destroy (void *user_data)
 {
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
 
-  for (hb_blob_t* b : data->tables.values())
-    hb_blob_destroy (b);
+  for (auto info : data->tables.values())
+    hb_blob_destroy (info.data);
 
   data->tables.fini ();
 
@@ -683,8 +692,8 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
   unsigned int table_count = data->tables.get_population ();
   unsigned int face_length = table_count * 16 + 12;
 
-  for (hb_blob_t* b : data->tables.values())
-    face_length += hb_ceil_to_4 (hb_blob_get_length (b));
+  for (auto info : data->tables.values())
+    face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
 
   char *buf = (char *) hb_malloc (face_length);
   if (unlikely (!buf))
@@ -699,7 +708,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
   hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
 
   // Sort the tags so that produced face is deterministic.
-  hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
+  hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
   data->tables.iter () | hb_sink (sorted_entries);
   if (unlikely (sorted_entries.in_error ()))
   {
@@ -708,7 +717,13 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
   }
 
   sorted_entries.qsort (compare_entries);
-  bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
+
+  bool ret = f->serialize_single (&c,
+                                  sfnt_tag,
+                                  + sorted_entries.iter()
+                                  | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
+                                    return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
+                                  }));
 
   c.end_serialize ();
 
@@ -729,7 +744,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
   if (!tag)
     return _hb_face_builder_data_reference_blob (data);
 
-  return hb_blob_reference (data->tables[tag]);
+  return hb_blob_reference (data->tables[tag].data);
 }
 
 
@@ -777,8 +792,8 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
 
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
 
-  hb_blob_t* previous = data->tables.get (tag);
-  if (!data->tables.set (tag, hb_blob_reference (blob)))
+  hb_blob_t* previous = data->tables.get (tag).data;
+  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0}))
   {
     hb_blob_destroy (blob);
     return false;
@@ -787,3 +802,36 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
   hb_blob_destroy (previous);
   return true;
 }
+
+/**
+ * hb_face_builder_sort_tables:
+ * @face: A face object created with hb_face_builder_create()
+ * @tags: (array zero-terminated=1): ordered list of table tags terminated by
+ *   %HB_TAG_NONE
+ *
+ * Set the ordering of tables for serialization. Any tables not
+ * specified in the tags list will be ordered after the tables in
+ * tags, ordered by the default sort ordering.
+ *
+ * Since: 5.3.0
+ **/
+void
+hb_face_builder_sort_tables (hb_face_t *face,
+                             const hb_tag_t  *tags)
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+  // Sort all unspecified tables after any specified tables.
+  for (auto& info : data->tables.values_ref())
+    info.order = -1;
+
+  unsigned order = 0;
+  for (const hb_tag_t* tag = tags;
+       *tag;
+       tag++)
+  {
+    face_table_info_t* info;
+    if (!data->tables.has (*tag, &info)) continue;
+    info->order = order++;
+  }
+}

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

@@ -171,6 +171,10 @@ hb_face_builder_add_table (hb_face_t *face,
 			   hb_tag_t   tag,
 			   hb_blob_t *blob);
 
+HB_EXTERN void
+hb_face_builder_sort_tables (hb_face_t *face,
+                             const hb_tag_t  *tags);
+
 
 HB_END_DECLS
 

+ 12 - 0
thirdparty/harfbuzz/src/hb-meta.hh

@@ -133,6 +133,18 @@ struct
 
   template <typename T> constexpr auto
   operator () (T *v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+  
+  template <typename T> constexpr auto
+  operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+  template <typename T> constexpr auto
+  operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
 }
 HB_FUNCOBJ (hb_deref);
 

+ 13 - 16
thirdparty/harfbuzz/src/hb-open-type.hh

@@ -141,27 +141,24 @@ typedef HBINT32 FWORD32;
 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
 typedef HBUINT16 UFWORD;
 
-/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : HBINT16
+template <typename Type, unsigned fraction_bits>
+struct HBFixed : Type
 {
-  F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
-  // 16384 means 1<<14
-  float to_float () const  { return ((int32_t) v) / 16384.f; }
-  void set_float (float f) { v = roundf (f * 16384.f); }
+  static constexpr float shift = (float) (1 << fraction_bits);
+  static_assert (Type::static_size * 8 > fraction_bits, "");
+
+  HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
+  float to_float () const  { return ((int32_t) Type::v) / shift; }
+  void set_float (float f) { Type::v = roundf (f * shift); }
   public:
-  DEFINE_SIZE_STATIC (2);
+  DEFINE_SIZE_STATIC (Type::static_size);
 };
 
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+using F2DOT14 = HBFixed<HBINT16, 14>;
+
 /* 32-bit signed fixed-point number (16.16). */
-struct HBFixed : HBINT32
-{
-  HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
-  // 65536 means 1<<16
-  float to_float () const  { return ((int32_t) v) / 65536.f; }
-  void set_float (float f) { v = roundf (f * 65536.f); }
-  public:
-  DEFINE_SIZE_STATIC (4);
-};
+using F16DOT16 = HBFixed<HBINT32, 16>;
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
  * 1904. The value is represented as a signed 64-bit integer. */

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

@@ -358,14 +358,14 @@ struct Affine2x3
     return_trace (c->check_struct (this));
   }
 
-  HBFixed xx;
-  HBFixed yx;
-  HBFixed xy;
-  HBFixed yy;
-  HBFixed dx;
-  HBFixed dy;
+  F16DOT16 xx;
+  F16DOT16 yx;
+  F16DOT16 xy;
+  F16DOT16 yy;
+  F16DOT16 dx;
+  F16DOT16 dy;
   public:
-  DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
+  DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
 };
 
 struct PaintColrLayers

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

@@ -295,8 +295,8 @@ hb_ot_color_has_png (hb_face_t *face)
  * @glyph: a glyph index
  *
  * Fetches the PNG image for a glyph. This function takes a font object, not a face object,
- * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
- * object. If UPEM is unset, the blob returned will be the largest PNG available.
+ * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
+ * object. If PPEM is unset, the blob returned will be the largest PNG available.
  *
  * If the glyph has no PNG image, the singleton empty blob is returned.
  *

+ 1 - 4
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -40,7 +40,6 @@
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-hmtx-table.hh"
-#include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-ot-vorg-table.hh"
@@ -349,15 +348,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
 
 #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
   if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
+  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
 #endif
   if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
 #ifndef HB_NO_OT_FONT_CFF
   if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
   if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
 #endif
-#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
-  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
-#endif
 
   // TODO Hook up side-bearings variations.
   return false;

+ 359 - 110
thirdparty/harfbuzz/src/hb-ot-layout-common.hh

@@ -94,6 +94,19 @@ static bool ClassDef_remap_and_serialize (
     hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
     hb_map_t *klass_map /*IN/OUT*/);
 
+struct hb_collect_feature_substitutes_with_var_context_t
+{
+  const hb_map_t *axes_index_tag_map;
+  const hb_hashmap_t<hb_tag_t, int> *axes_location;
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
+  hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+
+  // not stored in subset_plan
+  hb_set_t *feature_indices;
+  bool apply;
+  unsigned cur_record_idx;
+  hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
+};
 
 struct hb_prune_langsys_context_t
 {
@@ -160,24 +173,40 @@ struct hb_subset_layout_context_t :
   const hb_map_t *lookup_index_map;
   const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
   const hb_map_t *feature_index_map;
+  const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+
   unsigned cur_script_index;
+  unsigned cur_feature_var_record_idx;
 
   hb_subset_layout_context_t (hb_subset_context_t *c_,
-			      hb_tag_t tag_,
-			      hb_map_t *lookup_map_,
-			      hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
-			      hb_map_t *feature_index_map_) :
+			      hb_tag_t tag_) :
 				subset_context (c_),
 				table_tag (tag_),
-				lookup_index_map (lookup_map_),
-				script_langsys_map (script_langsys_map_),
-				feature_index_map (feature_index_map_),
 				cur_script_index (0xFFFFu),
+				cur_feature_var_record_idx (0u),
 				script_count (0),
 				langsys_count (0),
 				feature_index_count (0),
 				lookup_index_count (0)
-  {}
+  {
+    if (tag_ == HB_OT_TAG_GSUB)
+    {
+      lookup_index_map = c_->plan->gsub_lookups;
+      script_langsys_map = c_->plan->gsub_langsys;
+      feature_index_map = c_->plan->gsub_features;
+      feature_substitutes_map = c_->plan->gsub_feature_substitutes_map;
+      feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map;
+    }
+    else
+    {
+      lookup_index_map = c_->plan->gpos_lookups;
+      script_langsys_map = c_->plan->gpos_langsys;
+      feature_index_map = c_->plan->gpos_features;
+      feature_substitutes_map = c_->plan->gpos_feature_substitutes_map;
+      feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map;
+    }
+  }
 
   private:
   unsigned script_count;
@@ -324,6 +353,31 @@ struct subset_record_array_t
   const void *base;
 };
 
+template<typename OutputArray, typename Arg>
+struct subset_record_array_arg_t
+{
+  subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+			     const void *base_,
+			     Arg &&arg_) : subset_layout_context (c_),
+					   out (out_), base (base_), arg (arg_) {}
+
+  template <typename T>
+  void
+  operator () (T&& record)
+  {
+    auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+    bool ret = record.subset (subset_layout_context, base, arg);
+    if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
+    else out->len++;
+  }
+
+  private:
+  hb_subset_layout_context_t *subset_layout_context;
+  OutputArray *out;
+  const void *base;
+  Arg &&arg;
+};
+
 /*
  * Helper to subset a RecordList/record array. Subsets each Record in the array and
  * discards the record if the subset operation returns false.
@@ -335,6 +389,13 @@ struct
   operator () (hb_subset_layout_context_t *c, OutputArray* out,
 	       const void *base) const
   { return subset_record_array_t<OutputArray> (c, out, base); }
+
+  /* Variant with one extra argument passed to subset */
+  template<typename OutputArray, typename Arg>
+  subset_record_array_arg_t<OutputArray, Arg>
+  operator () (hb_subset_layout_context_t *c, OutputArray* out,
+               const void *base, Arg &&arg) const
+  { return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
 }
 HB_FUNCOBJ (subset_record_array);
 
@@ -431,94 +492,6 @@ struct IndexArray : Array16Of<Index>
 };
 
 
-struct Record_sanitize_closure_t {
-  hb_tag_t tag;
-  const void *list_base;
-};
-
-template <typename Type>
-struct Record
-{
-  int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
-  bool subset (hb_subset_layout_context_t *c, const void *base) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->subset_context->serializer->embed (this);
-    if (unlikely (!out)) return_trace (false);
-    bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
-    return_trace (ret);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    const Record_sanitize_closure_t closure = {tag, base};
-    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
-  }
-
-  Tag		tag;		/* 4-byte Tag identifier */
-  Offset16To<Type>
-		offset;		/* Offset from beginning of object holding
-				 * the Record */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-
-template <typename Type>
-struct RecordArrayOf : SortedArray16Of<Record<Type>>
-{
-  const Offset16To<Type>& get_offset (unsigned int i) const
-  { return (*this)[i].offset; }
-  Offset16To<Type>& get_offset (unsigned int i)
-  { return (*this)[i].offset; }
-  const Tag& get_tag (unsigned int i) const
-  { return (*this)[i].tag; }
-  unsigned int get_tags (unsigned int start_offset,
-			 unsigned int *record_count /* IN/OUT */,
-			 hb_tag_t     *record_tags /* OUT */) const
-  {
-    if (record_count)
-    {
-      + this->sub_array (start_offset, record_count)
-      | hb_map (&Record<Type>::tag)
-      | hb_sink (hb_array (record_tags, *record_count))
-      ;
-    }
-    return this->len;
-  }
-  bool find_index (hb_tag_t tag, unsigned int *index) const
-  {
-    return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
-  }
-};
-
-template <typename Type>
-struct RecordListOf : RecordArrayOf<Type>
-{
-  const Type& operator [] (unsigned int i) const
-  { return this+this->get_offset (i); }
-
-  bool subset (hb_subset_context_t *c,
-	       hb_subset_layout_context_t *l) const
-  {
-    TRACE_SUBSET (this);
-    auto *out = c->serializer->start_embed (*this);
-    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
-    + this->iter ()
-    | hb_apply (subset_record_array (l, out, this))
-    ;
-    return_trace (true);
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (RecordArrayOf<Type>::sanitize (c, this));
-  }
-};
-
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
 struct FeatureParamsSize
 {
@@ -801,6 +774,10 @@ struct FeatureParams
   DEFINE_SIZE_MIN (0);
 };
 
+struct Record_sanitize_closure_t {
+  hb_tag_t tag;
+  const void *list_base;
+};
 
 struct Feature
 {
@@ -897,6 +874,103 @@ struct Feature
   DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
 };
 
+template <typename Type>
+struct Record
+{
+  int cmp (hb_tag_t a) const { return tag.cmp (a); }
+
+  bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (!f_sub)
+      return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
+
+    const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
+    auto *s = c->subset_context->serializer;
+    s->push ();
+
+    out->offset = 0;
+    bool ret = f.subset (c->subset_context, c, &tag);
+    if (ret)
+      s->add_link (out->offset, s->pop_pack ());
+    else
+      s->pop_discard ();
+
+    return_trace (ret);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    const Record_sanitize_closure_t closure = {tag, base};
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+  }
+
+  Tag           tag;            /* 4-byte Tag identifier */
+  Offset16To<Type>
+                offset;         /* Offset from beginning of object holding
+                                 * the Record */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
+{
+  const Offset16To<Type>& get_offset (unsigned int i) const
+  { return (*this)[i].offset; }
+  Offset16To<Type>& get_offset (unsigned int i)
+  { return (*this)[i].offset; }
+  const Tag& get_tag (unsigned int i) const
+  { return (*this)[i].tag; }
+  unsigned int get_tags (unsigned int start_offset,
+                         unsigned int *record_count /* IN/OUT */,
+                         hb_tag_t     *record_tags /* OUT */) const
+  {
+    if (record_count)
+    {
+      + this->sub_array (start_offset, record_count)
+      | hb_map (&Record<Type>::tag)
+      | hb_sink (hb_array (record_tags, *record_count))
+      ;
+    }
+    return this->len;
+  }
+  bool find_index (hb_tag_t tag, unsigned int *index) const
+  {
+    return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+  }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+  const Type& operator [] (unsigned int i) const
+  { return this+this->get_offset (i); }
+
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + this->iter ()
+    | hb_apply (subset_record_array (l, out, this))
+    ;
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (RecordArrayOf<Type>::sanitize (c, this));
+  }
+};
+
 struct RecordListOfFeature : RecordListOf<Feature>
 {
   bool subset (hb_subset_context_t *c,
@@ -907,11 +981,20 @@ struct RecordListOfFeature : RecordListOf<Feature>
     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
 
     unsigned count = this->len;
+
     + hb_zip (*this, hb_range (count))
     | hb_filter (l->feature_index_map, hb_second)
-    | hb_map (hb_first)
-    | hb_apply (subset_record_array (l, out, this))
+    | hb_apply ([l, out, this] (const hb_pair_t<const Record<Feature>&, unsigned>& _)
+                {
+                  const Feature *f_sub = nullptr;
+                  const Feature **f = nullptr;
+                  if (l->feature_substitutes_map->has (_.second, &f))
+                    f_sub = *f;
+
+                  subset_record_array (l, out, this, f_sub) (_.first);
+                })
     ;
+
     return_trace (true);
   }
 };
@@ -2692,6 +2775,13 @@ struct VariationStore
 /*
  * Feature Variations
  */
+enum Cond_with_Var_flag_t
+{
+  KEEP_COND_WITH_VAR = 0,
+  DROP_COND_WITH_VAR = 1,
+  DROP_RECORD_WITH_VAR = 2,
+  MEM_ERR_WITH_VAR = 3,
+};
 
 struct ConditionFormat1
 {
@@ -2702,10 +2792,52 @@ struct ConditionFormat1
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
-    return_trace (true);
+
+    const hb_map_t *index_map = c->plan->axes_index_map;
+    if (index_map->is_empty ()) return_trace (true);
+
+    if (!index_map->has (axisIndex))
+      return_trace (false);
+
+    return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   private:
+  Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                             hb_map_t *condition_map /* OUT */) const
+  {
+    //invalid axis index, drop the entire record
+    if (!c->axes_index_tag_map->has (axisIndex))
+      return DROP_RECORD_WITH_VAR;
+
+    hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
+
+    //axis not pinned, keep the condition
+    if (!c->axes_location->has (axis_tag))
+    {
+      // add axisIndex->value into the hashmap so we can check if the record is
+      // unique with variations
+      int16_t min_val = filterRangeMinValue;
+      int16_t max_val = filterRangeMaxValue;
+      hb_codepoint_t val = (max_val << 16) + min_val;
+
+      condition_map->set (axisIndex, val);
+      return KEEP_COND_WITH_VAR;
+    }
+
+    //axis pinned, check if condition is met
+    //TODO: add check for axis Ranges
+    int v = c->axes_location->get (axis_tag);
+
+    //condition not met, drop the entire record
+    if (v < filterRangeMinValue || v > filterRangeMaxValue)
+      return DROP_RECORD_WITH_VAR;
+
+    //axis pinned and condition met, drop the condition
+    return DROP_COND_WITH_VAR;
+  }
+
   bool evaluate (const int *coords, unsigned int coord_len) const
   {
     int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
@@ -2737,6 +2869,15 @@ struct Condition
     }
   }
 
+  Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                             hb_map_t *condition_map /* OUT */) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.keep_with_variations (c, condition_map);
+    default:return KEEP_COND_WITH_VAR;
+    }
+  }
+
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
@@ -2778,15 +2919,65 @@ struct ConditionSet
     return true;
   }
 
-  bool subset (hb_subset_context_t *c) const
+  Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    hb_map_t *condition_map = hb_map_create ();
+    if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
+    hb::shared_ptr<hb_map_t> p {condition_map};
+
+    hb_set_t *cond_set = hb_set_create ();
+    if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
+    hb::shared_ptr<hb_set_t> s {cond_set};
+
+    unsigned num_kept_cond = 0, cond_idx = 0;
+    for (const auto& offset : conditions)
+    {
+      Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
+      // one condition is not met, drop the entire record
+      if (ret == DROP_RECORD_WITH_VAR)
+        return DROP_RECORD_WITH_VAR;
+
+      // axis not pinned, keep this condition
+      if (ret == KEEP_COND_WITH_VAR)
+      {
+        cond_set->add (cond_idx);
+        num_kept_cond++;
+      }
+      cond_idx++;
+    }
+
+    // all conditions met
+    if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
+ 
+    //check if condition_set is unique with variations
+    if (c->conditionset_map->has (p))
+      //duplicate found, drop the entire record
+      return DROP_RECORD_WITH_VAR;
+
+    c->conditionset_map->set (p, 1);
+    c->record_cond_idx_map->set (c->cur_record_idx, s);
+
+    return KEEP_COND_WITH_VAR;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
   {
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
 
-    + conditions.iter ()
-    | hb_apply (subset_offset_array (c, out->conditions, this))
-    ;
+    hb_set_t *retained_cond_set = nullptr;
+    if (l->feature_record_cond_idx_map != nullptr)
+      retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
+
+    unsigned int count = conditions.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (retained_cond_set != nullptr && !retained_cond_set->has (i))
+        continue;
+      subset_offset_array (c, out->conditions, this) (conditions[i]);
+    }
 
     return_trace (bool (out->conditions));
   }
@@ -2820,10 +3011,19 @@ struct FeatureTableSubstitutionRecord
       feature_indexes->add (featureIndex);
   }
 
+  void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+                                                    const hb_set_t *feature_indices,
+                                                    const void *base) const
+  {
+    if (feature_indices->has (featureIndex))
+      feature_substitutes_map->set (featureIndex, &(base+feature));
+  }
+
   bool subset (hb_subset_layout_context_t *c, const void *base) const
   {
     TRACE_SUBSET (this);
-    if (!c->feature_index_map->has (featureIndex)) {
+    if (!c->feature_index_map->has (featureIndex) ||
+        c->feature_substitutes_map->has (featureIndex)) {
       // Feature that is being substituted is not being retained, so we don't
       // need this.
       return_trace (false);
@@ -2865,10 +3065,16 @@ struct FeatureTableSubstitution
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
+			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
     + hb_iter (substitutions)
     | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+    | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
+                 {
+                   if (feature_substitutes_map == nullptr) return true;
+                   return !feature_substitutes_map->has (record.featureIndex);
+                 })
     | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
 		{ r.collect_lookups (this, lookup_indexes); })
     ;
@@ -2890,6 +3096,12 @@ struct FeatureTableSubstitution
     return false;
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    for (const FeatureTableSubstitutionRecord& record : substitutions)
+      record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+  }
+
   bool subset (hb_subset_context_t        *c,
 	       hb_subset_layout_context_t *l) const
   {
@@ -2929,9 +3141,10 @@ struct FeatureVariationRecord
 
   void collect_lookups (const void     *base,
 			const hb_set_t *feature_indexes,
+			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
-    return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+    return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
   }
 
   void closure_features (const void     *base,
@@ -2946,13 +3159,25 @@ struct FeatureVariationRecord
     return (base+substitutions).intersects_features (feature_index_map);
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+                                                    const void *base) const
+  {
+    // ret == 1, all conditions met
+    if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
+        c->apply)
+    {
+      (base+substitutions).collect_feature_substitutes_with_variations (c);
+      c->apply = false; // set variations only once
+    }
+  }
+
   bool subset (hb_subset_layout_context_t *c, const void *base) const
   {
     TRACE_SUBSET (this);
     auto *out = c->subset_context->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
 
-    out->conditions.serialize_subset (c->subset_context, conditions, base);
+    out->conditions.serialize_subset (c->subset_context, conditions, base, c);
     out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
 
     return_trace (true);
@@ -3002,6 +3227,16 @@ struct FeatureVariations
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  {
+    unsigned int count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      c->cur_record_idx = i;
+      varRecords[i].collect_feature_substitutes_with_variations (c, this);
+    }
+  }
+
   FeatureVariations* copy (hb_serialize_context_t *c) const
   {
     TRACE_SERIALIZE (this);
@@ -3009,17 +3244,25 @@ struct FeatureVariations
   }
 
   void collect_lookups (const hb_set_t *feature_indexes,
+			const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 			hb_set_t       *lookup_indexes /* OUT */) const
   {
     for (const FeatureVariationRecord& r : varRecords)
-      r.collect_lookups (this, feature_indexes, lookup_indexes);
+      r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
   }
 
   void closure_features (const hb_map_t *lookup_indexes,
+			 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
 			 hb_set_t       *feature_indexes /* OUT */) const
   {
-    for (const FeatureVariationRecord& record : varRecords)
-      record.closure_features (this, lookup_indexes, feature_indexes);
+    unsigned int count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (feature_record_cond_idx_map != nullptr &&
+          !feature_record_cond_idx_map->has (i))
+        continue;
+      varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
+    }
   }
 
   bool subset (hb_subset_context_t *c,
@@ -3041,7 +3284,13 @@ struct FeatureVariations
     }
 
     unsigned count = (unsigned) (keep_up_to + 1);
-    for (unsigned i = 0; i < count; i++) {
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (l->feature_record_cond_idx_map != nullptr &&
+          !l->feature_record_cond_idx_map->has (i))
+        continue;
+
+      l->cur_feature_var_record_idx = i;
       subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
     }
     return_trace (bool (out->varRecords));

+ 17 - 5
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh

@@ -4236,13 +4236,19 @@ struct GSUBGPOS
   }
 
   void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+					  const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
 					  hb_set_t       *lookup_indexes /* OUT */) const
   {
 #ifndef HB_NO_VAR
-    get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes);
+    get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
 #endif
   }
 
+#ifndef HB_NO_VAR
+  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+  { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
+#endif
+
   template <typename TLookup>
   void closure_lookups (hb_face_t      *face,
 			const hb_set_t *glyphs,
@@ -4278,6 +4284,8 @@ struct GSUBGPOS
   }
 
   void prune_features (const hb_map_t *lookup_indices, /* IN */
+		       const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
+		       const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
 		       hb_set_t       *feature_indices /* IN/OUT */) const
   {
 #ifndef HB_NO_VAR
@@ -4285,7 +4293,7 @@ struct GSUBGPOS
     // if the FeatureVariation's table and the alternate version(s) intersect the
     // set of lookup indices.
     hb_set_t alternate_feature_indices;
-    get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices);
+    get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
     if (unlikely (alternate_feature_indices.in_error()))
     {
       feature_indices->err ();
@@ -4295,7 +4303,6 @@ struct GSUBGPOS
 
     for (unsigned i : feature_indices->iter())
     {
-      const Feature& f = get_feature (i);
       hb_tag_t tag =  get_feature_tag (i);
       if (tag == HB_TAG ('p', 'r', 'e', 'f'))
         // Note: Never ever drop feature 'pref', even if it's empty.
@@ -4305,11 +4312,16 @@ struct GSUBGPOS
         continue;
 
 
-      if (!f.featureParams.is_null () &&
+      const Feature *f = &(get_feature (i));
+      const Feature** p = nullptr;
+      if (feature_substitutes_map->has (i, &p))
+        f = *p;
+
+      if (!f->featureParams.is_null () &&
           tag == HB_TAG ('s', 'i', 'z', 'e'))
         continue;
 
-      if (!f.intersects_lookup_indexes (lookup_indices)
+      if (!f->intersects_lookup_indexes (lookup_indices)
 #ifndef HB_NO_VAR
           && !alternate_feature_indices.has (i)
 #endif

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

@@ -1271,7 +1271,7 @@ hb_ot_layout_collect_lookups (hb_face_t      *face,
        hb_set_next (&feature_indexes, &feature_index);)
     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
 
-  g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
+  g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
 }
 
 
@@ -1709,6 +1709,8 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
 
   return false;
 }
+
+
 /**
  * hb_ot_layout_feature_get_name_ids:
  * @face: #hb_face_t to work upon
@@ -2341,6 +2343,7 @@ struct hb_get_glyph_alternates_dispatch_t :
   ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
 };
 
+#ifndef HB_NO_LAYOUT_RARELY_USED
 /**
  * hb_ot_layout_lookup_get_glyph_alternates:
  * @face: a face.
@@ -2373,4 +2376,72 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
   return ret;
 }
 
+
+struct hb_position_single_dispatch_t :
+       hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
+{
+  static return_t default_return_value () { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.position_single (std::forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( default_return_value () )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+};
+
+/**
+ * hb_ot_layout_lookup_get_optical_bound:
+ * @font: a font.
+ * @lookup_index: index of the feature lookup to query.
+ * @direction: edge of the glyph to query.
+ * @glyph: a glyph id.
+ *
+ * Fetches the optical bound of a glyph positioned at the margin of text.
+ * The direction identifies which edge of the glyph to query.
+ *
+ * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
+ *
+ * Since: 5.3.0
+ **/
+hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t      *font,
+				       unsigned        lookup_index,
+				       hb_direction_t  direction,
+				       hb_codepoint_t  glyph)
+{
+  const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+  hb_glyph_position_t pos = {0};
+  hb_position_single_dispatch_t c;
+  lookup.dispatch (&c, font, direction, glyph, pos);
+  hb_position_t ret = 0;
+  switch (direction)
+  {
+    case HB_DIRECTION_LTR:
+      ret = pos.x_offset;
+      break;
+    case HB_DIRECTION_RTL:
+      ret = pos.x_advance - pos.x_offset;
+      break;
+    case HB_DIRECTION_TTB:
+      ret = pos.y_offset;
+      break;
+    case HB_DIRECTION_BTT:
+      ret = pos.y_advance - pos.y_offset;
+      break;
+    case HB_DIRECTION_INVALID:
+    default:
+      break;
+  }
+  return ret;
+}
+#endif
+
+
 #endif

+ 11 - 0
thirdparty/harfbuzz/src/hb-ot-layout.h

@@ -403,6 +403,16 @@ hb_ot_layout_get_size_params (hb_face_t       *face,
 			      unsigned int    *range_start,       /* OUT.  May be NULL */
 			      unsigned int    *range_end          /* OUT.  May be NULL */);
 
+HB_EXTERN hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t      *font,
+				       unsigned        lookup_index,
+				       hb_direction_t  direction,
+				       hb_codepoint_t  glyph);
+
+
+/*
+ * GSUB/GPOS
+ */
 
 HB_EXTERN hb_bool_t
 hb_ot_layout_feature_get_name_ids (hb_face_t       *face,
@@ -423,6 +433,7 @@ hb_ot_layout_feature_get_characters (hb_face_t      *face,
 				     unsigned int   *char_count    /* IN/OUT.  May be NULL */,
 				     hb_codepoint_t *characters    /* OUT.     May be NULL */);
 
+
 /*
  * BASE
  */

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

@@ -282,7 +282,7 @@ struct post
 					 * 0x00020000 for version 2.0
 					 * 0x00025000 for version 2.5 (deprecated)
 					 * 0x00030000 for version 3.0 */
-  HBFixed	italicAngle;		/* Italic angle in counter-clockwise degrees
+  F16DOT16	italicAngle;		/* Italic angle in counter-clockwise degrees
 					 * from the vertical. Zero for upright text,
 					 * negative for text that leans to the right
 					 * (forward). */

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

@@ -527,18 +527,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
     }
 #endif
     /* Or part of the Other_Grapheme_Extend that is not marks.
-     * As of Unicode 11 that is just:
+     * As of Unicode 15 that is just:
      *
      * 200C          ; Other_Grapheme_Extend # Cf       ZERO WIDTH NON-JOINER
      * FF9E..FF9F    ; Other_Grapheme_Extend # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
      * E0020..E007F  ; Other_Grapheme_Extend # Cf  [96] TAG SPACE..CANCEL TAG
      *
      * ZWNJ is special, we don't want to merge it as there's no need, and keeping
-     * it separate results in more granular clusters.  Ignore Katakana for now.
+     * it separate results in more granular clusters.
      * Tags are used for Emoji sub-region flag sequences:
      * https://github.com/harfbuzz/harfbuzz/issues/1556
+     * Katakana ones were requested:
+     * https://github.com/harfbuzz/harfbuzz/issues/3844
      */
-    else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+    else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
       _hb_glyph_info_set_continuation (&info[i]);
   }
 }

+ 62 - 58
thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh

@@ -25,6 +25,7 @@
  * # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
  * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
  * # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
  * # Override values For Indic_Positional_Category
  * # Not derivable
  * # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -34,6 +35,7 @@
  * # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
  * # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
  * # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
  * UnicodeData.txt does not have a header.
  */
 
@@ -90,7 +92,7 @@
 #pragma GCC diagnostic pop
 
 static const uint8_t
-hb_use_u8[3115] =
+hb_use_u8[3141] =
 {
      16,   50,   51,   51,   51,   52,   51,   83,  118,  131,   51,   57,   58,  179,  195,   61,
      51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
@@ -125,11 +127,11 @@ hb_use_u8[3115] =
       2,    2,    2,    2,    2,    2,    2,    2,    2,   88,   89,    2,    2,    2,    2,    2,
       2,    2,    2,   90,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
       2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,   91,    2,    2,   92,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,   93,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-      2,   94,   94,   95,   96,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
-     94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,   94,
-     94,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
+      2,    2,    2,   91,    2,    2,   92,    2,    2,    2,   93,    2,    2,    2,    2,    2,
+      2,    2,    2,   94,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+      2,   95,   95,   96,   97,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,
+     95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,   95,
+     95,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,
       0,    2,    2,    2,    2,    2,    0,    0,    0,    3,    0,    0,    0,    0,    0,    4,
       0,    0,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,    0,
       0,    0,    0,    0,    0,    0,    0,    0,    6,    7,    0,    0,    0,    0,    0,    0,
@@ -226,70 +228,72 @@ hb_use_u8[3115] =
       0,    9,   47,    2,    2,    2,    2,    2,    2,    2,    2,    2,  125,   18,   20,  151,
      20,   19,  152,  153,    2,    2,    2,    2,    2,    0,    0,   63,  154,    0,    0,    0,
       0,    2,   11,    0,    0,    0,    0,    0,    0,    2,   63,   23,   18,   18,   18,   20,
-     20,  106,  155,    0,    0,  156,  157,   29,  158,   28,    2,    2,    2,    2,    2,    2,
-      2,    2,    2,    2,    2,    2,    2,   21,   17,   20,   20,  159,   42,    0,    0,    0,
+     20,  106,  155,    0,    0,   54,  156,   29,  157,   28,    2,    2,    2,    2,    2,    2,
+      2,    2,    2,    2,    2,    2,    2,   21,   17,   20,   20,  158,   42,    0,    0,    0,
      47,  125,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    7,    7,    2,    2,
      28,    2,    2,    2,    2,    2,    2,    2,   28,    2,    2,    2,    2,    2,    2,    2,
-      8,   16,   17,   19,   20,  160,   29,    0,    0,    9,    9,   28,    2,    2,    2,    7,
+      8,   16,   17,   19,   20,  159,   29,    0,    0,    9,    9,   28,    2,    2,    2,    7,
      28,    7,    2,   28,    2,    2,   56,   15,   21,   14,   21,   45,   30,   31,   30,   32,
       0,    0,    0,    0,   33,    0,    0,    0,    2,    2,   21,    0,    9,    9,    9,   44,
       0,    9,    9,   44,    0,    0,    0,    0,    0,    2,    2,   63,   23,   18,   18,   18,
      20,   21,  123,   13,   15,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,    0,
-    161,  162,    0,    0,    0,    0,    0,    0,    0,   16,   17,   18,   18,   64,   97,   23,
-    158,    9,  163,    7,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
-     63,   23,   18,   18,    0,   46,   46,    9,  164,   35,    0,    0,    0,    0,    0,    0,
+    160,  161,    0,    0,    0,    0,    0,    0,    0,   16,   17,   18,   18,   64,   97,   23,
+    157,    9,  162,    7,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,
+     63,   23,   18,   18,    0,   46,   46,    9,  163,   35,    0,    0,    0,    0,    0,    0,
       0,    0,    0,    0,    0,    2,    2,   18,    0,   21,   17,   18,   18,   19,   14,   80,
-    164,   36,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    8,  165,
-     23,   18,   20,   20,  163,    7,    0,    0,    0,    2,    2,    2,    2,    2,    7,   41,
+    163,   36,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    8,  164,
+     23,   18,   20,   20,  162,    7,    0,    0,    0,    2,    2,    2,    2,    2,    7,   41,
     133,   21,   20,   18,   74,   19,   20,    0,    0,    2,    2,    2,    7,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    2,   16,   17,   18,   19,   20,  103,  164,   35,    0,
+      0,    2,    2,    2,    2,    2,    2,   16,   17,   18,   19,   20,  103,  163,   35,    0,
       0,    2,    2,    2,    7,   28,    0,    2,    2,    2,    2,   28,    7,    2,    2,    2,
-      2,   21,   21,   16,   30,   31,   10,  166,  167,  168,  169,    0,    0,    0,    0,    0,
+      2,   21,   21,   16,   30,   31,   10,  165,  166,  167,  168,    0,    0,    0,    0,    0,
       0,    2,    2,    2,    2,    0,    2,    2,    2,   63,   23,   18,   18,    0,   20,   21,
      27,  106,    0,   31,    0,    0,    0,    0,    0,   50,   18,   20,   20,   20,  137,    2,
-      2,    2,  170,  171,    9,   13,  172,   70,  173,    0,    0,    1,  144,    0,    0,    0,
-      0,   50,   18,   20,   14,   17,   18,    2,    2,    2,    2,  155,  155,  155,  174,  174,
-    174,  174,  174,  174,   13,  175,    0,   28,    0,   20,   18,   18,   29,   20,   20,    9,
-    164,    0,   59,   59,   59,   59,   59,   59,   59,   64,   19,   80,   44,    0,    0,    0,
+      2,    2,  169,  170,    9,   13,  171,   70,  172,    0,    0,    1,  144,    0,    0,    0,
+      0,   50,   18,   20,   14,   17,   18,    2,    2,    2,    2,  155,  155,  155,  173,  173,
+    173,  173,  173,  173,   13,  174,    0,   28,    0,   20,   18,   18,   29,   20,   20,    9,
+    163,    0,   59,   59,   59,   59,   59,   59,   59,   64,   19,   80,   44,    0,    0,    0,
       0,    2,    2,    2,    7,    2,   28,    2,    2,   50,   20,   20,   29,    0,   36,   20,
-     25,    9,  157,  176,  172,    0,    0,    0,    0,    2,    2,    2,   28,    7,    2,    2,
+     25,    9,  156,  175,  171,    0,    0,    0,    0,    2,    2,    2,   28,    7,    2,    2,
       2,    2,    2,    2,    2,    2,   21,   21,   45,   20,   33,   80,   66,    0,    0,    0,
-      0,    2,  177,   64,   45,    0,    0,    0,    0,    9,  178,    2,    2,    2,    2,    2,
+      0,    2,  176,   64,   45,    0,    0,    0,    0,    9,  177,    2,    2,    2,    2,    2,
       2,    2,    2,   21,   20,   18,   29,    0,   46,   14,  140,    0,    0,    0,    0,    0,
-      0,  179,  179,  179,  106,    7,    0,    0,    0,    9,    9,    9,   44,    0,    0,    0,
-      0,    2,    2,    2,    2,    2,    7,    0,   56,  180,   18,   18,   18,   18,   18,   18,
+      0,  178,  178,  178,  106,  179,  178,    0,    0,  145,    2,    2,  180,  114,  114,  114,
+    114,  114,  114,  114,    0,    0,    0,    0,    0,    9,    9,    9,   44,    0,    0,    0,
+      0,    2,    2,    2,    2,    2,    7,    0,   56,  181,   18,   18,   18,   18,   18,   18,
      18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18,    0,    0,    0,
      38,  114,   24,    0,    0,    0,    0,    0,    0,    0,    0,    7,    0,    0,    0,    0,
       0,    2,    2,    2,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    0,   56,
      35,    0,    4,  118,  118,  118,  119,    0,    0,    9,    9,    9,   47,    2,    2,    2,
       0,    2,    2,    2,    2,    2,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
-     44,    2,    2,    2,    2,    2,    2,    9,    9,    2,    2,   42,   42,   42,   90,    0,
-      0,    O,    O,    O,   GB,    B,    B,   GB,    O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,
-      O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
-      B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre,
-   VPst,VMBlw,    O,    O, VAbv,   GB,VMAbv,VMPst,VMPst,    O,    B, VBlw,    O,    O, VPre, VPre,
-      O, VPre,    H,    O, VPst,FMAbv,    O,CMBlw,    O, VAbv,    O, VAbv,    H,    O,VMBlw,VMAbv,
-  CMAbv,   GB,   GB,    O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv,    O, VPst,    O, VPre, VPre,VMAbv,
-      B,    O,   CS,   CS,VMPst,    B, VAbv, VAbv,    B,    R,    O,  HVM,    O,    O, FBlw,    O,
-  CMAbv,    O,CMBlw, VAbv, VBlw,    B,  SUB,  SUB,  SUB,    O,  SUB,  SUB,    O, FBlw,    O,    B,
-   VPst, VBlw, VPre,VMAbv,VMBlw,VMPst,   IS, VAbv, MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,
-  VMPst,VMPst,    B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,
-    CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,
-    CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,    B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst,
-   FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,  SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,
-  VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw,
-   FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,   CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,
-      O,FMPst,    O,    O,    H, MPst, VPst,    H,VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,
-  VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,    O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B,
-   FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,
-  VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,   CS,   CS,    B,    N,    N,    O,   HN, VPre,
-   VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,    R,    O,FMBlw,CMBlw, VAbv, VPre,VMAbv,VMAbv,
-      H, VAbv,CMBlw,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,    H,VMPst, VAbv,VMAbv, VPst,   IS,
-      R, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,    R, MBlw, MBlw,   GB, FBlw, FBlw,CMAbv,
-     IS, VBlw,   IS,   GB, VAbv,    R,VMPst,    H,    H,    O, VBlw,
+     44,    2,    2,    2,    2,    2,    2,    9,    9,    2,    2,    2,    2,    2,    2,   20,
+     20,    2,    2,   42,   42,   42,   90,    0,    0,    O,    O,    O,   GB,    B,    B,   GB,
+      O,    O,   WJ,FMPst,FMPst,    O,  CGJ,    B,    O,    B,VMAbv,VMAbv,VMAbv,    O,VMAbv,    B,
+  CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,    B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
+   VAbv, VAbv, VAbv, VPst, VPst, VPst,    H, VPre, VPst,VMBlw,    O,    O, VAbv,   GB,VMAbv,VMPst,
+  VMPst,    O,    B, VBlw,    O,    O, VPre, VPre,    O, VPre,    H,    O, VPst,FMAbv,    O,CMBlw,
+      O, VAbv,    O, VAbv,    H,    O,VMBlw,VMAbv,CMAbv,   GB,   GB,    O, MBlw,CMAbv,CMAbv, VPst,
+   VAbv,VMAbv,    O, VPst,    O, VPre, VPre,VMAbv,    B,    O,   CS,   CS,VMPst,    B, VAbv, VAbv,
+      B,    R,    O,  HVM,    O,    O,FMBlw,    O,CMAbv,    O,CMBlw, VAbv, VBlw,    B,  SUB,  SUB,
+    SUB,    O,  SUB,  SUB,    O,FMBlw,    O,    B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst,   IS, VAbv,
+   MPst, MPre, MBlw, MBlw,    B, MBlw, MBlw, VPst,VMPst,VMPst,    B, MBlw, VPst, VPre, VAbv, VAbv,
+  VMPst,VMPst,VMBlw,    B,VMPst, VBlw, VPst,  CGJ,  CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
+  VMAbv,FMAbv, VAbv,   IS,FMAbv,    B,FMAbv,    B,  CGJ,   WJ,  CGJ,   GB,CMAbv,CMAbv,    B,   GB,
+      B, VAbv,  SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre,    B, MPre, MBlw,
+    SUB, FAbv, FAbv, MAbv,  SUB,   Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst,    H,    B,    O,
+  SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst,   IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
+     CS,    O,FMAbv, ZWNJ,  CGJ,   WJ,   WJ,   WJ,    O,FMPst,    O,    O,    H, MPst, VPst,    H,
+  VMAbv, VAbv,VMBlw,    B, VBlw, FPst, VPst, FAbv,VMPst,    B,CMAbv, VAbv, MBlw, MPst, MBlw,    H,
+      O, VBlw, MPst, MPre, MAbv, MBlw,    O,    B, FAbv, FAbv, FPst, VBlw,    B,    B, VPre,    O,
+  VMPst,   IS,    O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,    O,   IS,VMBlw,    B,VMPst,VMAbv,VMPst,
+     CS,   CS,    B,    N,    N,    O,   HN, VPre, VBlw, VAbv,   IS,CMAbv,    O, VPst,    B,    R,
+      R,CMBlw, VAbv, VPre,VMAbv,VMAbv,    H, VAbv,CMBlw,FMAbv,    B,   CS,   CS,    H,CMBlw,VMPst,
+      H,VMPst, VAbv,VMAbv, VPst,   IS,    R, MPst,    R, MPst,CMBlw,    B,FMBlw, VBlw,VMAbv,    R,
+   MBlw, MBlw,   GB, FBlw, FBlw,CMAbv,   IS, VBlw,   IS,   GB, VAbv,    R,VMPst,    H,    H,    B,
+      H,    B,VMBlw,    O, VBlw,
 };
 static const uint16_t
-hb_use_u16[776] =
+hb_use_u16[784] =
 {
     0,  0,  1,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  5,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,
@@ -332,14 +336,14 @@ hb_use_u16[776] =
     9,242, 73,243,  0,  0,  0,  0,244,  9,  9,245,246,  2,247,  9,
   248,249,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,250,
   251, 48,  9,252,253,  2,  0,  0,  9,  9,  9,  9,  9,  9,  9,  9,
-    9,  9, 98,254,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
-    9,  9,  9,255,  0,  0,  0,  0,  9,  9,  9,  9,256,257,258,258,
-  259,260,  0,  0,  0,  0,261,  0,  9,  9,  9,  9,  9,262,  0,  0,
-    9,  9,  9,  9,  9,  9,105, 70, 94,263,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,264,  9,  9, 70,265,266,  0,  0,  0,
-    0,  9,267,  0,  9,  9,268,  2,  9,  9,  9,  9,269,  2,  0,  0,
-  129,129,129,129,129,129,129,129,160,160,160,160,160,160,160,160,
-  160,160,160,160,160,160,160,129,
+    9,  9,  9,254,255,256,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+    9,  9,  9,257,  0,  0,  0,  0,  9,  9,  9,  9,258,259,260,260,
+  261,262,  0,  0,  0,  0,263,  0,  9,  9,  9,  9,  9,264,  0,  0,
+    9,  9,  9,  9,  9,  9,105, 70, 94,265,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,266,  9,  9, 70,267,268,  0,  0,  0,
+    0,  9,269,  0,  9,  9,270,  2,  0,  0,  0,  0,  0,  9,271,  2,
+    9,  9,  9,  9,272,  2,  0,  0,129,129,129,129,129,129,129,129,
+  160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
 };
 
 static inline unsigned
@@ -350,7 +354,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
 static inline uint_fast8_t
 hb_use_get_category (unsigned u)
 {
-  return u<921600u?hb_use_u8[2753+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+  return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
 }
 
 #undef B

+ 34 - 0
thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc

@@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
       }
       break;
 
+    case HB_SCRIPT_KHOJKI:
+      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+      {
+	bool matched = false;
+	switch (buffer->cur ().codepoint)
+	{
+	  case 0x11200u:
+	    switch (buffer->cur (1).codepoint)
+	    {
+	      case 0x1122Cu: case 0x11231u: case 0x11233u:
+		matched = true;
+		break;
+	    }
+	    break;
+	  case 0x11206u:
+	    matched = 0x1122Cu == buffer->cur (1).codepoint;
+	    break;
+	  case 0x1122Cu:
+	    switch (buffer->cur (1).codepoint)
+	    {
+	      case 0x11230u: case 0x11231u:
+		matched = true;
+		break;
+	    }
+	    break;
+	  case 0x11240u:
+	    matched = 0x1122Eu == buffer->cur (1).codepoint;
+	    break;
+	}
+	(void) buffer->next_glyph ();
+	if (matched) _output_with_dotted_circle (buffer);
+      }
+      break;
+
     case HB_SCRIPT_KHUDAWADI:
       for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
       {

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

@@ -136,7 +136,7 @@ struct AxisValueFormat1
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  HBFixed	value;		/* A numeric value for this attribute value. */
+  F16DOT16	value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
@@ -195,10 +195,10 @@ struct AxisValueFormat2
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  HBFixed	nominalValue;	/* A numeric value for this attribute value. */
-  HBFixed	rangeMinValue;	/* The minimum value for a range associated
+  F16DOT16	nominalValue;	/* A numeric value for this attribute value. */
+  F16DOT16	rangeMinValue;	/* The minimum value for a range associated
 				 * with the specified name ID. */
-  HBFixed	rangeMaxValue;	/* The maximum value for a range associated
+  F16DOT16	rangeMaxValue;	/* The maximum value for a range associated
 				 * with the specified name ID. */
   public:
   DEFINE_SIZE_STATIC (20);
@@ -258,8 +258,8 @@ struct AxisValueFormat3
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  HBFixed	value;		/* A numeric value for this attribute value. */
-  HBFixed	linkedValue;	/* The numeric value for a style-linked mapping
+  F16DOT16	value;		/* A numeric value for this attribute value. */
+  F16DOT16	linkedValue;	/* The numeric value for a style-linked mapping
 				 * from this value. */
   public:
   DEFINE_SIZE_STATIC (16);
@@ -280,7 +280,7 @@ struct AxisValueRecord
   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
 				 * identifying the axis to which this value
 				 * applies. Must be less than designAxisCount. */
-  HBFixed	value;		/* A numeric value for this attribute value. */
+  F16DOT16	value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (6);
 };

+ 89 - 9
thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh

@@ -44,9 +44,47 @@ struct InstanceRecord
 {
   friend struct fvar;
 
-  hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
+  hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
   { return coordinatesZ.as_array (axis_count); }
 
+  bool subset (hb_subset_context_t *c,
+               unsigned axis_count,
+               bool has_postscript_nameid) const
+  {
+    TRACE_SUBSET (this);
+    if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
+    if (unlikely (!c->serializer->embed (flags))) return_trace (false);
+
+    const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+    const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
+    for (unsigned i = 0 ; i < axis_count; i++)
+    {
+      unsigned *axis_tag;
+      // only keep instances whose coordinates == pinned axis location
+      if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
+
+      if (axes_location->has (*axis_tag) &&
+          fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
+        return_trace (false);
+
+      if (!c->plan->axes_index_map->has (i))
+        continue;
+
+      if (!c->serializer->embed (coords[i]))
+        return_trace (false);
+    }
+
+    if (has_postscript_nameid)
+    {
+      NameID name_id;
+      name_id = StructAfter<NameID> (coords);
+      if (!c->serializer->embed (name_id))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
   {
     TRACE_SANITIZE (this);
@@ -58,7 +96,7 @@ struct InstanceRecord
   NameID	subfamilyNameID;/* The name ID for entries in the 'name' table
 				 * that provide subfamily names for this instance. */
   HBUINT16	flags;		/* Reserved for future use — set to 0. */
-  UnsizedArrayOf<HBFixed>
+  UnsizedArrayOf<F16DOT16>
 		coordinatesZ;	/* The coordinates array for this instance. */
   //NameID	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
   //				  * table that provide PostScript names for this
@@ -151,9 +189,9 @@ struct AxisRecord
   public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
   protected:
-  HBFixed	minValue;	/* The minimum coordinate value for the axis. */
-  HBFixed	defaultValue;	/* The default coordinate value for the axis. */
-  HBFixed	maxValue;	/* The maximum coordinate value for the axis. */
+  F16DOT16	minValue;	/* The minimum coordinate value for the axis. */
+  F16DOT16	defaultValue;	/* The default coordinate value for the axis. */
+  F16DOT16	maxValue;	/* The maximum coordinate value for the axis. */
   public:
   HBUINT16	flags;		/* Axis flags. */
   NameID	axisNameID;	/* The name ID for entries in the 'name' table that
@@ -268,7 +306,7 @@ struct fvar
 
     if (coords_length && *coords_length)
     {
-      hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
+      hb_array_t<const F16DOT16> instanceCoords = instance->get_coordinates (axisCount)
 							 .sub_array (0, coords_length);
       for (unsigned int i = 0; i < instanceCoords.length; i++)
 	coords[i] = instanceCoords.arrayZ[i].to_float ();
@@ -301,7 +339,7 @@ struct fvar
 
       if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
                   | hb_filter (pinned_axes, hb_second)
-                  | hb_map ([&] (const hb_pair_t<const HBFixed&, unsigned>& _)
+                  | hb_map ([&] (const hb_pair_t<const F16DOT16&, unsigned>& _)
                             {
                               hb_tag_t axis_tag = pinned_axes.get (_.second);
                               float location = user_axes_location->get (axis_tag);
@@ -321,6 +359,48 @@ struct fvar
     }
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    unsigned retained_axis_count = c->plan->axes_index_map->get_population ();
+    if (!retained_axis_count) //all axes are pinned
+      return_trace (false);
+
+    fvar *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    bool has_postscript_nameid = false;
+    if (instanceSize >= axisCount * 4 + 6)
+      has_postscript_nameid = true;
+
+    if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
+                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    auto axes_records = get_axes ();
+    for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+    {
+      if (!c->plan->axes_index_map->has (i)) continue;
+      if (unlikely (!c->serializer->embed (axes_records[i])))
+        return_trace (false);
+    }
+
+    if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+    {
+      const InstanceRecord *instance = get_instance (i);
+      auto snap = c->serializer->snapshot ();
+      if (!instance->subset (c, axisCount, has_postscript_nameid))
+        c->serializer->revert (snap);
+    }
+    return_trace (true);
+  }
+
   public:
   hb_array_t<const AxisRecord> get_axes () const
   { return hb_array (&(this+firstAxis), axisCount); }
@@ -346,8 +426,8 @@ struct fvar
   HBUINT16	instanceCount;	/* The number of named instances defined in the font
 				 * (the number of records in the instances array). */
   HBUINT16	instanceSize;	/* The size in bytes of each InstanceRecord — set
-				 * to either axisCount * sizeof(HBFixed) + 4, or to
-				 * axisCount * sizeof(HBFixed) + 6. */
+				 * to either axisCount * sizeof(F16DOT16) + 4, or to
+				 * axisCount * sizeof(F16DOT16) + 6. */
 
   public:
   DEFINE_SIZE_STATIC (16);

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

@@ -244,7 +244,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
     {
       // The child object is shared, we may be able to eliminate the overflow
       // by duplicating it.
-      if (!sorted_graph.duplicate (r.parent, r.child)) continue;
+      if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
       return true;
     }
 

+ 76 - 0
thirdparty/harfbuzz/src/hb-subset-accelerator.hh

@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef HB_SUBSET_ACCELERATOR_HH
+#define HB_SUBSET_ACCELERATOR_HH
+
+
+#include "hb.hh"
+
+#include "hb-map.hh"
+#include "hb-set.hh"
+
+struct hb_subset_accelerator_t
+{
+  static hb_user_data_key_t* user_data_key()
+  {
+    static hb_user_data_key_t key;
+    return &key;
+  }
+
+  static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
+                                         const hb_set_t& unicodes_) {
+    hb_subset_accelerator_t* accel =
+        (hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
+    new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
+    return accel;
+  }
+
+  static void destroy(void* value) {
+    if (!value) return;
+
+    hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
+    accel->~hb_subset_accelerator_t ();
+    hb_free (accel);
+  }
+
+  hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
+                          const hb_set_t& unicodes_)
+      : unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
+
+  const hb_map_t unicode_to_gid;
+  const hb_set_t unicodes;
+  // TODO(garretrieger): cumulative glyf checksum map
+  // TODO(garretrieger): sanitized table cache.
+
+  bool in_error () const
+  {
+    return unicode_to_gid.in_error() || unicodes.in_error ();
+  }
+};
+
+
+#endif /* HB_SUBSET_ACCELERATOR_HH */

+ 51 - 4
thirdparty/harfbuzz/src/hb-subset-input.cc

@@ -49,7 +49,7 @@ hb_subset_input_create_or_fail (void)
     set = hb_set_create ();
 
   input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
-  
+
   if (!input->axes_location || input->in_error ())
   {
     hb_subset_input_destroy (input);
@@ -89,7 +89,6 @@ hb_subset_input_create_or_fail (void)
 
   hb_tag_t default_no_subset_tables[] = {
     HB_TAG ('a', 'v', 'a', 'r'),
-    HB_TAG ('f', 'v', 'a', 'r'),
     HB_TAG ('g', 'a', 's', 'p'),
     HB_TAG ('c', 'v', 't', ' '),
     HB_TAG ('f', 'p', 'g', 'm'),
@@ -393,7 +392,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
  *
  * Since: EXPERIMENTAL
  **/
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
                                      hb_face_t          *face,
                                      hb_tag_t            axis_tag)
@@ -417,7 +416,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t  *input,
  *
  * Since: EXPERIMENTAL
  **/
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
                                    hb_face_t          *face,
                                    hb_tag_t            axis_tag,
@@ -432,3 +431,51 @@ hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
 }
 #endif
 #endif
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_preprocess
+ * @input: a #hb_face_t object.
+ *
+ * Preprocesses the face and attaches data that will be needed by the
+ * subsetter. Future subsetting operations can then use the precomputed data
+ * to speed up the subsetting operation.
+ *
+ * Since: EXPERIMENTAL
+ **/
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source)
+{
+  hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+
+  hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+  hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+
+  hb_set_clear (hb_subset_input_set(input,
+                                    HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+  hb_set_invert (hb_subset_input_set(input,
+                                     HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+
+  hb_set_clear (hb_subset_input_set(input,
+                                    HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+  hb_set_invert (hb_subset_input_set(input,
+                                     HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+
+  hb_set_clear (hb_subset_input_set(input,
+                                    HB_SUBSET_SETS_NAME_ID));
+  hb_set_invert (hb_subset_input_set(input,
+                                     HB_SUBSET_SETS_NAME_ID));
+
+  hb_subset_input_set_flags(input,
+                            HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+                            HB_SUBSET_FLAGS_GLYPH_NAMES |
+                            HB_SUBSET_FLAGS_RETAIN_GIDS);
+  input->attach_accelerator_data = true;
+
+  hb_face_t* new_source = hb_subset_or_fail (source, input);
+  hb_subset_input_destroy (input);
+
+  return new_source;
+}
+#endif

+ 1 - 0
thirdparty/harfbuzz/src/hb-subset-input.hh

@@ -59,6 +59,7 @@ struct hb_subset_input_t
   };
 
   unsigned flags;
+  bool attach_accelerator_data = false;
   hb_hashmap_t<hb_tag_t, float> *axes_location;
 
   inline unsigned num_sets () const

+ 148 - 53
thirdparty/harfbuzz/src/hb-subset-plan.cc

@@ -25,6 +25,7 @@
  */
 
 #include "hb-subset-plan.hh"
+#include "hb-subset-accelerator.hh"
 #include "hb-map.hh"
 #include "hb-set.hh"
 
@@ -129,7 +130,9 @@ template <typename T>
 static void _collect_layout_indices (hb_subset_plan_t     *plan,
                                      const T&              table,
                                      hb_set_t		  *lookup_indices, /* OUT */
-                                     hb_set_t		  *feature_indices /* OUT */)
+                                     hb_set_t		  *feature_indices, /* OUT */
+                                     hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
+                                     hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
 {
   unsigned num_features = table.get_feature_count ();
   hb_vector_t<hb_tag_t> features;
@@ -154,16 +157,37 @@ static void _collect_layout_indices (hb_subset_plan_t     *plan,
                                  retain_all_features ? nullptr : features.arrayZ,
                                  feature_indices);
 
+#ifndef HB_NO_VAR
+  // collect feature substitutes with variations
+  if (!plan->user_axes_location->is_empty ())
+  {
+    hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
+    OT::hb_collect_feature_substitutes_with_var_context_t c =
+    {
+      plan->axes_old_index_tag_map,
+      plan->axes_location,
+      feature_record_cond_idx_map,
+      feature_substitutes_map,
+      feature_indices,
+      true,
+      0,
+      &conditionset_map
+    };
+    table.collect_feature_substitutes_with_variations (&c);
+  }
+#endif
+
   for (unsigned feature_index : *feature_indices)
   {
-    //TODO: replace HB_OT_LAYOUT_NO_VARIATIONS_INDEX with variation_index for
-    //instancing
-    const OT::Feature &f = table.get_feature_variation (feature_index, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
-    f.add_lookup_indexes_to (lookup_indices);
+    const OT::Feature* f = &(table.get_feature (feature_index));
+    const OT::Feature **p = nullptr;
+    if (feature_substitutes_map->has (feature_index, &p))
+      f = *p;
+
+    f->add_lookup_indexes_to (lookup_indices);
   }
 
-  //TODO: update for instancing: only collect lookups from feature_indexes that have no variations
-  table.feature_variation_collect_lookups (feature_indices, lookup_indices);
+  table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
 }
 
 
@@ -171,6 +195,7 @@ static inline void
 _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
 				   const hb_map_t *lookup_indices,
 				   const hb_set_t *feature_indices,
+				   const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
 				   hb_map_t *duplicate_feature_map /* OUT */)
 {
   if (feature_indices->is_empty ()) return;
@@ -195,16 +220,22 @@ _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
     hb_set_t* same_tag_features = unique_features.get (t);
     for (unsigned other_f_index : same_tag_features->iter ())
     {
-      const OT::Feature& f = g.get_feature (i);
-      const OT::Feature& other_f = g.get_feature (other_f_index);
+      const OT::Feature* f = &(g.get_feature (i));
+      const OT::Feature **p = nullptr;
+      if (feature_substitutes_map->has (i, &p))
+        f = *p;
+
+      const OT::Feature* other_f = &(g.get_feature (other_f_index));
+      if (feature_substitutes_map->has (other_f_index, &p))
+        f = *p;
 
       auto f_iter =
-      + hb_iter (f.lookupIndex)
+      + hb_iter (f->lookupIndex)
       | hb_filter (lookup_indices)
       ;
 
       auto other_f_iter =
-      + hb_iter (other_f.lookupIndex)
+      + hb_iter (other_f->lookupIndex)
       | hb_filter (lookup_indices)
       ;
 
@@ -237,7 +268,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
 				  hb_set_t	     *gids_to_retain,
 				  hb_map_t	     *lookups,
 				  hb_map_t	     *features,
-				  script_langsys_map *langsys_map)
+				  script_langsys_map *langsys_map,
+				  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
+				  hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
 {
   hb_blob_ptr_t<T> table = plan->source_table<T> ();
   hb_tag_t table_tag = table->tableTag;
@@ -245,7 +278,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
   _collect_layout_indices<T> (plan,
                               *table,
                               &lookup_indices,
-                              &feature_indices);
+                              &feature_indices,
+                              feature_record_cond_idx_map,
+                              feature_substitutes_map);
 
   if (table_tag == HB_OT_TAG_GSUB)
     hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -257,9 +292,12 @@ _closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
   _remap_indexes (&lookup_indices, lookups);
 
   // prune features
-  table->prune_features (lookups, &feature_indices);
+  table->prune_features (lookups,
+                         plan->user_axes_location->is_empty () ? nullptr : feature_record_cond_idx_map,
+                         feature_substitutes_map,
+                         &feature_indices);
   hb_map_t duplicate_feature_map;
-  _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map);
+  _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
 
   feature_indices.clear ();
   table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
@@ -419,41 +457,73 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
                               hb_subset_plan_t *plan)
 {
   OT::cmap::accelerator_t cmap (plan->source);
-
   unsigned size_threshold = plan->source->get_num_glyphs ();
   if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
   {
+
+    const hb_map_t* unicode_to_gid = nullptr;
+    if (plan->accelerator)
+      unicode_to_gid = &plan->accelerator->unicode_to_gid;
+
     // This is approach to collection is faster, but can only be used  if glyphs
     // are not being explicitly added to the subset and the input unicodes set is
     // not excessively large (eg. an inverted set).
     plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
-    for (hb_codepoint_t cp : *unicodes)
-    {
-      hb_codepoint_t gid;
-      if (!cmap.get_nominal_glyph (cp, &gid))
+    if (!unicode_to_gid) {
+      for (hb_codepoint_t cp : *unicodes)
       {
-        DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
-        continue;
+        hb_codepoint_t gid;
+        if (!cmap.get_nominal_glyph (cp, &gid))
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+          continue;
+        }
+
+        plan->codepoint_to_glyph->set (cp, gid);
+        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+      }
+    } else {
+      // Use in memory unicode to gid map it's faster then looking up from
+      // the map. This code is mostly duplicated from above to avoid doing
+      // conditionals on the presence of the unicode_to_gid map each
+      // iteration.
+      for (hb_codepoint_t cp : *unicodes)
+      {
+        hb_codepoint_t gid = unicode_to_gid->get (cp);
+        if (gid == HB_MAP_VALUE_INVALID)
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+          continue;
+        }
+
+        plan->codepoint_to_glyph->set (cp, gid);
+        plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
       }
-
-      plan->codepoint_to_glyph->set (cp, gid);
-      plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
     }
   }
   else
   {
     // This approach is slower, but can handle adding in glyphs to the subset and will match
     // them with cmap entries.
-    hb_map_t unicode_glyphid_map;
-    hb_set_t cmap_unicodes;
-    cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map);
-    plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
-                                                + glyphs->get_population (),
-                                                cmap_unicodes.get_population ()));
-
-    for (hb_codepoint_t cp : cmap_unicodes)
+
+    hb_map_t unicode_glyphid_map_storage;
+    hb_set_t cmap_unicodes_storage;
+    const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
+    const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
+
+    if (!plan->accelerator) {
+      cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
+      plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
+                                                  + glyphs->get_population (),
+                                                  cmap_unicodes->get_population ()));
+    } else {
+      unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
+      cmap_unicodes = &plan->accelerator->unicodes;
+    }
+
+    for (hb_codepoint_t cp : *cmap_unicodes)
     {
-      hb_codepoint_t gid = unicode_glyphid_map[cp];
+      hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
       if (!unicodes->has (cp) && !glyphs->has (gid))
         continue;
 
@@ -509,9 +579,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
 
 static void
 _populate_gids_to_retain (hb_subset_plan_t* plan,
-			  bool close_over_gsub,
-			  bool close_over_gpos,
-			  bool close_over_gdef)
+		          hb_set_t* drop_tables)
 {
   OT::glyf_accelerator_t glyf (plan->source);
 #ifndef HB_NO_SUBSET_CFF
@@ -523,32 +591,42 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
   _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
 
 #ifndef HB_NO_SUBSET_LAYOUT
-  if (close_over_gsub)
+  if (!drop_tables->has (HB_OT_TAG_GSUB))
     // closure all glyphs/lookups/features needed for GSUB substitutions.
     _closure_glyphs_lookups_features<GSUB> (
         plan,
         plan->_glyphset_gsub,
         plan->gsub_lookups,
         plan->gsub_features,
-        plan->gsub_langsys);
+        plan->gsub_langsys,
+        plan->gsub_feature_record_cond_idx_map,
+        plan->gsub_feature_substitutes_map);
 
-  if (close_over_gpos)
+  if (!drop_tables->has (HB_OT_TAG_GPOS))
     _closure_glyphs_lookups_features<GPOS> (
         plan,
         plan->_glyphset_gsub,
         plan->gpos_lookups,
         plan->gpos_features,
-        plan->gpos_langsys);
+        plan->gpos_langsys,
+        plan->gpos_feature_record_cond_idx_map,
+        plan->gpos_feature_substitutes_map);
 #endif
   _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
 
   hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
-  _math_closure (plan, plan->_glyphset_mathed);
-  _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+  if (!drop_tables->has (HB_OT_TAG_MATH))
+  {
+    _math_closure (plan, plan->_glyphset_mathed);
+    _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+  }
 
   hb_set_t cur_glyphset = *plan->_glyphset_mathed;
-  _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
-  _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
+  if (!drop_tables->has (HB_OT_TAG_COLR))
+  {
+    _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
+    _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
+  }
 
   hb_set_set (plan->_glyphset_colred, &cur_glyphset);
 
@@ -570,7 +648,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
 
 
 #ifndef HB_NO_VAR
-  if (close_over_gdef)
+  if (!drop_tables->has (HB_OT_TAG_GDEF))
     _collect_layout_variation_indices (plan);
 #endif
 }
@@ -659,18 +737,22 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
     seg_maps = face->table.avar->get_segment_maps ();
 
   bool axis_not_pinned = false;
-  unsigned axis_count = 0;
+  unsigned old_axis_idx = 0, new_axis_idx = 0;
   for (const auto& axis : axes)
   {
     hb_tag_t axis_tag = axis.get_axis_tag ();
+    plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag);
+
     if (!plan->user_axes_location->has (axis_tag))
     {
       axis_not_pinned = true;
+      plan->axes_index_map->set (old_axis_idx, new_axis_idx);
+      new_axis_idx++;
     }
     else
     {
       int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
-      if (has_avar && axis_count < face->table.avar->get_axis_count ())
+      if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
       {
         normalized_v = seg_maps->map (normalized_v);
       }
@@ -681,7 +763,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
     if (has_avar)
       seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
 
-    axis_count++;
+    old_axis_idx++;
   }
   plan->all_axes_pinned = !axis_not_pinned;
 }
@@ -741,6 +823,13 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
 
   plan->gsub_features = hb_map_create ();
   plan->gpos_features = hb_map_create ();
+
+  plan->check_success (plan->gsub_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+  plan->check_success (plan->gpos_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+
+  plan->check_success (plan->gsub_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+  plan->check_success (plan->gpos_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+
   plan->colrv1_layers = hb_map_create ();
   plan->colr_palettes = hb_map_create ();
   plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
@@ -751,12 +840,21 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
   plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
   if (plan->user_axes_location && input->axes_location)
       *plan->user_axes_location = *input->axes_location;
+  plan->check_success (plan->axes_index_map = hb_map_create ());
+  plan->check_success (plan->axes_old_index_tag_map = hb_map_create ());
   plan->all_axes_pinned = false;
   plan->pinned_at_default = true;
 
   plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
   plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
 
+  void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
+
+  plan->attach_accelerator_data = input->attach_accelerator_data;
+  if (accel)
+    plan->accelerator = (hb_subset_accelerator_t*) accel;
+
+
   if (unlikely (plan->in_error ())) {
     hb_subset_plan_destroy (plan);
     return nullptr;
@@ -768,10 +866,7 @@ hb_subset_plan_create_or_fail (hb_face_t	 *face,
 
   _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
 
-  _populate_gids_to_retain (plan,
-			    !input->sets.drop_tables->has (HB_OT_TAG_GSUB),
-			    !input->sets.drop_tables->has (HB_OT_TAG_GPOS),
-			    !input->sets.drop_tables->has (HB_OT_TAG_GDEF));
+  _populate_gids_to_retain (plan, input->sets.drop_tables);
 
   _create_old_gid_to_new_gid_map (face,
                                   input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,

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

@@ -31,11 +31,16 @@
 
 #include "hb-subset.h"
 #include "hb-subset-input.hh"
+#include "hb-subset-accelerator.hh"
 
 #include "hb-map.hh"
 #include "hb-bimap.hh"
 #include "hb-set.hh"
 
+namespace OT {
+struct Feature;
+}
+
 struct hb_subset_plan_t
 {
   hb_subset_plan_t ()
@@ -67,9 +72,15 @@ struct hb_subset_plan_t
     hb_map_destroy (gpos_features);
     hb_map_destroy (colrv1_layers);
     hb_map_destroy (colr_palettes);
+    hb_map_destroy (axes_index_map);
+    hb_map_destroy (axes_old_index_tag_map);
 
     hb_hashmap_destroy (gsub_langsys);
     hb_hashmap_destroy (gpos_langsys);
+    hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
+    hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
+    hb_hashmap_destroy (gsub_feature_substitutes_map);
+    hb_hashmap_destroy (gpos_feature_substitutes_map);
     hb_hashmap_destroy (axes_location);
     hb_hashmap_destroy (sanitized_table_cache);
     hb_hashmap_destroy (hmtx_map);
@@ -87,6 +98,7 @@ struct hb_subset_plan_t
 
   bool successful;
   unsigned flags;
+  bool attach_accelerator_data = false;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
@@ -143,6 +155,15 @@ struct hb_subset_plan_t
   hb_map_t *gsub_features;
   hb_map_t *gpos_features;
 
+  //active feature variation records/condition index with variations
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
+  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
+
+  //feature index-> address of substituation feature table mapping with
+  //variations
+  hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
+  hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
+
   //active layers/palettes we'd like to retain
   hb_map_t *colrv1_layers;
   hb_map_t *colr_palettes;
@@ -158,6 +179,10 @@ struct hb_subset_plan_t
   hb_hashmap_t<hb_tag_t, int> *axes_location;
   //user specified axes location map
   hb_hashmap_t<hb_tag_t, float> *user_axes_location;
+  //retained old axis index -> new axis index mapping in fvar axis array
+  hb_map_t *axes_index_map;
+  //axis_index->axis_tag mapping in fvar axis array
+  hb_map_t *axes_old_index_tag_map;
   bool all_axes_pinned;
   bool pinned_at_default;
 
@@ -166,6 +191,8 @@ struct hb_subset_plan_t
   //vmtx metrics map: new gid->(advance, lsb)
   hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
 
+  const hb_subset_accelerator_t* accelerator;
+
  public:
 
   template<typename T>

+ 30 - 0
thirdparty/harfbuzz/src/hb-subset.cc

@@ -50,11 +50,13 @@
 #include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-fvar-table.hh"
 #include "hb-ot-var-gvar-table.hh"
 #include "hb-ot-var-hvar-table.hh"
 #include "hb-ot-math-table.hh"
 #include "hb-ot-stat-table.hh"
 #include "hb-repacker.hh"
+#include "hb-subset-accelerator.hh"
 
 using OT::Layout::GSUB;
 using OT::Layout::GPOS;
@@ -475,6 +477,9 @@ _subset_table (hb_subset_plan_t *plan,
   case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
   case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
 #endif
+  case HB_OT_TAG_fvar:
+    if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
+    return _subset<const OT::fvar> (plan, buf);
   case HB_OT_TAG_STAT:
     /*TODO(qxliu): change the condition as we support more complex
      * instancing operation*/
@@ -490,6 +495,27 @@ _subset_table (hb_subset_plan_t *plan,
   }
 }
 
+static void _attach_accelerator_data (const hb_subset_plan_t* plan,
+                                      hb_face_t* face /* IN/OUT */)
+{
+  hb_subset_accelerator_t* accel =
+      hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
+                                       *plan->unicodes);
+
+  if (accel->in_error ())
+  {
+    hb_subset_accelerator_t::destroy (accel);
+    return;
+  }
+
+  if (!hb_face_set_user_data(face,
+                             hb_subset_accelerator_t::user_data_key(),
+                             accel,
+                             hb_subset_accelerator_t::destroy,
+                             true))
+    hb_subset_accelerator_t::destroy (accel);
+}
+
 /**
  * hb_subset_or_fail:
  * @source: font face data to be subset.
@@ -572,6 +598,10 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
     offset += num_tables;
   }
 
+  if (success && plan->attach_accelerator_data) {
+    _attach_accelerator_data (plan, plan->dest);
+  }
+
 end:
   return success ? hb_face_reference (plan->dest) : nullptr;
 }

+ 17 - 0
thirdparty/harfbuzz/src/hb-subset.h

@@ -70,6 +70,14 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
  * in the final subset.
  * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
  * OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified
+ * to produce a subset that is better suited to patching. For example cmap
+ * subtable format will be kept stable.
+ * @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final
+ * glyf table bytes. The table directory will include and entry as if the table was
+ * there but the actual final font blob will be truncated prior to the glyf data. This
+ * is a useful performance optimization when a font aware binary patching algorithm
+ * is being used to diff two subsets.
  *
  * List of boolean properties that can be configured on the subset input.
  *
@@ -86,6 +94,8 @@ typedef enum { /*< flags >*/
   HB_SUBSET_FLAGS_NOTDEF_OUTLINE =	     0x00000040u,
   HB_SUBSET_FLAGS_GLYPH_NAMES =		     0x00000080u,
   HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES =  0x00000100u,
+  // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u,
+  // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF =  0x00000400u,
 } hb_subset_flags_t;
 
 /**
@@ -169,6 +179,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t  *input,
 #endif
 #endif
 
+#ifdef HB_EXPERIMENTAL_API
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source);
+
+#endif
+
 HB_EXTERN hb_face_t *
 hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
 

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

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