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