[HarfBuzz] harfbuzz: Branch 'master' - 20 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Tue Sep 4 21:20:53 UTC 2018


 src/Makefile.sources                       |    1 
 src/hb-machinery.hh                        |  103 ++++---
 src/hb-null.hh                             |   43 ++-
 src/hb-open-file.hh                        |    3 
 src/hb-open-type.hh                        |   26 +
 src/hb-ot-cmap-table.hh                    |    1 
 src/hb-ot-glyf-table.hh                    |    2 
 src/hb-ot-hdmx-table.hh                    |    1 
 src/hb-ot-hmtx-table.hh                    |    1 
 src/hb-ot-layout-common.hh                 |  222 +++++++++++++---
 src/hb-ot-layout-gdef-table.hh             |   33 +-
 src/hb-ot-layout-gpos-table.hh             |  191 ++++++++++----
 src/hb-ot-layout-gsub-table.hh             |  360 +++++++++++++++++++-------
 src/hb-ot-layout-gsubgpos.hh               |  391 +++++++++++++++++++++++------
 src/hb-ot-maxp-table.hh                    |    1 
 src/hb-ot-os2-table.hh                     |    1 
 src/hb-ot-post-table.hh                    |    1 
 src/hb-ot-shape-complex-arabic-fallback.hh |    1 
 src/hb-subset-glyf.cc                      |    1 
 src/hb-subset-glyf.hh                      |    2 
 src/hb-subset-input.cc                     |   44 +--
 src/hb-subset-input.hh                     |   57 ++++
 src/hb-subset-plan.cc                      |   24 -
 src/hb-subset-plan.hh                      |   15 -
 src/hb-subset.cc                           |   13 
 src/hb-subset.h                            |   14 -
 src/hb-subset.hh                           |   37 +-
 src/hb-vector.hh                           |    2 
 test/api/test-subset-glyf.c                |   10 
 test/fuzzing/hb-subset-fuzzer.cc           |   10 
 util/hb-subset.cc                          |    3 
 31 files changed, 1199 insertions(+), 415 deletions(-)

New commits:
commit 0d160d5ff5158fd4190201becd652c8f28ef4430
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 20:50:11 2018 -0700

    [subset] Implement subsetting of SingleSubst

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 280a5a69..68994160 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -452,6 +452,8 @@ struct hb_serialize_context_t
     this->debug_depth = 0;
   }
 
+  inline bool err (bool e) { return this->ran_out_of_room = this->ran_out_of_room || e; }
+
   /* To be called around main operation. */
   template <typename Type>
   inline Type *start_serialize (void)
diff --git a/src/hb-null.hh b/src/hb-null.hh
index 19886a5c..7128f0a9 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -51,27 +51,40 @@ static inline Type const & Null (void) {
 
 /* Specializaitons for arbitrary-content Null objects expressed in bytes. */
 #define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-} /* Close namespace. */ \
-extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
-template <> \
-/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
-  return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
-} \
-namespace Namespace { \
-static_assert (true, "Just so we take semicolon after.")
+	} /* Close namespace. */ \
+	extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
+	template <> \
+	/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
+	  return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
+	} \
+	namespace Namespace { \
+	static_assert (true, "Just so we take semicolon after.")
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
+	const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
 
 /* Specializaitons for arbitrary-content Null objects expressed as struct initializer. */
 #define DECLARE_NULL_INSTANCE(Type) \
-extern HB_INTERNAL const Type _hb_Null_##Type; \
-template <> \
-/*static*/ inline const Type& Null<Type> (void) { \
-  return _hb_Null_##Type; \
-} \
+	extern HB_INTERNAL const Type _hb_Null_##Type; \
+	template <> \
+	/*static*/ inline const Type& Null<Type> (void) { \
+	  return _hb_Null_##Type; \
+	} \
 static_assert (true, "Just so we take semicolon after.")
 #define DEFINE_NULL_INSTANCE(Type) \
-const Type _hb_Null_##Type
+	const Type _hb_Null_##Type
+
+/* Specializaiton to disallow Null objects. */
+#define DECLARE_NULL_DISALLOW(Type) \
+	template <> inline const Type& Null<Type> (void)
+#define DECLARE_NULL_NAMSPACE_DISALLOW(Namespace, Type) \
+	} /* Close namespace. */ \
+	template <> \
+	/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
+	  extern void *_hb_undefined; \
+	  return *reinterpret_cast<const Namespace::Type *> (_hb_undefined); \
+	} \
+	namespace Namespace { \
+	static_assert (true, "Just so we take semicolon after.")
 
 /* Global writable pool.  Enlarge as necessary. */
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index c0f70815..57633610 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -35,6 +35,11 @@
 namespace OT {
 
 
+static inline void SingleSubst_serialize (hb_serialize_context_t *c,
+					  Supplier<GlyphID> &glyphs,
+					  Supplier<GlyphID> &substitutes,
+					  unsigned int num_glyphs);
+
 struct SingleSubstFormat1
 {
   inline bool intersects (const hb_set_t *glyphs) const
@@ -104,19 +109,26 @@ struct SingleSubstFormat1
 
   inline bool subset (hb_subset_context_t *c) const
   {
-    return false;
     TRACE_SUBSET (this);
-    hb_auto_t<hb_vector_t<hb_codepoint_t>> from;
-    hb_auto_t<hb_vector_t<hb_codepoint_t>> to;
+    hb_auto_t<hb_vector_t<GlyphID>> from;
+    hb_auto_t<hb_vector_t<GlyphID>> to;
     hb_codepoint_t delta = deltaGlyphID;
     for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
     {
-      //if (!c->plan->glyphs->has (iter.get_glyph ()))
-      //  continue;
-      from.push (iter.get_glyph ());
-      to.push ((iter.get_glyph () + delta) & 0xFFFF);
+      if (!c->plan->glyphset->has (iter.get_glyph ()))
+        continue;
+      from.push ()->set (iter.get_glyph ());
+      to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
     }
-    return_trace (false);
+    c->serializer->err (from.in_error () || to.in_error ());
+
+    Supplier<GlyphID> from_supplier (&from);
+    Supplier<GlyphID> to_supplier (&to);
+    SingleSubst_serialize (c->serializer,
+			   from_supplier,
+			   to_supplier,
+			   from.len);
+    return_trace (from.len);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -204,8 +216,24 @@ struct SingleSubstFormat2
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    hb_auto_t<hb_vector_t<GlyphID>> from;
+    hb_auto_t<hb_vector_t<GlyphID>> to;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (!c->plan->glyphset->has (iter.get_glyph ()))
+        continue;
+      from.push ()->set (iter.get_glyph ());
+      to.push ()->set (substitute[iter.get_coverage ()]);
+    }
+    c->serializer->err (from.in_error () || to.in_error ());
+
+    Supplier<GlyphID> from_supplier (&from);
+    Supplier<GlyphID> to_supplier (&to);
+    SingleSubst_serialize (c->serializer,
+			   from_supplier,
+			   to_supplier,
+			   from.len);
+    return_trace (from.len);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -275,6 +303,17 @@ struct SingleSubst
   } u;
 };
 
+static inline void
+SingleSubst_serialize (hb_serialize_context_t *c,
+		       Supplier<GlyphID> &glyphs,
+		       Supplier<GlyphID> &substitutes,
+		       unsigned int num_glyphs)
+{
+  c->start_embed<SingleSubst> ()->serialize (c,
+					     glyphs,
+					     substitutes,
+					     num_glyphs);
+}
 
 struct Sequence
 {
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 31341747..da548cbb 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -72,6 +72,8 @@ struct hb_vector_t
     return p;
   }
 
+  inline bool in_error (void) const { return allocated == 0; }
+
   /* Allocate for size but don't adjust len. */
   inline bool alloc (unsigned int size)
   {
commit 3f00d0b0df14d69859b15568ff28a810d08f59ea
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 18:54:32 2018 -0700

    [subset] Keep glyph set in plan
    
    Should remove the vector version at some point...

diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index d9d25b3d..05700603 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -68,7 +68,7 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
 }
 
 
-static void
+static hb_set_t *
 _populate_gids_to_retain (hb_face_t *face,
                           const hb_set_t *unicodes,
                           bool close_over_gsub,
@@ -117,9 +117,10 @@ _populate_gids_to_retain (hb_face_t *face,
   while (all_gids_to_retain->next (&gid))
     glyphs->push (gid);
 
-  hb_set_destroy (all_gids_to_retain);
   glyf.fini ();
   cmap.fini ();
+
+  return all_gids_to_retain;
 }
 
 static void
@@ -155,13 +156,12 @@ hb_subset_plan_create (hb_face_t           *face,
   plan->dest = hb_face_builder_create ();
   plan->codepoint_to_glyph = hb_map_create();
   plan->glyph_map = hb_map_create();
-
-  _populate_gids_to_retain (face,
-                            input->unicodes,
-                            !plan->drop_layout,
-                            plan->unicodes,
-                            plan->codepoint_to_glyph,
-                            &plan->glyphs);
+  plan->glyphset = _populate_gids_to_retain (face,
+					     input->unicodes,
+					     !plan->drop_layout,
+					     plan->unicodes,
+					     plan->codepoint_to_glyph,
+					     &plan->glyphs);
   _create_old_gid_to_new_gid_map (plan->glyphs,
                                   plan->glyph_map);
 
@@ -184,6 +184,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
   hb_face_destroy (plan->dest);
   hb_map_destroy (plan->codepoint_to_glyph);
   hb_map_destroy (plan->glyph_map);
+  hb_set_destroy (plan->glyphset);
 
   free (plan);
 }
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index 7b6bc77f..c2c484a5 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -45,9 +45,8 @@ struct hb_subset_plan_t
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
 
-  // This list contains the complete set of glyphs to retain and may contain
-  // more glyphs then the lists above.
   hb_vector_t<hb_codepoint_t> glyphs;
+  hb_set_t *glyphset;
 
   hb_map_t *codepoint_to_glyph;
   hb_map_t *glyph_map;
commit dc50493a8da05d6561242136d63cae836486c150
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 18:23:23 2018 -0700

    [subset] Towards subsetting SingleSubstFormat1
    
    Why does subset plan not have a hb_set_t of glyphs?

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 6e3e70c7..280a5a69 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -33,6 +33,7 @@
 #include "hb-blob.hh"
 
 #include "hb-iter.hh"
+#include "hb-vector.hh"
 
 
 /*
@@ -579,12 +580,19 @@ struct hb_serialize_context_t
 template <typename Type>
 struct Supplier
 {
-  inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
+  inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof (Type))
   {
     head = array;
     len = len_;
     stride = stride_;
   }
+  inline Supplier (const hb_vector_t<Type> *v)
+  {
+    head = v->arrayZ;
+    len = v->len;
+    stride = sizeof (Type);
+  }
+
   inline const Type operator [] (unsigned int i) const
   {
     if (unlikely (i >= len)) return Type ();
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index b5ac08ba..c0f70815 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -104,8 +104,18 @@ struct SingleSubstFormat1
 
   inline bool subset (hb_subset_context_t *c) const
   {
+    return false;
     TRACE_SUBSET (this);
-    // TODO(subset)
+    hb_auto_t<hb_vector_t<hb_codepoint_t>> from;
+    hb_auto_t<hb_vector_t<hb_codepoint_t>> to;
+    hb_codepoint_t delta = deltaGlyphID;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      //if (!c->plan->glyphs->has (iter.get_glyph ()))
+      //  continue;
+      from.push (iter.get_glyph ());
+      to.push ((iter.get_glyph () + delta) & 0xFFFF);
+    }
     return_trace (false);
   }
 
commit 339d3603b916cebf24ff86d9842b766261e1b262
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 17:33:34 2018 -0700

    [subset] Wire up subset() call down to subtables

diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 850ea965..656d31dc 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -703,6 +703,42 @@ struct Lookup
   }
 
   template <typename TSubTable>
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Lookup *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    /* Subset the actual subtables. */
+    /* TODO Drop empty ones, either by calling intersects() beforehand,
+     * or just dropping null offsets after. */
+    const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
+    OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
+    unsigned int count = subTable.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      struct Wrapper
+      {
+        inline Wrapper (const TSubTable &subtable_,
+			unsigned int lookup_type_) :
+			  subtable (subtable_),
+			  lookup_type (lookup_type_) {}
+
+	inline bool subset (hb_subset_context_t *c) const
+	{ return subtable.dispatch (c, lookup_type); }
+
+	private:
+	const TSubTable &subtable;
+	unsigned int lookup_type;
+      } wrapper (this+subtables[i], get_type ());
+
+      out_subtables[i].serialize_subset (c, wrapper, out);
+    }
+
+    return_trace (true);
+  }
+
+  template <typename TSubTable>
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 912bf85f..5847306d 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -484,6 +484,13 @@ struct SinglePosFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -537,6 +544,13 @@ struct SinglePosFormat2
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -742,6 +756,13 @@ struct PairPosFormat1
     return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -828,6 +849,13 @@ struct PairPosFormat2
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1040,6 +1068,13 @@ struct CursivePosFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1140,6 +1175,13 @@ struct MarkBasePosFormat1
     return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1259,6 +1301,13 @@ struct MarkLigPosFormat1
     return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1375,6 +1424,13 @@ struct MarkMarkPosFormat1
     return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1543,6 +1599,9 @@ struct PosLookup : Lookup
   inline typename context_t::return_t dispatch (context_t *c) const
   { return Lookup::dispatch<SubTable> (c); }
 
