Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-gsubgpos-private.hh
index 921859a..9054634 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-set-private.hh"
 namespace OT {
 
 
-#ifndef HB_DEBUG_CLOSURE
-#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
-#endif
-
-#define TRACE_CLOSURE(this) \
-       hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
-       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "");
-
 struct hb_closure_context_t :
        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
 {
@@ -77,7 +70,7 @@ struct hb_closure_context_t :
                        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
                          face (face_),
                          glyphs (glyphs_),
-                         recurse_func (NULL),
+                         recurse_func (nullptr),
                          nesting_level_left (nesting_level_left_),
                          debug_depth (0) {}
 
@@ -85,16 +78,6 @@ struct hb_closure_context_t :
 };
 
 
-
-#ifndef HB_DEBUG_WOULD_APPLY
-#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
-#endif
-
-#define TRACE_WOULD_APPLY(this) \
-       hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
-       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "%d glyphs", c->len);
-
 struct hb_would_apply_context_t :
        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
 {
@@ -122,16 +105,6 @@ struct hb_would_apply_context_t :
 };
 
 
-
-#ifndef HB_DEBUG_COLLECT_GLYPHS
-#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
-#endif
-
-#define TRACE_COLLECT_GLYPHS(this) \
-       hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
-       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "");
-
 struct hb_collect_glyphs_context_t :
        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
 {
@@ -146,7 +119,7 @@ struct hb_collect_glyphs_context_t :
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
-    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
      * glyphs in the recursion.  If output is not requested, we can go home now.
      *
@@ -160,7 +133,7 @@ struct hb_collect_glyphs_context_t :
       return HB_VOID;
 
     /* Return if new lookup was recursed to before. */
-    if (recursed_lookups.has (lookup_index))
+    if (recursed_lookups->has (lookup_index))
       return HB_VOID;
 
     hb_set_t *old_before = before;
@@ -176,7 +149,7 @@ struct hb_collect_glyphs_context_t :
     input  = old_input;
     after  = old_after;
 
-    recursed_lookups.add (lookup_index);
+    recursed_lookups->add (lookup_index);
 
     return HB_VOID;
   }
@@ -187,31 +160,31 @@ struct hb_collect_glyphs_context_t :
   hb_set_t *after;
   hb_set_t *output;
   recurse_func_t recurse_func;
-  hb_set_t recursed_lookups;
+  hb_set_t *recursed_lookups;
   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_before, /* OUT. May be nullptr */
+                              hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
+                              hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
+                              hb_set_t  *glyphs_output, /* OUT. May be nullptr */
                               unsigned int nesting_level_left_ = HB_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),
-                             recursed_lookups (),
+                             recurse_func (nullptr),
+                             recursed_lookups (nullptr),
                              nesting_level_left (nesting_level_left_),
                              debug_depth (0)
   {
-    recursed_lookups.init ();
+    recursed_lookups = hb_set_create ();
   }
   ~hb_collect_glyphs_context_t (void)
   {
-    recursed_lookups.fini ();
+    hb_set_destroy (recursed_lookups);
   }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
@@ -219,10 +192,6 @@ struct hb_collect_glyphs_context_t :
 
 
 
-#ifndef HB_DEBUG_GET_COVERAGE
-#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
-#endif
-
 /* XXX Can we remove this? */
 
 template <typename set_t>
@@ -249,19 +218,8 @@ struct hb_add_coverage_context_t :
 };
 
 
-
-#ifndef HB_DEBUG_APPLY
-#define HB_DEBUG_APPLY (HB_DEBUG+0)
-#endif
-
-#define TRACE_APPLY(this) \
-       hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
-       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-        "idx %d gid %u lookup %d", \
-        c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
-
-struct hb_apply_context_t :
-       hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
+struct hb_ot_apply_context_t :
+       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
 {
   struct matcher_t
   {
@@ -273,10 +231,10 @@ struct hb_apply_context_t :
 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
             syllable arg1(0),
 #undef arg1
-            match_func (NULL),
-            match_data (NULL) {};
+            match_func (nullptr),
+            match_data (nullptr) {};
 
-    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
@@ -294,7 +252,7 @@ struct hb_apply_context_t :
     };
 
     inline may_match_t may_match (const hb_glyph_info_t &info,
-                                 const USHORT          *glyph_data) const
+                                 const HBUINT16          *glyph_data) const
     {
       if (!(info.mask & mask) ||
          (syllable && syllable != info.syllable ()))
@@ -313,13 +271,13 @@ struct hb_apply_context_t :
     };
 
     inline may_skip_t
