[OTLayout] Add is_inplace() method to GSUB
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 56b3a4f..a9933d1 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -1429,6 +1429,12 @@
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
+  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 3b6635b..fc37cd9 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -37,6 +37,12 @@
 
 struct SingleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -115,6 +121,12 @@
 
 struct SingleSubstFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -251,6 +263,13 @@
 
 struct Sequence
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    /* For len==0 we don't do anything, so it's harmless. */
+    return TRACE_RETURN (substitute.len <= 1);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -315,6 +334,18 @@
 
 struct MultipleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    /* Some tools generate MultipleSubst with each substitute having length 1!
+     * So, check them. */
+    unsigned int count = sequence.len;
+    for (unsigned int i = 0; i < count; i++)
+	if (!(this+sequence[i]).is_inplace (c))
+	  return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -440,6 +471,12 @@
 
 struct AlternateSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -760,6 +797,12 @@
 
 struct LigatureSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (false);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -908,6 +951,12 @@
 
 struct ReverseChainSingleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1145,6 +1194,13 @@
     return lookup_type_is_reverse (type);
   }
 
+  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_is_inplace_context_t>);
+    return TRACE_RETURN (dispatch (c));
+  }
+
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 5169e78..9fc638b 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -44,6 +44,55 @@
 	 "");
 
 
+
+#ifndef HB_DEBUG_IS_INPLACE
+#define HB_DEBUG_IS_INPLACE (HB_DEBUG+0)
+#endif
+
+#define TRACE_IS_INPLACE(this) \
+	hb_auto_trace_t<HB_DEBUG_IS_INPLACE, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
+
+struct hb_is_inplace_context_t
+{
+  inline const char *get_name (void) { return "IS_INPLACE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_IS_INPLACE;
+  typedef bool return_t;
+  typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.is_inplace (this); }
+  static return_t default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (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 ();
+
+    nesting_level_left--;
+    bool ret = recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return ret;
+  }
+
+  hb_face_t *face;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int debug_depth;
+
+  hb_is_inplace_context_t (hb_face_t *face_,
+			   unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+			   face (face_),
+			   recurse_func (NULL),
+			   nesting_level_left (nesting_level_left_),
+			   debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
@@ -1102,6 +1151,17 @@
 
 struct Rule
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+    unsigned int count = lookupCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookupRecord[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1161,6 +1221,16 @@
 
 struct RuleSet
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if (!(this+rule[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1217,6 +1287,16 @@
 
 struct ContextFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1303,6 +1383,16 @@
 
 struct ContextFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1398,6 +1488,17 @@
 
 struct ContextFormat3
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    unsigned int count = lookupCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookupRecord[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1639,6 +1740,19 @@
 
 struct ChainRule
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (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);
+    unsigned int count = lookup.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookup.array[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1724,6 +1838,16 @@
 
 struct ChainRuleSet
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if (!(this+rule[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1777,6 +1901,16 @@
 
 struct ChainContextFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1860,6 +1994,16 @@
 
 struct ChainContextFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1984,6 +2128,20 @@
 
 struct ChainContextFormat3
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+
+    unsigned int count = lookup.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookup.array[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);