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