-    may_skip (const hb_apply_context_t *c,
+    may_skip (const hb_ot_apply_context_t *c,
              const hb_glyph_info_t    &info) const
     {
       if (!c->check_glyph_property (&info, lookup_props))
        return SKIP_YES;
 
-      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
+      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
                    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
                    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
        return SKIP_MAYBE;
@@ -339,16 +297,16 @@ struct hb_apply_context_t :
 
   struct skipping_iterator_t
   {
-    inline void init (hb_apply_context_t *c_, bool context_match = false)
+    inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      match_glyph_data = NULL;
-      matcher.set_match_func (NULL, NULL);
+      match_glyph_data = nullptr;
+      matcher.set_match_func (nullptr, nullptr);
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
-      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
-      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+      matcher.set_ignore_zwj  (c->table_index == 1 || (context_match || c->auto_zwj));
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
@@ -357,7 +315,7 @@ struct hb_apply_context_t :
     }
     inline void set_match_func (matcher_t::match_func_t match_func_,
                                const void *match_data_,
-                               const USHORT glyph_data[])
+                               const HBUINT16 glyph_data[])
     {
       matcher.set_match_func (match_func_, match_data_);
       match_glyph_data = glyph_data;
@@ -374,6 +332,12 @@ struct hb_apply_context_t :
 
     inline void reject (void) { num_items++; match_glyph_data--; }
 
+    inline matcher_t::may_skip_t
+    may_skip (const hb_glyph_info_t    &info) const
+    {
+      return matcher.may_skip (c, info);
+    }
+
     inline bool next (void)
     {
       assert (num_items > 0);
@@ -431,9 +395,9 @@ struct hb_apply_context_t :
 
     unsigned int idx;
     protected:
-    hb_apply_context_t *c;
+    hb_ot_apply_context_t *c;
     matcher_t matcher;
-    const USHORT *match_glyph_data;
+    const HBUINT16 *match_glyph_data;
 
     unsigned int num_items;
     unsigned int end;
@@ -441,61 +405,66 @@ struct hb_apply_context_t :
 
 
   inline const char *get_name (void) { return "APPLY"; }
-  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.apply (this); }
   static return_t default_return_value (void) { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
-  return_t recurse (unsigned int lookup_index)
+  return_t recurse (unsigned int sub_lookup_index)
   {
-    if (unlikely (nesting_level_left == 0 || !recurse_func))
+    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
       return default_return_value ();
 
     nesting_level_left--;
-    bool ret = recurse_func (this, lookup_index);
+    bool ret = recurse_func (this, sub_lookup_index);
     nesting_level_left++;
     return ret;
   }
 
-  unsigned int table_index; /* GSUB/GPOS */
+  skipping_iterator_t iter_input, iter_context;
+
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
-  hb_direction_t direction;
-  hb_mask_t lookup_mask;
-  bool auto_zwj;
   recurse_func_t recurse_func;
-  unsigned int nesting_level_left;
-  unsigned int lookup_props;
   const GDEF &gdef;
-  bool has_glyph_classes;
   const VariationStore &var_store;
-  skipping_iterator_t iter_input, iter_context;
+
+  hb_direction_t direction;
+  hb_mask_t lookup_mask;
+  unsigned int table_index; /* GSUB/GPOS */
   unsigned int lookup_index;
+  unsigned int lookup_props;
+  unsigned int nesting_level_left;
   unsigned int debug_depth;
 
+  bool auto_zwnj;
+  bool auto_zwj;
+  bool has_glyph_classes;
 
-  hb_apply_context_t (unsigned int table_index_,
+
+  hb_ot_apply_context_t (unsigned int table_index_,
                      hb_font_t *font_,
                      hb_buffer_t *buffer_) :
-                       table_index (table_index_),
+                       iter_input (), iter_context (),
                        font (font_), face (font->face), buffer (buffer_),
-                       direction (buffer_->props.direction),
-                       lookup_mask (1),
-                       auto_zwj (true),
-                       recurse_func (NULL),
-                       nesting_level_left (HB_MAX_NESTING_LEVEL),
-                       lookup_props (0),
+                       recurse_func (nullptr),
                        gdef (*hb_ot_layout_from_face (face)->gdef),
-                       has_glyph_classes (gdef.has_glyph_classes ()),
                        var_store (gdef.get_var_store ()),
-                       iter_input (),
-                       iter_context (),
+                       direction (buffer_->props.direction),
+                       lookup_mask (1),
+                       table_index (table_index_),
                        lookup_index ((unsigned int) -1),
-                       debug_depth (0) {}
+                       lookup_props (0),
+                       nesting_level_left (HB_MAX_NESTING_LEVEL),
+                       debug_depth (0),
+                       auto_zwnj (true),
+                       auto_zwj (true),
+                       has_glyph_classes (gdef.has_glyph_classes ()) {}
 
   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+  inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   inline void set_lookup_props (unsigned int lookup_props_)
@@ -598,9 +567,9 @@ 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);
+typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
 struct ContextClosureFuncs
 {
@@ -616,16 +585,16 @@ struct ContextApplyFuncs
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
@@ -633,7 +602,7 @@ static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, c
 
 static inline bool intersects_array (hb_closure_context_t *c,
                                     unsigned int count,
-                                    const USHORT values[],
+                                    const HBUINT16 values[],
                                     intersects_func_t intersects_func,
                                     const void *intersects_data)
 {
@@ -644,16 +613,16 @@ 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)
+static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &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)
+static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   (data+coverage).add_coverage (glyphs);
@@ -661,7 +630,7 @@ static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, cons
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
                                  hb_set_t *glyphs,
                                  unsigned int count,
-                                 const USHORT values[],
+                                 const HBUINT16 values[],
                                  collect_glyphs_func_t collect_func,
                                  const void *collect_data)
 {
@@ -670,16 +639,16 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 }
 
 
-static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
-static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
-static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
@@ -687,7 +656,7 @@ static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value,
 
 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 */
+                                     const HBUINT16 input[], /* Array of input values--start with second glyph */
                                      match_func_t match_func,
                                      const void *match_data)
 {
@@ -700,23 +669,23 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
 
   return true;
 }
-static inline bool match_input (hb_apply_context_t *c,
+static inline bool match_input (hb_ot_apply_context_t *c,
                                unsigned int count, /* Including the first glyph (not matched) */
-                               const USHORT input[], /* Array of input values--start with second glyph */
+                               const HBUINT16 input[], /* Array of input values--start with second glyph */
                                match_func_t match_func,
                                const void *match_data,
                                unsigned int *end_offset,
                                unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
-                               bool *p_is_mark_ligature = NULL,
-                               unsigned int *p_total_component_count = NULL)
+                               bool *p_is_mark_ligature = nullptr,
+                               unsigned int *p_total_component_count = nullptr)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
 
   hb_buffer_t *buffer = c->buffer;
 
-  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx, count - 1);
   skippy_iter.set_match_func (match_func, match_data, input);
 
