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