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

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri Nov 23 23:03:00 PST 2012


 src/hb-open-file-private.hh          |   10 
 src/hb-open-type-private.hh          |   82 ++-
 src/hb-ot-head-table.hh              |    2 
 src/hb-ot-hhea-table.hh              |    2 
 src/hb-ot-hmtx-table.hh              |    2 
 src/hb-ot-layout-common-private.hh   |   36 -
 src/hb-ot-layout-gdef-table.hh       |   20 
 src/hb-ot-layout-gpos-table.hh       |  496 +++++++++-------------
 src/hb-ot-layout-gsub-table.hh       |  740 ++++++++-------------------------
 src/hb-ot-layout-gsubgpos-private.hh |  780 ++++++++++++++++++++++-------------
 src/hb-ot-layout.cc                  |    9 
 src/hb-ot-maxp-table.hh              |    2 
 src/hb-ot-name-table.hh              |    6 
 src/hb-private.hh                    |   64 ++
 src/hb-shape-plan.cc                 |    1 
 src/hb-ucdn/ucdn.c                   |   16 
 src/hb-ucdn/unicodedata_db.h         |   28 -
 17 files changed, 1092 insertions(+), 1204 deletions(-)

New commits:
commit f1b12781d279a73b5754afee31e930b5cd87aac6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 01:55:34 2012 -0500

    [OTLayout] Implement ChainContext collect_glyphs()
    
    All of collect_glyphs() complete and untested now.

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 0b1bc68..51ae9b5 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -534,13 +534,14 @@ static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, cons
   (data+coverage).add_coverage (glyphs);
 }
 static inline void collect_array (hb_collect_glyphs_context_t *c,
+				  hb_set_t *glyphs,
 				  unsigned int count,
 				  const USHORT values[],
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
   for (unsigned int i = 0; i < count; i++)
-    collect_func (&c->input, values[i], collect_data);
+    collect_func (glyphs, values[i], collect_data);
 }
 
 
@@ -912,7 +913,7 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c
 						  const LookupRecord lookupRecord[],
 						  ContextCollectGlyphsLookupContext &lookup_context)
 {
-  collect_array (c,
+  collect_array (c, &c->input,
 		 inputCount ? inputCount - 1 : 0, input,
 		 lookup_context.funcs.collect, lookup_context.collect_data);
   recurse_lookups (c,
@@ -1093,7 +1094,7 @@ struct ContextFormat1
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
-	(this+ruleSet[i]).collect_glyphs (c, lookup_context);
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1181,7 +1182,7 @@ struct ContextFormat2
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
-	(this+ruleSet[i]).collect_glyphs (c, lookup_context);
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1375,6 +1376,12 @@ struct ChainContextClosureLookupContext
   const void *intersects_data[3];
 };
 
+struct ChainContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data[3];
+};
+
 struct ChainContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
@@ -1405,6 +1412,30 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 		     lookupCount, lookupRecord);
 }
 
+static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+						        unsigned int backtrackCount,
+						        const USHORT backtrack[],
+						        unsigned int inputCount, /* Including the first glyph (not matched) */
+						        const USHORT input[], /* Array of input values--start with second glyph */
+						        unsigned int lookaheadCount,
+						        const USHORT lookahead[],
+						        unsigned int lookupCount,
+						        const LookupRecord lookupRecord[],
+						        ChainContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, &c->before,
+		 backtrackCount, backtrack,
+		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
+  collect_array (c, &c->input,
+		 inputCount ? inputCount - 1 : 0, input,
+		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
+  collect_array (c, &c->after,
+		 lookaheadCount, lookahead,
+		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
+  recurse_lookups (c,
+		   lookupCount, lookupRecord);
+}
+
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
 						     const USHORT backtrack[],
@@ -1466,6 +1497,20 @@ struct ChainRule
 				  lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    chain_context_collect_glyphs_lookup (c,
+					 backtrack.len, backtrack.array,
+					 input.len, input.array,
+					 lookahead.len, lookahead.array,
+					 lookup.len, lookup.array,
+					 lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1531,6 +1576,14 @@ struct ChainRuleSet
       (this+rule[i]).closure (c, lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1588,7 +1641,17 @@ struct ChainContextFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1668,7 +1731,17 @@ struct ChainContextFormat2
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1769,7 +1842,23 @@ struct ChainContextFormat3
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    (this+input[0]).add_coverage (&c->input);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      {this, this, this}
+    };
+    chain_context_collect_glyphs_lookup (c,
+					 backtrack.len, (const USHORT *) backtrack.array,
+					 input.len, (const USHORT *) input.array + 1,
+					 lookahead.len, (const USHORT *) lookahead.array,
+					 lookup.len, lookup.array,
+					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
commit cdd756b9f40665a201f5c4e65a87b9a27c390601
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 01:38:41 2012 -0500

    [OTLayout] Implement GPOS collect_glyphs()

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index e0b8913..c2e5df0 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -419,6 +419,12 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 
 struct SinglePosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -458,6 +464,12 @@ struct SinglePosFormat1
 
 struct SinglePosFormat2
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -548,6 +560,23 @@ struct PairSet
 {
   friend struct PairPosFormat1;
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
+			      const ValueFormat *valueFormats) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = CastP<PairValueRecord> (array);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      c->input.add (record->secondGlyph);
+      record = &StructAtOffset<PairValueRecord> (record, record_size);
+    }
+  }
+
   inline bool apply (hb_apply_context_t *c,
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
@@ -557,8 +586,8 @@ struct PairSet
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
 
-    unsigned int count = len;
     const PairValueRecord *record = CastP<PairValueRecord> (array);
+    unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
     {
       if (c->buffer->info[pos].codepoint == record->secondGlyph)
@@ -606,6 +635,15 @@ struct PairSet
 
 struct PairPosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -660,6 +698,24 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    /* (this+coverage).add_coverage (&c->input); // Don't need this. */
+
+    /* TODO only add values for pairs that have nonzero adjustments. */
+
+    unsigned int count1 = class1Count;
+    const ClassDef &klass1 = this+classDef1;
+    for (unsigned int i = 0; i < count1; i++)
+      klass1.add_class (&c->input, i);
+
+    unsigned int count2 = class2Count;
+    const ClassDef &klass2 = this+classDef2;
+    for (unsigned int i = 0; i < count2; i++)
+      klass2.add_class (&c->input, i);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -800,6 +856,12 @@ struct EntryExitRecord
 
 struct CursivePosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -940,6 +1002,14 @@ typedef AnchorMatrix BaseArray;		/* base-major--
 
 struct MarkBasePosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (&c->input);
+    (this+baseCoverage).add_coverage (&c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
@@ -1036,6 +1106,14 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
 
 struct MarkLigPosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (&c->input);
+    (this+ligatureCoverage).add_coverage (&c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
@@ -1144,6 +1222,14 @@ typedef AnchorMatrix Mark2Array;	/* mark2-major--
 
 struct MarkMarkPosFormat1
 {
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+mark1Coverage).add_coverage (&c->input);
+    (this+mark2Coverage).add_coverage (&c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
@@ -1357,6 +1443,13 @@ struct PosLookup : Lookup
   template <typename context_t>
   static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
 
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (process_recurse_func<hb_collect_glyphs_context_t>);
+    return TRACE_RETURN (process (c));
+  }
+
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index d345ba6..022460a 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -412,18 +412,19 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
 
-//  OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
+  OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
 
   switch (table_tag) {
     case HB_OT_TAG_GSUB:
     {
-//      hb_ot_layout_from_face (face)->gsub->collect_glyphs_lookup (&c, lookup_index);
+      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+      l.collect_glyphs_lookup (&c);
       return;
     }
     case HB_OT_TAG_GPOS:
     {
-//      hb_ot_layout_from_face (face)->gpos->collect_glyphs_lookup (&c, lookup_index);
-//      l.collect_glyphs_lookup (&c);
+      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
+      l.collect_glyphs_lookup (&c);
       return;
     }
   }
commit 4c4e8f0e754b79ac6190d21878eaaf0b790c7579
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 01:13:20 2012 -0500

    [OTLayout] Reuse apply context for recursion

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 873060f..e0b8913 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1537,8 +1537,13 @@ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int l
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_property = c->property;
   c->set_lookup (l);
-  return l.apply_once (c);
+  bool ret = l.apply_once (c);
+  c->lookup_props = saved_lookup_props;
+  c->property = saved_property;
+  return ret;
 }
 
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 690b2d5..ddbb3b5 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1402,8 +1402,13 @@ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_property = c->property;
   c->set_lookup (l);
-  return l.apply_once (c);
+  bool ret = l.apply_once (c);
+  c->lookup_props = saved_lookup_props;
+  c->property = saved_property;
+  return ret;
 }
 
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 00a4bd4..0b1bc68 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -233,10 +233,10 @@ struct hb_apply_context_t
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
-    /* TODO Reuse context. */
-    hb_apply_context_t new_c (*this);
-    new_c.nesting_level_left--;
-    return recurse_func (&new_c, lookup_index);
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return default_return_value ();
   }
 
   hb_font_t *font;
commit 53a69f49e58ef4c4226958e0496fc22455ee6c87
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Nov 24 01:03:05 2012 -0500

    [OTLayout] Remove unused members

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 147fea6..00a4bd4 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -200,9 +200,6 @@ struct hb_get_coverage_context_t
   template <typename T>
   inline return_t process (const T &obj) { return obj.get_coverage (); }
   static return_t default_return_value (void) { return Null(Coverage); }
-  bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
-  return_t recurse (unsigned int lookup_index)
-  { return default_return_value (); }
 
   hb_get_coverage_context_t (void) :
 			    debug_depth (0) {}
commit d0a5233785eb327c4080432f597fe470a1046af3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 18:54:59 2012 -0500

    [OTLayout] Implement Context::collect_glyphs()

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 3e59d54..147fea6 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -477,17 +477,23 @@ struct hb_apply_context_t
 
 
 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
 };
+struct ContextCollectGlyphsFuncs
+{
+  collect_glyphs_func_t collect;
+};
 struct ContextApplyFuncs
 {
   match_func_t match;
 };
 
+
 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
@@ -516,6 +522,31 @@ static inline bool intersects_array (hb_closure_context_t *c,
 }
 
 
+static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+  glyphs->add (value);
+}
+static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  class_def.add_class (glyphs, value);
+}
+static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  (data+coverage).add_coverage (glyphs);
+}
+static inline void collect_array (hb_collect_glyphs_context_t *c,
+				  unsigned int count,
+				  const USHORT values[],
+				  collect_glyphs_func_t collect_func,
+				  const void *collect_data)
+{
+  for (unsigned int i = 0; i < count; i++)
+    collect_func (&c->input, values[i], collect_data);
+}
+
+
 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
@@ -531,7 +562,6 @@ static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value,
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
-
 static inline bool would_match_input (hb_would_apply_context_t *c,
 				      unsigned int count, /* Including the first glyph (not matched) */
 				      const USHORT input[], /* Array of input values--start with second glyph */
@@ -774,9 +804,10 @@ struct LookupRecord
 };
 
 
-static inline void closure_lookup (hb_closure_context_t *c,
-				   unsigned int lookupCount,
-				   const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
+template <typename context_t>
+static inline void recurse_lookups (context_t *c,
+				    unsigned int lookupCount,
+				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
     c->recurse (lookupRecord->lookupListIndex);
@@ -851,6 +882,12 @@ struct ContextClosureLookupContext
   const void *intersects_data;
 };
 
+struct ContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data;
+};
+
 struct ContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
@@ -867,10 +904,23 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
   if (intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data))
-    closure_lookup (c,
-		    lookupCount, lookupRecord);
+    recurse_lookups (c,
+		     lookupCount, lookupRecord);
 }
 
+static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+						  unsigned int inputCount, /* Including the first glyph (not matched) */
+						  const USHORT input[], /* Array of input values--start with second glyph */
+						  unsigned int lookupCount,
+						  const LookupRecord lookupRecord[],
+						  ContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c,
+		 inputCount ? inputCount - 1 : 0, input,
+		 lookup_context.funcs.collect, lookup_context.collect_data);
+  recurse_lookups (c,
+		   lookupCount, lookupRecord);
+}
 
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
@@ -910,6 +960,16 @@ struct Rule
 			    lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+    context_collect_glyphs_lookup (c,
+				   inputCount, input,
+				   lookupCount, lookupRecord,
+				   lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
@@ -957,6 +1017,14 @@ struct RuleSet
       (this+rule[i]).closure (c, lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1018,7 +1086,17 @@ struct ContextFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+	(this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1096,7 +1174,17 @@ struct ContextFormat2
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (&c->input);
+
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+	(this+ruleSet[i]).collect_glyphs (c, lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1176,7 +1264,19 @@ struct ContextFormat3
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    /* XXXXXXXXXX */
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage[0]).add_coverage (&c->input);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      NULL
+    };
+
+    context_collect_glyphs_lookup (c,
+				   glyphCount, (const USHORT *) (coverage + 1),
+				   lookupCount, lookupRecord,
+				   lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
@@ -1304,8 +1404,8 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
   && intersects_array (c,
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
-    closure_lookup (c,
-		    lookupCount, lookupRecord);
+    recurse_lookups (c,
+		     lookupCount, lookupRecord);
 }
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
commit 26514d51b6669f092d9ccb7523443a5ece74169a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 18:13:48 2012 -0500

    [OTLayout] More collect_glyphs()

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 2e6933f..873060f 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1374,10 +1374,10 @@ struct PosLookup : Lookup
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
+    TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
-
-    return process (c);
+      return TRACE_RETURN (false);
+    return TRACE_RETURN (process (c));
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 0d14a1c..690b2d5 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -50,6 +50,7 @@ struct SingleSubstFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       hb_codepoint_t glyph_id = iter.get_glyph ();
@@ -126,6 +127,7 @@ struct SingleSubstFormat2
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       c->input.add (iter.get_glyph ());
@@ -259,6 +261,7 @@ struct Sequence
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->output.add (substitute[i]);
@@ -316,6 +319,7 @@ struct MultipleSubstFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (&c->input);
     unsigned int count = sequence.len;
     for (unsigned int i = 0; i < count; i++)
@@ -444,6 +448,7 @@ struct AlternateSubstFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       c->input.add (iter.get_glyph ());
@@ -587,6 +592,7 @@ struct Ligature
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     unsigned int count = component.len;
     for (unsigned int i = 1; i < count; i++)
       c->input.add (component[i]);
@@ -680,6 +686,7 @@ struct LigatureSet
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
       (this+ligature[i]).collect_glyphs (c);
@@ -757,6 +764,7 @@ struct LigatureSubstFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       c->input.add (iter.get_glyph ());
@@ -919,6 +927,8 @@ struct ReverseChainSingleSubstFormat1
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
+
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
@@ -1145,8 +1155,16 @@ struct SubstLookup : Lookup
 
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
+    TRACE_CLOSURE (this);
     c->set_recurse_func (process_recurse_func<hb_closure_context_t>);
-    return process (c);
+    return TRACE_RETURN (process (c));
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (process_recurse_func<hb_collect_glyphs_context_t>);
+    return TRACE_RETURN (process (c));
   }
 
   template <typename set_t>
@@ -1174,10 +1192,10 @@ struct SubstLookup : Lookup
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
+    TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
-
-    return process (c);
+      return TRACE_RETURN (false);
+    return TRACE_RETURN (process (c));
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
@@ -1330,12 +1348,6 @@ struct GSUB : GSUBGPOS
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-#if 0
-  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
-								      unsigned int lookup_index) const
-  { return get_lookup (lookup_index).process (c); }
-#endif
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 93b14e9..3e59d54 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -147,15 +147,19 @@ struct hb_collect_glyphs_context_t
   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
   static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
   typedef void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t process (const T &obj) { obj.collect_glyphs (this); return VOID; }
   static return_t default_return_value (void) { return VOID; }
-  bool stop_iteration (const return_t r) const { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
-#if 0
-    /* XXX */
-#endif
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
     return default_return_value ();
   }
 
@@ -164,19 +168,26 @@ struct hb_collect_glyphs_context_t
   hb_set_t &input;
   hb_set_t &after;
   hb_set_t &output;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
 			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
 			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
 			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
-			       hb_set_t  *glyphs_output  /* OUT. May be NULL */) :
+			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
+			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			      face (face_),
 			      before (glyphs_before ? *glyphs_before : *hb_set_get_empty ()),
 			      input  (glyphs_input  ? *glyphs_input  : *hb_set_get_empty ()),
 			      after  (glyphs_after  ? *glyphs_after  : *hb_set_get_empty ()),
 			      output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()),