@@ -731,11 +700,17 @@ static inline bool match_input (hb_apply_context_t *c,
    * - Ligatures cannot be formed across glyphs attached to different components
    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
-   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
-   *   There is an exception to this: If a ligature tries ligating with marks that
-   *   belong to it itself, go ahead, assuming that the font designer knows what
-   *   they are doing (otherwise it can break Indic stuff when a matra wants to
-   *   ligate with a conjunct...)
+   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
+   *   There are a couple of exceptions to this:
+   *
+   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
+   *     assuming that the font designer knows what they are doing (otherwise it can
+   *     break Indic stuff when a matra wants to ligate with a conjunct,
+   *
+   *   o If two marks want to ligate and they belong to different components of the
+   *     same ligature glyph, and said ligature glyph is to be ignored according to
+   *     mark-filtering rules, then allow.
+   *     https://github.com/harfbuzz/harfbuzz/issues/545
    */
 
   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
@@ -746,6 +721,12 @@ static inline bool match_input (hb_apply_context_t *c,
   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
 
+  enum {
+    LIGBASE_NOT_CHECKED,
+    LIGBASE_MAY_NOT_SKIP,
+    LIGBASE_MAY_SKIP
+  } ligbase = LIGBASE_NOT_CHECKED;
+
   match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
@@ -756,13 +737,43 @@ static inline bool match_input (hb_apply_context_t *c,
     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
 
-    if (first_lig_id && first_lig_comp) {
+    if (first_lig_id && first_lig_comp)
+    {
       /* If first component was attached to a previous ligature component,
        * all subsequent components should be attached to the same ligature
-       * component, otherwise we shouldn't ligate them. */
+       * component, otherwise we shouldn't ligate them... */
       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
-       return_trace (false);
-    } else {
+      {
+        /* ...unless, we are attached to a base ligature and that base
+        * ligature is ignorable. */
+        if (ligbase == LIGBASE_NOT_CHECKED)
+       {
+         bool found = false;
+         const hb_glyph_info_t *out = buffer->out_info;
+         unsigned int j = buffer->out_len;
+         while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
+         {
+           if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
+           {
+             j--;
+             found = true;
+             break;
+           }
+           j--;
+         }
+
+         if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
+           ligbase = LIGBASE_MAY_SKIP;
+         else
+           ligbase = LIGBASE_MAY_NOT_SKIP;
+       }
+
+        if (ligbase == LIGBASE_MAY_NOT_SKIP)
+         return_trace (false);
+      }
+    }
+    else
+    {
       /* If first component was NOT attached to a previous ligature component,
        * all subsequent components should also NOT be attached to any ligature
        * component, unless they are attached to the first component itself! */
@@ -784,7 +795,7 @@ static inline bool match_input (hb_apply_context_t *c,
 
   return_trace (true);
 }
-static inline bool ligate_input (hb_apply_context_t *c,
+static inline bool ligate_input (hb_ot_apply_context_t *c,
                                 unsigned int count, /* Including the first glyph */
                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
                                 unsigned int match_length,
@@ -792,7 +803,7 @@ static inline bool ligate_input (hb_apply_context_t *c,
                                 bool is_mark_ligature,
                                 unsigned int total_component_count)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
 
@@ -882,15 +893,16 @@ static inline bool ligate_input (hb_apply_context_t *c,
   return_trace (true);
 }
 
-static inline bool match_backtrack (hb_apply_context_t *c,
+static inline bool match_backtrack (hb_ot_apply_context_t *c,
                                    unsigned int count,
-                                   const USHORT backtrack[],
+                                   const HBUINT16 backtrack[],
                                    match_func_t match_func,
-                                   const void *match_data)
+                                   const void *match_data,
+                                   unsigned int *match_start)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
-  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len (), count);
   skippy_iter.set_match_func (match_func, match_data, backtrack);
 
@@ -898,19 +910,22 @@ static inline bool match_backtrack (hb_apply_context_t *c,
     if (!skippy_iter.prev ())
       return_trace (false);
 
+  *match_start = skippy_iter.idx;
+
   return_trace (true);
 }
 
-static inline bool match_lookahead (hb_apply_context_t *c,
+static inline bool match_lookahead (hb_ot_apply_context_t *c,
                                    unsigned int count,
-                                   const USHORT lookahead[],
+                                   const HBUINT16 lookahead[],
                                    match_func_t match_func,
                                    const void *match_data,
-                                   unsigned int offset)
+                                   unsigned int offset,
+                                   unsigned int *end_index)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
-  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->idx + offset - 1, count);
   skippy_iter.set_match_func (match_func, match_data, lookahead);
 
@@ -918,6 +933,8 @@ static inline bool match_lookahead (hb_apply_context_t *c,
     if (!skippy_iter.next ())
       return_trace (false);
 
+  *end_index = skippy_iter.idx + 1;
+
   return_trace (true);
 }
 
@@ -931,9 +948,9 @@ struct LookupRecord
     return_trace (c->check_struct (this));
   }
 
-  USHORT       sequenceIndex;          /* Index into current glyph
+  HBUINT16     sequenceIndex;          /* Index into current glyph
                                         * sequence--first glyph = 0 */
-  USHORT       lookupListIndex;        /* Lookup to apply to that
+  HBUINT16     lookupListIndex;        /* Lookup to apply to that
                                         * position--zero--based */
   public:
   DEFINE_SIZE_STATIC (4);
@@ -949,14 +966,14 @@ static inline void recurse_lookups (context_t *c,
     c->recurse (lookupRecord[i].lookupListIndex);
 }
 
-static inline bool apply_lookup (hb_apply_context_t *c,
+static inline bool apply_lookup (hb_ot_apply_context_t *c,
                                 unsigned int count, /* Including the first glyph */
                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
                                 unsigned int lookupCount,
                                 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
                                 unsigned int match_length)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
   int end;
@@ -984,7 +1001,11 @@ static inline bool apply_lookup (hb_apply_context_t *c,
     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
       continue;
 
-    buffer->move_to (match_positions[idx]);
+    if (unlikely (!buffer->move_to (match_positions[idx])))
+      break;
+
+    if (unlikely (buffer->max_ops <= 0))
+      break;
 
     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
     if (!c->recurse (lookupRecord[i].lookupListIndex))
@@ -1090,7 +1111,7 @@ struct ContextApplyLookupContext
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
                                           unsigned int inputCount, /* Including the first glyph (not matched) */
-                                          const USHORT input[], /* Array of input values--start with second glyph */
+                                          const HBUINT16 input[], /* Array of input values--start with second glyph */
                                           unsigned int lookupCount,
                                           const LookupRecord lookupRecord[],
                                           ContextClosureLookupContext &lookup_context)
@@ -1104,7 +1125,7 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
 
 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 */
+                                                 const HBUINT16 input[], /* Array of input values--start with second glyph */
                                                  unsigned int lookupCount,
                                                  const LookupRecord lookupRecord[],
                                                  ContextCollectGlyphsLookupContext &lookup_context)
@@ -1118,7 +1139,7 @@ static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c
 
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
                                               unsigned int inputCount, /* Including the first glyph (not matched) */
-                                              const USHORT input[], /* Array of input values--start with second glyph */
+                                              const HBUINT16 input[], /* Array of input values--start with second glyph */
                                               unsigned int lookupCount HB_UNUSED,
                                               const LookupRecord lookupRecord[] HB_UNUSED,
                                               ContextApplyLookupContext &lookup_context)
@@ -1127,9 +1148,9 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
                            inputCount, input,
                            lookup_context.funcs.match, lookup_context.match_data);
 }
-static inline bool context_apply_lookup (hb_apply_context_t *c,
+static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
                                         unsigned int inputCount, /* Including the first glyph (not matched) */
-                                        const USHORT input[], /* Array of input values--start with second glyph */
+                                        const HBUINT16 input[], /* Array of input values--start with second glyph */
                                         unsigned int lookupCount,
                                         const LookupRecord lookupRecord[],
                                         ContextApplyLookupContext &lookup_context)
@@ -1140,10 +1161,11 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
                      inputCount, input,
                      lookup_context.funcs.match, lookup_context.match_data,
                      &match_length, match_positions)
-      && apply_lookup (c,
+      && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
+         apply_lookup (c,
                       inputCount, match_positions,
                       lookupCount, lookupRecord,
-                      match_length);
+                      match_length));
 }
 
 struct Rule