+  inline bool subset (hb_subset_context_t *c) const
+  { return Lookup::subset<SubTable> (c); }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   { return Lookup::sanitize<SubTable> (c); }
 };
@@ -1563,11 +1622,11 @@ struct GPOS : GSUBGPOS
   static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
   static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
 
+  inline bool subset (hb_subset_context_t *c) const
+  { return GSUBGPOS::subset<PosLookup> (c); }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (GSUBGPOS::sanitize<PosLookup> (c));
-  }
+  { return GSUBGPOS::sanitize<PosLookup> (c); }
 
   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
 };
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index d2a72093..b5ac08ba 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -102,6 +102,13 @@ struct SingleSubstFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -184,6 +191,13 @@ struct SingleSubstFormat2
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -387,6 +401,13 @@ struct MultipleSubstFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -570,6 +591,13 @@ struct AlternateSubstFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -911,6 +939,13 @@ struct LigatureSubstFormat1
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1101,6 +1136,13 @@ struct ReverseChainSingleSubstFormat1
     return_trace (false);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1367,7 +1409,7 @@ struct SubstLookup : Lookup
   { return Lookup::dispatch<SubTable> (c); }
 
   inline bool subset (hb_subset_context_t *c) const
-  { return false; }//XXX Lookup::subset<SubTable> (c); }
+  { return Lookup::subset<SubTable> (c); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   { return Lookup::sanitize<SubTable> (c); }
@@ -1386,16 +1428,10 @@ struct GSUB : GSUBGPOS
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
   inline bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    return_trace (GSUBGPOS::subset<SubstLookup> (c));
-  }
+  { return GSUBGPOS::subset<SubstLookup> (c); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
-  }
+  { return GSUBGPOS::sanitize<SubstLookup> (c); }
 
   typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
 };
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 5ccc5feb..315951a3 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -1435,6 +1435,13 @@ struct ContextFormat1
     return_trace (rule_set.apply (c, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1547,6 +1554,13 @@ struct ContextFormat2
     return_trace (rule_set.apply (c, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1648,6 +1662,13 @@ struct ContextFormat3
     return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2076,6 +2097,13 @@ struct ChainContextFormat1
     return_trace (rule_set.apply (c, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2209,6 +2237,13 @@ struct ChainContextFormat2
     return_trace (rule_set.apply (c, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2352,6 +2387,13 @@ struct ChainContextFormat3
 					      lookup.len, lookup.arrayZ, lookup_context));
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    // TODO(subset)
+    return_trace (false);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
commit 7b2ef551da0d53cd94106035b1f065a759cf3cd5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 17:16:09 2018 -0700

    Templatize Lookup::sanitize()

diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 343b62df..850ea965 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -634,16 +634,16 @@ struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
 
-  template <typename SubTableType>
-  inline const SubTableType& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+  template <typename TSubTable>
+  inline const TSubTable& get_subtable (unsigned int i) const
+  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
 
-  template <typename SubTableType>
-  inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
-  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
-  template <typename SubTableType>
-  inline OffsetArrayOf<SubTableType>& get_subtables (void)
-  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+  template <typename TSubTable>
+  inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
+  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+  template <typename TSubTable>
+  inline OffsetArrayOf<TSubTable>& get_subtables (void)
+  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
 
   inline unsigned int get_size (void) const
   {
@@ -669,14 +669,14 @@ struct Lookup
     return flag;
   }
 
-  template <typename SubTableType, typename context_t>
+  template <typename TSubTable, typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     unsigned int lookup_type = get_type ();
     TRACE_DISPATCH (this, lookup_type);
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
       if (c->stop_sublookup_iteration (r))
         return_trace (r);
     }
@@ -702,16 +702,32 @@ struct Lookup
     return_trace (true);
   }
 
+  template <typename TSubTable>
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
+
+    if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);
+
+    if (unlikely (get_type () == TSubTable::Extension))
+    {
+      /* The spec says all subtables of an Extension lookup should
+       * have the same type, which shall not be the Extension type
+       * itself (but we already checked for that).
+       * This is specially important if one has a reverse type! */
+      unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
+      unsigned int count = get_subtable_count ();
+      for (unsigned int i = 1; i < count; i++)
+        if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
+	  return_trace (false);
+    }
+    return_trace (true);
     return_trace (true);
   }
 
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 3ff72e36..912bf85f 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1445,6 +1445,7 @@ struct ExtensionPos : Extension<ExtensionPos>
 
 struct PosLookupSubTable
 {
+  friend struct Lookup;
   friend struct PosLookup;
 
   enum Type {
@@ -1543,11 +1544,7 @@ struct PosLookup : Lookup
   { return Lookup::dispatch<SubTable> (c); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
-    return_trace (dispatch (c));
-  }
+  { return Lookup::sanitize<SubTable> (c); }
 };
 
 /*
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index a77ab4ca..d2a72093 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1161,6 +1161,7 @@ struct ReverseChainSingleSubst
 
 struct SubstLookupSubTable
 {
+  friend struct Lookup;
   friend struct SubstLookup;
 
   enum Type {
@@ -1366,30 +1367,10 @@ struct SubstLookup : Lookup
   { return Lookup::dispatch<SubTable> (c); }
 
   inline bool subset (hb_subset_context_t *c) const
-  {
-    return false; //XXX
-  }
+  { return false; }//XXX Lookup::subset<SubTable> (c); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
-    if (unlikely (!dispatch (c))) return_trace (false);
-
-    if (unlikely (get_type () == SubTable::Extension))
-    {
-      /* The spec says all subtables of an Extension lookup should
-       * have the same type, which shall not be the Extension type
-       * itself (but we already checked for that).
-       * This is specially important if one has a reverse type! */
-      unsigned int type = get_subtable (0).u.extension.get_type ();
-      unsigned int count = get_subtable_count ();
-      for (unsigned int i = 1; i < count; i++)
-        if (get_subtable (i).u.extension.get_type () != type)
-	  return_trace (false);
-    }
-    return_trace (true);
-  }
+  { return Lookup::sanitize<SubTable> (c); }
 };
 
 /*
commit 9c3747c5e50423e0a7202f249728d5c5b2b09073
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 16:53:03 2018 -0700

    [subset] More

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index f0880610..3ff72e36 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1433,7 +1433,7 @@ struct ChainContextPos : ChainContext {};
 
 struct ExtensionPos : Extension<ExtensionPos>
 {
-  typedef struct PosLookupSubTable LookupSubTable;
+  typedef struct PosLookupSubTable SubTable;
 };
 
 
@@ -1498,8 +1498,10 @@ struct PosLookupSubTable
 
 struct PosLookup : Lookup
 {
-  inline const PosLookupSubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<PosLookupSubTable> (i); }
+  typedef struct PosLookupSubTable SubTable;
+
+  inline const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
 
   inline bool is_reverse (void) const
   {
@@ -1538,7 +1540,7 @@ struct PosLookup : Lookup
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<PosLookupSubTable> (c); }
+  { return Lookup::dispatch<SubTable> (c); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 31e3c2f3..a77ab4ca 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -980,7 +980,7 @@ struct ChainContextSubst : ChainContext {};
 
 struct ExtensionSubst : Extension<ExtensionSubst>
 {
-  typedef struct SubstLookupSubTable LookupSubTable;
+  typedef struct SubstLookupSubTable SubTable;
 
   inline bool is_reverse (void) const;
 };
@@ -1211,16 +1211,18 @@ struct SubstLookupSubTable
 
 struct SubstLookup : Lookup
 {
-  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
-  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
+  typedef SubstLookupSubTable SubTable;
+
+  inline const SubTable& get_subtable (unsigned int i) const
+  { return Lookup::get_subtable<SubTable> (i); }
 
   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
-  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
+  { return lookup_type == SubTable::ReverseChainSingle; }
 
   inline bool is_reverse (void) const
   {
     unsigned int type = get_type ();
-    if (unlikely (type == SubstLookupSubTable::Extension))
+    if (unlikely (type == SubTable::Extension))
       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
@@ -1277,9 +1279,9 @@ struct SubstLookup : Lookup
 
   static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
-  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
-						  unsigned int i)
-  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
+  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
+				       unsigned int i)
+  { return get_subtables<SubTable> ()[i].serialize (c, this); }
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
@@ -1288,7 +1290,7 @@ struct SubstLookup : Lookup
 			        unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
+    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
     return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
   }
 
@@ -1300,7 +1302,7 @@ struct SubstLookup : Lookup
 				  Supplier<GlyphID> &substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
+    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
     return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
 								  glyphs,
 								  substitute_len_list,
@@ -1316,7 +1318,7 @@ struct SubstLookup : Lookup
 				   Supplier<GlyphID> &alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
+    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
     return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
 								   glyphs,
 								   alternate_len_list,
@@ -1334,7 +1336,7 @@ struct SubstLookup : Lookup
 				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
+    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
     return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
 								  first_glyphs,
 								  ligature_per_first_glyph_count_list,
@@ -1361,7 +1363,12 @@ struct SubstLookup : Lookup
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<SubstLookupSubTable> (c); }
+  { return Lookup::dispatch<SubTable> (c); }
+
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    return false; //XXX
+  }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1369,7 +1376,7 @@ struct SubstLookup : Lookup
     if (unlikely (!Lookup::sanitize (c))) return_trace (false);
     if (unlikely (!dispatch (c))) return_trace (false);
 
-    if (unlikely (get_type () == SubstLookupSubTable::Extension))
+    if (unlikely (get_type () == SubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
@@ -1400,14 +1407,7 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
-    if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
-    //const OffsetTo<SubstLookupList> &list = CastR<const OffsetTo<SubstLookupList> > (lookupList);
-    //OffsetTo<SubstLookupList> &outList = CastR<OffsetTo<SubstLookupList> > (out->lookupList);
-    //outList.set (0);
-    //outList.serialize_subset (c, this+list, out);
-    /* TODO Use intersects() to count how many subtables survive? */
-    return_trace (true);
+    return_trace (GSUBGPOS::subset<SubstLookup> (c));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1425,8 +1425,8 @@ struct GSUB : GSUBGPOS
 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
 {
   unsigned int type = get_type ();
-  if (unlikely (type == SubstLookupSubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
+  if (unlikely (type == SubTable::Extension))
+    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index e32bbd5f..5ccc5feb 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2420,8 +2420,8 @@ struct ExtensionFormat1
   inline const X& get_subtable (void) const
   {
     unsigned int offset = extensionOffset;
-    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
-    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+    if (unlikely (!offset)) return Null(typename T::SubTable);
+    return StructAtOffset<typename T::SubTable> (this, offset);
   }
 
   template <typename context_t>
@@ -2429,7 +2429,7 @@ struct ExtensionFormat1
   {
     TRACE_DISPATCH (this, format);
     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
-    return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
+    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
   }
 
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
@@ -2438,7 +2438,7 @@ struct ExtensionFormat1
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  extensionOffset != 0 &&
-		  extensionLookupType != T::LookupSubTable::Extension);
+		  extensionLookupType != T::SubTable::Extension);
   }
 
   protected:
@@ -2466,8 +2466,8 @@ struct Extension
   inline const X& get_subtable (void) const
   {
     switch (u.format) {
-    case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
-    default:return Null(typename T::LookupSubTable);
+    case 1: return u.format1.template get_subtable<typename T::SubTable> ();
+    default:return Null(typename T::SubTable);
     }
   }
 
@@ -2546,6 +2546,7 @@ struct GSUBGPOS
     return get_feature (feature_index);
   }
 
+  template <typename TLookup>
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -2553,7 +2554,14 @@ struct GSUBGPOS
     if (unlikely (!out)) return_trace (false);
     out->scriptList.serialize_subset (c, this+scriptList, out);
     out->featureList.serialize_subset (c, this+featureList, out);
-    out->lookupList.set (0); /* GSUB/GPOS fill this one in. */
+
+    typedef OffsetListOf<TLookup> TLookupList;
+    /* TODO Use intersects() to count how many subtables survive? */
+    CastR<OffsetTo<TLookupList> > (out->lookupList)
+      .serialize_subset (c,
+			 this+CastR<const OffsetTo<TLookupList> > (lookupList),
+			 out);
+
     if (version.to_int () >= 0x00010001u)
      out->featureVars.serialize_subset (c, this+featureVars, out);
     return_trace (true);
commit 6d618522d63a94230ad708fc49c1c73927da0137
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 16:41:28 2018 -0700

    Templatize GSUBGPOS::sanitize()

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 641d16d8..f0880610 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1548,8 +1548,6 @@ struct PosLookup : Lookup
   }
 };
 
-typedef OffsetListOf<PosLookup> PosLookupList;
-
 /*
  * GPOS -- Glyph Positioning
  * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
@@ -1569,9 +1567,7 @@ struct GPOS : GSUBGPOS
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
-    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
-    return_trace (list.sanitize (c, this));
+    return_trace (GSUBGPOS::sanitize<PosLookup> (c));
   }
 
   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 5b913c78..31e3c2f3 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1385,8 +1385,6 @@ struct SubstLookup : Lookup
   }
 };
 
-typedef OffsetListOf<SubstLookup> SubstLookupList;
-
 /*
  * GSUB -- Glyph Substitution
  * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
@@ -1402,11 +1400,11 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GSUB *out = c->serializer->start_embed<GSUB> ();
+    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
     if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
-    const OffsetTo<SubstLookupList> &list = CastR<const OffsetTo<SubstLookupList> > (lookupList);
-    OffsetTo<SubstLookupList> &outList = CastR<OffsetTo<SubstLookupList> > (out->lookupList);
-    outList.set (0);
+    //const OffsetTo<SubstLookupList> &list = CastR<const OffsetTo<SubstLookupList> > (lookupList);
+    //OffsetTo<SubstLookupList> &outList = CastR<OffsetTo<SubstLookupList> > (out->lookupList);
+    //outList.set (0);
     //outList.serialize_subset (c, this+list, out);
     /* TODO Use intersects() to count how many subtables survive? */
     return_trace (true);
@@ -1415,9 +1413,7 @@ struct GSUB : GSUBGPOS
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
-    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
-    return_trace (list.sanitize (c, this));
+    return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
   }
 
   typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 6b163dce..e32bbd5f 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2565,14 +2565,16 @@ struct GSUBGPOS
 	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
   }
 
+  template <typename TLookup>
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
+    typedef OffsetListOf<TLookup> TLookupList;
     return_trace (version.sanitize (c) &&
 		  likely (version.major == 1) &&
 		  scriptList.sanitize (c, this) &&
 		  featureList.sanitize (c, this) &&
-		  lookupList.sanitize (c, this) &&
+		  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
 		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
   }
 
commit 49c44b58f6c2536ea5f403c54a40cab41b905150
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Sep 3 16:37:17 2018 -0700

    [subset] Fix serialize_subset() calls
    
    Ouch.

diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 24fafd9e..29afa945 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -525,7 +525,7 @@ struct OffsetListOf : OffsetArrayOf<Type>
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
-      out->arrayZ[i].serialize_subset (c, (*this)[i], this);
+      out->arrayZ[i].serialize_subset (c, (*this)[i], out);
     return_trace (true);
   }
 
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index de01bb41..343b62df 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -144,7 +144,7 @@ struct RecordListOf : RecordArrayOf<Type>
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
-      out->get_offset (i).serialize_subset (c, (*this)[i], this);
+      out->get_offset (i).serialize_subset (c, (*this)[i], out);
     return_trace (true);
   }
 
@@ -283,10 +283,10 @@ struct Script
     TRACE_SUBSET (this);
     struct Script *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
-    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, this);
+    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
     unsigned int count = langSys.len;
     for (unsigned int i = 0; i < count; i++)
-      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, this);
+      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
     return_trace (true);
   }
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index d6518b9c..5b913c78 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1402,14 +1402,13 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
+    struct GSUB *out = c->serializer->start_embed<GSUB> ();
     if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
-    /* TODO Replace following with c->iter_copy_and_subset()ish. */
-    unsigned int count = get_lookup_count ();
-    //LookupList &outLookupList = out+out->lookupList;
-    for (unsigned int i = 0; i < count; i++)
-      //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
-	return_trace (false);
+    const OffsetTo<SubstLookupList> &list = CastR<const OffsetTo<SubstLookupList> > (lookupList);
+    OffsetTo<SubstLookupList> &outList = CastR<OffsetTo<SubstLookupList> > (out->lookupList);
+    outList.set (0);
+    //outList.serialize_subset (c, this+list, out);
+    /* TODO Use intersects() to count how many subtables survive? */
     return_trace (true);
   }
 
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index e4399aea..6b163dce 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2551,11 +2551,11 @@ struct GSUBGPOS
     TRACE_SUBSET (this);
     struct GSUBGPOS *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
-    out->scriptList.serialize_subset (c, this+scriptList, this);
-    out->featureList.serialize_subset (c, this+featureList, this);
+    out->scriptList.serialize_subset (c, this+scriptList, out);
+    out->featureList.serialize_subset (c, this+featureList, out);
     out->lookupList.set (0); /* GSUB/GPOS fill this one in. */
     if (version.to_int () >= 0x00010001u)
-     out->featureVars.serialize_subset (c, this+featureVars, this);
+     out->featureVars.serialize_subset (c, this+featureVars, out);
     return_trace (true);
   }
 
commit 7c9cfa2b4002c18585a26134ab987ceb7ebc97a2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Sep 2 19:47:50 2018 -0700

    Add intersects() method to GSUB/GPOS lookups

diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index da8669d9..de01bb41 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -168,9 +168,8 @@ struct RangeRecord
     return_trace (c->check_struct (this));
   }
 