+			      recurse_func (NULL),
+			      nesting_level_left (nesting_level_left_),
 			      debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
@@ -1005,6 +1016,11 @@ struct ContextFormat1
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1078,6 +1094,11 @@ struct ContextFormat2
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1153,6 +1174,11 @@ struct ContextFormat3
 			    lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1463,6 +1489,11 @@ struct ChainContextFormat1
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1538,6 +1569,11 @@ struct ChainContextFormat2
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
@@ -1634,6 +1670,11 @@ struct ChainContextFormat3
 				  lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    /* XXXXXXXXXX */
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
commit c6fb843f2a1c26322c6f4c85d1589f01a9e7a2ef
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 18:04:08 2012 -0500

    [OTLayout] Templatize process_recurse_func

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 86c0d8d..2e6933f 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1354,6 +1354,8 @@ struct PosLookup : Lookup
     }
     return TRACE_RETURN (c->default_return_value ());
   }
+  template <typename context_t>
+  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
@@ -1523,6 +1525,14 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t
 
 /* Out-of-class implementation for methods recursing */
 
+template <typename context_t>
+inline typename context_t::return_t PosLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
+{
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+  const PosLookup &l = gpos.get_lookup (lookup_index);
+  return l.process (c);
+}
+
 inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 0679dc1..0d14a1c 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1140,11 +1140,12 @@ struct SubstLookup : Lookup
     }
     return TRACE_RETURN (c->default_return_value ());
   }
+  template <typename context_t>
+  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
 
-  static inline void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index);
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
-    c->set_recurse_func (closure_recurse_func);
+    c->set_recurse_func (process_recurse_func<hb_closure_context_t>);
     return process (c);
   }
 
@@ -1377,7 +1378,8 @@ inline bool ExtensionSubst::is_reverse (void) const
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
-inline void_t SubstLookup::closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+template <typename context_t>
+inline typename context_t::return_t SubstLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
commit 9b34677f362fb0ef5a7cb8a284a9e06d1a4cc03b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:55:40 2012 -0500

    [OTLayout] Clean up closure() a bit

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 201ca27..0679dc1 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1141,6 +1141,13 @@ struct SubstLookup : Lookup
     return TRACE_RETURN (c->default_return_value ());
   }
 
+  static inline void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index);
+  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
+  {
+    c->set_recurse_func (closure_recurse_func);
+    return process (c);
+  }
+
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
@@ -1173,7 +1180,6 @@ struct SubstLookup : Lookup
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
-
   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     bool ret = false;
@@ -1323,20 +1329,6 @@ struct GSUB : GSUBGPOS
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  static inline void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
-  {
-    const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
-    const SubstLookup &l = gsub.get_lookup (lookup_index);
-    return l.process (c);
-  }
-  inline hb_closure_context_t::return_t closure_lookup (hb_face_t *face,
-							hb_set_t *glyphs,
-							unsigned int lookup_index) const
-  {
-    hb_closure_context_t c (face, glyphs, closure_recurse_func);
-    return get_lookup (lookup_index).process (&c);
-  }
-
 #if 0
   inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 								      unsigned int lookup_index) const
@@ -1385,6 +1377,13 @@ inline bool ExtensionSubst::is_reverse (void) const
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
+inline void_t SubstLookup::closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+{
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
+  const SubstLookup &l = gsub.get_lookup (lookup_index);
+  return l.process (c);
+}
+
 inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index f47f80b..93b14e9 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -65,7 +65,7 @@ struct hb_closure_context_t
   bool stop_sublookup_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
-    if (unlikely (nesting_level_left == 0))
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
     nesting_level_left--;
@@ -82,13 +82,14 @@ struct hb_closure_context_t
 
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
-			recurse_func_t recurse_func_,
 		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
-			  recurse_func (recurse_func_),
+			  recurse_func (NULL),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 7af75c0..d345ba6 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -498,7 +498,11 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
 				        hb_set_t     *glyphs)
 {
-  _get_gsub (face).closure_lookup (face, glyphs, lookup_index);
+  OT::hb_closure_context_t c (face, glyphs);
+
+  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+
+  l.closure (&c);
 }
 
 /*
commit adf7758a27a11fb1a8a14a2673867589437d22a3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:32:00 2012 -0500

    Improve debug log format in presence of templates

diff --git a/src/hb-private.hh b/src/hb-private.hh
index feab7ca..265fba1 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -588,7 +588,11 @@ _hb_debug_msg_va (const char *what,
   } else
     fprintf (stderr, "   " VRBAR LBAR);
 
-  if (func) {
+  if (func)
+  {
+    /* Skip "typename" */
+    if (0 == strncmp (func, "typename ", 9))
+      func += 9;
     /* Skip return type */
     const char *space = strchr (func, ' ');
     if (space)
commit 2c53bd3c3ec4f81eff126c5bf84b7f2ddf2f0fef
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:29:05 2012 -0500

    [OTLayout] Start porting sanitize() to process()

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 541927b..2372235 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -168,12 +168,22 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 
 #define TRACE_SANITIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