@@ -1175,7 +1197,7 @@ struct Rule
     return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
@@ -1186,24 +1208,24 @@ struct Rule
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return inputCount.sanitize (c)
-       && lookupCount.sanitize (c)
-       && c->check_range (inputZ,
-                          inputZ[0].static_size * inputCount
-                          + lookupRecordX[0].static_size * lookupCount);
+    return_trace (inputCount.sanitize (c) &&
+                 lookupCount.sanitize (c) &&
+                 c->check_range (inputZ,
+                                 inputZ[0].static_size * inputCount +
+                                 LookupRecord::static_size * lookupCount));
   }
 
   protected:
-  USHORT       inputCount;             /* Total number of glyphs in input
+  HBUINT16     inputCount;             /* Total number of glyphs in input
                                         * glyph sequence--includes the first
                                         * glyph */
-  USHORT       lookupCount;            /* Number of LookupRecords */
-  USHORT       inputZ[VAR];            /* Array of match inputs--start with
+  HBUINT16     lookupCount;            /* Number of LookupRecords */
+  HBUINT16     inputZ[VAR];            /* Array of match inputs--start with
                                         * second glyph */
-  LookupRecord lookupRecordX[VAR];     /* Array of LookupRecords--in
+/*LookupRecord lookupRecordX[VAR];*/   /* Array of LookupRecords--in
                                         * design order */
   public:
-  DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
+  DEFINE_SIZE_ARRAY (4, inputZ);
 };
 
 struct RuleSet
@@ -1236,7 +1258,7 @@ struct RuleSet
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
@@ -1273,7 +1295,7 @@ struct ContextFormat1
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
@@ -1291,7 +1313,7 @@ struct ContextFormat1
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
@@ -1306,7 +1328,7 @@ struct ContextFormat1
     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
@@ -1316,7 +1338,7 @@ struct ContextFormat1
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -1326,7 +1348,7 @@ struct ContextFormat1
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -1338,7 +1360,7 @@ struct ContextFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
@@ -1408,7 +1430,7 @@ struct ContextFormat2
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -1431,7 +1453,7 @@ struct ContextFormat2
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 2 */
+  HBUINT16     format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
@@ -1460,7 +1482,7 @@ struct ContextFormat3
       this
     };
     context_closure_lookup (c,
-                           glyphCount, (const USHORT *) (coverageZ + 1),
+                           glyphCount, (const HBUINT16 *) (coverageZ + 1),
                            lookupCount, lookupRecord,
                            lookup_context);
   }
@@ -1477,7 +1499,7 @@ struct ContextFormat3
     };
 
     context_collect_glyphs_lookup (c,
-                                  glyphCount, (const USHORT *) (coverageZ + 1),
+                                  glyphCount, (const HBUINT16 *) (coverageZ + 1),
                                   lookupCount, lookupRecord,
                                   lookup_context);
   }