-  inline bool intersects (const hb_set_t *glyphs) const {
-    return glyphs->intersects (start, end);
-  }
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return glyphs->intersects (start, end); }
 
   template <typename set_t>
   inline bool add_coverage (set_t *glyphs) const {
@@ -767,9 +766,17 @@ struct CoverageFormat1
     return_trace (glyphArray.sanitize (c));
   }
 
-  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
-    return glyphs->has (glyphArray[index]);
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = glyphArray.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (glyphs->has (glyphArray[i]))
+        return true;
+    return false;
   }
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  { return glyphs->has (glyphArray[index]); }
 
   template <typename set_t>
   inline bool add_coverage (set_t *glyphs) const {
@@ -857,7 +864,17 @@ struct CoverageFormat2
     return_trace (rangeRecord.sanitize (c));
   }
 
-  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].intersects (glyphs))
+        return true;
+    return false;
+  }
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  {
     unsigned int i;
     unsigned int count = rangeRecord.len;
     for (i = 0; i < count; i++) {
@@ -985,13 +1002,13 @@ struct Coverage
 
   inline bool intersects (const hb_set_t *glyphs) const
   {
-    /* TODO speed this up */
-    for (hb_auto_t<Coverage::Iter> iter (*this); iter.more (); iter.next ())
-      if (glyphs->has (iter.get_glyph ()))
-        return true;
-    return false;
+    switch (u.format)
+    {
+    case 1: return u.format1.intersects (glyphs);
+    case 2: return u.format2.intersects (glyphs);
+    default:return false;
+    }
   }
-
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
   {
     switch (u.format)
@@ -1141,6 +1158,17 @@ struct ClassDefFormat1
     return true;
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next()? */
+    hb_codepoint_t start = startGlyph;
+    hb_codepoint_t end = startGlyph + classValue.len;
+    for (hb_codepoint_t iter = startGlyph - 1;
+	 hb_set_next (glyphs, &iter) && iter < end;)
+      if (classValue[iter - start])
+        return true;
+    return false;
+  }
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = classValue.len;
     if (klass == 0)
@@ -1191,7 +1219,8 @@ struct ClassDefFormat2
   }
 
   template <typename set_t>
-  inline bool add_coverage (set_t *glyphs) const {
+  inline bool add_coverage (set_t *glyphs) const
+  {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value)
@@ -1201,7 +1230,8 @@ struct ClassDefFormat2
   }
 
   template <typename set_t>
-  inline bool add_class (set_t *glyphs, unsigned int klass) const {
+  inline bool add_class (set_t *glyphs, unsigned int klass) const
+  {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
     {
@@ -1212,7 +1242,17 @@ struct ClassDefFormat2
     return true;
   }
 
-  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].intersects (glyphs))
+        return true;
+    return false;
+  }
+  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+  {
     unsigned int count = rangeRecord.len;
     if (klass == 0)
     {
@@ -1289,6 +1329,13 @@ struct ClassDef
     }
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const {
+    switch (u.format) {
+    case 1: return u.format1.intersects (glyphs);
+    case 2: return u.format2.intersects (glyphs);
+    default:return false;
+    }
+  }
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 16b54793..641d16d8 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 
 struct SinglePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -466,9 +469,7 @@ struct SinglePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -507,6 +508,9 @@ struct SinglePosFormat1
 
 struct SinglePosFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -514,9 +518,7 @@ struct SinglePosFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -598,6 +600,24 @@ struct PairSet
 {
   friend struct PairPosFormat1;
 
+  inline bool intersects (const hb_set_t *glyphs,
+			  const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs->has (record->secondGlyph))
+        return true;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+    return false;
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
 			      const ValueFormat *valueFormats) const
   {
@@ -652,7 +672,8 @@ struct PairSet
     return_trace (false);
   }
 
-  struct sanitize_closure_t {
+  struct sanitize_closure_t
+  {
     const void *base;
     const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
@@ -681,6 +702,20 @@ struct PairSet
 
 struct PairPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = pairSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+	  (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
+        return true;
+    }
+    return false;
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -691,9 +726,7 @@ struct PairPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -717,7 +750,8 @@ struct PairPosFormat1
 
     unsigned int len1 = valueFormat[0].get_len ();
     unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure = {
+    PairSet::sanitize_closure_t closure =
+    {
       this,
       valueFormat,
       len1,
@@ -747,6 +781,12 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+coverage).intersects (glyphs) &&
+	   (this+classDef2).intersects (glyphs);
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -755,9 +795,7 @@ struct PairPosFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -889,6 +927,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
 
 struct CursivePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -896,9 +937,7 @@ struct CursivePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1047,6 +1086,10 @@ typedef AnchorMatrix BaseArray;		/* base-major--
 
 struct MarkBasePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+markCoverage).intersects (glyphs) &&
+	   (this+baseCoverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1055,9 +1098,7 @@ struct MarkBasePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+markCoverage;
-  }
+  { return this+markCoverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1161,6 +1202,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
 
 struct MarkLigPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+markCoverage).intersects (glyphs) &&
+	   (this+ligatureCoverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1169,9 +1214,7 @@ struct MarkLigPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+markCoverage;
-  }
+  { return this+markCoverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1274,6 +1317,10 @@ typedef AnchorMatrix Mark2Array;	/* mark2-major--
 
 struct MarkMarkPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+mark1Coverage).intersects (glyphs) &&
+	   (this+mark2Coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1282,9 +1329,7 @@ struct MarkMarkPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+mark1Coverage;
-  }
+  { return this+mark1Coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1467,6 +1512,12 @@ struct PosLookup : Lookup
     return_trace (dispatch (c));
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index c108e165..d6518b9c 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -37,6 +37,9 @@ namespace OT {
 
 struct SingleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -64,9 +67,7 @@ struct SingleSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -120,6 +121,9 @@ struct SingleSubstFormat1
 
 struct SingleSubstFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -147,9 +151,7 @@ struct SingleSubstFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -160,14 +162,12 @@ struct SingleSubstFormat2
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
-    glyph_id = substitute[index];
-    c->replace_glyph (glyph_id);
+    c->replace_glyph (substitute[index]);
 
     return_trace (true);
   }
@@ -325,6 +325,9 @@ struct Sequence
 
 struct MultipleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -344,13 +347,11 @@ struct MultipleSubstFormat1
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     unsigned int count = sequence.len;
     for (unsigned int i = 0; i < count; i++)
-	(this+sequence[i]).collect_glyphs (c);
+      (this+sequence[i]).collect_glyphs (c);
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -440,12 +441,72 @@ struct MultipleSubst
   } u;
 };
 
+struct AlternateSet
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int count = alternates.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->out->add (alternates[i]);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->output->add_array (alternates.arrayZ, alternates.len);
+  }
+
+  inline bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = alternates.len;
+
+    if (unlikely (!count)) return_trace (false);
+
+    hb_mask_t glyph_mask = c->buffer->cur().mask;
+    hb_mask_t lookup_mask = c->lookup_mask;
+
+    /* Note: This breaks badly if two features enabled this lookup together. */
+    unsigned int shift = hb_ctz (lookup_mask);
+    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+    c->replace_glyph (alternates[alt_index - 1]);
 
-typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+			 Supplier<GlyphID> &glyphs,
+			 unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (alternates.sanitize (c));
+  }
+
+  protected:
+  ArrayOf<GlyphID>
+		alternates;		/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
+  public:
+  DEFINE_SIZE_ARRAY (2, alternates);
+};
 
 struct AlternateSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -454,12 +515,8 @@ struct AlternateSubstFormat1
     {
       if (unlikely (iter.get_coverage () >= count))
         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ())) {
-	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
-	unsigned int count = alt_set.len;
-	for (unsigned int i = 0; i < count; i++)
-	  c->out->add (alt_set[i]);
-      }
+      if (c->glyphs->has (iter.get_glyph ()))
+	(this+alternateSet[iter.get_coverage ()]).closure (c);
     }
   }
 
@@ -472,15 +529,12 @@ struct AlternateSubstFormat1
     {
       if (unlikely (iter.get_coverage () >= count))
         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
-      c->output->add_array (alt_set.arrayZ, alt_set.len);
+      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
     }
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -491,29 +545,11 @@ struct AlternateSubstFormat1
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const AlternateSet &alt_set = this+alternateSet[index];
-
-    if (unlikely (!alt_set.len)) return_trace (false);
-
-    hb_mask_t glyph_mask = c->buffer->cur().mask;
-    hb_mask_t lookup_mask = c->lookup_mask;
-
-    /* Note: This breaks badly if two features enabled this lookup together. */
-    unsigned int shift = hb_ctz (lookup_mask);
-    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
-
-    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
-
-    glyph_id = alt_set[alt_index - 1];
-
-    c->replace_glyph (glyph_id);
-
-    return_trace (true);
+    return_trace ((this+alternateSet[index]).apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -591,6 +627,15 @@ struct AlternateSubst
 
 struct Ligature
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      if (!glyphs->has (component[i]))
+        return false;
+    return true;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -694,6 +739,15 @@ struct Ligature
 
 struct LigatureSet
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      if ((this+ligature[i]).intersects (glyphs))
+        return true;
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -771,6 +825,20 @@ struct LigatureSet
 
 struct LigatureSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = ligatureSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+	  (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -798,9 +866,7 @@ struct LigatureSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -815,9 +881,8 @@ struct LigatureSubstFormat1
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
@@ -923,6 +988,28 @@ struct ExtensionSubst : Extension<ExtensionSubst>
 
 struct ReverseChainSingleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+backtrack[i]).intersects (glyphs))
+        return false;
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+lookahead[i]).intersects (glyphs))
+        return false;
+
+    return true;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -973,9 +1060,7 @@ struct ReverseChainSingleSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -1035,7 +1120,7 @@ struct ReverseChainSingleSubstFormat1
 					 * beginning of table */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
-					 * in backtracking sequence, in  glyph
+					 * in backtracking sequence, in glyph
 					 * sequence order */
   OffsetArrayOf<Coverage>
 		lookaheadX;		/* Array of coverage tables
@@ -1146,6 +1231,12 @@ struct SubstLookup : Lookup
     return_trace (dispatch (c));
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
   {
     TRACE_CLOSURE (this);
@@ -1311,11 +1402,11 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GSUB *out = c->serializer->start_embed<GSUB> ();
+    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
     if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
     /* TODO Replace following with c->iter_copy_and_subset()ish. */
     unsigned int count = get_lookup_count ();