-	(&c->debug_depth, "SANITIZE", this, HB_FUNC, \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
 
 struct hb_sanitize_context_t
 {
+  inline const char *get_name (void) { return "SANITIZE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
+  typedef bool return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.sanitize (this); }
+  static return_t default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (const return_t r) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  { return default_return_value (); }
+
   inline void init (hb_blob_t *b)
   {
     this->blob = hb_blob_reference (b);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 6be9238..f47f80b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -50,7 +50,7 @@ namespace OT {
 
 #define TRACE_CLOSURE(this) \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE, void_t> trace \
-	(&c->debug_depth, "CLOSURE", this, HB_FUNC, \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
 struct hb_closure_context_t
@@ -99,7 +99,7 @@ struct hb_closure_context_t
 
 #define TRACE_WOULD_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
-	(&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "%d glyphs", c->len);
 
 struct hb_would_apply_context_t
@@ -138,7 +138,7 @@ struct hb_would_apply_context_t
 
 #define TRACE_COLLECT_GLYPHS(this) \
 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, void_t> trace \
-	(&c->debug_depth, "COLLECT_GLYPHS", this, HB_FUNC, \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
 struct hb_collect_glyphs_context_t
@@ -206,7 +206,7 @@ struct hb_get_coverage_context_t
 
 #define TRACE_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
-	(&c->debug_depth, "APPLY", this, HB_FUNC, \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
 struct hb_apply_context_t
commit f48ec0e83432c038b50d9715a38ba1469e82e1e4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:23:41 2012 -0500

    [OTLayout] Add process() tracing

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 29faa18..86c0d8d 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -503,10 +503,11 @@ struct SinglePos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    case 2: return c->process (u.format2);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -748,10 +749,11 @@ struct PairPos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    case 2: return c->process (u.format2);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -907,9 +909,10 @@ struct CursivePos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -997,9 +1000,10 @@ struct MarkBasePos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1109,9 +1113,10 @@ struct MarkLigPos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1219,9 +1224,10 @@ struct MarkMarkPos
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1277,17 +1283,18 @@ struct PosLookupSubTable
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
+    TRACE_PROCESS (this);
     switch (lookup_type) {
-    case Single:		return u.single.process (c);
-    case Pair:			return u.pair.process (c);
-    case Cursive:		return u.cursive.process (c);
-    case MarkBase:		return u.markBase.process (c);
-    case MarkLig:		return u.markLig.process (c);
-    case MarkMark:		return u.markMark.process (c);
-    case Context:		return u.context.process (c);
-    case ChainContext:		return u.chainContext.process (c);
-    case Extension:		return u.extension.process (c);
-    default:			return c->default_return_value ();
+    case Single:		return TRACE_RETURN (u.single.process (c));
+    case Pair:			return TRACE_RETURN (u.pair.process (c));
+    case Cursive:		return TRACE_RETURN (u.cursive.process (c));
+    case MarkBase:		return TRACE_RETURN (u.markBase.process (c));
+    case MarkLig:		return TRACE_RETURN (u.markLig.process (c));
+    case MarkMark:		return TRACE_RETURN (u.markMark.process (c));
+    case Context:		return TRACE_RETURN (u.context.process (c));
+    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
+    case Extension:		return TRACE_RETURN (u.extension.process (c));
+    default:			return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1337,14 +1344,15 @@ struct PosLookup : Lookup
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     unsigned int lookup_type = get_type ();
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
       typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
       if (c->stop_sublookup_iteration (r))
-        return r;
+        return TRACE_RETURN (r);
     }
-    return c->default_return_value ();
+    return TRACE_RETURN (c->default_return_value ());
   }
 
   template <typename set_t>
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 1a2119d..201ca27 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -193,10 +193,11 @@ struct SingleSubst
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    case 2: return c->process (u.format2);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -382,9 +383,10 @@ struct MultipleSubst
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -531,9 +533,10 @@ struct AlternateSubst
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -832,9 +835,10 @@ struct LigatureSubst
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1010,9 +1014,10 @@ struct ReverseChainSingleSubst
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1056,16 +1061,17 @@ struct SubstLookupSubTable
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
+    TRACE_PROCESS (this);
     switch (lookup_type) {
-    case Single:		return u.single.process (c);
-    case Multiple:		return u.multiple.process (c);
-    case Alternate:		return u.alternate.process (c);
-    case Ligature:		return u.ligature.process (c);
-    case Context:		return u.context.process (c);
-    case ChainContext:		return u.chainContext.process (c);
-    case Extension:		return u.extension.process (c);
-    case ReverseChainSingle:	return u.reverseChainContextSingle.process (c);
-    default:			return c->default_return_value ();
+    case Single:		return TRACE_RETURN (u.single.process (c));
+    case Multiple:		return TRACE_RETURN (u.multiple.process (c));
+    case Alternate:		return TRACE_RETURN (u.alternate.process (c));
+    case Ligature:		return TRACE_RETURN (u.ligature.process (c));
+    case Context:		return TRACE_RETURN (u.context.process (c));
+    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
+    case Extension:		return TRACE_RETURN (u.extension.process (c));
+    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.process (c));
+    default:			return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1124,14 +1130,15 @@ struct SubstLookup : Lookup
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     unsigned int lookup_type = get_type ();
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
       typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
       if (c->stop_sublookup_iteration (r))
-        return r;
+        return TRACE_RETURN (r);
     }
-    return c->default_return_value ();
+    return TRACE_RETURN (c->default_return_value ());
   }
 
   template <typename set_t>
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 1fbfabd..6be9238 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -1213,11 +1213,12 @@ struct Context
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    case 2: return c->process (u.format2);
-    case 3: return c->process (u.format3);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    case 3: return TRACE_RETURN (c->process (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
@@ -1716,10 +1717,10 @@ struct ChainContext
   {
     TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return c->process (u.format1);
-    case 2: return c->process (u.format2);
-    case 3: return c->process (u.format3);
-    default:return c->default_return_value ();
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    case 3: return TRACE_RETURN (c->process (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
commit ed2e13594479c6ed7909401509962ea2f03f9a6e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:10:40 2012 -0500

    [OTLayout] More Extension templatizing

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 1a75880..29faa18 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1249,8 +1249,6 @@ struct ChainContextPos : ChainContext {};
 struct ExtensionPos : Extension<ExtensionPos>
 {
   typedef struct PosLookupSubTable LookupSubTable;
-
-  inline bool sanitize (hb_sanitize_context_t *c);
 };
 
 
@@ -1517,15 +1515,6 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t
 
 /* Out-of-class implementation for methods recursing */
 
-inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE (this);
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
 inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 9971875..1a2119d 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -882,8 +882,6 @@ struct ExtensionSubst : Extension<ExtensionSubst>
 {
   typedef struct SubstLookupSubTable LookupSubTable;
 
-  inline bool sanitize (hb_sanitize_context_t *c);
-
   inline bool is_reverse (void) const;
 };
 
@@ -1372,15 +1370,6 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE
 
 /* Out-of-class implementation for methods recursing */
 
-inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE (this);
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
 inline bool ExtensionSubst::is_reverse (void) const
 {
   unsigned int type = get_type ();
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 4ff8940..1fbfabd 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -1794,10 +1794,10 @@ struct Extension
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
-    return CastP<T>(this)->get_subtable<typename T::LookupSubTable> ().process (c, get_type ());
+    return get_subtable<typename T::LookupSubTable> ().process (c, get_type ());
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize_self (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
@@ -1806,6 +1806,14 @@ struct Extension
     }
   }
 
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    if (!sanitize_self (c)) return TRACE_RETURN (false);
+    unsigned int offset = get_offset ();
+    if (unlikely (!offset)) return TRACE_RETURN (true);
+    return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
+  }
+
   protected:
   union {
   USHORT		format;		/* Format identifier */
commit 7dddd4e72bc35be962d93dc1b76c7e26c63aaa6d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 17:04:55 2012 -0500

    [OTLayout] More templatizing Extension

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 38cf967..1a75880 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1248,12 +1248,7 @@ struct ChainContextPos : ChainContext {};
 
 struct ExtensionPos : Extension<ExtensionPos>
 {
-  inline const struct PosLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(PosLookupSubTable);
-    return StructAtOffset<PosLookupSubTable> (this, offset);
-  }
+  typedef struct PosLookupSubTable LookupSubTable;
 
   inline bool sanitize (hb_sanitize_context_t *c);
 };
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 7cf1e1b..9971875 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -880,12 +880,7 @@ struct ChainContextSubst : ChainContext {};
 
 struct ExtensionSubst : Extension<ExtensionSubst>
 {
-  inline const struct SubstLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(SubstLookupSubTable);
-    return StructAtOffset<SubstLookupSubTable> (this, offset);
-  }
+  typedef struct SubstLookupSubTable LookupSubTable;
 
   inline bool sanitize (hb_sanitize_context_t *c);
 
@@ -1390,7 +1385,7 @@ inline bool ExtensionSubst::is_reverse (void) const
 {
   unsigned int type = get_type ();
   if (unlikely (type == SubstLookupSubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
+    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 300ba7c..4ff8940 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -1783,10 +1783,18 @@ struct Extension
     }
   }
 
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    unsigned int offset = get_offset ();
+    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+  }
+
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
-    return CastP<T>(this)->get_subtable ().process (c, get_type ());
+    return CastP<T>(this)->get_subtable<typename T::LookupSubTable> ().process (c, get_type ());
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
commit 653eeb26450053b731b46346606931f5ae88db72
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 16:57:36 2012 -0500

    Make Extension a template

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 70be844..38cf967 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1246,7 +1246,7 @@ struct ContextPos : Context {};
 
 struct ChainContextPos : ChainContext {};
 
-struct ExtensionPos : Extension
+struct ExtensionPos : Extension<ExtensionPos>
 {
   inline const struct PosLookupSubTable& get_subtable (void) const
   {
@@ -1255,9 +1255,6 @@ struct ExtensionPos : Extension
     return StructAtOffset<PosLookupSubTable> (this, offset);
   }
 
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const;
-
   inline bool sanitize (hb_sanitize_context_t *c);
 };
 
@@ -1525,12 +1522,6 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t
 
 /* Out-of-class implementation for methods recursing */
 
-template <typename context_t>
-inline typename context_t::return_t ExtensionPos::process (context_t *c) const
-{
-  return get_subtable ().process (c, get_type ());
-}
-
 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
 {
   TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 7f23dec..7cf1e1b 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -878,7 +878,7 @@ struct ContextSubst : Context {};
 
 struct ChainContextSubst : ChainContext {};
 
-struct ExtensionSubst : Extension
+struct ExtensionSubst : Extension<ExtensionSubst>
 {
   inline const struct SubstLookupSubTable& get_subtable (void) const
   {
@@ -887,9 +887,6 @@ struct ExtensionSubst : Extension
     return StructAtOffset<SubstLookupSubTable> (this, offset);
   }
 
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const;
-
   inline bool sanitize (hb_sanitize_context_t *c);
 
   inline bool is_reverse (void) const;
@@ -1380,12 +1377,6 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE
 
 /* Out-of-class implementation for methods recursing */
 
-template <typename context_t>
-inline typename context_t::return_t ExtensionSubst::process (context_t *c) const
-{
-  return get_subtable ().process (c, get_type ());
-}
-
 inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
 {
   TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 30c43bc..300ba7c 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -1765,6 +1765,7 @@ struct ExtensionFormat1
   DEFINE_SIZE_STATIC (8);
 };
 
+template <typename T>
 struct Extension
 {
   inline unsigned int get_type (void) const
@@ -1782,6 +1783,12 @@ struct Extension
     }
   }
 
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
+  {
+    return CastP<T>(this)->get_subtable ().process (c, get_type ());
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
commit 08f1eede1bbc01ece2adf89847614a0670e50443
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 16:51:43 2012 -0500

    Minor

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 794e44f..70be844 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1242,24 +1242,9 @@ struct MarkMarkPos
 };
 
 
-struct ContextPos : Context
-{
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const
-  {
-    return Context::process (c);
-  }
-};
-
-struct ChainContextPos : ChainContext
-{
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const
-  {
-    return ChainContext::process (c);
-  }
-};
+struct ContextPos : Context {};
 
+struct ChainContextPos : ChainContext {};
 
 struct ExtensionPos : Extension
 {
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index fdf2cc2..7f23dec 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -874,24 +874,9 @@ struct LigatureSubst
 };
 
 
-struct ContextSubst : Context
-{
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const
-  {
-    return Context::process (c);
-  }
-};
-
-struct ChainContextSubst : ChainContext
-{
-  template <typename context_t>
-  inline typename context_t::return_t process (context_t *c) const
-  {
-    return ChainContext::process (c);
-  }
-};
+struct ContextSubst : Context {};
 
+struct ChainContextSubst : ChainContext {};
 
 struct ExtensionSubst : Extension
 {
commit 2c9d6485a1f89c11f84e720d3c7978dc11a5039a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 16:49:19 2012 -0500

    More tracing fixup

diff --git a/src/hb-private.hh b/src/hb-private.hh
index b5d417c..feab7ca 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -720,7 +720,7 @@ struct hb_auto_trace_t {
     if (plevel) --*plevel;
   }
 
-  inline ret_t &ret (ret_t &v, unsigned int line = 0)
+  inline ret_t ret (ret_t v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
@@ -751,8 +751,7 @@ struct hb_auto_trace_t<0, ret_t> {
 				   const char *message HB_UNUSED,
 				   ...) {}
 
-  template <typename T>
-  inline T ret (T v, unsigned int line = 0) { return v; }
+  inline ret_t ret (ret_t v, unsigned int line = 0) { return v; }
 };
 
 #define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
commit a1733db1c6ff40aae71fa142a12b1fea7b53dd37
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 16:40:04 2012 -0500

    [OTLayout] Start adding process() tracing

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 47f8f6b..30c43bc 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -38,6 +38,12 @@ namespace OT {
 
 
 
+#define TRACE_PROCESS(this) \
+	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
+
+
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
@@ -49,11 +55,13 @@ namespace OT {
 
 struct hb_closure_context_t
 {
+  inline const char *get_name (void) { return "CLOSURE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
   typedef void_t return_t;
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
-  inline return_t process (const T &obj) { obj.closure (this); return void_t (); }
-  static return_t default_return_value (void) { return return_t (); }
+  inline return_t process (const T &obj) { obj.closure (this); return VOID; }
+  static return_t default_return_value (void) { return VOID; }
   bool stop_sublookup_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
@@ -96,6 +104,8 @@ struct hb_closure_context_t
 
 struct hb_would_apply_context_t
 {
+  inline const char *get_name (void) { return "WOULD_APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
   typedef bool return_t;
   template <typename T>
   inline return_t process (const T &obj) { return obj.would_apply (this); }
@@ -117,7 +127,7 @@ struct hb_would_apply_context_t
 			      glyphs (glyphs_),
 			      len (len_),
 			      zero_context (zero_context_),
-			      debug_depth (0) {};
+			      debug_depth (0) {}
 };
 
 
@@ -133,10 +143,12 @@ struct hb_would_apply_context_t
 
 struct hb_collect_glyphs_context_t
 {
+  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
   typedef void_t return_t;
   template <typename T>
-  inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
-  static return_t default_return_value (void) { return return_t (); }
+  inline return_t process (const T &obj) { obj.collect_glyphs (this); return VOID; }
+  static return_t default_return_value (void) { return VOID; }
   bool stop_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
@@ -163,22 +175,27 @@ struct hb_collect_glyphs_context_t
 			      input  (glyphs_input  ? *glyphs_input  : *hb_set_get_empty ()),
 			      after  (glyphs_after  ? *glyphs_after  : *hb_set_get_empty ()),
 			      output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()),
-			      debug_depth (0) {};
+			      debug_depth (0) {}
 };
 
 
 
 struct hb_get_coverage_context_t
 {
+  inline const char *get_name (void) { return "GET_COVERAGE"; }
+  static const unsigned int max_debug_depth = 0;
   typedef const Coverage &return_t;
   template <typename T>
   inline return_t process (const T &obj) { return obj.get_coverage (); }
-  static const return_t default_return_value (void) { return Null(Coverage); }
+  static return_t default_return_value (void) { return Null(Coverage); }
   bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
   return_t recurse (unsigned int lookup_index)
   { return default_return_value (); }
 
-  hb_get_coverage_context_t (void) {}
+  hb_get_coverage_context_t (void) :
+			    debug_depth (0) {}
+
+  unsigned int debug_depth;
 };
 
 
@@ -194,6 +211,8 @@ struct hb_get_coverage_context_t
 
 struct hb_apply_context_t
 {
+  inline const char *get_name (void) { return "APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
   typedef bool return_t;
   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
@@ -205,6 +224,7 @@ struct hb_apply_context_t
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
+    /* TODO Reuse context. */
     hb_apply_context_t new_c (*this);
     new_c.nesting_level_left--;
     return recurse_func (&new_c, lookup_index);
@@ -219,9 +239,9 @@ struct hb_apply_context_t
   unsigned int nesting_level_left;
   unsigned int lookup_props;
   unsigned int property; /* propety of first glyph */
-  unsigned int debug_depth;
   const GDEF &gdef;
   bool has_glyph_classes;
+  unsigned int debug_depth;
 
 
   hb_apply_context_t (hb_font_t *font_,
@@ -232,9 +252,10 @@ struct hb_apply_context_t
 			lookup_mask (lookup_mask_),
 			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
-			lookup_props (0), property (0), debug_depth (0),
+			lookup_props (0), property (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
-			has_glyph_classes (gdef.has_glyph_classes ()) {}
+			has_glyph_classes (gdef.has_glyph_classes ()),
+			debug_depth (0) {}
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
@@ -1693,6 +1714,7 @@ struct ChainContext
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
     case 1: return c->process (u.format1);
     case 2: return c->process (u.format2);
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 34f2e15..b5d417c 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -63,7 +63,9 @@
 
 
 /* Void! */
-typedef struct {} void_t;
+struct _void_t;
+typedef const _void_t &void_t;
+#define VOID (* (const _void_t *) NULL)
 
 
 /* Basics */
@@ -718,7 +720,7 @@ struct hb_auto_trace_t {
     if (plevel) --*plevel;
   }
 
-  inline ret_t ret (ret_t v, unsigned int line = 0)
+  inline ret_t &ret (ret_t &v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
commit 73c18ae1b982a4e65086afe5177afa79e721e2c0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 15:34:11 2012 -0500

    Cleanup

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 19ed9f7..47f8f6b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -523,9 +523,7 @@ static inline bool match_input (hb_apply_context_t *c,
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
-    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
-     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
@@ -682,9 +680,7 @@ static inline bool match_backtrack (hb_apply_context_t *c,
 				    match_func_t match_func,
 				    const void *match_data)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
-    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
-     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
   if (skippy_iter.has_no_chance ())
@@ -709,9 +705,7 @@ static inline bool match_lookahead (hb_apply_context_t *c,
 				    const void *match_data,
 				    unsigned int offset)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
-    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
-     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
   if (skippy_iter.has_no_chance ())
@@ -760,9 +754,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
-    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
-     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   unsigned int end = c->buffer->len;
   if (unlikely (count == 0 || c->buffer->idx + count > end))
commit be218c688cbb037a99c8c64bb835f3c980040c0b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 15:32:14 2012 -0500

    Pass this object to trace macros

diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index 20d5e87..250504a 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -54,7 +54,7 @@ struct TTCHeader;
 typedef struct TableRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -103,7 +103,7 @@ typedef struct OffsetTable
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
   }
 
@@ -131,7 +131,7 @@ struct TTCHeaderVersion1
   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (table.sanitize (c, this));
   }
 
@@ -170,7 +170,7 @@ struct TTCHeader
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
@@ -232,7 +232,7 @@ struct OpenTypeFontFile
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
     switch (u.tag) {
     case CFFTag:	/* All the non-collection tags */
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 95603ad..541927b 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -166,7 +166,7 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 #endif
 
 
-#define TRACE_SANITIZE() \
+#define TRACE_SANITIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
 	(&c->debug_depth, "SANITIZE", this, HB_FUNC, \
 	 "");
@@ -342,7 +342,7 @@ struct Sanitizer
 #endif
 
 
-#define TRACE_SERIALIZE() \
+#define TRACE_SERIALIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
 	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
 	 "");
@@ -539,7 +539,7 @@ struct IntType
   inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
   inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
   protected:
@@ -564,7 +564,7 @@ typedef USHORT UFWORD;
 struct LONGDATETIME
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
   private:
@@ -628,7 +628,7 @@ struct FixedVersion
   inline uint32_t to_int (void) const { return (major << 16) + minor; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -668,7 +668,7 @@ struct GenericOffsetTo : OffsetType
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
@@ -677,7 +677,7 @@ struct GenericOffsetTo : OffsetType
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
@@ -741,7 +741,7 @@ struct GenericArrayOf
   inline bool serialize (hb_serialize_context_t *c,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
     if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
@@ -752,7 +752,7 @@ struct GenericArrayOf
 			 Supplier<Type> &items,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < items_len; i++)
       array[i] = items[i];
@@ -761,7 +761,7 @@ struct GenericArrayOf
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
@@ -776,7 +776,7 @@ struct GenericArrayOf
     return TRACE_RETURN (true);
   }
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
@@ -786,7 +786,7 @@ struct GenericArrayOf
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
@@ -797,7 +797,7 @@ struct GenericArrayOf
 
   private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
   }
 
@@ -839,12 +839,12 @@ struct OffsetListOf : OffsetArrayOf<Type>
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
@@ -867,7 +867,7 @@ struct HeadlessArrayOf
 			 Supplier<Type> &items,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
     if (unlikely (!items_len)) return TRACE_RETURN (true);
@@ -884,7 +884,7 @@ struct HeadlessArrayOf
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index b3b3a14..3a94512 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -52,7 +52,7 @@ struct head
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index fa3088c..2b89c4e 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -45,7 +45,7 @@ struct hhea
   static const hb_tag_t Tag	= HB_OT_TAG_hhea;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index e09996c..b94337d 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -53,7 +53,7 @@ struct hmtx
   static const hb_tag_t Tag	= HB_OT_TAG_hmtx;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return TRACE_RETURN (true);
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 54f5936..7a055c5 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -61,7 +61,7 @@ struct Record
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base));
   }
 
@@ -115,7 +115,7 @@ struct RecordListOf : RecordArrayOf<Type>
   { return this+RecordArrayOf<Type>::operator [](i).offset; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
   }
 };
@@ -129,7 +129,7 @@ struct RangeRecord
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -193,7 +193,7 @@ struct LangSys
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
@@ -231,7 +231,7 @@ struct Script
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
   }
 
@@ -261,7 +261,7 @@ struct Feature
   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c));
   }
 
@@ -318,7 +318,7 @@ struct Lookup
 			 uint32_t lookup_props,
 			 unsigned int num_subtables)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     lookupType.set (lookup_type);
     lookupFlag.set (lookup_props & 0xFFFF);
@@ -332,7 +332,7 @@ struct Lookup
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
@@ -377,7 +377,7 @@ struct CoverageFormat1
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     glyphArray.len.set (num_glyphs);
     if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
@@ -388,7 +388,7 @@ struct CoverageFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (glyphArray.sanitize (c));
   }
 
@@ -445,7 +445,7 @@ struct CoverageFormat2
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
 
     if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
@@ -474,7 +474,7 @@ struct CoverageFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
@@ -556,7 +556,7 @@ struct Coverage
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     unsigned int num_ranges = 1;
     for (unsigned int i = 1; i < num_glyphs; i++)
@@ -571,7 +571,7 @@ struct Coverage
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -682,7 +682,7 @@ struct ClassDefFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
   }
 
@@ -725,7 +725,7 @@ struct ClassDefFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
@@ -768,7 +768,7 @@ struct ClassDef
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -860,7 +860,7 @@ struct Device
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 900dedd..9120cb2 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -72,7 +72,7 @@ struct AttachList
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
   }
 
@@ -102,7 +102,7 @@ struct CaretValueFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -128,7 +128,7 @@ struct CaretValueFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -151,7 +151,7 @@ struct CaretValueFormat3
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
@@ -179,7 +179,7 @@ struct CaretValue
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -220,7 +220,7 @@ struct LigGlyph
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (carets.sanitize (c, this));
   }
 
@@ -254,7 +254,7 @@ struct LigCaretList
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
   }
 
@@ -276,7 +276,7 @@ struct MarkGlyphSetsFormat1
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this));
   }
 
@@ -300,7 +300,7 @@ struct MarkGlyphSets
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -365,7 +365,7 @@ struct GDEF
   { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (version.sanitize (c) &&
 			 likely (version.major == 1) &&
 			 glyphClassDef.sanitize (c, this) &&
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index e0c8ede..794e44f 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -172,12 +172,12 @@ struct ValueFormat : USHORT
   }
 
   inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   }
 
   inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     unsigned int len = get_len ();
 
     if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
