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