-    LookupList &outLookupList = out+out->lookupList;
+    //LookupList &outLookupList = out+out->lookupList;
     for (unsigned int i = 0; i < count; i++)
       //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
 	return_trace (false);
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 5bdbf9a5..e4399aea 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -40,6 +40,23 @@
 namespace OT {
 
 
+struct hb_intersects_context_t :
+       hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
+{
+  inline const char *get_name (void) { return "INTERSECTS"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  const hb_set_t *glyphs;
+  unsigned int debug_depth;
+
+  hb_intersects_context_t (const hb_set_t *glyphs_) :
+			     glyphs (glyphs_),
+			     debug_depth (0) {}
+};
+
 struct hb_closure_context_t :
        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
 {
@@ -49,15 +66,14 @@ struct hb_closure_context_t :
   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
   static return_t default_return_value (void) { return HB_VOID; }
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
-  return_t recurse (unsigned int lookup_index)
+  void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
-      return default_return_value ();
+      return;
 
     nesting_level_left--;
     recurse_func (this, lookup_index);
     nesting_level_left++;
-    return HB_VOID;
   }
 
   bool should_visit_lookup (unsigned int lookup_index)
@@ -146,10 +162,10 @@ struct hb_collect_glyphs_context_t :
   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
   static return_t default_return_value (void) { return HB_VOID; }
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
-  return_t recurse (unsigned int lookup_index)
+  void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
-      return default_return_value ();
+      return;
 
     /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
@@ -162,11 +178,11 @@ struct hb_collect_glyphs_context_t :
      */
 
     if (output == hb_set_get_empty ())
-      return HB_VOID;
+      return;
 
     /* Return if new lookup was recursed to before. */
     if (recursed_lookups->has (lookup_index))
-      return HB_VOID;
+      return;
 
     hb_set_t *old_before = before;
     hb_set_t *old_input  = input;
@@ -183,7 +199,7 @@ struct hb_collect_glyphs_context_t :
 
     recursed_lookups->add (lookup_index);
 
-    return HB_VOID;
+    return;
   }
 
   hb_face_t *face;
@@ -208,24 +224,16 @@ struct hb_collect_glyphs_context_t :
 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
 			      recurse_func (nullptr),
-			      recursed_lookups (nullptr),
+			      recursed_lookups (hb_set_create ()),
 			      nesting_level_left (nesting_level_left_),
-			      debug_depth (0)
-  {
-    recursed_lookups = hb_set_create ();
-  }
-  ~hb_collect_glyphs_context_t (void)
-  {
-    hb_set_destroy (recursed_lookups);
-  }
+			      debug_depth (0) {}
+  ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
-/* XXX Can we remove this? */
-
 template <typename set_t>
 struct hb_add_coverage_context_t :
        hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
@@ -599,7 +607,7 @@ struct hb_ot_apply_context_t :
 
 
 
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
@@ -617,29 +625,29 @@ struct ContextApplyFuncs
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
 }
 
-static inline bool intersects_array (hb_closure_context_t *c,
+static inline bool intersects_array (const hb_set_t *glyphs,
 				     unsigned int count,
 				     const HBUINT16 values[],
 				     intersects_func_t intersects_func,
 				     const void *intersects_data)
 {
   for (unsigned int i = 0; i < count; i++)
-    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
+    if (likely (!intersects_func (glyphs, values[i], intersects_data)))
       return false;
   return true;
 }
@@ -1140,6 +1148,16 @@ struct ContextApplyLookupContext
   const void *match_data;
 };
 
+static inline bool context_intersects (const hb_set_t *glyphs,
+				       unsigned int inputCount, /* Including the first glyph (not matched) */
+				       const HBUINT16 input[], /* Array of input values--start with second glyph */
+				       ContextClosureLookupContext &lookup_context)
+{
+  return intersects_array (glyphs,
+			   inputCount ? inputCount - 1 : 0, input,
+			   lookup_context.funcs.intersects, lookup_context.intersects_data);
+}
+
 static inline void context_closure_lookup (hb_closure_context_t *c,
 					   unsigned int inputCount, /* Including the first glyph (not matched) */
 					   const HBUINT16 input[], /* Array of input values--start with second glyph */
@@ -1147,9 +1165,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
 					   const LookupRecord lookupRecord[],
 					   ContextClosureLookupContext &lookup_context)
 {
-  if (intersects_array (c,
-			inputCount ? inputCount - 1 : 0, input,
-			lookup_context.funcs.intersects, lookup_context.intersects_data))
+  if (context_intersects (c->glyphs,
+			  inputCount, input,
+			  lookup_context))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
@@ -1201,6 +1219,13 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
 
 struct Rule
 {
+  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+  {
+    return context_intersects (glyphs,
+			       inputCount, inputZ,
+			       lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1261,6 +1286,15 @@ struct Rule
 
 struct RuleSet
 {
+  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+  {
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).intersects (glyphs, lookup_context))
+        return true;
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1318,23 +1352,42 @@ struct RuleSet
 
 struct ContextFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      nullptr
+    };
+
+    unsigned int count = ruleSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
 
-    const Coverage &cov = (this+coverage);
-
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       nullptr
     };
 
     unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (cov.intersects_coverage (c->glyphs, i)) {
-	const RuleSet &rule_set = this+ruleSet[i];
-	rule_set.closure (c, lookup_context);
-      }
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (c->glyphs->has (iter.get_glyph ()))
+	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+    }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1365,9 +1418,7 @@ struct ContextFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1405,6 +1456,27 @@ struct ContextFormat1
 
 struct ContextFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const ClassDef &class_def = this+classDef;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (class_def.intersects_class (glyphs, i) &&
+	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
+        return true;
+
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1457,9 +1529,7 @@ struct ContextFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1501,6 +1571,20 @@ struct ContextFormat2
 
 struct ContextFormat3
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverageZ[0]).intersects (glyphs))
+      return false;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      this
+    };
+    return context_intersects (glyphs,
+			       glyphCount, (const HBUINT16 *) (coverageZ + 1),
+			       lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1548,9 +1632,7 @@ struct ContextFormat3
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverageZ[0];
-  }
+  { return this+coverageZ[0]; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1638,6 +1720,26 @@ struct ChainContextApplyLookupContext
   const void *match_data[3];
 };
 