@@ -195,7 +195,7 @@ struct ValueFormat : USHORT
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
   inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
 
     if (!has_device ()) return TRACE_RETURN (true);
 
@@ -220,7 +220,7 @@ struct AnchorFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -249,7 +249,7 @@ struct AnchorFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -277,7 +277,7 @@ struct AnchorFormat3
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
@@ -312,7 +312,7 @@ struct Anchor
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -342,7 +342,7 @@ struct AnchorMatrix
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
     unsigned int count = rows * cols;
@@ -367,7 +367,7 @@ struct MarkRecord
   friend struct MarkArray;
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
@@ -387,7 +387,7 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 		     const AnchorMatrix &anchors, unsigned int class_count,
 		     unsigned int glyph_pos) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
@@ -409,7 +409,7 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
@@ -426,7 +426,7 @@ struct SinglePosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -438,7 +438,7 @@ struct SinglePosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
   }
 
@@ -465,7 +465,7 @@ struct SinglePosFormat2
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -480,7 +480,7 @@ struct SinglePosFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
@@ -511,7 +511,7 @@ struct SinglePos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -551,7 +551,7 @@ struct PairSet
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
@@ -585,7 +585,7 @@ struct PairSet
   };
 
   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
 
@@ -612,7 +612,7 @@ struct PairPosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
@@ -625,7 +625,7 @@ struct PairPosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
@@ -666,7 +666,7 @@ struct PairPosFormat2
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
@@ -697,7 +697,7 @@ struct PairPosFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
        && classDef1.sanitize (c, this)
@@ -756,7 +756,7 @@ struct PairPos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -779,7 +779,7 @@ struct EntryExitRecord
   friend struct CursivePosFormat1;
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
@@ -805,7 +805,7 @@ struct CursivePosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
 
     /* We don't handle mark glyphs here. */
     if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
@@ -886,7 +886,7 @@ struct CursivePosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
@@ -914,7 +914,7 @@ struct CursivePos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -944,7 +944,7 @@ struct MarkBasePosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -968,7 +968,7 @@ struct MarkBasePosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
 			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
   }
@@ -1004,7 +1004,7 @@ struct MarkBasePos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1039,7 +1039,7 @@ struct MarkLigPosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1079,7 +1079,7 @@ struct MarkLigPosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
 			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
@@ -1116,7 +1116,7 @@ struct MarkLigPos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1146,7 +1146,7 @@ struct MarkMarkPosFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint);
     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1187,7 +1187,7 @@ struct MarkMarkPosFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
 			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
 			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
@@ -1226,7 +1226,7 @@ struct MarkMarkPos
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1317,7 +1317,7 @@ struct PosLookupSubTable
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.header.sub_format.sanitize (c))
       return TRACE_RETURN (false);
     switch (lookup_type) {
@@ -1423,7 +1423,7 @@ struct PosLookup : Lookup
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
     return TRACE_RETURN (list.sanitize (c, this, get_type ()));
@@ -1451,7 +1451,7 @@ struct GPOS : GSUBGPOS
   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
@@ -1548,7 +1548,7 @@ inline typename context_t::return_t ExtensionPos::process (context_t *c) const
 
 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
 {
-  TRACE_SANITIZE ();
+  TRACE_SANITIZE (this);
   if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
   unsigned int offset = get_offset ();
   if (unlikely (!offset)) return TRACE_RETURN (true);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 032abb0..fdf2cc2 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -39,7 +39,7 @@ struct SingleSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       hb_codepoint_t glyph_id = iter.get_glyph ();
@@ -65,13 +65,13 @@ struct SingleSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
@@ -89,7 +89,7 @@ struct SingleSubstFormat1
 			 unsigned int num_glyphs,
 			 int delta)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
@@ -97,7 +97,7 @@ struct SingleSubstFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
@@ -116,7 +116,7 @@ struct SingleSubstFormat2
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -140,13 +140,13 @@ struct SingleSubstFormat2
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
@@ -164,7 +164,7 @@ struct SingleSubstFormat2
 			 Supplier<GlyphID> &substitutes,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
@@ -172,7 +172,7 @@ struct SingleSubstFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
@@ -205,7 +205,7 @@ struct SingleSubst
 			 Supplier<GlyphID> &substitutes,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 2;
     int delta;
@@ -228,7 +228,7 @@ struct SingleSubst
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -250,7 +250,7 @@ struct Sequence
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->glyphs->add (substitute[i]);
@@ -265,7 +265,7 @@ struct Sequence
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
 
     unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
@@ -283,14 +283,14 @@ struct Sequence
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (substitute.sanitize (c));
   }
 
@@ -305,7 +305,7 @@ struct MultipleSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -328,13 +328,13 @@ struct MultipleSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
 
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
@@ -348,7 +348,7 @@ struct MultipleSubstFormat1
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
@@ -361,7 +361,7 @@ struct MultipleSubstFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
@@ -394,7 +394,7 @@ struct MultipleSubst
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
@@ -405,7 +405,7 @@ struct MultipleSubst
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -428,7 +428,7 @@ struct AlternateSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ())) {
@@ -459,13 +459,13 @@ struct AlternateSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage) (glyph_id);
@@ -497,7 +497,7 @@ struct AlternateSubstFormat1
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
@@ -510,7 +510,7 @@ struct AlternateSubstFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
@@ -543,7 +543,7 @@ struct AlternateSubst
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
@@ -554,7 +554,7 @@ struct AlternateSubst
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -574,7 +574,7 @@ struct Ligature
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = component.len;
     for (unsigned int i = 1; i < count; i++)
       if (!c->glyphs->has (component[i]))
@@ -592,7 +592,7 @@ struct Ligature
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     if (c->len != component.len)
       return TRACE_RETURN (false);
 
@@ -605,7 +605,7 @@ struct Ligature
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int count = component.len;
     if (unlikely (count < 1)) return TRACE_RETURN (false);
 
@@ -642,7 +642,7 @@ struct Ligature
 			 Supplier<GlyphID> &components, /* Starting from second */
 			 unsigned int num_components /* Including first component */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     ligGlyph = ligature;
     if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
@@ -651,7 +651,7 @@ struct Ligature
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
   }
 
@@ -669,7 +669,7 @@ struct LigatureSet
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
       (this+ligature[i]).closure (c);
@@ -684,7 +684,7 @@ struct LigatureSet
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
@@ -697,7 +697,7 @@ struct LigatureSet
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
@@ -714,7 +714,7 @@ struct LigatureSet
 			 unsigned int num_ligatures,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_ligatures; i++)
@@ -728,7 +728,7 @@ struct LigatureSet
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligature.sanitize (c, this));
   }
 
@@ -744,7 +744,7 @@ struct LigatureSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -768,7 +768,7 @@ struct LigatureSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int index = (this+coverage) (c->glyphs[0]);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -778,7 +778,7 @@ struct LigatureSubstFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage) (glyph_id);
@@ -796,7 +796,7 @@ struct LigatureSubstFormat1
 			 Supplier<unsigned int> &component_count_list,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_first_glyphs; i++)
@@ -811,7 +811,7 @@ struct LigatureSubstFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
@@ -846,7 +846,7 @@ struct LigatureSubst
 			 Supplier<unsigned int> &component_count_list,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
@@ -858,7 +858,7 @@ struct LigatureSubst
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -915,7 +915,7 @@ struct ReverseChainSingleSubstFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
@@ -967,13 +967,13 @@ struct ReverseChainSingleSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
       return TRACE_RETURN (false); /* No chaining to this type */
 
@@ -1000,7 +1000,7 @@ struct ReverseChainSingleSubstFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return TRACE_RETURN (false);
     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -1042,7 +1042,7 @@ struct ReverseChainSingleSubst
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1095,7 +1095,7 @@ struct SubstLookupSubTable
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.header.sub_format.sanitize (c))
       return TRACE_RETURN (false);
     switch (lookup_type) {
@@ -1176,7 +1176,7 @@ struct SubstLookup : Lookup
 
   inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     if (unlikely (!c->len))  return TRACE_RETURN (false);
     if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
       return TRACE_RETURN (process (c));
@@ -1251,7 +1251,7 @@ struct SubstLookup : Lookup
 			        Supplier<GlyphID> &substitutes,
 			        unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
   }
@@ -1263,7 +1263,7 @@ struct SubstLookup : Lookup
 				  unsigned int num_glyphs,
 				  Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
 									 substitute_glyphs_list));
@@ -1276,7 +1276,7 @@ struct SubstLookup : Lookup
 				   unsigned int num_glyphs,
 				   Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
 									  alternate_glyphs_list));
@@ -1291,7 +1291,7 @@ struct SubstLookup : Lookup
 				  Supplier<unsigned int> &component_count_list,
 				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
 									 ligatures_list, component_count_list, component_list));
@@ -1299,7 +1299,7 @@ struct SubstLookup : Lookup
 
   inline bool sanitize (hb_sanitize_context_t *c)
   {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
     OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
     if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
@@ -1362,7 +1362,7 @@ struct GSUB : GSUBGPOS
 #endif
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
     OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
@@ -1403,7 +1403,7 @@ inline typename context_t::return_t ExtensionSubst::process (context_t *c) const
 
 inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
 {
-  TRACE_SANITIZE ();
+  TRACE_SANITIZE (this);
   if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
   unsigned int offset = get_offset ();
   if (unlikely (!offset)) return TRACE_RETURN (true);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index bc4f5be..19ed9f7 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -42,7 +42,7 @@ namespace OT {
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
-#define TRACE_CLOSURE() \
+#define TRACE_CLOSURE(this) \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE, void_t> trace \
 	(&c->debug_depth, "CLOSURE", this, HB_FUNC, \
 	 "");
@@ -89,7 +89,7 @@ struct hb_closure_context_t
 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 #endif
 
-#define TRACE_WOULD_APPLY() \
+#define TRACE_WOULD_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
 	(&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, \
 	 "%d glyphs", c->len);
@@ -126,7 +126,7 @@ struct hb_would_apply_context_t
 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
 #endif
 
-#define TRACE_COLLECT_GLYPHS() \
+#define TRACE_COLLECT_GLYPHS(this) \
 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, void_t> trace \
 	(&c->debug_depth, "COLLECT_GLYPHS", this, HB_FUNC, \
 	 "");
@@ -187,7 +187,7 @@ struct hb_get_coverage_context_t
 #define HB_DEBUG_APPLY (HB_DEBUG+0)
 #endif
 
-#define TRACE_APPLY() \
+#define TRACE_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
 	(&c->debug_depth, "APPLY", this, HB_FUNC, \
 	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
@@ -734,7 +734,7 @@ static inline bool match_lookahead (hb_apply_context_t *c,
 struct LookupRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -877,7 +877,7 @@ struct Rule
 {
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     context_closure_lookup (c,
 			    inputCount, input,
@@ -887,21 +887,21 @@ struct Rule
 
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return inputCount.sanitize (c)
 	&& lookupCount.sanitize (c)
 	&& c->check_range (input,
@@ -926,7 +926,7 @@ struct RuleSet
 {
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
@@ -934,7 +934,7 @@ struct RuleSet
 
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
@@ -946,7 +946,7 @@ struct RuleSet
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
@@ -957,7 +957,7 @@ struct RuleSet
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
@@ -974,7 +974,7 @@ struct ContextFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
@@ -993,7 +993,7 @@ struct ContextFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
@@ -1010,7 +1010,7 @@ struct ContextFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED))
       return TRACE_RETURN (false);
@@ -1024,7 +1024,7 @@ struct ContextFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
@@ -1045,7 +1045,7 @@ struct ContextFormat2
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
@@ -1066,7 +1066,7 @@ struct ContextFormat2
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const ClassDef &class_def = this+classDef;
     unsigned int index = class_def (c->glyphs[0]);
@@ -1085,7 +1085,7 @@ struct ContextFormat2
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1100,7 +1100,7 @@ struct ContextFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
@@ -1124,7 +1124,7 @@ struct ContextFormat3
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage[0]).intersects (c->glyphs))
       return;
 
@@ -1141,7 +1141,7 @@ struct ContextFormat3
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
@@ -1158,7 +1158,7 @@ struct ContextFormat3
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1171,7 +1171,7 @@ struct ContextFormat3
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     unsigned int count = glyphCount;
     if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
@@ -1209,7 +1209,7 @@ struct Context
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1316,7 +1316,7 @@ struct ChainRule
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -1330,7 +1330,7 @@ struct ChainRule
 
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -1343,7 +1343,7 @@ struct ChainRule
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -1355,7 +1355,7 @@ struct ChainRule
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     if (!input.sanitize (c)) return TRACE_RETURN (false);
@@ -1387,7 +1387,7 @@ struct ChainRuleSet
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
@@ -1395,7 +1395,7 @@ struct ChainRuleSet
 
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).would_apply (c, lookup_context))
@@ -1406,7 +1406,7 @@ struct ChainRuleSet
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).apply (c, lookup_context))
@@ -1416,7 +1416,7 @@ struct ChainRuleSet
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
@@ -1432,7 +1432,7 @@ struct ChainContextFormat1
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
@@ -1450,7 +1450,7 @@ struct ChainContextFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
@@ -1467,7 +1467,7 @@ struct ChainContextFormat1
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1480,7 +1480,7 @@ struct ChainContextFormat1
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
@@ -1500,7 +1500,7 @@ struct ChainContextFormat2
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
@@ -1525,7 +1525,7 @@ struct ChainContextFormat2
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const ClassDef &input_class_def = this+inputClassDef;
 
@@ -1545,7 +1545,7 @@ struct ChainContextFormat2
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
@@ -1565,7 +1565,7 @@ struct ChainContextFormat2
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
 			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
 			 ruleSet.sanitize (c, this));
@@ -1599,7 +1599,7 @@ struct ChainContextFormat3
 {
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
@@ -1621,7 +1621,7 @@ struct ChainContextFormat3
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
@@ -1645,7 +1645,7 @@ struct ChainContextFormat3
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
@@ -1665,7 +1665,7 @@ struct ChainContextFormat3
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
@@ -1710,7 +1710,7 @@ struct ChainContext
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1736,7 +1736,7 @@ struct ExtensionFormat1
   inline unsigned int get_offset (void) const { return extensionOffset; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -1769,7 +1769,7 @@ struct Extension
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -1826,7 +1826,7 @@ struct GSUBGPOS
   { return (this+lookupList)[i]; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
 			 scriptList.sanitize (c, this) &&
 			 featureList.sanitize (c, this) &&
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index ef2b9f1..0ce3ebc 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -48,7 +48,7 @@ struct maxp
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
 			 likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000)));
   }
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index ab7a692..75a1b94 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -57,7 +57,7 @@ struct NameRecord
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
     return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
@@ -99,7 +99,7 @@ struct name
   }
 
   inline bool sanitize_records (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
     for (unsigned int i = 0; i < _count; i++)
@@ -108,7 +108,7 @@ struct name
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
 			 likely (format == 0 || format == 1) &&
 			 c->check_array (nameRecord, nameRecord[0].static_size, count) &&
commit 902cc8aca0b3ff25eeee50b3a84d729e31731ef3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 15:06:59 2012 -0500

    [OTLayout] Start unbreaking tracing

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 15198b1..95603ad 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -167,7 +167,9 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 
 
 #define TRACE_SANITIZE() \
-	hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
+	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+	(&c->debug_depth, "SANITIZE", this, HB_FUNC, \
+	 "");
 
 
 struct hb_sanitize_context_t
@@ -206,10 +208,11 @@ struct hb_sanitize_context_t
   {
     const char *p = (const char *) base;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "check_range [%p..%p] (%d bytes) in [%p..%p]",
-					      p, p + len, len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "check_range [%p..%p] (%d bytes) in [%p..%p]",
+       p, p + len, len,
+       this->start, this->end);
 
     return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
   }