@@ -1491,7 +1513,7 @@ struct ContextFormat3
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1499,7 +1521,7 @@ struct ContextFormat3
     return this+coverageZ[0];
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
@@ -1510,7 +1532,7 @@ struct ContextFormat3
       {match_coverage},
       this
     };
-    return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1527,17 +1549,17 @@ struct ContextFormat3
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 3 */
-  USHORT       glyphCount;             /* Number of glyphs in the input glyph
+  HBUINT16     format;                 /* Format identifier--format = 3 */
+  HBUINT16     glyphCount;             /* Number of glyphs in the input glyph
                                         * sequence */
-  USHORT       lookupCount;            /* Number of LookupRecords */
+  HBUINT16     lookupCount;            /* Number of LookupRecords */
   OffsetTo<Coverage>
                coverageZ[VAR];         /* Array of offsets to Coverage
                                         * table in glyph sequence order */
-  LookupRecord lookupRecordX[VAR];     /* Array of LookupRecords--in
+/*LookupRecord lookupRecordX[VAR];*/   /* Array of LookupRecords--in
                                         * design order */
   public:
-  DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
+  DEFINE_SIZE_ARRAY (6, coverageZ);
 };
 
 struct Context
@@ -1557,7 +1579,7 @@ struct Context
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   ContextFormat1       format1;
   ContextFormat2       format2;
   ContextFormat3       format3;
@@ -1587,11 +1609,11 @@ struct ChainContextApplyLookupContext
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
                                                 unsigned int backtrackCount,
-                                                const USHORT backtrack[],
+                                                const HBUINT16 backtrack[],
                                                 unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                const USHORT input[], /* Array of input values--start with second glyph */
+                                                const HBUINT16 input[], /* Array of input values--start with second glyph */
                                                 unsigned int lookaheadCount,
-                                                const USHORT lookahead[],
+                                                const HBUINT16 lookahead[],
                                                 unsigned int lookupCount,
                                                 const LookupRecord lookupRecord[],
                                                 ChainContextClosureLookupContext &lookup_context)
@@ -1611,11 +1633,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
                                                        unsigned int backtrackCount,
-                                                       const USHORT backtrack[],
+                                                       const HBUINT16 backtrack[],
                                                        unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                       const USHORT input[], /* Array of input values--start with second glyph */
+                                                       const HBUINT16 input[], /* Array of input values--start with second glyph */
                                                        unsigned int lookaheadCount,
-                                                       const USHORT lookahead[],
+                                                       const HBUINT16 lookahead[],
                                                        unsigned int lookupCount,
                                                        const LookupRecord lookupRecord[],
                                                        ChainContextCollectGlyphsLookupContext &lookup_context)
@@ -1635,11 +1657,11 @@ static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_contex
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
                                                     unsigned int backtrackCount,
-                                                    const USHORT backtrack[] HB_UNUSED,
+                                                    const HBUINT16 backtrack[] HB_UNUSED,
                                                     unsigned int inputCount, /* Including the first glyph (not matched) */
