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