@@ -219,10 +222,11 @@ struct hb_sanitize_context_t
     const char *p = (const char *) base;
     bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
-					      p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
+       p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
+       this->start, this->end);
 
     return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
   }
@@ -238,11 +242,12 @@ struct hb_sanitize_context_t
     const char *p = (const char *) base;
     this->edit_count++;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-					      this->edit_count,
-					      p, p + len, len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end);
 
     return TRACE_RETURN (this->writable);
   }
@@ -338,7 +343,9 @@ struct Sanitizer
 
 
 #define TRACE_SERIALIZE() \
-	hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE", c, HB_FUNC, "");
+	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
+	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
+	 "");
 
 
 struct hb_serialize_context_t
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 608ed5a..bc4f5be 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -37,12 +37,15 @@
 namespace OT {
 
 
+
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
 #define TRACE_CLOSURE() \
-	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
+	hb_auto_trace_t<HB_DEBUG_CLOSURE, void_t> trace \
+	(&c->debug_depth, "CLOSURE", this, HB_FUNC, \
+	 "");
 
 struct hb_closure_context_t
 {
@@ -87,8 +90,9 @@ struct hb_closure_context_t
 #endif
 
 #define TRACE_WOULD_APPLY() \
-	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "%d glyphs", c->len);
-
+	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
+	(&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, \
+	 "%d glyphs", c->len);
 
 struct hb_would_apply_context_t
 {
@@ -123,8 +127,9 @@ struct hb_would_apply_context_t
 #endif
 
 #define TRACE_COLLECT_GLYPHS() \
-	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS> trace (&c->debug_depth, "COLLECT_GLYPHS", this, HB_FUNC, "");
-
+	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, void_t> trace \
+	(&c->debug_depth, "COLLECT_GLYPHS", this, HB_FUNC, \
+	 "");
 
 struct hb_collect_glyphs_context_t
 {
@@ -183,8 +188,9 @@ struct hb_get_coverage_context_t
 #endif
 
 #define TRACE_APPLY() \
-	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
-
+	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+	(&c->debug_depth, "APPLY", this, HB_FUNC, \
+	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
 struct hb_apply_context_t
 {
@@ -517,7 +523,9 @@ static inline bool match_input (hb_apply_context_t *c,
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
+    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
+     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
@@ -674,7 +682,9 @@ static inline bool match_backtrack (hb_apply_context_t *c,
 				    match_func_t match_func,
 				    const void *match_data)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
+    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
+     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
   hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
   if (skippy_iter.has_no_chance ())
@@ -699,7 +709,9 @@ static inline bool match_lookahead (hb_apply_context_t *c,
 				    const void *match_data,
 				    unsigned int offset)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
+    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
+     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
   if (skippy_iter.has_no_chance ())
@@ -748,7 +760,10 @@ static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
+    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
+     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+
   unsigned int end = c->buffer->len;
   if (unlikely (count == 0 || c->buffer->idx + count > end))
     return TRACE_RETURN (false);
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 16c3562..34f2e15 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -682,7 +682,18 @@ struct hb_printer_t<void_t> {
  * Trace
  */
 
-template <int max_level>
+template <typename T>
+static inline void _hb_warn_no_return (bool returned)
+{
+  if (unlikely (!returned)) {
+    fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.\n");
+  }
+}
+template <>
+inline void _hb_warn_no_return<void_t> (bool returned)
+{}
+
+template <int max_level, typename ret_t>
 struct hb_auto_trace_t {
   explicit inline hb_auto_trace_t (unsigned int *plevel_,
 				   const char *what_,
@@ -700,24 +711,23 @@ struct hb_auto_trace_t {
   }
   inline ~hb_auto_trace_t (void)
   {
-    if (unlikely (!returned)) {
-      fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.  Level was %d.\n", plevel ? *plevel : -1);
+    _hb_warn_no_return<ret_t> (returned);
+    if (!returned) {
       _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
-      return;
     }
-
     if (plevel) --*plevel;
   }
 
-  template <typename T>
-  inline T ret (T v, unsigned int line = 0)
+  inline ret_t ret (ret_t v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
       return v;
     }
 
-    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s (line %d)", hb_printer_t<bool>().print (v), line);
+    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
+			      "return %s (line %d)",
+			      hb_printer_t<ret_t>().print (v), line);
     if (plevel) --*plevel;
     plevel = NULL;
     returned = true;
@@ -730,8 +740,8 @@ struct hb_auto_trace_t {
   const void *obj;
   bool returned;
 };
-template <> /* Optimize when tracing is disabled */
-struct hb_auto_trace_t<0> {
+template <typename ret_t> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0, ret_t> {
   explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
 				   const char *what HB_UNUSED,
 				   const void *obj HB_UNUSED,
commit dabe698fcbeb02911128b17aa8e3b2d864795960
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 14:21:35 2012 -0500

    Minor

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index b585e18..15198b1 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -37,11 +37,6 @@
 namespace OT {
 
 
-/*
- * Void!
- */
-typedef struct {} void_t;
-
 
 /*
  * Casts
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 55ea9ca..608ed5a 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -50,7 +50,7 @@ struct hb_closure_context_t
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t process (const T &obj) { obj.closure (this); return void_t (); }
-  static const return_t default_return_value (void) { return return_t (); }
+  static return_t default_return_value (void) { return return_t (); }
   bool stop_sublookup_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
@@ -82,7 +82,6 @@ struct hb_closure_context_t
 
 
 
-/* TODO Add TRACE_RETURN annotation to gsub. */
 #ifndef HB_DEBUG_WOULD_APPLY
 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 #endif
@@ -119,7 +118,6 @@ struct hb_would_apply_context_t
 
 
 
-/* TODO Add TRACE_RETURN annotation to gsub. */
 #ifndef HB_DEBUG_COLLECT_GLYPHS
 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
 #endif
@@ -133,7 +131,7 @@ struct hb_collect_glyphs_context_t
   typedef void_t return_t;
   template <typename T>
   inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
-  static const return_t default_return_value (void) { return return_t (); }
+  static return_t default_return_value (void) { return return_t (); }
   bool stop_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
@@ -170,7 +168,7 @@ struct hb_get_coverage_context_t
   typedef const Coverage &return_t;
   template <typename T>
   inline return_t process (const T &obj) { return obj.get_coverage (); }
-  static return_t default_return_value (void) { return Null(Coverage); }
+  static const return_t default_return_value (void) { return Null(Coverage); }
   bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
   return_t recurse (unsigned int lookup_index)
   { return default_return_value (); }
@@ -194,7 +192,7 @@ struct hb_apply_context_t
   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t process (const T &obj) { return obj.apply (this); }
-  static const return_t default_return_value (void) { return false; }
+  static return_t default_return_value (void) { return false; }
   bool stop_sublookup_iteration (const return_t r) const { return r; }
   return_t recurse (unsigned int lookup_index)
   {
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 5c53591..16c3562 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -62,6 +62,10 @@
 #endif
 
 
+/* Void! */
+typedef struct {} void_t;
+
+
 /* Basics */
 
 
@@ -657,6 +661,24 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
 
 
 /*
+ * Printer
+ */
+
+template <typename T>
+struct hb_printer_t {};
+
+template <>
+struct hb_printer_t<bool> {
+  const char *print (bool v) { return v ? "true" : "false"; }
+};
+
+template <>
+struct hb_printer_t<void_t> {
+  const char *print (void_t v) { return ""; }
+};
+
+
+/*
  * Trace
  */
 
@@ -687,14 +709,15 @@ struct hb_auto_trace_t {
     if (plevel) --*plevel;
   }
 
-  inline bool ret (bool v, unsigned int line = 0)
+  template <typename T>
+  inline T ret (T v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
       return v;
     }
 
-    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s (line %d)", v ? "true" : "false", line);
+    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s (line %d)", hb_printer_t<bool>().print (v), line);
     if (plevel) --*plevel;
     plevel = NULL;
     returned = true;
commit c779d82b2fc801eec0d349a106c0e860448fcf4e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 14:07:24 2012 -0500

    Fix warnings

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index aebc73f..e0c8ede 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1389,8 +1389,6 @@ struct PosLookup : Lookup
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
       return false;
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index f82663a..032abb0 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -609,9 +609,9 @@ struct Ligature
     unsigned int count = component.len;
     if (unlikely (count < 1)) return TRACE_RETURN (false);
 
-    unsigned int end_offset;
-    bool is_mark_ligature;
-    unsigned int total_component_count;
+    unsigned int end_offset = 0;
+    bool is_mark_ligature = false;
+    unsigned int total_component_count = 0;
 
     if (likely (!match_input (c, count,
 			      &component[1],
@@ -1184,8 +1184,6 @@ struct SubstLookup : Lookup
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
       return false;
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 16476e9..55ea9ca 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -1282,7 +1282,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
-  unsigned int lookahead_offset;
+  unsigned int lookahead_offset = 0;
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data[1],
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 42c0259..5c53591 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -703,9 +703,9 @@ struct hb_auto_trace_t {
 
   private:
   unsigned int *plevel;
-  bool returned;
   const char *what;
   const void *obj;
+  bool returned;
 };
 template <> /* Optimize when tracing is disabled */
 struct hb_auto_trace_t<0> {
commit 81822528efc63d867cb2343a8ff7af64fac1c70d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Nov 23 13:27:16 2012 -0500

    Minor

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 2e03dc3..b585e18 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -38,6 +38,12 @@ namespace OT {
 
 
 /*
+ * Void!
+ */
+typedef struct {} void_t;
+
+
+/*
  * Casts
  */
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 820030b..16476e9 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -37,9 +37,6 @@
 namespace OT {
 
 
-typedef struct {} void_t; /* To be used as return value when void is meant. */
-
-
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
commit 1d67ef980f35ae30d4f8975f65ee07b8cc5deeea
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Nov 22 16:47:53 2012 -0500

    Move code around

diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index a311cc9..820030b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -96,6 +96,13 @@ struct hb_closure_context_t
 
 struct hb_would_apply_context_t
 {
+  typedef bool return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.would_apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return r; }
+  return_t recurse (unsigned int lookup_index) { return true; }
+
   hb_face_t *face;
   const hb_codepoint_t *glyphs;
   unsigned int len;
@@ -111,13 +118,6 @@ struct hb_would_apply_context_t
 			      len (len_),
 			      zero_context (zero_context_),
 			      debug_depth (0) {};
-
-  typedef bool return_t;
-  template <typename T>
-  inline return_t process (const T &obj) { return obj.would_apply (this); }
-  static return_t default_return_value (void) { return false; }
-  bool stop_sublookup_iteration (const return_t r) const { return r; }
-  return_t recurse (unsigned int lookup_index) { return true; }
 };
 
 
@@ -133,6 +133,19 @@ struct hb_would_apply_context_t
 
 struct hb_collect_glyphs_context_t
 {
+  typedef void_t return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
+  static const return_t default_return_value (void) { return return_t (); }
+  bool stop_iteration (const return_t r) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+#if 0
+    /* XXX */
+#endif
+    return default_return_value ();
+  }
+
   hb_face_t *face;
   hb_set_t &before;
   hb_set_t &input;
@@ -151,27 +164,12 @@ struct hb_collect_glyphs_context_t
 			      after  (glyphs_after  ? *glyphs_after  : *hb_set_get_empty ()),
 			      output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()),
 			      debug_depth (0) {};
-
-  typedef void_t return_t;
-  template <typename T>
-  inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
-  static const return_t default_return_value (void) { return return_t (); }
-  bool stop_iteration (const return_t r) const { return false; }
-  return_t recurse (unsigned int lookup_index)
-  {
-#if 0
-    /* XXX */
-#endif
-    return default_return_value ();
-  }
 };
 
 
 
 struct hb_get_coverage_context_t
 {
-  hb_get_coverage_context_t (void) {}
-
   typedef const Coverage &return_t;
   template <typename T>
   inline return_t process (const T &obj) { return obj.get_coverage (); }
@@ -179,6 +177,8 @@ struct hb_get_coverage_context_t
   bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
   return_t recurse (unsigned int lookup_index)
   { return default_return_value (); }
+
+  hb_get_coverage_context_t (void) {}
 };
 
 
commit ec35a72a44301934b8f123ab2833f59d8c875a09
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Nov 22 16:05:59 2012 -0500

    [OTLayout] Port apply() operator to process() template

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index d578760..aebc73f 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -510,16 +510,6 @@ struct SinglePos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -765,16 +755,6 @@ struct PairPos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -933,15 +913,6 @@ struct CursivePos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1032,15 +1003,6 @@ struct MarkBasePos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1153,15 +1115,6 @@ struct MarkLigPos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1272,15 +1225,6 @@ struct MarkMarkPos
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1298,23 +1242,21 @@ struct MarkMarkPos
 };
 
 
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-
 struct ContextPos : Context
 {
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, position_lookup));
+    return Context::process (c);
   }
 };
 
 struct ChainContextPos : ChainContext
 {
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, position_lookup));
+    return ChainContext::process (c);
   }
 };
 
@@ -1331,8 +1273,6 @@ struct ExtensionPos : Extension
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const;
 
-  inline bool apply (hb_apply_context_t *c) const;
-
   inline bool sanitize (hb_sanitize_context_t *c);
 };
 
@@ -1376,23 +1316,6 @@ struct PosLookupSubTable
     }
   }
 
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
-  {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.apply (c));
-    case Pair:			return TRACE_RETURN (u.pair.apply (c));
-    case Cursive:		return TRACE_RETURN (u.cursive.apply (c));
-    case MarkBase:		return TRACE_RETURN (u.markBase.apply (c));
-    case MarkLig:		return TRACE_RETURN (u.markLig.apply (c));
-    case MarkMark:		return TRACE_RETURN (u.markMark.apply (c));
-    case Context:		return TRACE_RETURN (u.context.apply (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:		return TRACE_RETURN (u.extension.apply (c));
-    default:			return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
     TRACE_SANITIZE ();
     if (!u.header.sub_format.sanitize (c))
@@ -1471,14 +1394,11 @@ struct PosLookup : Lookup
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
       return false;
 
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).apply (c, lookup_type))
-	return true;
-
-    return false;
+    return process (c);
   }
 
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+
   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     bool ret = false;
@@ -1486,6 +1406,7 @@ struct PosLookup : Lookup
     if (unlikely (!c->buffer->len || !c->lookup_mask))
       return false;
 
+    c->set_recurse_func (apply_recurse_func);
     c->set_lookup (*this);
 
     c->buffer->idx = 0;
@@ -1627,12 +1548,6 @@ inline typename context_t::return_t ExtensionPos::process (context_t *c) const
   return get_subtable ().process (c, get_type ());
 }
 
-inline bool ExtensionPos::apply (hb_apply_context_t *c) const
-{
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
 {
   TRACE_SANITIZE ();
@@ -1642,18 +1557,12 @@ inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
   return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
 }
 
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
-
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+  c->set_lookup (l);
+  return l.apply_once (c);
 }
 
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 3d43966..f82663a 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -200,16 +200,6 @@ struct SingleSubst
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<GlyphID> &substitutes,
@@ -398,15 +388,6 @@ struct MultipleSubst
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &substitute_len_list,
@@ -556,15 +537,6 @@ struct AlternateSubst
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &alternate_len_list,
@@ -866,15 +838,6 @@ struct LigatureSubst
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &first_glyphs,
 			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
@@ -911,8 +874,6 @@ struct LigatureSubst
 };
 
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-
 struct ContextSubst : Context
 {
   template <typename context_t>
@@ -920,12 +881,6 @@ struct ContextSubst : Context
   {
     return Context::process (c);
   }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, substitute_lookup));
-  }
 };
 
 struct ChainContextSubst : ChainContext
