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