+static inline bool chain_context_intersects (const hb_set_t *glyphs,
+					     unsigned int backtrackCount,
+					     const HBUINT16 backtrack[],
+					     unsigned int inputCount, /* Including the first glyph (not matched) */
+					     const HBUINT16 input[], /* Array of input values--start with second glyph */
+					     unsigned int lookaheadCount,
+					     const HBUINT16 lookahead[],
+					     ChainContextClosureLookupContext &lookup_context)
+{
+  return intersects_array (glyphs,
+			   backtrackCount, backtrack,
+			   lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+      && intersects_array (glyphs,
+			   inputCount ? inputCount - 1 : 0, input,
+			   lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+      && intersects_array (glyphs,
+			  lookaheadCount, lookahead,
+			  lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+}
+
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
 						 const HBUINT16 backtrack[],
@@ -1649,15 +1751,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 const LookupRecord lookupRecord[],
 						 ChainContextClosureLookupContext &lookup_context)
 {
-  if (intersects_array (c,
-			backtrackCount, backtrack,
-			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
-   && intersects_array (c,
-			inputCount ? inputCount - 1 : 0, input,
-			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-   && intersects_array (c,
-		       lookaheadCount, lookahead,
-		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
+  if (chain_context_intersects (c->glyphs,
+				backtrackCount, backtrack,
+				inputCount, input,
+				lookaheadCount, lookahead,
+				lookup_context))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
@@ -1737,6 +1835,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
 
 struct ChainRule
 {
+  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+  {
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    return chain_context_intersects (glyphs,
+				     backtrack.len, backtrack.arrayZ,
+				     input.len, input.arrayZ,
+				     lookahead.len, lookahead.arrayZ,
+				     lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1823,6 +1932,14 @@ struct ChainRule
 
 struct ChainRuleSet
 {
+  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+  {
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).intersects (glyphs, lookup_context))
+        return true;
+    return false;
+  }
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1877,10 +1994,28 @@ struct ChainRuleSet
 
 struct ChainContextFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      {nullptr, nullptr, nullptr}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
-    const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
@@ -1888,11 +2023,13 @@ struct ChainContextFormat1
     };
 
     unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (cov.intersects_coverage (c->glyphs, i)) {
-	const ChainRuleSet &rule_set = this+ruleSet[i];
-	rule_set.closure (c, lookup_context);
-      }
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (c->glyphs->has (iter.get_glyph ()))
+	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+    }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1923,9 +2060,7 @@ struct ChainContextFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1961,6 +2096,30 @@ struct ChainContextFormat1
 
 struct ChainContextFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (input_class_def.intersects_class (glyphs, i) &&
+	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
+        return true;
+
+    return false;
+  }
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -2027,9 +2186,7 @@ struct ChainContextFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -2088,6 +2245,25 @@ struct ChainContextFormat2
 
 struct ChainContextFormat3
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    if (!(this+input[0]).intersects (glyphs))
+      return false;
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      {this, this, this}
+    };
+    return chain_context_intersects (glyphs,
+				     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
+				     input.len, (const HBUINT16 *) input.arrayZ + 1,
+				     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
+				     lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
commit 61ce62e55455bb0d6c9db3b076676ab18e51d449
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Sep 2 17:00:27 2018 -0700

    [subset] Minor
    
    Remove Lookup::subset().

diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index a51a6c7e..da8669d9 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -703,17 +703,6 @@ struct Lookup
     return_trace (true);
   }
 
-  inline bool subset (hb_subset_context_t *c) const
-  {
-    TRACE_SUBSET (this);
-    struct Lookup *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    unsigned int count = subTable.len;
-    for (unsigned int i = 0; i < count; i++)
-      out->subTable[i].set (0); /* To be filled out by SubstLookup/PosLookup. */
-    return_trace (true);
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 1749f58c..5bdbf9a5 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2377,7 +2377,7 @@ struct GSUBGPOS
     if (unlikely (!out)) return_trace (false);
     out->scriptList.serialize_subset (c, this+scriptList, this);
     out->featureList.serialize_subset (c, this+featureList, this);
-    out->lookupList.serialize_subset (c, this+lookupList, this);
+    out->lookupList.set (0); /* GSUB/GPOS fill this one in. */
     if (version.to_int () >= 0x00010001u)
      out->featureVars.serialize_subset (c, this+featureVars, this);
     return_trace (true);
commit bfa72a9a72a15d977f503f12eef376a355679d76
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 1 18:34:50 2018 -0700

    [subset] Towards GSUB/GPOS subsetting
    
    Add subset() call for GSUBGPOS struct and its dependencies.
    Not hooked up anywhere.

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 3f867543..6e3e70c7 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -111,9 +111,13 @@ static inline Type& StructAfter(TObject &X)
   static const unsigned int min_size = (size)
 
 #define DEFINE_SIZE_ARRAY(size, array) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
   DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
-  static const unsigned int min_size = (size)
+  static const unsigned int min_size = (size); \
+
+#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
+	DEFINE_SIZE_ARRAY(size, array); \
+	inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); }
 
 #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
@@ -508,7 +512,7 @@ struct hb_serialize_context_t
     unsigned int size = obj.get_size ();
     Type *ret = this->allocate_size<Type> (size);
     if (unlikely (!ret)) return nullptr;
-    memcpy (ret, obj, size);
+    memcpy (ret, &obj, size);
     return ret;
   }
 
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index d43dcac7..24fafd9e 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -247,6 +247,19 @@ struct OffsetTo : Offset<OffsetType>
     return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
+  template <typename T>
+  inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+  {
+    if (&src == &Null(T))
+    {
+      this->set (0);
+      return;
+    }
+    serialize (c->serializer, base);
+    if (!src.subset (c))
+      this->set (0);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -405,7 +418,6 @@ struct ArrayOf
     if (unlikely (!c->extend (*this))) return_trace (false);
     return_trace (true);
   }
-
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<Type> &items,
 			 unsigned int items_len)
@@ -506,6 +518,17 @@ struct OffsetListOf : OffsetArrayOf<Type>
     return this+this->arrayZ[i];
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = this->len;
+    for (unsigned int i = 0; i < count; i++)
+      out->arrayZ[i].serialize_subset (c, (*this)[i], this);
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 887f27e9..a51a6c7e 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -97,15 +97,14 @@ struct Record
 };
 
 template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type> > {
+struct RecordArrayOf : SortedArrayOf<Record<Type> >
+{
+  inline const OffsetTo<Type>& get_offset (unsigned int i) const
+  { return (*this)[i].offset; }
+  inline OffsetTo<Type>& get_offset (unsigned int i)
+  { return (*this)[i].offset; }
   inline const Tag& get_tag (unsigned int i) const
-  {
-    /* We cheat slightly and don't define separate Null objects
-     * for Record types.  Instead, we return the correct Null(Tag)
-     * here. */
-    if (unlikely (i >= this->len)) return Null(Tag);
-    return (*this)[i].tag;
-  }
+  { return (*this)[i].tag; }
   inline unsigned int get_tags (unsigned int start_offset,
 				unsigned int *record_count /* IN/OUT */,
 				hb_tag_t     *record_tags /* OUT */) const
@@ -136,7 +135,18 @@ template <typename Type>
 struct RecordListOf : RecordArrayOf<Type>
 {
   inline const Type& operator [] (unsigned int i) const
-  { return this+RecordArrayOf<Type>::operator [](i).offset; }
+  { return this+this->get_offset (i); }
+
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct RecordListOf<Type> *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = this->len;
+    for (unsigned int i = 0; i < count; i++)
+      out->get_offset (i).serialize_subset (c, (*this)[i], this);
+    return_trace (true);
+  }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -224,6 +234,12 @@ struct LangSys
    return reqFeatureIndex;;
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (c->serializer->embed (*this));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
 			const Record<LangSys>::sanitize_closure_t * = nullptr) const
   {
@@ -238,7 +254,7 @@ struct LangSys
 				 * = 0xFFFFu */
   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
   public:
-  DEFINE_SIZE_ARRAY (6, featureIndex);
+  DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
 
@@ -263,6 +279,18 @@ struct Script
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Script *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, this);
+    unsigned int count = langSys.len;
+    for (unsigned int i = 0; i < count; i++)
+      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, this);
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
 			const Record<Script>::sanitize_closure_t * = nullptr) const
   {
@@ -278,7 +306,7 @@ struct Script
 		langSys;	/* Array of LangSysRecords--listed
 				 * alphabetically by LangSysTag */
   public:
-  DEFINE_SIZE_ARRAY (4, langSys);
+  DEFINE_SIZE_ARRAY_SIZED (4, langSys);
 };
 
 typedef RecordListOf<Script> ScriptList;
@@ -516,6 +544,15 @@ struct Feature
   inline const FeatureParams &get_feature_params (void) const
   { return this+featureParams; }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Feature *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->featureParams.set (0); /* TODO(subset) FeatureParams. */
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
 			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
   {
@@ -567,7 +604,7 @@ struct Feature
 				 * if not required */
   IndexArray	 lookupIndex;	/* Array of LookupList indices */
   public:
-  DEFINE_SIZE_ARRAY (4, lookupIndex);
+  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
 };
 
 typedef RecordListOf<Feature> FeatureList;
@@ -666,6 +703,17 @@ struct Lookup
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Lookup *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = subTable.len;
+    for (unsigned int i = 0; i < count; i++)
+      out->subTable[i].set (0); /* To be filled out by SubstLookup/PosLookup. */
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1629,6 +1677,12 @@ struct FeatureVariations
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (c->serializer->embed (*this));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1642,7 +1696,7 @@ struct FeatureVariations
   LArrayOf<FeatureVariationRecord>
 			varRecords;
   public:
-  DEFINE_SIZE_ARRAY (8, varRecords);
+  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
 };
 
 
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 79308649..cad99a3d 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -387,19 +387,6 @@ struct GDEF
   inline const VariationStore &get_var_store (void) const
   { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (version.sanitize (c) &&
-		  likely (version.major == 1) &&
-		  glyphClassDef.sanitize (c, this) &&
-		  attachList.sanitize (c, this) &&
-		  ligCaretList.sanitize (c, this) &&
-		  markAttachClassDef.sanitize (c, this) &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
-		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
-  }
-
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
    * Not to be confused with lookup_props which is very similar. */
@@ -434,6 +421,26 @@ struct GDEF
     const GDEF *table;
   };
 
+  inline unsigned int get_size (void) const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  glyphClassDef.sanitize (c, this) &&
+		  attachList.sanitize (c, this) &&
+		  ligCaretList.sanitize (c, this) &&
+		  markAttachClassDef.sanitize (c, this) &&
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+  }
+
   protected:
   FixedVersion<>version;		/* Version of the GDEF table--currently
 					 * 0x00010003u */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 7f8489f3..c108e165 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1308,15 +1308,20 @@ struct GSUB : GSUBGPOS
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
-  inline bool subset (hb_subset_context_t *c)
+  inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
     struct GSUB *out = c->serializer->start_embed<GSUB> ();
-    //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
+    if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
+    /* TODO Replace following with c->iter_copy_and_subset()ish. */
+    unsigned int count = get_lookup_count ();
+    LookupList &outLookupList = out+out->lookupList;
+    for (unsigned int i = 0; i < count; i++)
+      //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
+	return_trace (false);
     return_trace (true);
   }
 
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 3727dd9e..1749f58c 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2370,6 +2370,25 @@ struct GSUBGPOS
     return get_feature (feature_index);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct GSUBGPOS *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->scriptList.serialize_subset (c, this+scriptList, this);
+    out->featureList.serialize_subset (c, this+featureList, this);
+    out->lookupList.serialize_subset (c, this+lookupList, this);
+    if (version.to_int () >= 0x00010001u)
+     out->featureVars.serialize_subset (c, this+featureVars, this);
+    return_trace (true);
+  }
+
+  inline unsigned int get_size (void) const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
commit 6803ed8674028a656957910381150ab28d75a5f8
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 17:11:08 2018 -0700

    [serialize] Add reset()

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 26392b32..3f867543 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -437,7 +437,11 @@ struct hb_serialize_context_t
   {
     this->start = (char *) start_;
     this->end = this->start + size;
+    reset ();
+  }
 
+  inline void reset (void)
+  {
     this->ran_out_of_room = false;
     this->head = this->start;
     this->debug_depth = 0;
commit e58b190292f85c9676fe14cf63d2831d4d6e6bab
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 16:46:35 2018 -0700

    [subset] De-templatize hb_subset_context_t
    
    We're going to (finally) use virtual methods for hb_serialize_context_t
    customization, so don't need to carry a Serializer template variable
    around...  Simplifies code.

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 0452693d..26392b32 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -473,7 +473,7 @@ struct hb_serialize_context_t
   }
 
   template <typename Type>
-  inline Type *start_embed (void)
+  inline Type *start_embed (void) const
   {
     Type *ret = reinterpret_cast<Type *> (this->head);
     return ret;
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index d7f89830..7f8489f3 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1308,11 +1308,10 @@ struct GSUB : GSUBGPOS
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
-  template <typename Serializer>
-  inline bool subset (hb_subset_context_t<Serializer> *c)
+  inline bool subset (hb_subset_context_t *c)
   {
     TRACE_SUBSET (this);
-    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
+    struct GSUB *out = c->serializer->start_embed<GSUB> ();
     //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
     return_trace (true);
   }
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index 5202f73b..9cdd388d 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -36,9 +36,8 @@
 #include "hb-subset-input.hh"
 #include "hb-subset-plan.hh"
 
-template <typename Serializer>
 struct hb_subset_context_t :
-       hb_dispatch_context_t<hb_subset_context_t<Serializer>, bool, HB_DEBUG_SUBSET>
+       hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET>
 {
   inline const char *get_name (void) { return "SUBSET"; }
   template <typename T>
@@ -47,11 +46,11 @@ struct hb_subset_context_t :
   bool stop_sublookup_iteration (bool r) const { return false; }
 
   hb_subset_plan_t *plan;
-  Serializer *serializer;
+  hb_serialize_context_t *serializer;
   unsigned int debug_depth;
 
   hb_subset_context_t (hb_subset_plan_t *plan_,
-		       Serializer *serializer_) :
+		       hb_serialize_context_t *serializer_) :
 			plan (plan_),
 			serializer (serializer_),
 			debug_depth (0) {}
commit 22acd424ca77c16d28405021f06c5562497920ab
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 16:38:04 2018 -0700

    [serialize] Add a couple small methods

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 1e0f7ccf..0452693d 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -443,6 +443,7 @@ struct hb_serialize_context_t
     this->debug_depth = 0;
   }
 