@@ -935,12 +890,6 @@ struct ChainContextSubst : ChainContext
   {
     return ChainContext::process (c);
   }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
-  }
 };
 
 
@@ -956,8 +905,6 @@ struct ExtensionSubst : Extension
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const;
 
-  inline bool apply (hb_apply_context_t *c) const;
-
   inline bool sanitize (hb_sanitize_context_t *c);
 
   inline bool is_reverse (void) const;
@@ -1094,15 +1041,6 @@ struct ReverseChainSingleSubst
     }
   }
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1156,22 +1094,6 @@ struct SubstLookupSubTable
     }
   }
 
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
-  {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.apply (c));
-    case Multiple:		return TRACE_RETURN (u.multiple.apply (c));
-    case Alternate:		return TRACE_RETURN (u.alternate.apply (c));
-    case Ligature:		return TRACE_RETURN (u.ligature.apply (c));
-    case Context:		return TRACE_RETURN (u.context.apply (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:		return TRACE_RETURN (u.extension.apply (c));
-    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
-    default:			return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
     TRACE_SANITIZE ();
     if (!u.header.sub_format.sanitize (c))
@@ -1267,14 +1189,11 @@ struct SubstLookup : Lookup
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
       return false;
 
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).apply (c, lookup_type))
-	return true;
-
-    return false;
+    return process (c);
   }
 
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+
   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     bool ret = false;
@@ -1282,6 +1201,7 @@ struct SubstLookup : Lookup
     if (unlikely (!c->buffer->len || !c->lookup_mask))
       return false;
 
+    c->set_recurse_func (apply_recurse_func);
     c->set_lookup (*this);
 
     if (likely (!is_reverse ()))
@@ -1423,7 +1343,7 @@ struct GSUB : GSUBGPOS
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  static void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+  static inline void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
   {
     const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
     const SubstLookup &l = gsub.get_lookup (lookup_index);
@@ -1483,12 +1403,6 @@ inline typename context_t::return_t ExtensionSubst::process (context_t *c) const
   return get_subtable ().process (c, get_type ());
 }
 
-inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
-{
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
 inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
 {
   TRACE_SANITIZE ();
@@ -1506,18 +1420,12 @@ inline bool ExtensionSubst::is_reverse (void) const
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
-
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+  c->set_lookup (l);
+  return l.apply_once (c);
 }
 
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index d1381dd..a311cc9 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -193,11 +193,28 @@ struct hb_get_coverage_context_t
 
 struct hb_apply_context_t
 {
+  typedef bool return_t;
+  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.apply (this); }
+  static const return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return r; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    hb_apply_context_t new_c (*this);
+    new_c.nesting_level_left--;
+    return recurse_func (&new_c, lookup_index);
+  }
+
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
   hb_direction_t direction;
   hb_mask_t lookup_mask;
+  recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int lookup_props;
   unsigned int property; /* propety of first glyph */
@@ -212,18 +229,15 @@ struct hb_apply_context_t
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
+			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
 			lookup_props (0), property (0), debug_depth (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			has_glyph_classes (gdef.has_glyph_classes ()) {}
 
-  void set_lookup_props (unsigned int lookup_props_) {
-    lookup_props = lookup_props_;
-  }
-
-  void set_lookup (const Lookup &l) {
-    lookup_props = l.get_props ();
-  }
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+  void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+  void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
 
   struct mark_skipping_forward_iterator_t
   {
@@ -430,7 +444,6 @@ struct hb_apply_context_t
 
 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
-typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
 
 struct ContextClosureFuncs
 {
@@ -439,7 +452,6 @@ struct ContextClosureFuncs
 struct ContextApplyFuncs
 {
   match_func_t match;
-  apply_lookup_func_t apply;
 };
 
 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
@@ -739,8 +751,7 @@ static inline void closure_lookup (hb_closure_context_t *c,
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 unsigned int lookupCount,
-				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-				 apply_lookup_func_t apply_func)
+				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
   unsigned int end = c->buffer->len;
@@ -771,7 +782,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
       unsigned int old_pos = c->buffer->idx;
 
       /* Apply a lookup */
-      bool done = apply_func (c, lookupRecord->lookupListIndex);
+      bool done = c->recurse (lookupRecord->lookupListIndex);
 
       lookupRecord++;
       lookupCount--;
@@ -849,8 +860,7 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
 		      lookup_context.funcs.match, lookup_context.match_data)
       && apply_lookup (c,
 		       inputCount,
-		       lookupCount, lookupRecord,
-		       lookup_context.funcs.apply);
+		       lookupCount, lookupRecord);
 }
 
 struct Rule
@@ -977,7 +987,7 @@ struct ContextFormat1
 
     const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
-      {match_glyph, NULL},
+      {match_glyph},
       NULL
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
@@ -988,7 +998,7 @@ struct ContextFormat1
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
@@ -997,7 +1007,7 @@ struct ContextFormat1
 
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       NULL
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
@@ -1052,7 +1062,7 @@ struct ContextFormat2
     unsigned int index = class_def (c->glyphs[0]);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_class, NULL},
+      {match_class},
       &class_def
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
@@ -1063,7 +1073,7 @@ struct ContextFormat2
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
@@ -1073,7 +1083,7 @@ struct ContextFormat2
     index = class_def (c->buffer->cur().codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       &class_def
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
@@ -1125,7 +1135,7 @@ struct ContextFormat3
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
-      {match_coverage, NULL},
+      {match_coverage},
       this
     };
     return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
@@ -1136,7 +1146,7 @@ struct ContextFormat3
     return this+coverage[0];
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
@@ -1144,7 +1154,7 @@ struct ContextFormat3
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       this
     };
     return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
@@ -1188,17 +1198,6 @@ struct Context
     }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
@@ -1300,8 +1299,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 			  lookahead_offset)
       && apply_lookup (c,
 		       inputCount,
-		       lookupCount, lookupRecord,
-		       lookup_context.funcs.apply);
+		       lookupCount, lookupRecord);
 }
 
 struct ChainRule
@@ -1446,7 +1444,7 @@ struct ChainContextFormat1
 
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph, NULL},
+      {match_glyph},
       {NULL, NULL, NULL}
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
@@ -1457,7 +1455,7 @@ struct ChainContextFormat1
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
@@ -1465,7 +1463,7 @@ struct ChainContextFormat1
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       {NULL, NULL, NULL}
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
@@ -1524,7 +1522,7 @@ struct ChainContextFormat2
     unsigned int index = input_class_def (c->glyphs[0]);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class, NULL},
+      {match_class},
       {NULL, &input_class_def, NULL}
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
@@ -1535,7 +1533,7 @@ struct ChainContextFormat2
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
@@ -1548,7 +1546,7 @@ struct ChainContextFormat2
     index = input_class_def (c->buffer->cur().codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -1619,7 +1617,7 @@ struct ChainContextFormat3
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage, NULL},
+      {match_coverage},
       {this, this, this}
     };
     return TRACE_RETURN (chain_context_would_apply_lookup (c,
@@ -1635,7 +1633,7 @@ struct ChainContextFormat3
     return this+input[0];
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -1646,7 +1644,7 @@ struct ChainContextFormat3
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       {this, this, this}
     };
     return TRACE_RETURN (chain_context_apply_lookup (c,
@@ -1701,17 +1699,6 @@ struct ChainContext
     }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 9185584..7af75c0 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -412,7 +412,7 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
 
-  OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
+//  OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
 
   switch (table_tag) {
     case HB_OT_TAG_GSUB:
commit 2005fa5340fc528c32dc2af945ad2431964a47d2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Nov 22 14:38:10 2012 -0500

    [OTLayout] Port would_apply() and get_coverage() to process() templates

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index afe18b5..d578760 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -212,9 +212,6 @@ struct ValueFormat : USHORT
 
 struct AnchorFormat1
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
@@ -237,9 +234,6 @@ struct AnchorFormat1
 
 struct AnchorFormat2
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
   {
@@ -270,9 +264,6 @@ struct AnchorFormat2
 
 struct AnchorFormat3
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
@@ -428,10 +419,6 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 
 struct SinglePosFormat1
 {
-  friend struct SinglePos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -471,10 +458,6 @@ struct SinglePosFormat1
 
 struct SinglePosFormat2
 {
-  friend struct SinglePos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -517,16 +500,13 @@ struct SinglePosFormat2
 
 struct SinglePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    case 2: return c->process (u.format2);
+    default:return c->default_return_value ();
     }
   }
 
@@ -635,10 +615,6 @@ struct PairSet
 
 struct PairPosFormat1
 {
-  friend struct PairPos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -693,10 +669,6 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
-  friend struct PairPos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -783,16 +755,13 @@ struct PairPosFormat2
 
 struct PairPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    case 2: return c->process (u.format2);
+    default:return c->default_return_value ();
     }
   }
 
@@ -849,10 +818,6 @@ struct EntryExitRecord
 
 struct CursivePosFormat1
 {
-  friend struct CursivePos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
@@ -959,15 +924,12 @@ struct CursivePosFormat1
 
 struct CursivePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value ();
     }
   }
 
@@ -1004,10 +966,6 @@ typedef AnchorMatrix BaseArray;		/* base-major--
 
 struct MarkBasePosFormat1
 {
-  friend struct MarkBasePos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
@@ -1065,15 +1023,12 @@ struct MarkBasePosFormat1
 
 struct MarkBasePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value ();
     }
   }
 
@@ -1115,10 +1070,6 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
 
 struct MarkLigPosFormat1
 {
-  friend struct MarkLigPos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
@@ -1193,15 +1144,12 @@ struct MarkLigPosFormat1
 
 struct MarkLigPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value ();
     }
   }
 
@@ -1238,10 +1186,6 @@ typedef AnchorMatrix Mark2Array;	/* mark2-major--
 
 struct MarkMarkPosFormat1
 {
-  friend struct MarkMarkPos;
-
-  private:
-
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
@@ -1319,15 +1263,12 @@ struct MarkMarkPosFormat1
 
 struct MarkMarkPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value ();
     }
   }
 
@@ -1361,9 +1302,6 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
 
 struct ContextPos : Context
 {
-  friend struct PosLookupSubTable;
-
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -1373,9 +1311,6 @@ struct ContextPos : Context
 
 struct ChainContextPos : ChainContext
 {
-  friend struct PosLookupSubTable;
-
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -1386,9 +1321,6 @@ struct ChainContextPos : ChainContext
 
 struct ExtensionPos : Extension
 {
-  friend struct PosLookupSubTable;
-
-  private:
   inline const struct PosLookupSubTable& get_subtable (void) const
   {
     unsigned int offset = get_offset ();
@@ -1396,7 +1328,8 @@ struct ExtensionPos : Extension
     return StructAtOffset<PosLookupSubTable> (this, offset);
   }
 
-  inline const Coverage &get_coverage (void) const;
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const;
 
   inline bool apply (hb_apply_context_t *c) const;
 
@@ -1426,19 +1359,20 @@ struct PosLookupSubTable
     Extension		= 9
   };
 
-  inline const Coverage &get_coverage (unsigned int lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
     switch (lookup_type) {
-    case Single:		return u.single.get_coverage ();
-    case Pair:			return u.pair.get_coverage ();
-    case Cursive:		return u.cursive.get_coverage ();
-    case MarkBase:		return u.markBase.get_coverage ();
-    case MarkLig:		return u.markLig.get_coverage ();
-    case MarkMark:		return u.markMark.get_coverage ();
-    case Context:		return u.context.get_coverage ();
-    case ChainContext:		return u.chainContext.get_coverage ();
-    case Extension:		return u.extension.get_coverage ();
-    default:			return Null(Coverage);
+    case Single:		return u.single.process (c);
+    case Pair:			return u.pair.process (c);
+    case Cursive:		return u.cursive.process (c);
+    case MarkBase:		return u.markBase.process (c);
+    case MarkLig:		return u.markLig.process (c);
+    case MarkMark:		return u.markMark.process (c);
+    case Context:		return u.context.process (c);
+    case ChainContext:		return u.chainContext.process (c);
+    case Extension:		return u.extension.process (c);
+    default:			return c->default_return_value ();
     }
   }
 
@@ -1480,7 +1414,7 @@ struct PosLookupSubTable
   protected:
   union {
   struct {
-    USHORT			sub_format;
+    USHORT		sub_format;
   } header;
   SinglePos		single;
   PairPos		pair;
@@ -1502,16 +1436,30 @@ struct PosLookup : Lookup
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
+  {
+    unsigned int lookup_type = get_type ();
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return r;
+    }
+    return c->default_return_value ();
+  }
+
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
+    hb_get_coverage_context_t c;
     const Coverage *last = NULL;
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
-      if (c != last) {
-        c->add_coverage (glyphs);
-        last = c;
+      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
+      if (coverage != last) {
+        coverage->add_coverage (glyphs);
+        last = coverage;
       }
     }
   }
@@ -1673,9 +1621,10 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t
 
 /* Out-of-class implementation for methods recursing */
 
-inline const Coverage & ExtensionPos::get_coverage (void) const
+template <typename context_t>
+inline typename context_t::return_t ExtensionPos::process (context_t *c) const
 {
-  return get_subtable ().get_coverage (get_type ());
+  return get_subtable ().process (c, get_type ());
 }
 
 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 389e3d0..3d43966 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -63,6 +63,12 @@ struct SingleSubstFormat1
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY ();
+    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -132,6 +138,12 @@ struct SingleSubstFormat2
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY ();
+    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -184,16 +196,7 @@ struct SingleSubst
     switch (u.format) {
     case 1: return c->process (u.format1);
     case 2: return c->process (u.format2);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
+    default:return c->default_return_value ();
     }
   }
 
@@ -333,6 +336,12 @@ struct MultipleSubstFormat1
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY ();
+    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -385,15 +394,7 @@ struct MultipleSubst
   {
     switch (u.format) {
     case 1: return c->process (u.format1);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    default:return c->default_return_value ();
     }
   }
 
@@ -475,6 +476,12 @@ struct AlternateSubstFormat1
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY ();
+    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -545,15 +552,7 @@ struct AlternateSubst
   {
     switch (u.format) {
     case 1: return c->process (u.format1);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    default:return c->default_return_value ();
     }
   }
 
@@ -621,14 +620,15 @@ struct Ligature
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
+    TRACE_WOULD_APPLY ();
     if (c->len != component.len)
-      return false;
+      return TRACE_RETURN (false);
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
-	return false;
+	return TRACE_RETURN (false);
 
-    return true;
+    return TRACE_RETURN (true);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -712,14 +712,15 @@ struct LigatureSet
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
+    TRACE_WOULD_APPLY ();
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const Ligature &lig = this+ligature[i];
       if (lig.would_apply (c))
-        return true;
+        return TRACE_RETURN (true);
     }