-                                                    const USHORT input[], /* Array of input values--start with second glyph */
+                                                    const HBUINT16 input[], /* Array of input values--start with second glyph */
                                                     unsigned int lookaheadCount,
-                                                    const USHORT lookahead[] HB_UNUSED,
+                                                    const HBUINT16 lookahead[] HB_UNUSED,
                                                     unsigned int lookupCount HB_UNUSED,
                                                     const LookupRecord lookupRecord[] HB_UNUSED,
                                                     ChainContextApplyLookupContext &lookup_context)
@@ -1650,18 +1672,18 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
                            lookup_context.funcs.match, lookup_context.match_data[1]);
 }
 
-static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
+static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
                                               unsigned int backtrackCount,
-                                              const USHORT backtrack[],
+                                              const HBUINT16 backtrack[],
                                               unsigned int inputCount, /* Including the first glyph (not matched) */
-                                              const USHORT input[], /* Array of input values--start with second glyph */
+                                              const HBUINT16 input[], /* Array of input values--start with second glyph */
                                               unsigned int lookaheadCount,
-                                              const USHORT lookahead[],
+                                              const HBUINT16 lookahead[],
                                               unsigned int lookupCount,
                                               const LookupRecord lookupRecord[],
                                               ChainContextApplyLookupContext &lookup_context)
 {
-  unsigned int match_length = 0;
+  unsigned int start_index = 0, match_length = 0, end_index = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
                      inputCount, input,
@@ -1669,15 +1691,17 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
                      &match_length, match_positions)
       && match_backtrack (c,
                          backtrackCount, backtrack,
-                         lookup_context.funcs.match, lookup_context.match_data[0])
+                         lookup_context.funcs.match, lookup_context.match_data[0],
+                         &start_index)
       && match_lookahead (c,
                          lookaheadCount, lookahead,
                          lookup_context.funcs.match, lookup_context.match_data[2],
-                         match_length)
-      && apply_lookup (c,
+                         match_length, &end_index)
+      && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
+          apply_lookup (c,
                       inputCount, match_positions,
                       lookupCount, lookupRecord,
-                      match_length);
+                      match_length));
 }
 
 struct ChainRule
@@ -1685,8 +1709,8 @@ struct ChainRule
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
                                  backtrack.len, backtrack.array,
@@ -1699,8 +1723,8 @@ struct ChainRule
   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 HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_collect_glyphs_lookup (c,
                                         backtrack.len, backtrack.array,
@@ -1713,8 +1737,8 @@ struct ChainRule
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_would_apply_lookup (c,
                                                    backtrack.len, backtrack.array,
@@ -1723,11 +1747,11 @@ struct ChainRule
                                                    lookup.array, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_apply_lookup (c,
                                              backtrack.len, backtrack.array,
@@ -1740,23 +1764,23 @@ struct ChainRule
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
     if (!lookahead.sanitize (c)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  ArrayOf<USHORT>
+  ArrayOf<HBUINT16>
                backtrack;              /* Array of backtracking values
                                         * (to be matched before the input
                                         * sequence) */
-  HeadlessArrayOf<USHORT>
+  HeadlessArrayOf<HBUINT16>
                inputX;                 /* Array of input values (start with
                                         * second glyph) */
-  ArrayOf<USHORT>
+  ArrayOf<HBUINT16>
                lookaheadX;             /* Array of lookahead values's (to be
                                         * matched after the input sequence) */
   ArrayOf<LookupRecord>
@@ -1795,7 +1819,7 @@ struct ChainRuleSet
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
@@ -1829,7 +1853,7 @@ struct ChainContextFormat1
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
@@ -1847,7 +1871,7 @@ struct ChainContextFormat1
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
@@ -1862,7 +1886,7 @@ struct ChainContextFormat1
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
@@ -1872,7 +1896,7 @@ struct ChainContextFormat1
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -1881,7 +1905,7 @@ struct ChainContextFormat1
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -1893,7 +1917,7 @@ struct ChainContextFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
@@ -1976,7 +2000,7 @@ struct ChainContextFormat2
     return this+coverage;
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -2008,7 +2032,7 @@ struct ChainContextFormat2
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 2 */
+  HBUINT16     format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
@@ -2048,9 +2072,9 @@ struct ChainContextFormat3
       {this, this, this}
     };
     chain_context_closure_lookup (c,
-                                 backtrack.len, (const USHORT *) backtrack.array,
-                                 input.len, (const USHORT *) input.array + 1,
-                                 lookahead.len, (const USHORT *) lookahead.array,
+                                 backtrack.len, (const HBUINT16 *) backtrack.array,
+                                 input.len, (const HBUINT16 *) input.array + 1,
+                                 lookahead.len, (const HBUINT16 *) lookahead.array,
                                  lookup.len, lookup.array,
                                  lookup_context);
   }
@@ -2069,9 +2093,9 @@ struct ChainContextFormat3
       {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,
+                                        backtrack.len, (const HBUINT16 *) backtrack.array,
+                                        input.len, (const HBUINT16 *) input.array + 1,
+                                        lookahead.len, (const HBUINT16 *) lookahead.array,
                                         lookup.len, lookup.array,
                                         lookup_context);
   }
@@ -2088,9 +2112,9 @@ struct ChainContextFormat3
       {this, this, this}
     };
     return_trace (chain_context_would_apply_lookup (c,
-                                                   backtrack.len, (const USHORT *) backtrack.array,
-                                                   input.len, (const USHORT *) input.array + 1,
-                                                   lookahead.len, (const USHORT *) lookahead.array,
+                                                   backtrack.len, (const HBUINT16 *) backtrack.array,
+                                                   input.len, (const HBUINT16 *) input.array + 1,
+                                                   lookahead.len, (const HBUINT16 *) lookahead.array,
                                                    lookup.len, lookup.array, lookup_context));
   }
 