+  /* To be called around main operation. */
   template <typename Type>
   inline Type *start_serialize (void)
   {
@@ -453,7 +454,6 @@ struct hb_serialize_context_t
 
     return start_embed<Type> ();
   }
-
   inline void end_serialize (void)
   {
     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
@@ -463,6 +463,22 @@ struct hb_serialize_context_t
 		     this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
   }
 
+  inline unsigned int length (void) const { return this->head - this->start; }
+
+  inline void align (unsigned int alignment)
+  {
+    unsigned int l = length () % alignment;
+    if (l)
+      allocate_size<void> (alignment - l);
+  }
+
+  template <typename Type>
+  inline Type *start_embed (void)
+  {
+    Type *ret = reinterpret_cast<Type *> (this->head);
+    return ret;
+  }
+
   template <typename Type>
   inline Type *allocate_size (unsigned int size)
   {
@@ -483,13 +499,6 @@ struct hb_serialize_context_t
   }
 
   template <typename Type>
-  inline Type *start_embed (void)
-  {
-    Type *ret = reinterpret_cast<Type *> (this->head);
-    return ret;
-  }
-
-  template <typename Type>
   inline Type *embed (const Type &obj)
   {
     unsigned int size = obj.get_size ();
diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh
index 97e736ee..847f9b06 100644
--- a/src/hb-open-file.hh
+++ b/src/hb-open-file.hh
@@ -161,8 +161,7 @@ typedef struct OffsetTable
       memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
 
       /* 4-byte allignment. */
-      if (rec.length % 4)
-	c->allocate_size<void> (4 - rec.length % 4);
+      c->align (4);
       const char *end = (const char *) c->head;
 
       if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 5737b21b..d7f89830 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1312,6 +1312,7 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t<Serializer> *c)
   {
     TRACE_SUBSET (this);
+    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
     //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
     return_trace (true);
   }
commit d1f29908c281b1685eea00b71bae934d9f1f20eb
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 16:31:00 2018 -0700

    [subset] Add hb_subset_context_t<>

diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 48a8eaa7..d43dcac7 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -33,6 +33,7 @@
 #include "hb-blob.hh"
 #include "hb-face.hh"
 #include "hb-machinery.hh"
+#include "hb-subset.hh"
 
 
 namespace OT {
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index b7db145c..e6876d12 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -29,7 +29,6 @@
 
 #include "hb-open-type.hh"
 #include "hb-set.hh"
-#include "hb-subset.hh"
 
 /*
  * cmap -- Character to Glyph Index Mapping
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 3702d84c..d684de0b 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -28,7 +28,6 @@
 #define HB_OT_HDMX_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset.hh"
 
 /*
  * hdmx -- Horizontal Device Metrics
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 5500e9cd..3e4b3bde 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -31,7 +31,6 @@
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
-#include "hb-subset.hh"
 
 /*
  * hmtx -- Horizontal Metrics
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 55696c5a..5737b21b 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1308,6 +1308,15 @@ struct GSUB : GSUBGPOS
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
+  template <typename Serializer>
+  inline bool subset (hb_subset_context_t<Serializer> *c)
+  {
+    TRACE_SUBSET (this);
+    //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
+    return_trace (true);
+  }
+
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 8a889eed..efcf593e 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -28,7 +28,6 @@
 #define HB_OT_MAXP_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset.hh"
 
 namespace OT {
 
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index e00f3cad..f28858c5 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -29,7 +29,6 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-os2-unicode-ranges.hh"
-#include "hb-subset.hh"
 
 namespace OT {
 
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 955a6d66..d0265d05 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -28,7 +28,6 @@
 #define HB_OT_POST_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset.hh"
 
 #define HB_STRING_ARRAY_NAME format1_names
 #define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index a9d00c6c..5202f73b 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -32,9 +32,30 @@
 
 #include "hb-subset.h"
 
+#include "hb-machinery.hh"
 #include "hb-subset-input.hh"
 #include "hb-subset-plan.hh"
 
+template <typename Serializer>
+struct hb_subset_context_t :
+       hb_dispatch_context_t<hb_subset_context_t<Serializer>, bool, HB_DEBUG_SUBSET>
+{
+  inline const char *get_name (void) { return "SUBSET"; }
+  template <typename T>
+  inline bool dispatch (const T &obj) { return obj.subset (this); }
+  static bool default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (bool r) const { return false; }
+
+  hb_subset_plan_t *plan;
+  Serializer *serializer;
+  unsigned int debug_depth;
+
+  hb_subset_context_t (hb_subset_plan_t *plan_,
+		       Serializer *serializer_) :
+			plan (plan_),
+			serializer (serializer_),
+			debug_depth (0) {}
+};
 
 
 #endif /* HB_SUBSET_HH */
commit aba0a945c5f8724cc7bd1a9b7f7b5df1c64b03f4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 13:25:19 2018 -0700

    [subset] Add hb-subset-input.hh and make hb-subset.hh toplevel include

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 97efda22..654255e2 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -213,6 +213,7 @@ HB_SUBSET_sources = \
 	hb-subset-glyf.cc \
 	hb-subset-glyf.hh \
 	hb-subset-input.cc \
+	hb-subset-input.hh \
 	hb-subset-plan.cc \
 	hb-subset-plan.hh \
 	$(NULL)
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index faf0a2c6..b7db145c 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -29,7 +29,7 @@
 
 #include "hb-open-type.hh"
 #include "hb-set.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 /*
  * cmap -- Character to Glyph Index Mapping
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 65758861..7c209836 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -30,8 +30,6 @@
 #include "hb-open-type.hh"
 #include "hb-ot-head-table.hh"
 #include "hb-subset-glyf.hh"
-#include "hb-subset-plan.hh"
-#include "hb-subset.hh"
 
 namespace OT {
 
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 5ce5fe4a..3702d84c 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -28,7 +28,7 @@
 #define HB_OT_HDMX_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 /*
  * hdmx -- Horizontal Device Metrics
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 9bdca7eb..5500e9cd 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -31,7 +31,7 @@
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 /*
  * hmtx -- Horizontal Metrics
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index cd2a85eb..8a889eed 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -28,7 +28,7 @@
 #define HB_OT_MAXP_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 namespace OT {
 
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index c5ad803a..e00f3cad 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -29,7 +29,7 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-os2-unicode-ranges.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 namespace OT {
 
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 0c3e596a..955a6d66 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -28,7 +28,7 @@
 #define HB_OT_POST_TABLE_HH
 
 #include "hb-open-type.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 #define HB_STRING_ARRAY_NAME format1_names
 #define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index e335912f..499380a9 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -28,7 +28,6 @@
 #include "hb-ot-glyf-table.hh"
 #include "hb-set.h"
 #include "hb-subset-glyf.hh"
-#include "hb-subset-plan.hh"
 
 static bool
 _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
diff --git a/src/hb-subset-glyf.hh b/src/hb-subset-glyf.hh
index c564206b..3109ecb6 100644
--- a/src/hb-subset-glyf.hh
+++ b/src/hb-subset-glyf.hh
@@ -29,7 +29,7 @@
 
 #include "hb.hh"
 
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
 
 HB_INTERNAL bool
 hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh
new file mode 100644
index 00000000..9fc86154
--- /dev/null
+++ b/src/hb-subset-input.hh
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2018  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, Roderick Sheeter
+ */
+
+#ifndef HB_SUBSET_INPUT_HH
+#define HB_SUBSET_INPUT_HH
+
+
+#include "hb.hh"
+
+#include "hb-subset.h"
+
+#include "hb-font.hh"
+
+struct hb_subset_input_t
+{
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_set_t *unicodes;
+  hb_set_t *glyphs;
+
+  bool drop_hints : 1;
+  bool drop_layout : 1;
+  /* TODO
+   *
+   * features
+   * lookups
+   * nameIDs
+   * ...
+   */
+};
+
+
+#endif /* HB_SUBSET_INPUT_HH */
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 2d8538ef..d9d25b3d 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -24,11 +24,10 @@
  * Google Author(s): Garret Rieger, Roderick Sheeter
  */
 
+#include "hb-subset-plan.hh"
 #include "hb-map.hh"
-#include "hb-subset.hh"
 #include "hb-set.hh"
 
-#include "hb-subset-plan.hh"
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
 
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index af7c5d33..7b6bc77f 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -30,7 +30,7 @@
 #include "hb.hh"
 
 #include "hb-subset.h"
-#include "hb-subset.hh"
+#include "hb-subset-input.hh"
 
 #include "hb-map.hh"
 
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 332a1e28..f6abdc43 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -27,9 +27,8 @@
 #include "hb.hh"
 #include "hb-open-type.hh"
 
-#include "hb-subset-glyf.hh"
 #include "hb-subset.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset-glyf.hh"
 
 #include "hb-open-file.hh"
 #include "hb-ot-cmap-table.hh"
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index efc354b9..a9d00c6c 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -32,26 +32,9 @@
 
 #include "hb-subset.h"
 
-#include "hb-font.hh"
-
-struct hb_subset_input_t
-{
-  hb_object_header_t header;
-  ASSERT_POD ();
-
-  hb_set_t *unicodes;
-  hb_set_t *glyphs;
-
-  bool drop_hints : 1;
-  bool drop_layout : 1;
-  /* TODO
-   *
-   * features
-   * lookups
-   * nameIDs
-   * ...
-   */
-};
+#include "hb-subset-input.hh"
+#include "hb-subset-plan.hh"
+
 
 
 #endif /* HB_SUBSET_HH */
commit 18d01eac7f2870e2804ceed2c70a604a5dc6a320
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Aug 31 13:00:57 2018 -0700

    Minor

diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 03f46d84..0ef60f64 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -173,7 +173,6 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
 					 ligatures_supplier,
 					 component_count_supplier,
 					 component_supplier);
-
   c.end_serialize ();
   /* TODO sanitize the results? */
 
commit a23b892fe6cc4859a30edc7ffc003ab7624aa5f0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 29 18:28:39 2018 -0700

    Shuffle

diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 35a8b6c1..1e0f7ccf 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -464,36 +464,6 @@ struct hb_serialize_context_t
   }
 
   template <typename Type>