-    return false;
+    return TRACE_RETURN (false);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -795,7 +796,12 @@ struct LigatureSubstFormat1
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
+    TRACE_WOULD_APPLY ();
+    unsigned int index = (this+coverage) (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return TRACE_RETURN (lig_set.would_apply (c));
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -856,23 +862,7 @@ struct LigatureSubst
   {
     switch (u.format) {
     case 1: return c->process (u.format1);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    default:return false;
+    default:return c->default_return_value ();
     }
   }
 
@@ -966,10 +956,6 @@ struct ExtensionSubst : Extension
   template <typename context_t>
   inline typename context_t::return_t process (context_t *c) const;
 
-  inline const Coverage &get_coverage (void) const;
-
-  inline bool would_apply (hb_would_apply_context_t *c) const;
-
   inline bool apply (hb_apply_context_t *c) const;
 
   inline bool sanitize (hb_sanitize_context_t *c);
@@ -1032,6 +1018,12 @@ struct ReverseChainSingleSubstFormat1
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY ();
+    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
@@ -1098,15 +1090,7 @@ struct ReverseChainSingleSubst
   {
     switch (u.format) {
     case 1: return c->process (u.format1);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
+    default:return c->default_return_value ();
     }
   }
 
@@ -1168,48 +1152,7 @@ struct SubstLookupSubTable
     case ChainContext:		return u.chainContext.process (c);
     case Extension:		return u.extension.process (c);
     case ReverseChainSingle:	return u.reverseChainContextSingle.process (c);
-    default:			return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (unsigned int lookup_type) const
-  {
-    switch (lookup_type) {
-    case Single:		return u.single.get_coverage ();
-    case Multiple:		return u.multiple.get_coverage ();
-    case Alternate:		return u.alternate.get_coverage ();
-    case Ligature:		return u.ligature.get_coverage ();
-    case Context:		return u.context.get_coverage ();
-    case ChainContext:		return u.chainContext.get_coverage ();
-    case Extension:		return u.extension.get_coverage ();
-    case ReverseChainSingle:	return u.reverseChainContextSingle.get_coverage ();
-    default:			return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c,
-			   unsigned int lookup_type) const
-  {
-    TRACE_WOULD_APPLY ();
-    if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
-    if (c->len == 1) {
-      switch (lookup_type) {
-      case Single:
-      case Multiple:
-      case Alternate:
-      case ReverseChainSingle:
-        return true;
-      }
-    }
-
-    /* Only need to look further for lookups that support substitutions
-     * of input longer than 1. */
-    switch (lookup_type) {
-    case Ligature:		return u.ligature.would_apply (c);
-    case Context:		return u.context.would_apply (c);
-    case ChainContext:		return u.chainContext.would_apply (c);
-    case Extension:		return u.extension.would_apply (c);
-    default:			return false;
+    default:			return c->default_return_value ();
     }
   }
 
@@ -1286,36 +1229,35 @@ struct SubstLookup : Lookup
   {
     unsigned int lookup_type = get_type ();
     unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (c->stop_sublookup_iteration (get_subtable (i).process (c, lookup_type)))
-        return c->default_return_value;
-    return c->default_return_value;
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return r;
+    }
+    return c->default_return_value ();
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
+    hb_get_coverage_context_t c;
     const Coverage *last = NULL;
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
-      if (c != last) {
-        c->add_coverage (glyphs);
-        last = c;
+      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
+      if (coverage != last) {
+        coverage->add_coverage (glyphs);
+        last = coverage;
       }
     }
   }
 
   inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
   {
-    if (unlikely (!c->len)) return false;
-    if (!digest->may_have (c->glyphs[0])) return false;
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).would_apply (c, lookup_type))
-	return true;
-    return false;
+    TRACE_WOULD_APPLY ();
+    if (unlikely (!c->len))  return TRACE_RETURN (false);
+    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
+      return TRACE_RETURN (process (c));
   }
 
   inline bool apply_once (hb_apply_context_t *c) const
@@ -1491,7 +1433,7 @@ struct GSUB : GSUBGPOS
 							hb_set_t *glyphs,
 							unsigned int lookup_index) const
   {
-    OT::hb_closure_context_t c (face, glyphs, closure_recurse_func);
+    hb_closure_context_t c (face, glyphs, closure_recurse_func);
     return get_lookup (lookup_index).process (&c);
   }
 
@@ -1541,16 +1483,6 @@ inline typename context_t::return_t ExtensionSubst::process (context_t *c) const
   return get_subtable ().process (c, get_type ());
 }
 
-inline const Coverage & ExtensionSubst::get_coverage (void) const
-{
-  return get_subtable ().get_coverage (get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
-{
-  return get_subtable ().would_apply (c, get_type ());
-}
-
 inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
 {
   TRACE_APPLY ();
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index b214fbf..d1381dd 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -53,17 +53,17 @@ struct hb_closure_context_t
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t process (const T &obj) { obj.closure (this); return void_t (); }
-  static const return_t default_return_value;
+  static const return_t default_return_value (void) { return return_t (); }
   bool stop_sublookup_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0))
-      return default_return_value;
+      return default_return_value ();
 
     nesting_level_left--;
     recurse_func (this, lookup_index);
     nesting_level_left++;
-    return default_return_value;
+    return default_return_value ();
   }
 
   hb_face_t *face;
@@ -111,6 +111,13 @@ struct hb_would_apply_context_t
 			      len (len_),
 			      zero_context (zero_context_),
 			      debug_depth (0) {};
+
+  typedef bool return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.would_apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return r; }
+  return_t recurse (unsigned int lookup_index) { return true; }
 };
 
 
@@ -148,19 +155,34 @@ struct hb_collect_glyphs_context_t
   typedef void_t return_t;
   template <typename T>
   inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
-  static const return_t default_return_value;
+  static const return_t default_return_value (void) { return return_t (); }
   bool stop_iteration (const return_t r) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
 #if 0
     /* XXX */
 #endif
-    return default_return_value;
+    return default_return_value ();
   }
 };
 
 
 
+struct hb_get_coverage_context_t
+{
+  hb_get_coverage_context_t (void) {}
+
+  typedef const Coverage &return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.get_coverage (); }
+  static return_t default_return_value (void) { return Null(Coverage); }
+  bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
+  return_t recurse (unsigned int lookup_index)
+  { return default_return_value (); }
+};
+
+
+
 #ifndef HB_DEBUG_APPLY
 #define HB_DEBUG_APPLY (HB_DEBUG+0)
 #endif
@@ -1162,27 +1184,7 @@ struct Context
     case 1: return c->process (u.format1);
     case 2: return c->process (u.format2);
     case 3: return c->process (u.format3);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    case 3: return u.format3.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    case 2: return u.format2.would_apply (c);
-    case 3: return u.format3.would_apply (c);
-    default:return false;
+    default:return c->default_return_value ();
     }
   }
 
@@ -1695,27 +1697,7 @@ struct ChainContext
     case 1: return c->process (u.format1);
     case 2: return c->process (u.format2);
     case 3: return c->process (u.format3);
-    default:return c->default_return_value;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    case 3: return u.format3.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    case 2: return u.format2.would_apply (c);
-    case 3: return u.format3.would_apply (c);
-    default:return false;
+    default:return c->default_return_value ();
     }
   }
 
commit 44fc237b53ebfbaf8a539de16ad735d2c6afc52b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Nov 21 23:33:13 2012 -0500

    [OTLayout] Port closure() to process() template

diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 4acd67b..389e3d0 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -37,10 +37,6 @@ namespace OT {
 
 struct SingleSubstFormat1
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -112,10 +108,6 @@ struct SingleSubstFormat1
 
 struct SingleSubstFormat2
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -186,28 +178,13 @@ struct SingleSubstFormat2
 
 struct SingleSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    case 2: u.format2.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.collect_glyphs (c); break;
-    case 2: u.format2.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    case 2: return c->process (u.format2);
+    default:return c->default_return_value;
     }
   }
 
@@ -278,10 +255,6 @@ struct SingleSubst
 
 struct Sequence
 {
-  friend struct MultipleSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -323,7 +296,6 @@ struct Sequence
     return TRACE_RETURN (true);
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return TRACE_RETURN (substitute.sanitize (c));
@@ -338,10 +310,6 @@ struct Sequence
 
 struct MultipleSubstFormat1
 {
-  friend struct MultipleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -412,25 +380,12 @@ struct MultipleSubstFormat1
 
 struct MultipleSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: u.format1.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value;
     }
   }
 
@@ -489,10 +444,6 @@ typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 
 struct AlternateSubstFormat1
 {
-  friend struct AlternateSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -589,25 +540,12 @@ struct AlternateSubstFormat1
 
 struct AlternateSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: u.format1.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value;
     }
   }
 
@@ -663,10 +601,6 @@ struct AlternateSubst
 
 struct Ligature
 {
-  friend struct LigatureSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -761,10 +695,6 @@ struct Ligature
 
 struct LigatureSet
 {
-  friend struct LigatureSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -824,7 +754,6 @@ struct LigatureSet
     return TRACE_RETURN (true);
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return TRACE_RETURN (ligature.sanitize (c, this));
@@ -840,10 +769,6 @@ struct LigatureSet
 
 struct LigatureSubstFormat1
 {
-  friend struct LigatureSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -926,25 +851,12 @@ struct LigatureSubstFormat1
 
 struct LigatureSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: u.format1.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value;
     }
   }
 
@@ -1010,24 +922,13 @@ struct LigatureSubst
 
 
 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
-static inline void collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
 
 struct ContextSubst : Context
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
-    return Context::closure (c, closure_lookup);
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    return Context::collect_glyphs (c, collect_glyphs_lookup);
+    return Context::process (c);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1039,19 +940,10 @@ struct ContextSubst : Context
 
 struct ChainContextSubst : ChainContext
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
-    return ChainContext::closure (c, closure_lookup);
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    return ChainContext::collect_glyphs (c, collect_glyphs_lookup);
+    return ChainContext::process (c);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1064,10 +956,6 @@ struct ChainContextSubst : ChainContext
 
 struct ExtensionSubst : Extension
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
   inline const struct SubstLookupSubTable& get_subtable (void) const
   {
     unsigned int offset = get_offset ();
@@ -1075,9 +963,8 @@ struct ExtensionSubst : Extension
     return StructAtOffset<SubstLookupSubTable> (this, offset);
   }
 
-  inline void closure (hb_closure_context_t *c) const;
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const;
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const;
 
   inline const Coverage &get_coverage (void) const;
 
@@ -1093,10 +980,6 @@ struct ExtensionSubst : Extension
 
 struct ReverseChainSingleSubstFormat1
 {
-  friend struct ReverseChainSingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
@@ -1210,24 +1093,12 @@ struct ReverseChainSingleSubstFormat1
 
 struct ReverseChainSingleSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     switch (u.format) {
-    case 1: u.format1.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    default:return c->default_return_value;
     }
   }
 
@@ -1285,36 +1156,19 @@ struct SubstLookupSubTable
     ReverseChainSingle	= 8
   };
 
-  inline void closure (hb_closure_context_t *c,
-		       unsigned int    lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
-    TRACE_CLOSURE ();
     switch (lookup_type) {
-    case Single:		u.single.closure (c); break;
-    case Multiple:		u.multiple.closure (c); break;
-    case Alternate:		u.alternate.closure (c); break;
-    case Ligature:		u.ligature.closure (c); break;
-    case Context:		u.context.closure (c); break;
-    case ChainContext:		u.chainContext.closure (c); break;
-    case Extension:		u.extension.closure (c); break;
-    case ReverseChainSingle:	u.reverseChainContextSingle.closure (c); break;
-    default:                    break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
-			      unsigned int lookup_type) const
-  {
-    switch (lookup_type) {
-    case Single:		u.single.collect_glyphs (c); break;
-    case Multiple:		u.multiple.collect_glyphs (c); break;
-    case Alternate:		u.alternate.collect_glyphs (c); break;
-    case Ligature:		u.ligature.collect_glyphs (c); break;
-    case Context:		u.context.collect_glyphs (c); break;
-    case ChainContext:		u.chainContext.collect_glyphs (c); break;
-    case Extension:		u.extension.collect_glyphs (c); break;
-    case ReverseChainSingle:	u.reverseChainContextSingle.collect_glyphs (c); break;
-    default:                    break;
+    case Single:		return u.single.process (c);
+    case Multiple:		return u.multiple.process (c);
+    case Alternate:		return u.alternate.process (c);
+    case Ligature:		return u.ligature.process (c);
+    case Context:		return u.context.process (c);
+    case ChainContext:		return u.chainContext.process (c);
+    case Extension:		return u.extension.process (c);
+    case ReverseChainSingle:	return u.reverseChainContextSingle.process (c);
+    default:			return c->default_return_value;
     }
   }
 
@@ -1427,12 +1281,15 @@ struct SubstLookup : Lookup
     return lookup_type_is_reverse (type);
   }
 
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
     unsigned int lookup_type = get_type ();
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++)
-      get_subtable (i).closure (c, lookup_type);
+      if (c->stop_sublookup_iteration (get_subtable (i).process (c, lookup_type)))
+        return c->default_return_value;
+    return c->default_return_value;
   }
 
   template <typename set_t>
@@ -1449,14 +1306,6 @@ struct SubstLookup : Lookup
     }
   }
 
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      get_subtable (i).collect_glyphs (c, lookup_type);
-  }
-
   inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     if (unlikely (!c->len)) return false;
@@ -1532,11 +1381,9 @@ struct SubstLookup : Lookup
     return ret;
   }
 
-  private:
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
 						  unsigned int i)
   { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
-  public:
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
@@ -1634,9 +1481,25 @@ struct GSUB : GSUBGPOS
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  inline void closure_lookup (hb_closure_context_t *c,
-			      unsigned int          lookup_index) const
-  { return get_lookup (lookup_index).closure (c); }
+  static void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+  {
+    const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
+    const SubstLookup &l = gsub.get_lookup (lookup_index);
+    return l.process (c);
+  }
+  inline hb_closure_context_t::return_t closure_lookup (hb_face_t *face,
+							hb_set_t *glyphs,
+							unsigned int lookup_index) const
+  {
+    OT::hb_closure_context_t c (face, glyphs, closure_recurse_func);
+    return get_lookup (lookup_index).process (&c);
+  }
+
+#if 0
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+								      unsigned int lookup_index) const
+  { return get_lookup (lookup_index).process (c); }
+#endif
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
@@ -1672,14 +1535,10 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE
 
 /* Out-of-class implementation for methods recursing */
 
-inline void ExtensionSubst::closure (hb_closure_context_t *c) const
-{
-  get_subtable ().closure (c, get_type ());
-}
-
-inline void ExtensionSubst::collect_glyphs (hb_collect_glyphs_context_t *c) const
+template <typename context_t>
+inline typename context_t::return_t ExtensionSubst::process (context_t *c) const
 {
-  get_subtable ().collect_glyphs (c, get_type ());
+  return get_subtable ().process (c, get_type ());
 }
 
 inline const Coverage & ExtensionSubst::get_coverage (void) const
@@ -1715,28 +1574,6 @@ inline bool ExtensionSubst::is_reverse (void) const
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
-{
-  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
-  const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return;
-
-  c->nesting_level_left--;
-  l.closure (c);
-  c->nesting_level_left++;
-}
-
-static inline void collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int lookup_index)
-{
-  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
-  const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  /* XXX TODO */
-  l.collect_glyphs (c);
-}
-
 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 4272681..b214fbf 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -37,6 +37,9 @@
 namespace OT {
 
 
+typedef struct {} void_t; /* To be used as return value when void is meant. */
+
+
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
@@ -44,20 +47,38 @@ namespace OT {
 #define TRACE_CLOSURE() \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
 
-
 struct hb_closure_context_t
 {
+  typedef void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t process (const T &obj) { obj.closure (this); return void_t (); }
+  static const return_t default_return_value;
+  bool stop_sublookup_iteration (const return_t r) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0))
+      return default_return_value;
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return default_return_value;
+  }
+
   hb_face_t *face;
   hb_set_t *glyphs;
