Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2007,2008,2009,2010  Red Hat, Inc.
      3  * Copyright  2010,2012  Google, Inc.
      4  *
      5  *  This is part of HarfBuzz, a text shaping library.
      6  *
      7  * Permission is hereby granted, without written agreement and without
      8  * license or royalty fees, to use, copy, modify, and distribute this
      9  * software and its documentation for any purpose, provided that the
     10  * above copyright notice and the following two paragraphs appear in
     11  * all copies of this software.
     12  *
     13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17  * DAMAGE.
     18  *
     19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24  *
     25  * Red Hat Author(s): Behdad Esfahbod
     26  * Google Author(s): Behdad Esfahbod
     27  */
     28 
     29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
     30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
     31 
     32 #include "hb-buffer-private.hh"
     33 #include "hb-ot-layout-gdef-table.hh"
     34 #include "hb-set-private.hh"
     35 
     36 
     37 namespace OT {
     38 
     39 
     40 
     41 #define TRACE_DISPATCH(this) \
     42 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
     43 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
     44 	 "");
     45 
     46 #ifndef HB_DEBUG_CLOSURE
     47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
     48 #endif
     49 
     50 #define TRACE_CLOSURE(this) \
     51 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
     52 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
     53 	 "");
     54 
     55 struct hb_closure_context_t
     56 {
     57   inline const char *get_name (void) { return "CLOSURE"; }
     58   static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
     59   typedef hb_void_t return_t;
     60   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
     61   template <typename T>
     62   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
     63   static return_t default_return_value (void) { return HB_VOID; }
     64   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
     65   return_t recurse (unsigned int lookup_index)
     66   {
     67     if (unlikely (nesting_level_left == 0 || !recurse_func))
     68       return default_return_value ();
     69 
     70     nesting_level_left--;
     71     recurse_func (this, lookup_index);
     72     nesting_level_left++;
     73     return HB_VOID;
     74   }
     75 
     76   hb_face_t *face;
     77   hb_set_t *glyphs;
     78   recurse_func_t recurse_func;
     79   unsigned int nesting_level_left;
     80   unsigned int debug_depth;
     81 
     82   hb_closure_context_t (hb_face_t *face_,
     83 			hb_set_t *glyphs_,
     84 		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
     85 			  face (face_),
     86 			  glyphs (glyphs_),
     87 			  recurse_func (NULL),
     88 			  nesting_level_left (nesting_level_left_),
     89 			  debug_depth (0) {}
     90 
     91   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
     92 };
     93 
     94 
     95 
     96 #ifndef HB_DEBUG_WOULD_APPLY
     97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
     98 #endif
     99 
    100 #define TRACE_WOULD_APPLY(this) \
    101 	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
    102 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
    103 	 "%d glyphs", c->len);
    104 
    105 struct hb_would_apply_context_t
    106 {
    107   inline const char *get_name (void) { return "WOULD_APPLY"; }
    108   static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
    109   typedef bool return_t;
    110   template <typename T>
    111   inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
    112   static return_t default_return_value (void) { return false; }
    113   bool stop_sublookup_iteration (return_t r) const { return r; }
    114 
    115   hb_face_t *face;
    116   const hb_codepoint_t *glyphs;
    117   unsigned int len;
    118   bool zero_context;
    119   unsigned int debug_depth;
    120 
    121   hb_would_apply_context_t (hb_face_t *face_,
    122 			    const hb_codepoint_t *glyphs_,
    123 			    unsigned int len_,
    124 			    bool zero_context_) :
    125 			      face (face_),
    126 			      glyphs (glyphs_),
    127 			      len (len_),
    128 			      zero_context (zero_context_),
    129 			      debug_depth (0) {}
    130 };
    131 
    132 
    133 
    134 #ifndef HB_DEBUG_COLLECT_GLYPHS
    135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
    136 #endif
    137 
    138 #define TRACE_COLLECT_GLYPHS(this) \
    139 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
    140 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
    141 	 "");
    142 
    143 struct hb_collect_glyphs_context_t
    144 {
    145   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
    146   static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
    147   typedef hb_void_t return_t;
    148   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
    149   template <typename T>
    150   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
    151   static return_t default_return_value (void) { return HB_VOID; }
    152   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
    153   return_t recurse (unsigned int lookup_index)
    154   {
    155     if (unlikely (nesting_level_left == 0 || !recurse_func))
    156       return default_return_value ();
    157 
    158     /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
    159      * past the previous check.  For GSUB, we only want to collect the output
    160      * glyphs in the recursion.  If output is not requested, we can go home now.
    161      *
    162      * Note further, that the above is not exactly correct.  A recursed lookup
    163      * is allowed to match input that is not matched in the context, but that's
    164      * not how most fonts are built.  It's possible to relax that and recurse
    165      * with all sets here if it proves to be an issue.
    166      */
    167 
    168     if (output == hb_set_get_empty ())
    169       return HB_VOID;
    170 
    171     hb_set_t *old_before = before;
    172     hb_set_t *old_input  = input;
    173     hb_set_t *old_after  = after;
    174     before = input = after = hb_set_get_empty ();
    175 
    176     nesting_level_left--;
    177     recurse_func (this, lookup_index);
    178     nesting_level_left++;
    179 
    180     before = old_before;
    181     input  = old_input;
    182     after  = old_after;
    183 
    184     return HB_VOID;
    185   }
    186 
    187   hb_face_t *face;
    188   hb_set_t *before;
    189   hb_set_t *input;
    190   hb_set_t *after;
    191   hb_set_t *output;
    192   recurse_func_t recurse_func;
    193   unsigned int nesting_level_left;
    194   unsigned int debug_depth;
    195 
    196   hb_collect_glyphs_context_t (hb_face_t *face_,
    197 			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
    198 			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
    199 			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
    200 			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
    201 			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
    202 			      face (face_),
    203 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
    204 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
    205 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
    206 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
    207 			      recurse_func (NULL),
    208 			      nesting_level_left (nesting_level_left_),
    209 			      debug_depth (0) {}
    210 
    211   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
    212 };
    213 
    214 
    215 
    216 struct hb_get_coverage_context_t
    217 {
    218   inline const char *get_name (void) { return "GET_COVERAGE"; }
    219   static const unsigned int max_debug_depth = 0;
    220   typedef const Coverage &return_t;
    221   template <typename T>
    222   inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
    223   static return_t default_return_value (void) { return Null(Coverage); }
    224 
    225   hb_get_coverage_context_t (void) :
    226 			    debug_depth (0) {}
    227 
    228   unsigned int debug_depth;
    229 };
    230 
    231 
    232 
    233 #ifndef HB_DEBUG_APPLY
    234 #define HB_DEBUG_APPLY (HB_DEBUG+0)
    235 #endif
    236 
    237 #define TRACE_APPLY(this) \
    238 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
    239 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
    240 	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
    241 
    242 struct hb_apply_context_t
    243 {
    244   inline const char *get_name (void) { return "APPLY"; }
    245   static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
    246   typedef bool return_t;
    247   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
    248   template <typename T>
    249   inline return_t dispatch (const T &obj) { return obj.apply (this); }
    250   static return_t default_return_value (void) { return false; }
    251   bool stop_sublookup_iteration (return_t r) const { return r; }
    252   return_t recurse (unsigned int lookup_index)
    253   {
    254     if (unlikely (nesting_level_left == 0 || !recurse_func))
    255       return default_return_value ();
    256 
    257     nesting_level_left--;
    258     bool ret = recurse_func (this, lookup_index);
    259     nesting_level_left++;
    260     return ret;
    261   }
    262 
    263   unsigned int table_index; /* GSUB/GPOS */
    264   hb_font_t *font;
    265   hb_face_t *face;
    266   hb_buffer_t *buffer;
    267   hb_direction_t direction;
    268   hb_mask_t lookup_mask;
    269   bool auto_zwj;
    270   recurse_func_t recurse_func;
    271   unsigned int nesting_level_left;
    272   unsigned int lookup_props;
    273   const GDEF &gdef;
    274   bool has_glyph_classes;
    275   unsigned int debug_depth;
    276 
    277 
    278   hb_apply_context_t (unsigned int table_index_,
    279 		      hb_font_t *font_,
    280 		      hb_buffer_t *buffer_) :
    281 			table_index (table_index_),
    282 			font (font_), face (font->face), buffer (buffer_),
    283 			direction (buffer_->props.direction),
    284 			lookup_mask (1),
    285 			auto_zwj (true),
    286 			recurse_func (NULL),
    287 			nesting_level_left (MAX_NESTING_LEVEL),
    288 			lookup_props (0),
    289 			gdef (*hb_ot_layout_from_face (face)->gdef),
    290 			has_glyph_classes (gdef.has_glyph_classes ()),
    291 			debug_depth (0) {}
    292 
    293   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
    294   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
    295   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
    296   inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
    297   inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
    298 
    299   struct matcher_t
    300   {
    301     inline matcher_t (void) :
    302 	     lookup_props (0),
    303 	     ignore_zwnj (false),
    304 	     ignore_zwj (false),
    305 	     mask (-1),
    306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
    307 	     syllable arg1(0),
    308 #undef arg1
    309 	     match_func (NULL),
    310 	     match_data (NULL) {};
    311 
    312     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
    313 
    314     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
    315     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
    316     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
    317     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
    318     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
    319     inline void set_match_func (match_func_t match_func_,
    320 				const void *match_data_)
    321     { match_func = match_func_; match_data = match_data_; }
    322 
    323     enum may_match_t {
    324       MATCH_NO,
    325       MATCH_YES,
    326       MATCH_MAYBE
    327     };
    328 
    329     inline may_match_t may_match (const hb_glyph_info_t &info,
    330 				  const USHORT          *glyph_data) const
    331     {
    332       if (!(info.mask & mask) ||
    333 	  (syllable && syllable != info.syllable ()))
    334 	return MATCH_NO;
    335 
    336       if (match_func)
    337         return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
    338 
    339       return MATCH_MAYBE;
    340     }
    341 
    342     enum may_skip_t {
    343       SKIP_NO,
    344       SKIP_YES,
    345       SKIP_MAYBE
    346     };
    347 
    348     inline may_skip_t
    349     may_skip (const hb_apply_context_t *c,
    350 	      const hb_glyph_info_t    &info) const
    351     {
    352       unsigned int property;
    353 
    354       property = _hb_glyph_info_get_glyph_props (&info);
    355 
    356       if (!c->match_properties (info.codepoint, property, lookup_props))
    357 	return SKIP_YES;
    358 
    359       if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
    360 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
    361 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
    362 		    !_hb_glyph_info_ligated (&info)))
    363 	return SKIP_MAYBE;
    364 
    365       return SKIP_NO;
    366     }
    367 
    368     protected:
    369     unsigned int lookup_props;
    370     bool ignore_zwnj;
    371     bool ignore_zwj;
    372     hb_mask_t mask;
    373     uint8_t syllable;
    374     match_func_t match_func;
    375     const void *match_data;
    376   };
    377 
    378   struct skipping_forward_iterator_t
    379   {
    380     inline skipping_forward_iterator_t (hb_apply_context_t *c_,
    381 					unsigned int start_index_,
    382 					unsigned int num_items_,
    383 					bool context_match = false) :
    384 					 idx (start_index_),
    385 					 c (c_),
    386 					 match_glyph_data (NULL),
    387 					 num_items (num_items_),
    388 					 end (c->buffer->len)
    389     {
    390       matcher.set_lookup_props (c->lookup_props);
    391       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
    392       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
    393       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
    394       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
    395       if (!context_match)
    396 	matcher.set_mask (c->lookup_mask);
    397       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
    398     }
    399     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
    400     inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
    401     inline void set_match_func (matcher_t::match_func_t match_func,
    402 				const void *match_data,
    403 				const USHORT glyph_data[])
    404     {
    405       matcher.set_match_func (match_func, match_data);
    406       match_glyph_data = glyph_data;
    407     }
    408 
    409     inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
    410     inline void reject (void) { num_items++; match_glyph_data--; }
    411     inline bool next (void)
    412     {
    413       assert (num_items > 0);
    414       while (!has_no_chance ())
    415       {
    416 	idx++;
    417 	const hb_glyph_info_t &info = c->buffer->info[idx];
    418 
    419 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
    420 	if (unlikely (skip == matcher_t::SKIP_YES))
    421 	  continue;
    422 
    423 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
    424 	if (match == matcher_t::MATCH_YES ||
    425 	    (match == matcher_t::MATCH_MAYBE &&
    426 	     skip == matcher_t::SKIP_NO))
    427 	{
    428 	  num_items--;
    429 	  match_glyph_data++;
    430 	  return true;
    431 	}
    432 
    433 	if (skip == matcher_t::SKIP_NO)
    434 	  return false;
    435       }
    436       return false;
    437     }
    438 
    439     unsigned int idx;
    440     protected:
    441     hb_apply_context_t *c;
    442     matcher_t matcher;
    443     const USHORT *match_glyph_data;
    444 
    445     unsigned int num_items;
    446     unsigned int end;
    447   };
    448 
    449   struct skipping_backward_iterator_t
    450   {
    451     inline skipping_backward_iterator_t (hb_apply_context_t *c_,
    452 					 unsigned int start_index_,
    453 					 unsigned int num_items_,
    454 					 bool context_match = false) :
    455 					  idx (start_index_),
    456 					  c (c_),
    457 					  match_glyph_data (NULL),
    458 					  num_items (num_items_)
    459     {
    460       matcher.set_lookup_props (c->lookup_props);
    461       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
    462       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
    463       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
    464       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
    465       if (!context_match)
    466 	matcher.set_mask (c->lookup_mask);
    467       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
    468     }
    469     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
    470     inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
    471     inline void set_match_func (matcher_t::match_func_t match_func,
    472 				const void *match_data,
    473 				const USHORT glyph_data[])
    474     {
    475       matcher.set_match_func (match_func, match_data);
    476       match_glyph_data = glyph_data;
    477     }
    478 
    479     inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
    480     inline void reject (void) { num_items++; }
    481     inline bool prev (void)
    482     {
    483       assert (num_items > 0);
    484       while (!has_no_chance ())
    485       {
    486 	idx--;
    487 	const hb_glyph_info_t &info = c->buffer->out_info[idx];
    488 
    489 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
    490 
    491 	if (unlikely (skip == matcher_t::SKIP_YES))
    492 	  continue;
    493 
    494 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
    495 	if (match == matcher_t::MATCH_YES ||
    496 	    (match == matcher_t::MATCH_MAYBE &&
    497 	     skip == matcher_t::SKIP_NO))
    498 	{
    499 	  num_items--;
    500 	  match_glyph_data++;
    501 	  return true;
    502 	}
    503 
    504 	if (skip == matcher_t::SKIP_NO)
    505 	  return false;
    506       }
    507       return false;
    508     }
    509 
    510     unsigned int idx;
    511     protected:
    512     hb_apply_context_t *c;
    513     matcher_t matcher;
    514     const USHORT *match_glyph_data;
    515 
    516     unsigned int num_items;
    517   };
    518 
    519   inline bool
    520   match_properties_mark (hb_codepoint_t  glyph,
    521 			 unsigned int    glyph_props,
    522 			 unsigned int    lookup_props) const
    523   {
    524     /* If using mark filtering sets, the high short of
    525      * lookup_props has the set index.
    526      */
    527     if (lookup_props & LookupFlag::UseMarkFilteringSet)
    528       return gdef.mark_set_covers (lookup_props >> 16, glyph);
    529 
    530     /* The second byte of lookup_props has the meaning
    531      * "ignore marks of attachment type different than
    532      * the attachment type specified."
    533      */
    534     if (lookup_props & LookupFlag::MarkAttachmentType)
    535       return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
    536 
    537     return true;
    538   }
    539 
    540   inline bool
    541   match_properties (hb_codepoint_t  glyph,
    542 		    unsigned int    glyph_props,
    543 		    unsigned int    lookup_props) const
    544   {
    545     /* Not covered, if, for example, glyph class is ligature and
    546      * lookup_props includes LookupFlags::IgnoreLigatures
    547      */
    548     if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
    549       return false;
    550 
    551     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
    552       return match_properties_mark (glyph, glyph_props, lookup_props);
    553 
    554     return true;
    555   }
    556 
    557   inline bool
    558   check_glyph_property (hb_glyph_info_t *info,
    559 			unsigned int  lookup_props) const
    560   {
    561     unsigned int property;
    562 
    563     property = _hb_glyph_info_get_glyph_props (info);
    564 
    565     return match_properties (info->codepoint, property, lookup_props);
    566   }
    567 
    568   inline void _set_glyph_props (hb_codepoint_t glyph_index,
    569 			  unsigned int class_guess = 0,
    570 			  bool ligature = false) const
    571   {
    572     unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
    573 			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
    574     add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
    575     if (ligature)
    576       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
    577     if (likely (has_glyph_classes))
    578       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
    579     else if (class_guess)
    580       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
    581   }
    582 
    583   inline void replace_glyph (hb_codepoint_t glyph_index) const
    584   {
    585     _set_glyph_props (glyph_index);
    586     buffer->replace_glyph (glyph_index);
    587   }
    588   inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
    589   {
    590     _set_glyph_props (glyph_index);
    591     buffer->cur().codepoint = glyph_index;
    592   }
    593   inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
    594 					   unsigned int class_guess) const
    595   {
    596     _set_glyph_props (glyph_index, class_guess, true);
    597     buffer->replace_glyph (glyph_index);
    598   }
    599   inline void output_glyph (hb_codepoint_t glyph_index,
    600 			    unsigned int class_guess) const
    601   {
    602     _set_glyph_props (glyph_index, class_guess);
    603     buffer->output_glyph (glyph_index);
    604   }
    605 };
    606 
    607 
    608 
    609 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
    610 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
    611 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
    612 
    613 struct ContextClosureFuncs
    614 {
    615   intersects_func_t intersects;
    616 };
    617 struct ContextCollectGlyphsFuncs
    618 {
    619   collect_glyphs_func_t collect;
    620 };
    621 struct ContextApplyFuncs
    622 {
    623   match_func_t match;
    624 };
    625 
    626 
    627 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
    628 {
    629   return glyphs->has (value);
    630 }
    631 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
    632 {
    633   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
    634   return class_def.intersects_class (glyphs, value);
    635 }
    636 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
    637 {
    638   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
    639   return (data+coverage).intersects (glyphs);
    640 }
    641 
    642 static inline bool intersects_array (hb_closure_context_t *c,
    643 				     unsigned int count,
    644 				     const USHORT values[],
    645 				     intersects_func_t intersects_func,
    646 				     const void *intersects_data)
    647 {
    648   for (unsigned int i = 0; i < count; i++)
    649     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
    650       return false;
    651   return true;
    652 }
    653 
    654 
    655 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
    656 {
    657   glyphs->add (value);
    658 }
    659 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
    660 {
    661   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
    662   class_def.add_class (glyphs, value);
    663 }
    664 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
    665 {
    666   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
    667   (data+coverage).add_coverage (glyphs);
    668 }
    669 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
    670 				  hb_set_t *glyphs,
    671 				  unsigned int count,
    672 				  const USHORT values[],
    673 				  collect_glyphs_func_t collect_func,
    674 				  const void *collect_data)
    675 {
    676   for (unsigned int i = 0; i < count; i++)
    677     collect_func (glyphs, values[i], collect_data);
    678 }
    679 
    680 
    681 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
    682 {
    683   return glyph_id == value;
    684 }
    685 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
    686 {
    687   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
    688   return class_def.get_class (glyph_id) == value;
    689 }
    690 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
    691 {
    692   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
    693   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
    694 }
    695 
    696 static inline bool would_match_input (hb_would_apply_context_t *c,
    697 				      unsigned int count, /* Including the first glyph (not matched) */
    698 				      const USHORT input[], /* Array of input values--start with second glyph */
    699 				      match_func_t match_func,
    700 				      const void *match_data)
    701 {
    702   if (count != c->len)
    703     return false;
    704 
    705   for (unsigned int i = 1; i < count; i++)
    706     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
    707       return false;
    708 
    709   return true;
    710 }
    711 static inline bool match_input (hb_apply_context_t *c,
    712 				unsigned int count, /* Including the first glyph (not matched) */
    713 				const USHORT input[], /* Array of input values--start with second glyph */
    714 				match_func_t match_func,
    715 				const void *match_data,
    716 				unsigned int *end_offset,
    717 				unsigned int match_positions[MAX_CONTEXT_LENGTH],
    718 				bool *p_is_mark_ligature = NULL,
    719 				unsigned int *p_total_component_count = NULL)
    720 {
    721   TRACE_APPLY (NULL);
    722 
    723   if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
    724 
    725   hb_buffer_t *buffer = c->buffer;
    726 
    727   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
    728   skippy_iter.set_match_func (match_func, match_data, input);
    729   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
    730 
    731   /*
    732    * This is perhaps the trickiest part of OpenType...  Remarks:
    733    *
    734    * - If all components of the ligature were marks, we call this a mark ligature.
    735    *
    736    * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
    737    *   it as a ligature glyph.
    738    *
    739    * - Ligatures cannot be formed across glyphs attached to different components
    740    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
    741    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
    742    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
    743    *   There is an exception to this: If a ligature tries ligating with marks that
    744    *   belong to it itself, go ahead, assuming that the font designer knows what
    745    *   they are doing (otherwise it can break Indic stuff when a matra wants to
    746    *   ligate with a conjunct...)
    747    */
    748 
    749   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
    750 
    751   unsigned int total_component_count = 0;
    752   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
    753 
    754   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    755   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
    756 
    757   match_positions[0] = buffer->idx;
    758   for (unsigned int i = 1; i < count; i++)
    759   {
    760     if (!skippy_iter.next ()) return TRACE_RETURN (false);
    761 
    762     match_positions[i] = skippy_iter.idx;
    763 
    764     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
    765     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
    766 
    767     if (first_lig_id && first_lig_comp) {
    768       /* If first component was attached to a previous ligature component,
    769        * all subsequent components should be attached to the same ligature
    770        * component, otherwise we shouldn't ligate them. */
    771       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
    772 	return TRACE_RETURN (false);
    773     } else {
    774       /* If first component was NOT attached to a previous ligature component,
    775        * all subsequent components should also NOT be attached to any ligature
    776        * component, unless they are attached to the first component itself! */
    777       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
    778 	return TRACE_RETURN (false);
    779     }
    780 
    781     is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
    782     total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
    783   }
    784 
    785   *end_offset = skippy_iter.idx - buffer->idx + 1;
    786 
    787   if (p_is_mark_ligature)
    788     *p_is_mark_ligature = is_mark_ligature;
    789 
    790   if (p_total_component_count)
    791     *p_total_component_count = total_component_count;
    792 
    793   return TRACE_RETURN (true);
    794 }
    795 static inline void ligate_input (hb_apply_context_t *c,
    796 				 unsigned int count, /* Including the first glyph */
    797 				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
    798 				 unsigned int match_length,
    799 				 hb_codepoint_t lig_glyph,
    800 				 bool is_mark_ligature,
    801 				 unsigned int total_component_count)
    802 {
    803   TRACE_APPLY (NULL);
    804 
    805   hb_buffer_t *buffer = c->buffer;
    806 
    807   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
    808 
    809   /*
    810    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
    811    *   the ligature to keep its old ligature id.  This will allow it to attach to
    812    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
    813    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
    814    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
    815    *   later, we don't want them to lose their ligature id/component, otherwise
    816    *   GPOS will fail to correctly position the mark ligature on top of the
    817    *   LAM,LAM,HEH ligature.  See:
    818    *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
    819    *
    820    * - If a ligature is formed of components that some of which are also ligatures
    821    *   themselves, and those ligature components had marks attached to *their*
    822    *   components, we have to attach the marks to the new ligature component
    823    *   positions!  Now *that*'s tricky!  And these marks may be following the
    824    *   last component of the whole sequence, so we should loop forward looking
    825    *   for them and update them.
    826    *
    827    *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
    828    *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
    829    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
    830    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
    831    *   the new ligature with a component value of 2.
    832    *
    833    *   This in fact happened to a font...  See:
    834    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
    835    */
    836 
    837   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
    838   unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
    839   unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    840   unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
    841   unsigned int components_so_far = last_num_components;
    842 
    843   if (!is_mark_ligature)
    844   {
    845     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
    846     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    847     {
    848       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
    849       _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
    850     }
    851   }
    852   c->replace_glyph_with_ligature (lig_glyph, klass);
    853 
    854   for (unsigned int i = 1; i < count; i++)
    855   {
    856     while (buffer->idx < match_positions[i])
    857     {
    858       if (!is_mark_ligature) {
    859 	unsigned int new_lig_comp = components_so_far - last_num_components +
    860 				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
    861 	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
    862       }
    863       buffer->next_glyph ();
    864     }
    865 
    866     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    867     last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
    868     components_so_far += last_num_components;
    869 
    870     /* Skip the base glyph */
    871     buffer->idx++;
    872   }
    873 
    874   if (!is_mark_ligature && last_lig_id) {
    875     /* Re-adjust components for any marks following. */
    876     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
    877       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
    878 	unsigned int new_lig_comp = components_so_far - last_num_components +
    879 				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
    880 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
    881       } else
    882 	break;
    883     }
    884   }
    885 }
    886 
    887 static inline bool match_backtrack (hb_apply_context_t *c,
    888 				    unsigned int count,
    889 				    const USHORT backtrack[],
    890 				    match_func_t match_func,
    891 				    const void *match_data)
    892 {
    893   TRACE_APPLY (NULL);
    894 
    895   hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
    896   skippy_iter.set_match_func (match_func, match_data, backtrack);
    897   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
    898 
    899   for (unsigned int i = 0; i < count; i++)
    900     if (!skippy_iter.prev ())
    901       return TRACE_RETURN (false);
    902 
    903   return TRACE_RETURN (true);
    904 }
    905 
    906 static inline bool match_lookahead (hb_apply_context_t *c,
    907 				    unsigned int count,
    908 				    const USHORT lookahead[],
    909 				    match_func_t match_func,
    910 				    const void *match_data,
    911 				    unsigned int offset)
    912 {
    913   TRACE_APPLY (NULL);
    914 
    915   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
    916   skippy_iter.set_match_func (match_func, match_data, lookahead);
    917   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
    918 
    919   for (unsigned int i = 0; i < count; i++)
    920     if (!skippy_iter.next ())
    921       return TRACE_RETURN (false);
    922 
    923   return TRACE_RETURN (true);
    924 }
    925 
    926 
    927 
    928 struct LookupRecord
    929 {
    930   inline bool sanitize (hb_sanitize_context_t *c) {
    931     TRACE_SANITIZE (this);
    932     return TRACE_RETURN (c->check_struct (this));
    933   }
    934 
    935   USHORT	sequenceIndex;		/* Index into current glyph
    936 					 * sequence--first glyph = 0 */
    937   USHORT	lookupListIndex;	/* Lookup to apply to that
    938 					 * position--zero--based */
    939   public:
    940   DEFINE_SIZE_STATIC (4);
    941 };
    942 
    943 
    944 template <typename context_t>
    945 static inline void recurse_lookups (context_t *c,
    946 				    unsigned int lookupCount,
    947 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
    948 {
    949   for (unsigned int i = 0; i < lookupCount; i++)
    950     c->recurse (lookupRecord[i].lookupListIndex);
    951 }
    952 
    953 static inline bool apply_lookup (hb_apply_context_t *c,
    954 				 unsigned int count, /* Including the first glyph */
    955 				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
    956 				 unsigned int lookupCount,
    957 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
    958 				 unsigned int match_length)
    959 {
    960   TRACE_APPLY (NULL);
    961 
    962   hb_buffer_t *buffer = c->buffer;
    963   unsigned int end;
    964 
    965   /* All positions are distance from beginning of *output* buffer.
    966    * Adjust. */
    967   {
    968     unsigned int bl = buffer->backtrack_len ();
    969     end = bl + match_length;
    970 
    971     int delta = bl - buffer->idx;
    972     /* Convert positions to new indexing. */
    973     for (unsigned int j = 0; j < count; j++)
    974       match_positions[j] += delta;
    975   }
    976 
    977   for (unsigned int i = 0; i < lookupCount; i++)
    978   {
    979     unsigned int idx = lookupRecord[i].sequenceIndex;
    980     if (idx >= count)
    981       continue;
    982 
    983     buffer->move_to (match_positions[idx]);
    984 
    985     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
    986     if (!c->recurse (lookupRecord[i].lookupListIndex))
    987       continue;
    988 
    989     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
    990     int delta = new_len - orig_len;
    991 
    992     if (!delta)
    993         continue;
    994 
    995     /* Recursed lookup changed buffer len.  Adjust. */
    996 
    997     /* end can't go back past the current match position. */
    998     end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
    999 
   1000     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
   1001 
   1002     if (delta > 0)
   1003     {
   1004       if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
   1005 	break;
   1006     }
   1007     else
   1008     {
   1009       /* NOTE: delta is negative. */
   1010       delta = MAX (delta, (int) next - (int) count);
   1011       next -= delta;
   1012     }
   1013 
   1014     /* Shift! */
   1015     memmove (match_positions + next + delta, match_positions + next,
   1016 	     (count - next) * sizeof (match_positions[0]));
   1017     next += delta;
   1018     count += delta;
   1019 
   1020     /* Fill in new entries. */
   1021     for (unsigned int j = idx + 1; j < next; j++)
   1022       match_positions[j] = match_positions[j - 1] + 1;
   1023 
   1024     /* And fixup the rest. */
   1025     for (; next < count; next++)
   1026       match_positions[next] += delta;
   1027   }
   1028 
   1029   buffer->move_to (end);
   1030 
   1031   return TRACE_RETURN (true);
   1032 }
   1033 
   1034 
   1035 
   1036 /* Contextual lookups */
   1037 
   1038 struct ContextClosureLookupContext
   1039 {
   1040   ContextClosureFuncs funcs;
   1041   const void *intersects_data;
   1042 };
   1043 
   1044 struct ContextCollectGlyphsLookupContext
   1045 {
   1046   ContextCollectGlyphsFuncs funcs;
   1047   const void *collect_data;
   1048 };
   1049 
   1050 struct ContextApplyLookupContext
   1051 {
   1052   ContextApplyFuncs funcs;
   1053   const void *match_data;
   1054 };
   1055 
   1056 static inline void context_closure_lookup (hb_closure_context_t *c,
   1057 					   unsigned int inputCount, /* Including the first glyph (not matched) */
   1058 					   const USHORT input[], /* Array of input values--start with second glyph */
   1059 					   unsigned int lookupCount,
   1060 					   const LookupRecord lookupRecord[],
   1061 					   ContextClosureLookupContext &lookup_context)
   1062 {
   1063   if (intersects_array (c,
   1064 			inputCount ? inputCount - 1 : 0, input,
   1065 			lookup_context.funcs.intersects, lookup_context.intersects_data))
   1066     recurse_lookups (c,
   1067 		     lookupCount, lookupRecord);
   1068 }
   1069 
   1070 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
   1071 						  unsigned int inputCount, /* Including the first glyph (not matched) */
   1072 						  const USHORT input[], /* Array of input values--start with second glyph */
   1073 						  unsigned int lookupCount,
   1074 						  const LookupRecord lookupRecord[],
   1075 						  ContextCollectGlyphsLookupContext &lookup_context)
   1076 {
   1077   collect_array (c, c->input,
   1078 		 inputCount ? inputCount - 1 : 0, input,
   1079 		 lookup_context.funcs.collect, lookup_context.collect_data);
   1080   recurse_lookups (c,
   1081 		   lookupCount, lookupRecord);
   1082 }
   1083 
   1084 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
   1085 					       unsigned int inputCount, /* Including the first glyph (not matched) */
   1086 					       const USHORT input[], /* Array of input values--start with second glyph */
   1087 					       unsigned int lookupCount HB_UNUSED,
   1088 					       const LookupRecord lookupRecord[] HB_UNUSED,
   1089 					       ContextApplyLookupContext &lookup_context)
   1090 {
   1091   return would_match_input (c,
   1092 			    inputCount, input,
   1093 			    lookup_context.funcs.match, lookup_context.match_data);
   1094 }
   1095 static inline bool context_apply_lookup (hb_apply_context_t *c,
   1096 					 unsigned int inputCount, /* Including the first glyph (not matched) */
   1097 					 const USHORT input[], /* Array of input values--start with second glyph */
   1098 					 unsigned int lookupCount,
   1099 					 const LookupRecord lookupRecord[],
   1100 					 ContextApplyLookupContext &lookup_context)
   1101 {
   1102   unsigned int match_length = 0;
   1103   unsigned int match_positions[MAX_CONTEXT_LENGTH];
   1104   return match_input (c,
   1105 		      inputCount, input,
   1106 		      lookup_context.funcs.match, lookup_context.match_data,
   1107 		      &match_length, match_positions)
   1108       && apply_lookup (c,
   1109 		       inputCount, match_positions,
   1110 		       lookupCount, lookupRecord,
   1111 		       match_length);
   1112 }
   1113 
   1114 struct Rule
   1115 {
   1116   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   1117   {
   1118     TRACE_CLOSURE (this);
   1119     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
   1120     context_closure_lookup (c,
   1121 			    inputCount, input,
   1122 			    lookupCount, lookupRecord,
   1123 			    lookup_context);
   1124   }
   1125 
   1126   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
   1127   {
   1128     TRACE_COLLECT_GLYPHS (this);
   1129     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
   1130     context_collect_glyphs_lookup (c,
   1131 				   inputCount, input,
   1132 				   lookupCount, lookupRecord,
   1133 				   lookup_context);
   1134   }
   1135 
   1136   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   1137   {
   1138     TRACE_WOULD_APPLY (this);
   1139     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
   1140     return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   1141   }
   1142 
   1143   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   1144   {
   1145     TRACE_APPLY (this);
   1146     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
   1147     return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   1148   }
   1149 
   1150   public:
   1151   inline bool sanitize (hb_sanitize_context_t *c) {
   1152     TRACE_SANITIZE (this);
   1153     return inputCount.sanitize (c)
   1154 	&& lookupCount.sanitize (c)
   1155 	&& c->check_range (input,
   1156 			   input[0].static_size * inputCount
   1157 			   + lookupRecordX[0].static_size * lookupCount);
   1158   }
   1159 
   1160   protected:
   1161   USHORT	inputCount;		/* Total number of glyphs in input
   1162 					 * glyph sequence--includes the first
   1163 					 * glyph */
   1164   USHORT	lookupCount;		/* Number of LookupRecords */
   1165   USHORT	input[VAR];		/* Array of match inputs--start with
   1166 					 * second glyph */
   1167   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
   1168 					 * design order */
   1169   public:
   1170   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
   1171 };
   1172 
   1173 struct RuleSet
   1174 {
   1175   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   1176   {
   1177     TRACE_CLOSURE (this);
   1178     unsigned int num_rules = rule.len;
   1179     for (unsigned int i = 0; i < num_rules; i++)
   1180       (this+rule[i]).closure (c, lookup_context);
   1181   }
   1182 
   1183   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
   1184   {
   1185     TRACE_COLLECT_GLYPHS (this);
   1186     unsigned int num_rules = rule.len;
   1187     for (unsigned int i = 0; i < num_rules; i++)
   1188       (this+rule[i]).collect_glyphs (c, lookup_context);
   1189   }
   1190 
   1191   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   1192   {
   1193     TRACE_WOULD_APPLY (this);
   1194     unsigned int num_rules = rule.len;
   1195     for (unsigned int i = 0; i < num_rules; i++)
   1196     {
   1197       if ((this+rule[i]).would_apply (c, lookup_context))
   1198         return TRACE_RETURN (true);
   1199     }
   1200     return TRACE_RETURN (false);
   1201   }
   1202 
   1203   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   1204   {
   1205     TRACE_APPLY (this);
   1206     unsigned int num_rules = rule.len;
   1207     for (unsigned int i = 0; i < num_rules; i++)
   1208     {
   1209       if ((this+rule[i]).apply (c, lookup_context))
   1210         return TRACE_RETURN (true);
   1211     }
   1212     return TRACE_RETURN (false);
   1213   }
   1214 
   1215   inline bool sanitize (hb_sanitize_context_t *c) {
   1216     TRACE_SANITIZE (this);
   1217     return TRACE_RETURN (rule.sanitize (c, this));
   1218   }
   1219 
   1220   protected:
   1221   OffsetArrayOf<Rule>
   1222 		rule;			/* Array of Rule tables
   1223 					 * ordered by preference */
   1224   public:
   1225   DEFINE_SIZE_ARRAY (2, rule);
   1226 };
   1227 
   1228 
   1229 struct ContextFormat1
   1230 {
   1231   inline void closure (hb_closure_context_t *c) const
   1232   {
   1233     TRACE_CLOSURE (this);
   1234 
   1235     const Coverage &cov = (this+coverage);
   1236 
   1237     struct ContextClosureLookupContext lookup_context = {
   1238       {intersects_glyph},
   1239       NULL
   1240     };
   1241 
   1242     unsigned int count = ruleSet.len;
   1243     for (unsigned int i = 0; i < count; i++)
   1244       if (cov.intersects_coverage (c->glyphs, i)) {
   1245 	const RuleSet &rule_set = this+ruleSet[i];
   1246 	rule_set.closure (c, lookup_context);
   1247       }
   1248   }
   1249 
   1250   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1251   {
   1252     TRACE_COLLECT_GLYPHS (this);
   1253     (this+coverage).add_coverage (c->input);
   1254 
   1255     struct ContextCollectGlyphsLookupContext lookup_context = {
   1256       {collect_glyph},
   1257       NULL
   1258     };
   1259 
   1260     unsigned int count = ruleSet.len;
   1261     for (unsigned int i = 0; i < count; i++)
   1262       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   1263   }
   1264 
   1265   inline bool would_apply (hb_would_apply_context_t *c) const
   1266   {
   1267     TRACE_WOULD_APPLY (this);
   1268 
   1269     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
   1270     struct ContextApplyLookupContext lookup_context = {
   1271       {match_glyph},
   1272       NULL
   1273     };
   1274     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   1275   }
   1276 
   1277   inline const Coverage &get_coverage (void) const
   1278   {
   1279     return this+coverage;
   1280   }
   1281 
   1282   inline bool apply (hb_apply_context_t *c) const
   1283   {
   1284     TRACE_APPLY (this);
   1285     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
   1286     if (likely (index == NOT_COVERED))
   1287       return TRACE_RETURN (false);
   1288 
   1289     const RuleSet &rule_set = this+ruleSet[index];
   1290     struct ContextApplyLookupContext lookup_context = {
   1291       {match_glyph},
   1292       NULL
   1293     };
   1294     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   1295   }
   1296 
   1297   inline bool sanitize (hb_sanitize_context_t *c) {
   1298     TRACE_SANITIZE (this);
   1299     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   1300   }
   1301 
   1302   protected:
   1303   USHORT	format;			/* Format identifier--format = 1 */
   1304   OffsetTo<Coverage>
   1305 		coverage;		/* Offset to Coverage table--from
   1306 					 * beginning of table */
   1307   OffsetArrayOf<RuleSet>
   1308 		ruleSet;		/* Array of RuleSet tables
   1309 					 * ordered by Coverage Index */
   1310   public:
   1311   DEFINE_SIZE_ARRAY (6, ruleSet);
   1312 };
   1313 
   1314 
   1315 struct ContextFormat2
   1316 {
   1317   inline void closure (hb_closure_context_t *c) const
   1318   {
   1319     TRACE_CLOSURE (this);
   1320     if (!(this+coverage).intersects (c->glyphs))
   1321       return;
   1322 
   1323     const ClassDef &class_def = this+classDef;
   1324 
   1325     struct ContextClosureLookupContext lookup_context = {
   1326       {intersects_class},
   1327       &class_def
   1328     };
   1329 
   1330     unsigned int count = ruleSet.len;
   1331     for (unsigned int i = 0; i < count; i++)
   1332       if (class_def.intersects_class (c->glyphs, i)) {
   1333 	const RuleSet &rule_set = this+ruleSet[i];
   1334 	rule_set.closure (c, lookup_context);
   1335       }
   1336   }
   1337 
   1338   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1339   {
   1340     TRACE_COLLECT_GLYPHS (this);
   1341     (this+coverage).add_coverage (c->input);
   1342 
   1343     const ClassDef &class_def = this+classDef;
   1344     struct ContextCollectGlyphsLookupContext lookup_context = {
   1345       {collect_class},
   1346       &class_def
   1347     };
   1348 
   1349     unsigned int count = ruleSet.len;
   1350     for (unsigned int i = 0; i < count; i++)
   1351       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   1352   }
   1353 
   1354   inline bool would_apply (hb_would_apply_context_t *c) const
   1355   {
   1356     TRACE_WOULD_APPLY (this);
   1357 
   1358     const ClassDef &class_def = this+classDef;
   1359     unsigned int index = class_def.get_class (c->glyphs[0]);
   1360     const RuleSet &rule_set = this+ruleSet[index];
   1361     struct ContextApplyLookupContext lookup_context = {
   1362       {match_class},
   1363       &class_def
   1364     };
   1365     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   1366   }
   1367 
   1368   inline const Coverage &get_coverage (void) const
   1369   {
   1370     return this+coverage;
   1371   }
   1372 
   1373   inline bool apply (hb_apply_context_t *c) const
   1374   {
   1375     TRACE_APPLY (this);
   1376     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
   1377     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1378 
   1379     const ClassDef &class_def = this+classDef;
   1380     index = class_def.get_class (c->buffer->cur().codepoint);
   1381     const RuleSet &rule_set = this+ruleSet[index];
   1382     struct ContextApplyLookupContext lookup_context = {
   1383       {match_class},
   1384       &class_def
   1385     };
   1386     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   1387   }
   1388 
   1389   inline bool sanitize (hb_sanitize_context_t *c) {
   1390     TRACE_SANITIZE (this);
   1391     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   1392   }
   1393 
   1394   protected:
   1395   USHORT	format;			/* Format identifier--format = 2 */
   1396   OffsetTo<Coverage>
   1397 		coverage;		/* Offset to Coverage table--from
   1398 					 * beginning of table */
   1399   OffsetTo<ClassDef>
   1400 		classDef;		/* Offset to glyph ClassDef table--from
   1401 					 * beginning of table */
   1402   OffsetArrayOf<RuleSet>
   1403 		ruleSet;		/* Array of RuleSet tables
   1404 					 * ordered by class */
   1405   public:
   1406   DEFINE_SIZE_ARRAY (8, ruleSet);
   1407 };
   1408 
   1409 
   1410 struct ContextFormat3
   1411 {
   1412   inline void closure (hb_closure_context_t *c) const
   1413   {
   1414     TRACE_CLOSURE (this);
   1415     if (!(this+coverage[0]).intersects (c->glyphs))
   1416       return;
   1417 
   1418     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
   1419     struct ContextClosureLookupContext lookup_context = {
   1420       {intersects_coverage},
   1421       this
   1422     };
   1423     context_closure_lookup (c,
   1424 			    glyphCount, (const USHORT *) (coverage + 1),
   1425 			    lookupCount, lookupRecord,
   1426 			    lookup_context);
   1427   }
   1428 
   1429   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1430   {
   1431     TRACE_COLLECT_GLYPHS (this);
   1432     (this+coverage[0]).add_coverage (c->input);
   1433 
   1434     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
   1435     struct ContextCollectGlyphsLookupContext lookup_context = {
   1436       {collect_coverage},
   1437       this
   1438     };
   1439 
   1440     context_collect_glyphs_lookup (c,
   1441 				   glyphCount, (const USHORT *) (coverage + 1),
   1442 				   lookupCount, lookupRecord,
   1443 				   lookup_context);
   1444   }
   1445 
   1446   inline bool would_apply (hb_would_apply_context_t *c) const
   1447   {
   1448     TRACE_WOULD_APPLY (this);
   1449 
   1450     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
   1451     struct ContextApplyLookupContext lookup_context = {
   1452       {match_coverage},
   1453       this
   1454     };
   1455     return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
   1456   }
   1457 
   1458   inline const Coverage &get_coverage (void) const
   1459   {
   1460     return this+coverage[0];
   1461   }
   1462 
   1463   inline bool apply (hb_apply_context_t *c) const
   1464   {
   1465     TRACE_APPLY (this);
   1466     unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
   1467     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1468 
   1469     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
   1470     struct ContextApplyLookupContext lookup_context = {
   1471       {match_coverage},
   1472       this
   1473     };
   1474     return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
   1475   }
   1476 
   1477   inline bool sanitize (hb_sanitize_context_t *c) {
   1478     TRACE_SANITIZE (this);
   1479     if (!c->check_struct (this)) return TRACE_RETURN (false);
   1480     unsigned int count = glyphCount;
   1481     if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
   1482     for (unsigned int i = 0; i < count; i++)
   1483       if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
   1484     LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
   1485     return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   1486   }
   1487 
   1488   protected:
   1489   USHORT	format;			/* Format identifier--format = 3 */
   1490   USHORT	glyphCount;		/* Number of glyphs in the input glyph
   1491 					 * sequence */
   1492   USHORT	lookupCount;		/* Number of LookupRecords */
   1493   OffsetTo<Coverage>
   1494 		coverage[VAR];		/* Array of offsets to Coverage
   1495 					 * table in glyph sequence order */
   1496   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
   1497 					 * design order */
   1498   public:
   1499   DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
   1500 };
   1501 
   1502 struct Context
   1503 {
   1504   template <typename context_t>
   1505   inline typename context_t::return_t dispatch (context_t *c) const
   1506   {
   1507     TRACE_DISPATCH (this);
   1508     switch (u.format) {
   1509     case 1: return TRACE_RETURN (c->dispatch (u.format1));
   1510     case 2: return TRACE_RETURN (c->dispatch (u.format2));
   1511     case 3: return TRACE_RETURN (c->dispatch (u.format3));
   1512     default:return TRACE_RETURN (c->default_return_value ());
   1513     }
   1514   }
   1515 
   1516   inline bool sanitize (hb_sanitize_context_t *c) {
   1517     TRACE_SANITIZE (this);
   1518     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   1519     switch (u.format) {
   1520     case 1: return TRACE_RETURN (u.format1.sanitize (c));
   1521     case 2: return TRACE_RETURN (u.format2.sanitize (c));
   1522     case 3: return TRACE_RETURN (u.format3.sanitize (c));
   1523     default:return TRACE_RETURN (true);
   1524     }
   1525   }
   1526 
   1527   protected:
   1528   union {
   1529   USHORT		format;		/* Format identifier */
   1530   ContextFormat1	format1;
   1531   ContextFormat2	format2;
   1532   ContextFormat3	format3;
   1533   } u;
   1534 };
   1535 
   1536 
   1537 /* Chaining Contextual lookups */
   1538 
   1539 struct ChainContextClosureLookupContext
   1540 {
   1541   ContextClosureFuncs funcs;
   1542   const void *intersects_data[3];
   1543 };
   1544 
   1545 struct ChainContextCollectGlyphsLookupContext
   1546 {
   1547   ContextCollectGlyphsFuncs funcs;
   1548   const void *collect_data[3];
   1549 };
   1550 
   1551 struct ChainContextApplyLookupContext
   1552 {
   1553   ContextApplyFuncs funcs;
   1554   const void *match_data[3];
   1555 };
   1556 
   1557 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
   1558 						 unsigned int backtrackCount,
   1559 						 const USHORT backtrack[],
   1560 						 unsigned int inputCount, /* Including the first glyph (not matched) */
   1561 						 const USHORT input[], /* Array of input values--start with second glyph */
   1562 						 unsigned int lookaheadCount,
   1563 						 const USHORT lookahead[],
   1564 						 unsigned int lookupCount,
   1565 						 const LookupRecord lookupRecord[],
   1566 						 ChainContextClosureLookupContext &lookup_context)
   1567 {
   1568   if (intersects_array (c,
   1569 			backtrackCount, backtrack,
   1570 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
   1571    && intersects_array (c,
   1572 			inputCount ? inputCount - 1 : 0, input,
   1573 			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
   1574    && intersects_array (c,
   1575 		       lookaheadCount, lookahead,
   1576 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
   1577     recurse_lookups (c,
   1578 		     lookupCount, lookupRecord);
   1579 }
   1580 
   1581 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
   1582 						        unsigned int backtrackCount,
   1583 						        const USHORT backtrack[],
   1584 						        unsigned int inputCount, /* Including the first glyph (not matched) */
   1585 						        const USHORT input[], /* Array of input values--start with second glyph */
   1586 						        unsigned int lookaheadCount,
   1587 						        const USHORT lookahead[],
   1588 						        unsigned int lookupCount,
   1589 						        const LookupRecord lookupRecord[],
   1590 						        ChainContextCollectGlyphsLookupContext &lookup_context)
   1591 {
   1592   collect_array (c, c->before,
   1593 		 backtrackCount, backtrack,
   1594 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
   1595   collect_array (c, c->input,
   1596 		 inputCount ? inputCount - 1 : 0, input,
   1597 		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
   1598   collect_array (c, c->after,
   1599 		 lookaheadCount, lookahead,
   1600 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
   1601   recurse_lookups (c,
   1602 		   lookupCount, lookupRecord);
   1603 }
   1604 
   1605 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
   1606 						     unsigned int backtrackCount,
   1607 						     const USHORT backtrack[] HB_UNUSED,
   1608 						     unsigned int inputCount, /* Including the first glyph (not matched) */
   1609 						     const USHORT input[], /* Array of input values--start with second glyph */
   1610 						     unsigned int lookaheadCount,
   1611 						     const USHORT lookahead[] HB_UNUSED,
   1612 						     unsigned int lookupCount HB_UNUSED,
   1613 						     const LookupRecord lookupRecord[] HB_UNUSED,
   1614 						     ChainContextApplyLookupContext &lookup_context)
   1615 {
   1616   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
   1617       && would_match_input (c,
   1618 			    inputCount, input,
   1619 			    lookup_context.funcs.match, lookup_context.match_data[1]);
   1620 }
   1621 
   1622 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
   1623 					       unsigned int backtrackCount,
   1624 					       const USHORT backtrack[],
   1625 					       unsigned int inputCount, /* Including the first glyph (not matched) */
   1626 					       const USHORT input[], /* Array of input values--start with second glyph */
   1627 					       unsigned int lookaheadCount,
   1628 					       const USHORT lookahead[],
   1629 					       unsigned int lookupCount,
   1630 					       const LookupRecord lookupRecord[],
   1631 					       ChainContextApplyLookupContext &lookup_context)
   1632 {
   1633   unsigned int match_length = 0;
   1634   unsigned int match_positions[MAX_CONTEXT_LENGTH];
   1635   return match_input (c,
   1636 		      inputCount, input,
   1637 		      lookup_context.funcs.match, lookup_context.match_data[1],
   1638 		      &match_length, match_positions)
   1639       && match_backtrack (c,
   1640 			  backtrackCount, backtrack,
   1641 			  lookup_context.funcs.match, lookup_context.match_data[0])
   1642       && match_lookahead (c,
   1643 			  lookaheadCount, lookahead,
   1644 			  lookup_context.funcs.match, lookup_context.match_data[2],
   1645 			  match_length)
   1646       && apply_lookup (c,
   1647 		       inputCount, match_positions,
   1648 		       lookupCount, lookupRecord,
   1649 		       match_length);
   1650 }
   1651 
   1652 struct ChainRule
   1653 {
   1654   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   1655   {
   1656     TRACE_CLOSURE (this);
   1657     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
   1658     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
   1659     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   1660     chain_context_closure_lookup (c,
   1661 				  backtrack.len, backtrack.array,
   1662 				  input.len, input.array,
   1663 				  lookahead.len, lookahead.array,
   1664 				  lookup.len, lookup.array,
   1665 				  lookup_context);
   1666   }
   1667 
   1668   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   1669   {
   1670     TRACE_COLLECT_GLYPHS (this);
   1671     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
   1672     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
   1673     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   1674     chain_context_collect_glyphs_lookup (c,
   1675 					 backtrack.len, backtrack.array,
   1676 					 input.len, input.array,
   1677 					 lookahead.len, lookahead.array,
   1678 					 lookup.len, lookup.array,
   1679 					 lookup_context);
   1680   }
   1681 
   1682   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   1683   {
   1684     TRACE_WOULD_APPLY (this);
   1685     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
   1686     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
   1687     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   1688     return TRACE_RETURN (chain_context_would_apply_lookup (c,
   1689 							   backtrack.len, backtrack.array,
   1690 							   input.len, input.array,
   1691 							   lookahead.len, lookahead.array, lookup.len,
   1692 							   lookup.array, lookup_context));
   1693   }
   1694 
   1695   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   1696   {
   1697     TRACE_APPLY (this);
   1698     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
   1699     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
   1700     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   1701     return TRACE_RETURN (chain_context_apply_lookup (c,
   1702 						     backtrack.len, backtrack.array,
   1703 						     input.len, input.array,
   1704 						     lookahead.len, lookahead.array, lookup.len,
   1705 						     lookup.array, lookup_context));
   1706   }
   1707 
   1708   inline bool sanitize (hb_sanitize_context_t *c) {
   1709     TRACE_SANITIZE (this);
   1710     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
   1711     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
   1712     if (!input.sanitize (c)) return TRACE_RETURN (false);
   1713     ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
   1714     if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
   1715     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   1716     return TRACE_RETURN (lookup.sanitize (c));
   1717   }
   1718 
   1719   protected:
   1720   ArrayOf<USHORT>
   1721 		backtrack;		/* Array of backtracking values
   1722 					 * (to be matched before the input
   1723 					 * sequence) */
   1724   HeadlessArrayOf<USHORT>
   1725 		inputX;			/* Array of input values (start with
   1726 					 * second glyph) */
   1727   ArrayOf<USHORT>
   1728 		lookaheadX;		/* Array of lookahead values's (to be
   1729 					 * matched after the input sequence) */
   1730   ArrayOf<LookupRecord>
   1731 		lookupX;		/* Array of LookupRecords--in
   1732 					 * design order) */
   1733   public:
   1734   DEFINE_SIZE_MIN (8);
   1735 };
   1736 
   1737 struct ChainRuleSet
   1738 {
   1739   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   1740   {
   1741     TRACE_CLOSURE (this);
   1742     unsigned int num_rules = rule.len;
   1743     for (unsigned int i = 0; i < num_rules; i++)
   1744       (this+rule[i]).closure (c, lookup_context);
   1745   }
   1746 
   1747   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   1748   {
   1749     TRACE_COLLECT_GLYPHS (this);
   1750     unsigned int num_rules = rule.len;
   1751     for (unsigned int i = 0; i < num_rules; i++)
   1752       (this+rule[i]).collect_glyphs (c, lookup_context);
   1753   }
   1754 
   1755   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   1756   {
   1757     TRACE_WOULD_APPLY (this);
   1758     unsigned int num_rules = rule.len;
   1759     for (unsigned int i = 0; i < num_rules; i++)
   1760       if ((this+rule[i]).would_apply (c, lookup_context))
   1761         return TRACE_RETURN (true);
   1762 
   1763     return TRACE_RETURN (false);
   1764   }
   1765 
   1766   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   1767   {
   1768     TRACE_APPLY (this);
   1769     unsigned int num_rules = rule.len;
   1770     for (unsigned int i = 0; i < num_rules; i++)
   1771       if ((this+rule[i]).apply (c, lookup_context))
   1772         return TRACE_RETURN (true);
   1773 
   1774     return TRACE_RETURN (false);
   1775   }
   1776 
   1777   inline bool sanitize (hb_sanitize_context_t *c) {
   1778     TRACE_SANITIZE (this);
   1779     return TRACE_RETURN (rule.sanitize (c, this));
   1780   }
   1781 
   1782   protected:
   1783   OffsetArrayOf<ChainRule>
   1784 		rule;			/* Array of ChainRule tables
   1785 					 * ordered by preference */
   1786   public:
   1787   DEFINE_SIZE_ARRAY (2, rule);
   1788 };
   1789 
   1790 struct ChainContextFormat1
   1791 {
   1792   inline void closure (hb_closure_context_t *c) const
   1793   {
   1794     TRACE_CLOSURE (this);
   1795     const Coverage &cov = (this+coverage);
   1796 
   1797     struct ChainContextClosureLookupContext lookup_context = {
   1798       {intersects_glyph},
   1799       {NULL, NULL, NULL}
   1800     };
   1801 
   1802     unsigned int count = ruleSet.len;
   1803     for (unsigned int i = 0; i < count; i++)
   1804       if (cov.intersects_coverage (c->glyphs, i)) {
   1805 	const ChainRuleSet &rule_set = this+ruleSet[i];
   1806 	rule_set.closure (c, lookup_context);
   1807       }
   1808   }
   1809 
   1810   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1811   {
   1812     TRACE_COLLECT_GLYPHS (this);
   1813     (this+coverage).add_coverage (c->input);
   1814 
   1815     struct ChainContextCollectGlyphsLookupContext lookup_context = {
   1816       {collect_glyph},
   1817       {NULL, NULL, NULL}
   1818     };
   1819 
   1820     unsigned int count = ruleSet.len;
   1821     for (unsigned int i = 0; i < count; i++)
   1822       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   1823   }
   1824 
   1825   inline bool would_apply (hb_would_apply_context_t *c) const
   1826   {
   1827     TRACE_WOULD_APPLY (this);
   1828 
   1829     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
   1830     struct ChainContextApplyLookupContext lookup_context = {
   1831       {match_glyph},
   1832       {NULL, NULL, NULL}
   1833     };
   1834     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   1835   }
   1836 
   1837   inline const Coverage &get_coverage (void) const
   1838   {
   1839     return this+coverage;
   1840   }
   1841 
   1842   inline bool apply (hb_apply_context_t *c) const
   1843   {
   1844     TRACE_APPLY (this);
   1845     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
   1846     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1847 
   1848     const ChainRuleSet &rule_set = this+ruleSet[index];
   1849     struct ChainContextApplyLookupContext lookup_context = {
   1850       {match_glyph},
   1851       {NULL, NULL, NULL}
   1852     };
   1853     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   1854   }
   1855 
   1856   inline bool sanitize (hb_sanitize_context_t *c) {
   1857     TRACE_SANITIZE (this);
   1858     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   1859   }
   1860 
   1861   protected:
   1862   USHORT	format;			/* Format identifier--format = 1 */
   1863   OffsetTo<Coverage>
   1864 		coverage;		/* Offset to Coverage table--from
   1865 					 * beginning of table */
   1866   OffsetArrayOf<ChainRuleSet>
   1867 		ruleSet;		/* Array of ChainRuleSet tables
   1868 					 * ordered by Coverage Index */
   1869   public:
   1870   DEFINE_SIZE_ARRAY (6, ruleSet);
   1871 };
   1872 
   1873 struct ChainContextFormat2
   1874 {
   1875   inline void closure (hb_closure_context_t *c) const
   1876   {
   1877     TRACE_CLOSURE (this);
   1878     if (!(this+coverage).intersects (c->glyphs))
   1879       return;
   1880 
   1881     const ClassDef &backtrack_class_def = this+backtrackClassDef;
   1882     const ClassDef &input_class_def = this+inputClassDef;
   1883     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
   1884 
   1885     struct ChainContextClosureLookupContext lookup_context = {
   1886       {intersects_class},
   1887       {&backtrack_class_def,
   1888        &input_class_def,
   1889        &lookahead_class_def}
   1890     };
   1891 
   1892     unsigned int count = ruleSet.len;
   1893     for (unsigned int i = 0; i < count; i++)
   1894       if (input_class_def.intersects_class (c->glyphs, i)) {
   1895 	const ChainRuleSet &rule_set = this+ruleSet[i];
   1896 	rule_set.closure (c, lookup_context);
   1897       }
   1898   }
   1899 
   1900   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1901   {
   1902     TRACE_COLLECT_GLYPHS (this);
   1903     (this+coverage).add_coverage (c->input);
   1904 
   1905     const ClassDef &backtrack_class_def = this+backtrackClassDef;
   1906     const ClassDef &input_class_def = this+inputClassDef;
   1907     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
   1908 
   1909     struct ChainContextCollectGlyphsLookupContext lookup_context = {
   1910       {collect_class},
   1911       {&backtrack_class_def,
   1912        &input_class_def,
   1913        &lookahead_class_def}
   1914     };
   1915 
   1916     unsigned int count = ruleSet.len;
   1917     for (unsigned int i = 0; i < count; i++)
   1918       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
   1919   }
   1920 
   1921   inline bool would_apply (hb_would_apply_context_t *c) const
   1922   {
   1923     TRACE_WOULD_APPLY (this);
   1924 
   1925     const ClassDef &backtrack_class_def = this+backtrackClassDef;
   1926     const ClassDef &input_class_def = this+inputClassDef;
   1927     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
   1928 
   1929     unsigned int index = input_class_def.get_class (c->glyphs[0]);
   1930     const ChainRuleSet &rule_set = this+ruleSet[index];
   1931     struct ChainContextApplyLookupContext lookup_context = {
   1932       {match_class},
   1933       {&backtrack_class_def,
   1934        &input_class_def,
   1935        &lookahead_class_def}
   1936     };
   1937     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   1938   }
   1939 
   1940   inline const Coverage &get_coverage (void) const
   1941   {
   1942     return this+coverage;
   1943   }
   1944 
   1945   inline bool apply (hb_apply_context_t *c) const
   1946   {
   1947     TRACE_APPLY (this);
   1948     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
   1949     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1950 
   1951     const ClassDef &backtrack_class_def = this+backtrackClassDef;
   1952     const ClassDef &input_class_def = this+inputClassDef;
   1953     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
   1954 
   1955     index = input_class_def.get_class (c->buffer->cur().codepoint);
   1956     const ChainRuleSet &rule_set = this+ruleSet[index];
   1957     struct ChainContextApplyLookupContext lookup_context = {
   1958       {match_class},
   1959       {&backtrack_class_def,
   1960        &input_class_def,
   1961        &lookahead_class_def}
   1962     };
   1963     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   1964   }
   1965 
   1966   inline bool sanitize (hb_sanitize_context_t *c) {
   1967     TRACE_SANITIZE (this);
   1968     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
   1969 			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
   1970 			 ruleSet.sanitize (c, this));
   1971   }
   1972 
   1973   protected:
   1974   USHORT	format;			/* Format identifier--format = 2 */
   1975   OffsetTo<Coverage>
   1976 		coverage;		/* Offset to Coverage table--from
   1977 					 * beginning of table */
   1978   OffsetTo<ClassDef>
   1979 		backtrackClassDef;	/* Offset to glyph ClassDef table
   1980 					 * containing backtrack sequence
   1981 					 * data--from beginning of table */
   1982   OffsetTo<ClassDef>
   1983 		inputClassDef;		/* Offset to glyph ClassDef
   1984 					 * table containing input sequence
   1985 					 * data--from beginning of table */
   1986   OffsetTo<ClassDef>
   1987 		lookaheadClassDef;	/* Offset to glyph ClassDef table
   1988 					 * containing lookahead sequence
   1989 					 * data--from beginning of table */
   1990   OffsetArrayOf<ChainRuleSet>
   1991 		ruleSet;		/* Array of ChainRuleSet tables
   1992 					 * ordered by class */
   1993   public:
   1994   DEFINE_SIZE_ARRAY (12, ruleSet);
   1995 };
   1996 
   1997 struct ChainContextFormat3
   1998 {
   1999   inline void closure (hb_closure_context_t *c) const
   2000   {
   2001     TRACE_CLOSURE (this);
   2002     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2003 
   2004     if (!(this+input[0]).intersects (c->glyphs))
   2005       return;
   2006 
   2007     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
   2008     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   2009     struct ChainContextClosureLookupContext lookup_context = {
   2010       {intersects_coverage},
   2011       {this, this, this}
   2012     };
   2013     chain_context_closure_lookup (c,
   2014 				  backtrack.len, (const USHORT *) backtrack.array,
   2015 				  input.len, (const USHORT *) input.array + 1,
   2016 				  lookahead.len, (const USHORT *) lookahead.array,
   2017 				  lookup.len, lookup.array,
   2018 				  lookup_context);
   2019   }
   2020 
   2021   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   2022   {
   2023     TRACE_COLLECT_GLYPHS (this);
   2024     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2025 
   2026     (this+input[0]).add_coverage (c->input);
   2027 
   2028     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
   2029     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   2030     struct ChainContextCollectGlyphsLookupContext lookup_context = {
   2031       {collect_coverage},
   2032       {this, this, this}
   2033     };
   2034     chain_context_collect_glyphs_lookup (c,
   2035 					 backtrack.len, (const USHORT *) backtrack.array,
   2036 					 input.len, (const USHORT *) input.array + 1,
   2037 					 lookahead.len, (const USHORT *) lookahead.array,
   2038 					 lookup.len, lookup.array,
   2039 					 lookup_context);
   2040   }
   2041 
   2042   inline bool would_apply (hb_would_apply_context_t *c) const
   2043   {
   2044     TRACE_WOULD_APPLY (this);
   2045 
   2046     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2047     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
   2048     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   2049     struct ChainContextApplyLookupContext lookup_context = {
   2050       {match_coverage},
   2051       {this, this, this}
   2052     };
   2053     return TRACE_RETURN (chain_context_would_apply_lookup (c,
   2054 							   backtrack.len, (const USHORT *) backtrack.array,
   2055 							   input.len, (const USHORT *) input.array + 1,
   2056 							   lookahead.len, (const USHORT *) lookahead.array,
   2057 							   lookup.len, lookup.array, lookup_context));
   2058   }
   2059 
   2060   inline const Coverage &get_coverage (void) const
   2061   {
   2062     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2063     return this+input[0];
   2064   }
   2065 
   2066   inline bool apply (hb_apply_context_t *c) const
   2067   {
   2068     TRACE_APPLY (this);
   2069     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2070 
   2071     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
   2072     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   2073 
   2074     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
   2075     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   2076     struct ChainContextApplyLookupContext lookup_context = {
   2077       {match_coverage},
   2078       {this, this, this}
   2079     };
   2080     return TRACE_RETURN (chain_context_apply_lookup (c,
   2081 						     backtrack.len, (const USHORT *) backtrack.array,
   2082 						     input.len, (const USHORT *) input.array + 1,
   2083 						     lookahead.len, (const USHORT *) lookahead.array,
   2084 						     lookup.len, lookup.array, lookup_context));
   2085   }
   2086 
   2087   inline bool sanitize (hb_sanitize_context_t *c) {
   2088     TRACE_SANITIZE (this);
   2089     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
   2090     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
   2091     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
   2092     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
   2093     if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
   2094     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
   2095     return TRACE_RETURN (lookup.sanitize (c));
   2096   }
   2097 
   2098   protected:
   2099   USHORT	format;			/* Format identifier--format = 3 */
   2100   OffsetArrayOf<Coverage>
   2101 		backtrack;		/* Array of coverage tables
   2102 					 * in backtracking sequence, in  glyph
   2103 					 * sequence order */
   2104   OffsetArrayOf<Coverage>
   2105 		inputX		;	/* Array of coverage
   2106 					 * tables in input sequence, in glyph
   2107 					 * sequence order */
   2108   OffsetArrayOf<Coverage>
   2109 		lookaheadX;		/* Array of coverage tables
   2110 					 * in lookahead sequence, in glyph
   2111 					 * sequence order */
   2112   ArrayOf<LookupRecord>
   2113 		lookupX;		/* Array of LookupRecords--in
   2114 					 * design order) */
   2115   public:
   2116   DEFINE_SIZE_MIN (10);
   2117 };
   2118 
   2119 struct ChainContext
   2120 {
   2121   template <typename context_t>
   2122   inline typename context_t::return_t dispatch (context_t *c) const
   2123   {
   2124     TRACE_DISPATCH (this);
   2125     switch (u.format) {
   2126     case 1: return TRACE_RETURN (c->dispatch (u.format1));
   2127     case 2: return TRACE_RETURN (c->dispatch (u.format2));
   2128     case 3: return TRACE_RETURN (c->dispatch (u.format3));
   2129     default:return TRACE_RETURN (c->default_return_value ());
   2130     }
   2131   }
   2132 
   2133   inline bool sanitize (hb_sanitize_context_t *c) {
   2134     TRACE_SANITIZE (this);
   2135     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   2136     switch (u.format) {
   2137     case 1: return TRACE_RETURN (u.format1.sanitize (c));
   2138     case 2: return TRACE_RETURN (u.format2.sanitize (c));
   2139     case 3: return TRACE_RETURN (u.format3.sanitize (c));
   2140     default:return TRACE_RETURN (true);
   2141     }
   2142   }
   2143 
   2144   protected:
   2145   union {
   2146   USHORT		format;	/* Format identifier */
   2147   ChainContextFormat1	format1;
   2148   ChainContextFormat2	format2;
   2149   ChainContextFormat3	format3;
   2150   } u;
   2151 };
   2152 
   2153 
   2154 struct ExtensionFormat1
   2155 {
   2156   inline unsigned int get_type (void) const { return extensionLookupType; }
   2157   inline unsigned int get_offset (void) const { return extensionOffset; }
   2158 
   2159   inline bool sanitize (hb_sanitize_context_t *c) {
   2160     TRACE_SANITIZE (this);
   2161     return TRACE_RETURN (c->check_struct (this));
   2162   }
   2163 
   2164   protected:
   2165   USHORT	format;			/* Format identifier. Set to 1. */
   2166   USHORT	extensionLookupType;	/* Lookup type of subtable referenced
   2167 					 * by ExtensionOffset (i.e. the
   2168 					 * extension subtable). */
   2169   ULONG		extensionOffset;	/* Offset to the extension subtable,
   2170 					 * of lookup type subtable. */
   2171   public:
   2172   DEFINE_SIZE_STATIC (8);
   2173 };
   2174 
   2175 template <typename T>
   2176 struct Extension
   2177 {
   2178   inline unsigned int get_type (void) const
   2179   {
   2180     switch (u.format) {
   2181     case 1: return u.format1.get_type ();
   2182     default:return 0;
   2183     }
   2184   }
   2185   inline unsigned int get_offset (void) const
   2186   {
   2187     switch (u.format) {
   2188     case 1: return u.format1.get_offset ();
   2189     default:return 0;
   2190     }
   2191   }
   2192 
   2193   template <typename X>
   2194   inline const X& get_subtable (void) const
   2195   {
   2196     unsigned int offset = get_offset ();
   2197     if (unlikely (!offset)) return Null(typename T::LookupSubTable);
   2198     return StructAtOffset<typename T::LookupSubTable> (this, offset);
   2199   }
   2200 
   2201   template <typename context_t>
   2202   inline typename context_t::return_t dispatch (context_t *c) const
   2203   {
   2204     return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
   2205   }
   2206 
   2207   inline bool sanitize_self (hb_sanitize_context_t *c) {
   2208     TRACE_SANITIZE (this);
   2209     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   2210     switch (u.format) {
   2211     case 1: return TRACE_RETURN (u.format1.sanitize (c));
   2212     default:return TRACE_RETURN (true);
   2213     }
   2214   }
   2215 
   2216   inline bool sanitize (hb_sanitize_context_t *c) {
   2217     TRACE_SANITIZE (this);
   2218     if (!sanitize_self (c)) return TRACE_RETURN (false);
   2219     unsigned int offset = get_offset ();
   2220     if (unlikely (!offset)) return TRACE_RETURN (true);
   2221     return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
   2222   }
   2223 
   2224   protected:
   2225   union {
   2226   USHORT		format;		/* Format identifier */
   2227   ExtensionFormat1	format1;
   2228   } u;
   2229 };
   2230 
   2231 
   2232 /*
   2233  * GSUB/GPOS Common
   2234  */
   2235 
   2236 struct GSUBGPOS
   2237 {
   2238   static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
   2239   static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
   2240 
   2241   inline unsigned int get_script_count (void) const
   2242   { return (this+scriptList).len; }
   2243   inline const Tag& get_script_tag (unsigned int i) const
   2244   { return (this+scriptList).get_tag (i); }
   2245   inline unsigned int get_script_tags (unsigned int start_offset,
   2246 				       unsigned int *script_count /* IN/OUT */,
   2247 				       hb_tag_t     *script_tags /* OUT */) const
   2248   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
   2249   inline const Script& get_script (unsigned int i) const
   2250   { return (this+scriptList)[i]; }
   2251   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
   2252   { return (this+scriptList).find_index (tag, index); }
   2253 
   2254   inline unsigned int get_feature_count (void) const
   2255   { return (this+featureList).len; }
   2256   inline const Tag& get_feature_tag (unsigned int i) const
   2257   { return (this+featureList).get_tag (i); }
   2258   inline unsigned int get_feature_tags (unsigned int start_offset,
   2259 					unsigned int *feature_count /* IN/OUT */,
   2260 					hb_tag_t     *feature_tags /* OUT */) const
   2261   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
   2262   inline const Feature& get_feature (unsigned int i) const
   2263   { return (this+featureList)[i]; }
   2264   inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
   2265   { return (this+featureList).find_index (tag, index); }
   2266 
   2267   inline unsigned int get_lookup_count (void) const
   2268   { return (this+lookupList).len; }
   2269   inline const Lookup& get_lookup (unsigned int i) const
   2270   { return (this+lookupList)[i]; }
   2271 
   2272   inline bool sanitize (hb_sanitize_context_t *c) {
   2273     TRACE_SANITIZE (this);
   2274     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
   2275 			 scriptList.sanitize (c, this) &&
   2276 			 featureList.sanitize (c, this) &&
   2277 			 lookupList.sanitize (c, this));
   2278   }
   2279 
   2280   protected:
   2281   FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
   2282 				 * to 0x00010000 */
   2283   OffsetTo<ScriptList>
   2284 		scriptList;  	/* ScriptList table */
   2285   OffsetTo<FeatureList>
   2286 		featureList; 	/* FeatureList table */
   2287   OffsetTo<LookupList>
   2288 		lookupList; 	/* LookupList table */
   2289   public:
   2290   DEFINE_SIZE_STATIC (10);
   2291 };
   2292 
   2293 
   2294 } /* namespace OT */
   2295 
   2296 
   2297 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
   2298