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