+  recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
-
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
+			recurse_func_t recurse_func_,
 		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
+			  recurse_func (recurse_func_),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
 };
@@ -123,6 +144,19 @@ struct hb_collect_glyphs_context_t
 			      after  (glyphs_after  ? *glyphs_after  : *hb_set_get_empty ()),
 			      output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()),
 			      debug_depth (0) {};
+
+  typedef void_t return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
+  static const return_t default_return_value;
+  bool stop_iteration (const return_t r) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+#if 0
+    /* XXX */
+#endif
+    return default_return_value;
+  }
 };
 
 
@@ -374,14 +408,11 @@ struct hb_apply_context_t
 
 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
-typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
-typedef void (*collect_glyphs_lookup_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
 typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
-  closure_lookup_func_t closure;
 };
 struct ContextApplyFuncs
 {
@@ -677,11 +708,10 @@ struct LookupRecord
 
 static inline void closure_lookup (hb_closure_context_t *c,
 				   unsigned int lookupCount,
-				   const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-				   closure_lookup_func_t closure_func)
+				   const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
-    closure_func (c, lookupRecord->lookupListIndex);
+    c->recurse (lookupRecord->lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
@@ -770,8 +800,7 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data))
     closure_lookup (c,
-		    lookupCount, lookupRecord,
-		    lookup_context.funcs.closure);
+		    lookupCount, lookupRecord);
 }
 
 
@@ -804,10 +833,6 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
 
 struct Rule
 {
-  friend struct RuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE ();
@@ -905,18 +930,14 @@ struct RuleSet
 
 struct ContextFormat1
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       NULL
     };
 
@@ -940,6 +961,11 @@ struct ContextFormat1
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -975,11 +1001,7 @@ struct ContextFormat1
 
 struct ContextFormat2
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
     if (!(this+coverage).intersects (c->glyphs))
@@ -988,7 +1010,7 @@ struct ContextFormat2
     const ClassDef &class_def = this+classDef;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
+      {intersects_class},
       NULL
     };
 
@@ -1014,6 +1036,11 @@ struct ContextFormat2
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -1053,11 +1080,7 @@ struct ContextFormat2
 
 struct ContextFormat3
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
     if (!(this+coverage[0]).intersects (c->glyphs))
@@ -1065,7 +1088,7 @@ struct ContextFormat3
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       this
     };
     context_closure_lookup (c,
@@ -1086,6 +1109,11 @@ struct ContextFormat3
     return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage[0];
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -1127,36 +1155,23 @@ struct ContextFormat3
 
 struct Context
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c, collect_glyphs_lookup_func_t closure_func) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
     switch (u.format) {
-//    case 1: u.format1.collect_glyphs (c); break;
-//    case 2: u.format2.collect_glyphs (c); break;
-//    case 3: u.format2.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    case 2: return c->process (u.format2);
+    case 3: return c->process (u.format3);
+    default:return c->default_return_value;
     }
   }
 
   inline const Coverage &get_coverage (void) const
   {
     switch (u.format) {
-    case 1: return this + u.format1.coverage;
-    case 2: return this + u.format2.coverage;
-    case 3: return this + u.format3.coverage[0];
+    case 1: return u.format1.get_coverage ();
+    case 2: return u.format2.get_coverage ();
+    case 3: return u.format3.get_coverage ();
     default:return Null(Coverage);
     }
   }
@@ -1238,8 +1253,7 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
     closure_lookup (c,
-		    lookupCount, lookupRecord,
-		    lookup_context.funcs.closure);
+		    lookupCount, lookupRecord);
 }
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
@@ -1290,10 +1304,6 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 
 struct ChainRule
 {
-  friend struct ChainRuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE ();
@@ -1334,7 +1344,6 @@ struct ChainRule
 						     lookup.array, lookup_context));
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
@@ -1411,17 +1420,13 @@ struct ChainRuleSet
 
 struct ChainContextFormat1
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       {NULL, NULL, NULL}
     };
 
@@ -1445,6 +1450,11 @@ struct ChainContextFormat1
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -1478,11 +1488,7 @@ struct ChainContextFormat1
 
 struct ChainContextFormat2
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
     if (!(this+coverage).intersects (c->glyphs))
@@ -1493,7 +1499,7 @@ struct ChainContextFormat2
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
+      {intersects_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -1522,6 +1528,11 @@ struct ChainContextFormat2
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -1576,11 +1587,7 @@ struct ChainContextFormat2
 
 struct ChainContextFormat3
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE ();
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -1591,7 +1598,7 @@ struct ChainContextFormat3
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       {this, this, this}
     };
     chain_context_closure_lookup (c,
@@ -1602,12 +1609,6 @@ struct ChainContextFormat3
 				  lookup_context);
   }
 
-  inline const Coverage &get_coverage (void) const
-  {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    return this+input[0];
-  }
-
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY ();
@@ -1626,6 +1627,12 @@ struct ChainContextFormat3
 							   lookup.len, lookup.array, lookup_context));
   }
 
+  inline const Coverage &get_coverage (void) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    return this+input[0];
+  }
+
   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
   {
     TRACE_APPLY ();
@@ -1681,35 +1688,22 @@ struct ChainContextFormat3
 
 struct ChainContext
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline void collect_glyphs (hb_collect_glyphs_context_t *c, collect_glyphs_lookup_func_t closure_func) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
     switch (u.format) {
-//    case 1: u.format1.collect_glyphs (c); break;
-//    case 2: u.format2.collect_glyphs (c); break;
-//    case 3: u.format2.collect_glyphs (c); break;
-    default:                              break;
+    case 1: return c->process (u.format1);
+    case 2: return c->process (u.format2);
+    case 3: return c->process (u.format3);
+    default:return c->default_return_value;
     }
   }
 
   inline const Coverage &get_coverage (void) const
   {
     switch (u.format) {
-    case 1: return this + u.format1.coverage;
-    case 2: return this + u.format2.coverage;
+    case 1: return u.format1.get_coverage ();
+    case 2: return u.format2.get_coverage ();
     case 3: return u.format3.get_coverage ();
     default:return Null(Coverage);
     }
@@ -1759,9 +1753,6 @@ struct ChainContext
 
 struct ExtensionFormat1
 {
-  friend struct Extension;
-
-  protected:
   inline unsigned int get_type (void) const { return extensionLookupType; }
   inline unsigned int get_offset (void) const { return extensionOffset; }
 
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 580f95d..9185584 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -417,14 +417,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
   switch (table_tag) {
     case HB_OT_TAG_GSUB:
     {
-      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
-      l.collect_glyphs (&c);
+//      hb_ot_layout_from_face (face)->gsub->collect_glyphs_lookup (&c, lookup_index);
       return;
     }
     case HB_OT_TAG_GPOS:
     {
-      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
-//      l.collect_glyphs (&c);
+//      hb_ot_layout_from_face (face)->gpos->collect_glyphs_lookup (&c, lookup_index);
+//      l.collect_glyphs_lookup (&c);
       return;
     }
   }
@@ -499,8 +498,7 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
 				        hb_set_t     *glyphs)
 {
-  OT::hb_closure_context_t c (face, glyphs);
-  _get_gsub (face).closure_lookup (&c, lookup_index);
+  _get_gsub (face).closure_lookup (face, glyphs, lookup_index);
 }
 
 /*
commit 5be86b1bb4fbb37b50a1e2798df0c9a3a528b6b2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Nov 22 16:26:22 2012 -0500

    [ucdn] Make data tables const!

diff --git a/src/hb-ucdn/ucdn.c b/src/hb-ucdn/ucdn.c
index 5fbc0f3..473ea63 100644
--- a/src/hb-ucdn/ucdn.c
+++ b/src/hb-ucdn/ucdn.c
@@ -51,7 +51,7 @@ typedef struct {
 #define TCOUNT 28
 #define NCOUNT (VCOUNT * TCOUNT)
 
-static UCDRecord *get_ucd_record(uint32_t code)
+static const UCDRecord *get_ucd_record(uint32_t code)
 {
     int index, offset;
 
@@ -68,7 +68,7 @@ static UCDRecord *get_ucd_record(uint32_t code)
     return &ucd_records[index];
 }
 
-static unsigned short *get_decomp_record(uint32_t code)
+static const unsigned short *get_decomp_record(uint32_t code)
 {
     int index, offset;
 
@@ -86,12 +86,12 @@ static unsigned short *get_decomp_record(uint32_t code)
     return &decomp_data[index];
 }
 
-static int get_comp_index(uint32_t code, Reindex *idx)
+static const int get_comp_index(uint32_t code, const Reindex *idx)
 {
     int i;
 
     for (i = 0; idx[i].start; i++) {
-        Reindex *cur = &idx[i];
+        const Reindex *cur = &idx[i];
         if (code < cur->start)
             return -1;
         if (code <= cur->start + cur->count) {
@@ -151,9 +151,9 @@ static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
     }
 }
 
-static uint32_t decode_utf16(unsigned short **code_ptr)
+static uint32_t decode_utf16(const unsigned short **code_ptr)
 {
-    unsigned short *code = *code_ptr;
+    const unsigned short *code = *code_ptr;
 
     if ((code[0] & 0xd800) != 0xd800) {
         *code_ptr += 1;
@@ -220,7 +220,7 @@ uint32_t ucdn_mirror(uint32_t code)
 
 int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
 {
-    unsigned short *rec;
+    const unsigned short *rec;
     int len;
 
     if (hangul_pair_decompose(code, a, b))
@@ -268,7 +268,7 @@ int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
 int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
 {
     int i, len;
-    unsigned short *rec = get_decomp_record(code);
+    const unsigned short *rec = get_decomp_record(code);
     len = rec[0] >> 8;
 
     if (len == 0)
diff --git a/src/hb-ucdn/unicodedata_db.h b/src/hb-ucdn/unicodedata_db.h
index 305a7ff..20244ac 100644
--- a/src/hb-ucdn/unicodedata_db.h
+++ b/src/hb-ucdn/unicodedata_db.h
@@ -2,7 +2,7 @@
 
 #define UNIDATA_VERSION "6.2.0"
 /* a list of unique database records */
-static UCDRecord ucd_records[] = {
+static const UCDRecord ucd_records[] = {
     {2, 0, 18, 0, 5, 0, 102},
     {0, 0, 14, 0, 5, 0, 0},
     {0, 0, 16, 0, 5, 0, 0},
@@ -704,7 +704,7 @@ static UCDRecord ucd_records[] = {
 };
 
 #define BIDI_MIRROR_LEN 364
-static MirrorPair mirror_pairs[] = {
+static const MirrorPair mirror_pairs[] = {
     {40, 41},
     {41, 40},
     {60, 62},
@@ -1074,7 +1074,7 @@ static MirrorPair mirror_pairs[] = {
 /* Reindexing of NFC first characters. */
 #define TOTAL_FIRST 372
 #define TOTAL_LAST 56
-static Reindex nfc_first[] = {
+static const Reindex nfc_first[] = {
   { 60, 2, 0},
   { 65, 15, 3},
   { 82, 8, 19},
@@ -1285,7 +1285,7 @@ static Reindex nfc_first[] = {
   {0,0,0}
 };
 
-static Reindex nfc_last[] = {
+static const Reindex nfc_last[] = {
   { 768, 4, 0},
   { 774, 6, 5},
   { 783, 0, 12},
@@ -1487,7 +1487,7 @@ static Reindex nfc_last[] = {
 /* index tables for the database records */
 #define SHIFT1 5
 #define SHIFT2 3
-static unsigned char index0[] = {
+static const unsigned char index0[] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 
     39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 53, 53, 53, 
@@ -1737,7 +1737,7 @@ static unsigned char index0[] = {
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 131, 
 };
 
-static unsigned short index1[] = {
+static const unsigned short index1[] = {
     0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15, 
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32, 
     33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 
@@ -2042,7 +2042,7 @@ static unsigned short index1[] = {
     854, 854, 854, 854, 854, 854, 854, 1119, 
 };
 
-static unsigned short index2[] = {
+static const unsigned short index2[] = {
     1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 4, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 2, 
     5, 6, 6, 7, 8, 7, 6, 6, 9, 10, 6, 11, 12, 13, 12, 12, 14, 14, 14, 14, 14, 
     14, 14, 14, 14, 14, 12, 6, 15, 16, 15, 6, 6, 17, 17, 17, 17, 17, 17, 17, 
@@ -2624,7 +2624,7 @@ static unsigned short index2[] = {
 };
 
 /* decomposition data */
-static unsigned short decomp_data[] = {
+static const unsigned short decomp_data[] = {
     0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514, 
     32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52, 
     772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512, 
@@ -3702,7 +3702,7 @@ static unsigned short decomp_data[] = {
 /* index tables for the decomposition data */
 #define DECOMP_SHIFT1 6
 #define DECOMP_SHIFT2 4
-static unsigned char decomp_index0[] = {
+static const unsigned char decomp_index0[] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 5, 5, 5, 5, 5, 
     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 15, 5, 5, 5, 5, 16, 5, 
@@ -3751,7 +3751,7 @@ static unsigned char decomp_index0[] = {
     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
 };
 
-static unsigned short decomp_index1[] = {
+static const unsigned short decomp_index1[] = {
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
     14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 
     25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0, 
@@ -3825,7 +3825,7 @@ static unsigned short decomp_index1[] = {
     0, 0, 0, 
 };
 
-static unsigned short decomp_index2[] = {
+static const unsigned short decomp_index2[] = {
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
     3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27, 
     31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81, 
@@ -4414,7 +4414,7 @@ static unsigned short decomp_index2[] = {
 /* NFC pairs */
 #define COMP_SHIFT1 2
 #define COMP_SHIFT2 1
-static unsigned short comp_index0[] = {
+static const unsigned short comp_index0[] = {
     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 
     0, 0, 0, 0, 7, 0, 8, 9, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 13, 14, 15, 16, 
     0, 0, 0, 17, 18, 19, 20, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 22, 23, 24, 0, 0, 
@@ -4538,7 +4538,7 @@ static unsigned short comp_index0[] = {
     0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 542, 0, 0, 0, 0, 0, 0, 543, 
 };
 
-static unsigned short comp_index1[] = {
+static const unsigned short comp_index1[] = {
     0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 4, 5, 6, 7, 8, 9, 10, 0, 
     11, 12, 0, 13, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 17, 18, 0, 19, 0, 
     20, 0, 0, 0, 0, 21, 0, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0, 25, 26, 0, 27, 0, 
@@ -4651,7 +4651,7 @@ static unsigned short comp_index1[] = {
     725, 0, 0, 0, 726, 
 };
 
-static unsigned int comp_data[] = {
+static const unsigned int comp_data[] = {
     0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196, 
     7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684, 
     7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0, 
commit 7c5b7fe686c9163afe2f31fbeac6f8c8512f5516
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Nov 22 14:15:08 2012 -0500

    Fix hb_shape_plan_get_shaper()

diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 7735d4e..22a226f 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -304,4 +304,5 @@ retry:
 const char *
 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
 {
+  return shape_plan->shaper_name;
 }



More information about the HarfBuzz mailing list