-  inline Type *copy (void) const
-  {
-    assert (!this->ran_out_of_room);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    return reinterpret_cast<Type *> (p);
-  }
-  inline hb_bytes_t copy_bytes (void) const
-  {
-    assert (!this->ran_out_of_room);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    else
-      return hb_bytes_t ();
-    return hb_bytes_t (p, len);
-  }
-  inline hb_blob_t *copy_blob (void) const
-  {
-    assert (!this->ran_out_of_room);
-    return hb_blob_create (this->start,
-			   this->head - this->start,
-			   HB_MEMORY_MODE_DUPLICATE,
-			   nullptr, nullptr);
-  }
-
-  template <typename Type>
   inline Type *allocate_size (unsigned int size)
   {
     if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
@@ -547,6 +517,38 @@ struct hb_serialize_context_t
     return reinterpret_cast<Type *> (&obj);
   }
 
+  /* Output routines. */
+  template <typename Type>
+  inline Type *copy (void) const
+  {
+    assert (!this->ran_out_of_room);
+    unsigned int len = this->head - this->start;
+    void *p = malloc (len);
+    if (p)
+      memcpy (p, this->start, len);
+    return reinterpret_cast<Type *> (p);
+  }
+  inline hb_bytes_t copy_bytes (void) const
+  {
+    assert (!this->ran_out_of_room);
+    unsigned int len = this->head - this->start;
+    void *p = malloc (len);
+    if (p)
+      memcpy (p, this->start, len);
+    else
+      return hb_bytes_t ();
+    return hb_bytes_t (p, len);
+  }
+  inline hb_blob_t *copy_blob (void) const
+  {
+    assert (!this->ran_out_of_room);
+    return hb_blob_create (this->start,
+			   this->head - this->start,
+			   HB_MEMORY_MODE_DUPLICATE,
+			   nullptr, nullptr);
+  }
+
+  public:
   unsigned int debug_depth;
   char *start, *end, *head;
   bool ran_out_of_room;
commit 93fe0faaee45b8fb646f7aa33620105c62193885
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 29 18:24:03 2018 -0700

    [subset] Clean up hb_subset_input_t API

diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index d68550d7..d59b5bae 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -44,7 +44,7 @@ hb_subset_input_create_or_fail (void)
 
   input->unicodes = hb_set_create ();
   input->glyphs = hb_set_create ();
-  input->drop_ot_layout = true;
+  input->drop_layout = true;
 
   return input;
 }
@@ -106,30 +106,28 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
   return subset_input->glyphs;
 }
 
-/**
- * hb_subset_input_drop_hints:
- * @subset_input: a subset_input.
- *
- * Since: 1.8.0
- **/
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
+HB_EXTERN void
+hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
+				hb_bool_t drop_hints)
 {
-  return &subset_input->drop_hints;
+  subset_input->drop_hints = drop_hints;
 }
 
-/**
- * hb_subset_input_drop_ot_layout:
- * @subset_input: a subset_input.
- *
- * If enabled ot layout tables will be dropped as part of
- * the subsetting operation. Currently this defaults to
- * true.
- *
- * Since: REPLACEME
- **/
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input)
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
+{
+  return subset_input->drop_hints;
+}
+
+HB_EXTERN void
+hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
+				hb_bool_t drop_layout)
+{
+  subset_input->drop_layout = drop_layout;
+}
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
 {
-  return &subset_input->drop_ot_layout;
+  return subset_input->drop_layout;
 }
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 7efa1c19..2d8538ef 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -149,7 +149,7 @@ hb_subset_plan_create (hb_face_t           *face,
   hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
 
   plan->drop_hints = input->drop_hints;
-  plan->drop_ot_layout = input->drop_ot_layout;
+  plan->drop_layout = input->drop_layout;
   plan->unicodes = hb_set_create();
   plan->glyphs.init();
   plan->source = hb_face_reference (face);
@@ -159,7 +159,7 @@ hb_subset_plan_create (hb_face_t           *face,
 
   _populate_gids_to_retain (face,
                             input->unicodes,
-                            !plan->drop_ot_layout,
+                            !plan->drop_layout,
                             plan->unicodes,
                             plan->codepoint_to_glyph,
                             &plan->glyphs);
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index a5be50a6..af7c5d33 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -39,8 +39,8 @@ struct hb_subset_plan_t
   hb_object_header_t header;
   ASSERT_POD ();
 
-  hb_bool_t drop_hints;
-  hb_bool_t drop_ot_layout;
+  bool drop_hints : 1;
+  bool drop_layout : 1;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
@@ -56,7 +56,7 @@ struct hb_subset_plan_t
   hb_face_t *source;
   hb_face_t *dest;
 
-  inline hb_bool_t
+  inline bool
   new_gid_for_codepoint (hb_codepoint_t codepoint,
                          hb_codepoint_t *new_gid) const
   {
@@ -67,7 +67,7 @@ struct hb_subset_plan_t
     return new_gid_for_old_gid (old_gid, new_gid);
   }
 
-  inline hb_bool_t
+  inline bool
   new_gid_for_old_gid (hb_codepoint_t old_gid,
                       hb_codepoint_t *new_gid) const
   {
@@ -79,7 +79,7 @@ struct hb_subset_plan_t
     return true;
   }
 
-  inline hb_bool_t
+  inline bool
   add_table (hb_tag_t tag,
              hb_blob_t *contents)
   {
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index a0729977..332a1e28 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -136,7 +136,7 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
     case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
     case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
     case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
-      return plan->drop_ot_layout;
+      return plan->drop_layout;
     // Drop these tables below by default, list pulled
     // from fontTools:
     case HB_TAG ('B', 'A', 'S', 'E'):
diff --git a/src/hb-subset.h b/src/hb-subset.h
index 3b39706d..8b07a45e 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -54,11 +54,17 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
 HB_EXTERN hb_set_t *
 hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
 
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_hints (hb_subset_input_t *subset_input);
+HB_EXTERN void
+hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
+				hb_bool_t drop_hints);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
 
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input);
+HB_EXTERN void
+hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
+				hb_bool_t drop_layout);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
 
 
 /* hb_subset() */
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index e3023d65..efc354b9 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -42,8 +42,8 @@ struct hb_subset_input_t
   hb_set_t *unicodes;
   hb_set_t *glyphs;
 
-  hb_bool_t drop_hints;
-  hb_bool_t drop_ot_layout;
+  bool drop_hints : 1;
+  bool drop_layout : 1;
   /* TODO
    *
    * features
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index e4440e0f..6f669dae 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -112,7 +112,7 @@ test_subset_glyf_with_gsub (void)
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  *hb_subset_input_drop_ot_layout (input) = false;
+  hb_subset_input_set_drop_layout (input, false);
 
   hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -137,7 +137,7 @@ test_subset_glyf_without_gsub (void)
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  *hb_subset_input_drop_ot_layout (input) = true;
+  hb_subset_input_set_drop_layout (input, true);
 
   hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -183,7 +183,7 @@ test_subset_glyf_strip_hints_simple (void)
   hb_set_add (codepoints, 'a');
   hb_set_add (codepoints, 'c');
   input = hb_subset_test_create_input (codepoints);
-  *hb_subset_input_drop_hints(input) = true;
+  hb_subset_input_set_drop_hints (input, true);
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
@@ -207,7 +207,7 @@ test_subset_glyf_strip_hints_composite (void)
   hb_face_t *face_generated_subset;
   hb_set_add (codepoints, 0x1fc);
   input = hb_subset_test_create_input (codepoints);
-  *hb_subset_input_drop_hints(input) = true;
+  hb_subset_input_set_drop_hints (input, true);
 
   face_generated_subset = hb_subset_test_create_subset (face_components, input);
   hb_set_destroy (codepoints);
@@ -239,7 +239,7 @@ test_subset_glyf_strip_hints_invalid (void)
   }
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
-  *hb_subset_input_drop_hints(input) = true;
+  hb_subset_input_set_drop_hints (input, true);
   hb_set_destroy (codepoints);
 
   hb_face_t *face_subset = hb_subset_test_create_subset (face, input);
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index 108f6ec1..9e4aafca 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -10,11 +10,11 @@ void trySubset (hb_face_t *face,
                 const hb_codepoint_t text[],
                 int text_length,
                 bool drop_hints,
-                bool drop_ot_layout)
+                bool drop_layout)
 {
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
-  *hb_subset_input_drop_hints (input) = drop_hints;
-  *hb_subset_input_drop_ot_layout (input) = drop_ot_layout;
+  hb_subset_input_set_drop_hints (input, drop_hints);
+  hb_subset_input_set_drop_layout (input, drop_layout);
   hb_set_t *codepoints = hb_subset_input_unicode_set (input);
 
   for (int i = 0; i < text_length; i++)
@@ -34,10 +34,10 @@ void trySubset (hb_face_t *face,
 {
   for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
   {
-    for (unsigned int drop_ot_layout = 0; drop_ot_layout < 2; drop_ot_layout++)
+    for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++)
     {
       trySubset (face, text, text_length,
-                 (bool) drop_hints, (bool) drop_ot_layout);
+                 (bool) drop_hints, (bool) drop_layout);
     }
   }
 }
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index f333be8a..3f0963c3 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -29,7 +29,6 @@
 
 #include "main-font-text.hh"
 #include "hb-subset.h"
-#include "hb-subset.hh" /* XXX */
 
 /*
  * Command line interface to the harfbuzz font subsetter.
@@ -90,7 +89,7 @@ struct subset_consumer_t
 
   void finish (const font_options_t *font_opts)
   {
-    input->drop_hints = subset_options.drop_hints;
+    hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
 
     hb_face_t *face = hb_font_get_face (font);
 
commit d237ce71810045ee400c52740cd8ab6e1113aada
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Aug 29 18:13:07 2018 -0700

    [subset] Bail if subsetting a table failed

diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 1695d371..a0729977 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -53,11 +53,9 @@ _subset (hb_subset_plan_t *plan)
   hb_tag_t tag = TableType::tableTag;
   hb_bool_t result = false;
   if (source_blob->data)
-  {
-    result = table->subset(plan);
-  } else {
+    result = table->subset (plan);
+  else
     DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
-  }
 
   hb_blob_destroy (source_blob);
   DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
@@ -196,7 +194,7 @@ hb_subset (hb_face_t *source,
       success = success && _subset_table (plan, tag);
     }
     offset += count;
-  } while (count == ARRAY_LENGTH (table_tags));
+  } while (success && count == ARRAY_LENGTH (table_tags));
 
   hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty();
   hb_subset_plan_destroy (plan);


More information about the HarfBuzz mailing list