@@ -2100,7 +2124,7 @@ struct ChainContextFormat3
     return this+input[0];
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -2115,9 +2139,9 @@ struct ChainContextFormat3
       {this, this, this}
     };
     return_trace (chain_context_apply_lookup (c,
-                                             backtrack.len, (const USHORT *) backtrack.array,
-                                             input.len, (const USHORT *) input.array + 1,
-                                             lookahead.len, (const USHORT *) lookahead.array,
+                                             backtrack.len, (const HBUINT16 *) backtrack.array,
+                                             input.len, (const HBUINT16 *) input.array + 1,
+                                             lookahead.len, (const HBUINT16 *) lookahead.array,
                                              lookup.len, lookup.array, lookup_context));
   }
 
@@ -2135,7 +2159,7 @@ struct ChainContextFormat3
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 3 */
+  HBUINT16     format;                 /* Format identifier--format = 3 */
   OffsetArrayOf<Coverage>
                backtrack;              /* Array of coverage tables
                                         * in backtracking sequence, in  glyph
@@ -2172,7 +2196,7 @@ struct ChainContext
 
   protected:
   union {
-  USHORT               format; /* Format identifier */
+  HBUINT16             format; /* Format identifier */
   ChainContextFormat1  format1;
   ChainContextFormat2  format2;
   ChainContextFormat3  format3;
@@ -2205,15 +2229,17 @@ struct ExtensionFormat1
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && extensionOffset != 0);
+    return_trace (c->check_struct (this) &&
+                 extensionOffset != 0 &&
+                 extensionLookupType != T::LookupSubTable::Extension);
   }
 
   protected:
-  USHORT       format;                 /* Format identifier. Set to 1. */
-  USHORT       extensionLookupType;    /* Lookup type of subtable referenced
+  HBUINT16     format;                 /* Format identifier. Set to 1. */
+  HBUINT16     extensionLookupType;    /* Lookup type of subtable referenced
                                         * by ExtensionOffset (i.e. the
                                         * extension subtable). */
-  ULONG                extensionOffset;        /* Offset to the extension subtable,
+  HBUINT32     extensionOffset;        /* Offset to the extension subtable,
                                         * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -2251,7 +2277,7 @@ struct Extension
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   ExtensionFormat1<T>  format1;
   } u;
 };
@@ -2263,9 +2289,6 @@ struct Extension
 
 struct GSUBGPOS
 {
-  static const hb_tag_t GSUBTag        = HB_OT_TAG_GSUB;
-  static const hb_tag_t GPOSTag        = HB_OT_TAG_GPOS;
-
   inline unsigned int get_script_count (void) const
   { return (this+scriptList).len; }
   inline const Tag& get_script_tag (unsigned int i) const