hb-ot-layout-gsubgpos-private.hh revision e6f7479fe34fb4a7cada61d84c2ed70d1fd565c8
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
35
36
37#ifndef HB_DEBUG_CLOSURE
38#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
39#endif
40
41#define TRACE_CLOSURE() \
42	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
43
44
45/* TODO Add TRACE_RETURN annotation to gsub. */
46#ifndef HB_DEBUG_WOULD_APPLY
47#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
48#endif
49
50#define TRACE_WOULD_APPLY() \
51	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "first %u second %u", c->first, c->second);
52
53
54struct hb_closure_context_t
55{
56  hb_face_t *face;
57  hb_set_t *glyphs;
58  unsigned int nesting_level_left;
59  unsigned int debug_depth;
60
61
62  hb_closure_context_t (hb_face_t *face_,
63			hb_set_t *glyphs_,
64		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
65			  face (face_),
66			  glyphs (glyphs_),
67			  nesting_level_left (nesting_level_left_),
68			  debug_depth (0) {}
69};
70
71
72
73
74struct hb_would_apply_context_t
75{
76  hb_face_t *face;
77  hb_codepoint_t first;
78  hb_codepoint_t second;
79  unsigned int len;
80  unsigned int debug_depth;
81
82  hb_would_apply_context_t (hb_face_t *face_,
83			    hb_codepoint_t first_,
84			    hb_codepoint_t second_ = -1) :
85			      face (face_),
86			      first (first_), second (second_), len (second == (hb_codepoint_t) -1 ? 1 : 2),
87			      debug_depth (0) {};
88};
89
90
91#ifndef HB_DEBUG_APPLY
92#define HB_DEBUG_APPLY (HB_DEBUG+0)
93#endif
94
95#define TRACE_APPLY() \
96	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
97
98
99
100struct hb_apply_context_t
101{
102  hb_font_t *font;
103  hb_face_t *face;
104  hb_buffer_t *buffer;
105  hb_direction_t direction;
106  hb_mask_t lookup_mask;
107  unsigned int nesting_level_left;
108  unsigned int lookup_props;
109  unsigned int property; /* propety of first glyph */
110  unsigned int debug_depth;
111  bool has_glyph_classes;
112
113
114  hb_apply_context_t (hb_font_t *font_,
115		      hb_face_t *face_,
116		      hb_buffer_t *buffer_,
117		      hb_mask_t lookup_mask_) :
118			font (font_), face (face_), buffer (buffer_),
119			direction (buffer_->props.direction),
120			lookup_mask (lookup_mask_),
121			nesting_level_left (MAX_NESTING_LEVEL),
122			lookup_props (0), property (0), debug_depth (0),
123			has_glyph_classes (hb_ot_layout_has_glyph_classes (face_)) {}
124
125  void set_lookup (const Lookup &l) {
126    lookup_props = l.get_props ();
127  }
128
129  struct mark_skipping_forward_iterator_t
130  {
131    inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
132					     unsigned int start_index_,
133					     unsigned int num_items_,
134					     bool context_match = false)
135    {
136      c = c_;
137      idx = start_index_;
138      num_items = num_items_;
139      mask = context_match ? -1 : c->lookup_mask;
140      syllable = context_match ? 0 : c->buffer->cur().syllable ();
141      end = c->buffer->len;
142    }
143    inline bool has_no_chance (void) const
144    {
145      return unlikely (num_items && idx + num_items >= end);
146    }
147    inline void reject (void)
148    {
149      num_items++;
150    }
151    inline bool next (unsigned int *property_out,
152		      unsigned int  lookup_props)
153    {
154      assert (num_items > 0);
155      do
156      {
157	if (has_no_chance ())
158	  return false;
159	idx++;
160      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out));
161      num_items--;
162      return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
163    }
164    inline bool next (unsigned int *property_out = NULL)
165    {
166      return next (property_out, c->lookup_props);
167    }
168
169    unsigned int idx;
170    protected:
171    hb_apply_context_t *c;
172    unsigned int num_items;
173    hb_mask_t mask;
174    uint8_t syllable;
175    unsigned int end;
176  };
177
178  struct mark_skipping_backward_iterator_t
179  {
180    inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
181					      unsigned int start_index_,
182					      unsigned int num_items_,
183					      hb_mask_t mask_ = 0,
184					      bool match_syllable_ = true)
185    {
186      c = c_;
187      idx = start_index_;
188      num_items = num_items_;
189      mask = mask_ ? mask_ : c->lookup_mask;
190      syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
191    }
192    inline bool has_no_chance (void) const
193    {
194      return unlikely (idx < num_items);
195    }
196    inline void reject (void)
197    {
198      num_items++;
199    }
200    inline bool prev (unsigned int *property_out,
201		      unsigned int  lookup_props)
202    {
203      assert (num_items > 0);
204      do
205      {
206	if (has_no_chance ())
207	  return false;
208	idx--;
209      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out));
210      num_items--;
211      return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
212    }
213    inline bool prev (unsigned int *property_out = NULL)
214    {
215      return prev (property_out, c->lookup_props);
216    }
217
218    unsigned int idx;
219    protected:
220    hb_apply_context_t *c;
221    unsigned int num_items;
222    hb_mask_t mask;
223    uint8_t syllable;
224  };
225
226  inline bool should_mark_skip_current_glyph (void) const
227  {
228    unsigned int property;
229    return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, &property);
230  }
231
232  inline void set_klass_guess (unsigned int klass_guess) const
233  {
234    buffer->cur().props_cache() = has_glyph_classes ? 0 : klass_guess;
235  }
236
237  inline void output_glyph (hb_codepoint_t glyph_index,
238			    unsigned int klass_guess = 0) const
239  {
240    set_klass_guess (klass_guess);
241    buffer->output_glyph (glyph_index);
242  }
243  inline void replace_glyph (hb_codepoint_t glyph_index,
244			     unsigned int klass_guess = 0) const
245  {
246    set_klass_guess (klass_guess);
247    buffer->replace_glyph (glyph_index);
248  }
249  inline void replace_glyphs (unsigned int num_in,
250			      unsigned int num_out,
251			      hb_codepoint_t *glyph_data,
252			      unsigned int klass_guess = 0) const
253  {
254    set_klass_guess (klass_guess);
255    buffer->replace_glyphs (num_in, num_out, glyph_data);
256  }
257};
258
259
260
261typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
262typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
263typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
264typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
265
266struct ContextClosureFuncs
267{
268  intersects_func_t intersects;
269  closure_lookup_func_t closure;
270};
271struct ContextApplyFuncs
272{
273  match_func_t match;
274  apply_lookup_func_t apply;
275};
276
277static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
278{
279  return glyphs->has (value);
280}
281static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
282{
283  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
284  return class_def.intersects_class (glyphs, value);
285}
286static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
287{
288  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
289  return (data+coverage).intersects (glyphs);
290}
291
292static inline bool intersects_array (hb_closure_context_t *c,
293				     unsigned int count,
294				     const USHORT values[],
295				     intersects_func_t intersects_func,
296				     const void *intersects_data)
297{
298  for (unsigned int i = 0; i < count; i++)
299    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
300      return false;
301  return true;
302}
303
304
305static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
306{
307  return glyph_id == value;
308}
309static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
310{
311  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
312  return class_def.get_class (glyph_id) == value;
313}
314static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
315{
316  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
317  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
318}
319
320
321static inline bool would_match_input (hb_would_apply_context_t *c,
322				      unsigned int count, /* Including the first glyph (not matched) */
323				      const USHORT input[], /* Array of input values--start with second glyph */
324				      match_func_t match_func,
325				      const void *match_data)
326{
327  if (count != c->len)
328    return false;
329
330  for (unsigned int i = 1; i < count; i++)
331    if (likely (!match_func (c->second, input[i - 1], match_data)))
332      return false;
333
334  return true;
335}
336static inline bool match_input (hb_apply_context_t *c,
337				unsigned int count, /* Including the first glyph (not matched) */
338				const USHORT input[], /* Array of input values--start with second glyph */
339				match_func_t match_func,
340				const void *match_data,
341				unsigned int *end_offset = NULL)
342{
343  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
344  if (skippy_iter.has_no_chance ())
345    return false;
346
347  for (unsigned int i = 1; i < count; i++)
348  {
349    if (!skippy_iter.next ())
350      return false;
351
352    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
353      return false;
354  }
355
356  if (end_offset)
357    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
358
359  return true;
360}
361
362static inline bool match_backtrack (hb_apply_context_t *c,
363				    unsigned int count,
364				    const USHORT backtrack[],
365				    match_func_t match_func,
366				    const void *match_data)
367{
368  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
369  if (skippy_iter.has_no_chance ())
370    return false;
371
372  for (unsigned int i = 0; i < count; i++)
373  {
374    if (!skippy_iter.prev ())
375      return false;
376
377    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
378      return false;
379  }
380
381  return true;
382}
383
384static inline bool match_lookahead (hb_apply_context_t *c,
385				    unsigned int count,
386				    const USHORT lookahead[],
387				    match_func_t match_func,
388				    const void *match_data,
389				    unsigned int offset)
390{
391  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
392  if (skippy_iter.has_no_chance ())
393    return false;
394
395  for (unsigned int i = 0; i < count; i++)
396  {
397    if (!skippy_iter.next ())
398      return false;
399
400    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
401      return false;
402  }
403
404  return true;
405}
406
407
408
409struct LookupRecord
410{
411  inline bool sanitize (hb_sanitize_context_t *c) {
412    TRACE_SANITIZE ();
413    return TRACE_RETURN (c->check_struct (this));
414  }
415
416  USHORT	sequenceIndex;		/* Index into current glyph
417					 * sequence--first glyph = 0 */
418  USHORT	lookupListIndex;	/* Lookup to apply to that
419					 * position--zero--based */
420  public:
421  DEFINE_SIZE_STATIC (4);
422};
423
424
425static inline void closure_lookup (hb_closure_context_t *c,
426				   unsigned int lookupCount,
427				   const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
428				   closure_lookup_func_t closure_func)
429{
430  for (unsigned int i = 0; i < lookupCount; i++)
431    closure_func (c, lookupRecord->lookupListIndex);
432}
433
434static inline bool apply_lookup (hb_apply_context_t *c,
435				 unsigned int count, /* Including the first glyph */
436				 unsigned int lookupCount,
437				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
438				 apply_lookup_func_t apply_func)
439{
440  unsigned int end = c->buffer->len;
441  if (unlikely (count == 0 || c->buffer->idx + count > end))
442    return false;
443
444  /* TODO We don't support lookupRecord arrays that are not increasing:
445   *      Should be easy for in_place ones at least. */
446
447  /* Note: If sublookup is reverse, it will underflow after the first loop
448   * and we jump out of it.  Not entirely disastrous.  So we don't check
449   * for reverse lookup here.
450   */
451  for (unsigned int i = 0; i < count; /* NOP */)
452  {
453    if (unlikely (c->buffer->idx == end))
454      return true;
455    while (c->should_mark_skip_current_glyph ())
456    {
457      /* No lookup applied for this index */
458      c->buffer->next_glyph ();
459      if (unlikely (c->buffer->idx == end))
460	return true;
461    }
462
463    if (lookupCount && i == lookupRecord->sequenceIndex)
464    {
465      unsigned int old_pos = c->buffer->idx;
466
467      /* Apply a lookup */
468      bool done = apply_func (c, lookupRecord->lookupListIndex);
469
470      lookupRecord++;
471      lookupCount--;
472      /* Err, this is wrong if the lookup jumped over some glyphs */
473      i += c->buffer->idx - old_pos;
474      if (unlikely (c->buffer->idx == end))
475	return true;
476
477      if (!done)
478	goto not_applied;
479    }
480    else
481    {
482    not_applied:
483      /* No lookup applied for this index */
484      c->buffer->next_glyph ();
485      i++;
486    }
487  }
488
489  return true;
490}
491
492
493
494/* Contextual lookups */
495
496struct ContextClosureLookupContext
497{
498  ContextClosureFuncs funcs;
499  const void *intersects_data;
500};
501
502struct ContextApplyLookupContext
503{
504  ContextApplyFuncs funcs;
505  const void *match_data;
506};
507
508static inline void context_closure_lookup (hb_closure_context_t *c,
509					   unsigned int inputCount, /* Including the first glyph (not matched) */
510					   const USHORT input[], /* Array of input values--start with second glyph */
511					   unsigned int lookupCount,
512					   const LookupRecord lookupRecord[],
513					   ContextClosureLookupContext &lookup_context)
514{
515  if (intersects_array (c,
516			inputCount ? inputCount - 1 : 0, input,
517			lookup_context.funcs.intersects, lookup_context.intersects_data))
518    closure_lookup (c,
519		    lookupCount, lookupRecord,
520		    lookup_context.funcs.closure);
521}
522
523
524static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
525					       unsigned int inputCount, /* Including the first glyph (not matched) */
526					       const USHORT input[], /* Array of input values--start with second glyph */
527					       unsigned int lookupCount,
528					       const LookupRecord lookupRecord[],
529					       ContextApplyLookupContext &lookup_context)
530{
531  return would_match_input (c,
532			    inputCount, input,
533			    lookup_context.funcs.match, lookup_context.match_data);
534}
535static inline bool context_apply_lookup (hb_apply_context_t *c,
536					 unsigned int inputCount, /* Including the first glyph (not matched) */
537					 const USHORT input[], /* Array of input values--start with second glyph */
538					 unsigned int lookupCount,
539					 const LookupRecord lookupRecord[],
540					 ContextApplyLookupContext &lookup_context)
541{
542  return match_input (c,
543		      inputCount, input,
544		      lookup_context.funcs.match, lookup_context.match_data)
545      && apply_lookup (c,
546		       inputCount,
547		       lookupCount, lookupRecord,
548		       lookup_context.funcs.apply);
549}
550
551struct Rule
552{
553  friend struct RuleSet;
554
555  private:
556
557  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
558  {
559    TRACE_CLOSURE ();
560    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
561    context_closure_lookup (c,
562			    inputCount, input,
563			    lookupCount, lookupRecord,
564			    lookup_context);
565  }
566
567  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
568  {
569    TRACE_WOULD_APPLY ();
570    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
571    return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
572  }
573
574  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
575  {
576    TRACE_APPLY ();
577    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
578    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
579  }
580
581  public:
582  inline bool sanitize (hb_sanitize_context_t *c) {
583    TRACE_SANITIZE ();
584    return inputCount.sanitize (c)
585	&& lookupCount.sanitize (c)
586	&& c->check_range (input,
587			   input[0].static_size * inputCount
588			   + lookupRecordX[0].static_size * lookupCount);
589  }
590
591  protected:
592  USHORT	inputCount;		/* Total number of glyphs in input
593					 * glyph sequence--includes the first
594					 * glyph */
595  USHORT	lookupCount;		/* Number of LookupRecords */
596  USHORT	input[VAR];		/* Array of match inputs--start with
597					 * second glyph */
598  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
599					 * design order */
600  public:
601  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
602};
603
604struct RuleSet
605{
606  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
607  {
608    TRACE_CLOSURE ();
609    unsigned int num_rules = rule.len;
610    for (unsigned int i = 0; i < num_rules; i++)
611      (this+rule[i]).closure (c, lookup_context);
612  }
613
614  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
615  {
616    TRACE_WOULD_APPLY ();
617    unsigned int num_rules = rule.len;
618    for (unsigned int i = 0; i < num_rules; i++)
619    {
620      if ((this+rule[i]).would_apply (c, lookup_context))
621        return TRACE_RETURN (true);
622    }
623    return TRACE_RETURN (false);
624  }
625
626  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
627  {
628    TRACE_APPLY ();
629    unsigned int num_rules = rule.len;
630    for (unsigned int i = 0; i < num_rules; i++)
631    {
632      if ((this+rule[i]).apply (c, lookup_context))
633        return TRACE_RETURN (true);
634    }
635    return TRACE_RETURN (false);
636  }
637
638  inline bool sanitize (hb_sanitize_context_t *c) {
639    TRACE_SANITIZE ();
640    return TRACE_RETURN (rule.sanitize (c, this));
641  }
642
643  protected:
644  OffsetArrayOf<Rule>
645		rule;			/* Array of Rule tables
646					 * ordered by preference */
647  public:
648  DEFINE_SIZE_ARRAY (2, rule);
649};
650
651
652struct ContextFormat1
653{
654  friend struct Context;
655
656  private:
657
658  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
659  {
660    TRACE_CLOSURE ();
661
662    const Coverage &cov = (this+coverage);
663
664    struct ContextClosureLookupContext lookup_context = {
665      {intersects_glyph, closure_func},
666      NULL
667    };
668
669    unsigned int count = ruleSet.len;
670    for (unsigned int i = 0; i < count; i++)
671      if (cov.intersects_coverage (c->glyphs, i)) {
672	const RuleSet &rule_set = this+ruleSet[i];
673	rule_set.closure (c, lookup_context);
674      }
675  }
676
677  inline bool would_apply (hb_would_apply_context_t *c) const
678  {
679    TRACE_WOULD_APPLY ();
680
681    const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->first)];
682    struct ContextApplyLookupContext lookup_context = {
683      {match_glyph, NULL},
684      NULL
685    };
686    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
687  }
688
689  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
690  {
691    TRACE_APPLY ();
692    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
693    if (likely (index == NOT_COVERED))
694      return TRACE_RETURN (false);
695
696    const RuleSet &rule_set = this+ruleSet[index];
697    struct ContextApplyLookupContext lookup_context = {
698      {match_glyph, apply_func},
699      NULL
700    };
701    return TRACE_RETURN (rule_set.apply (c, lookup_context));
702  }
703
704  inline bool sanitize (hb_sanitize_context_t *c) {
705    TRACE_SANITIZE ();
706    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
707  }
708
709  protected:
710  USHORT	format;			/* Format identifier--format = 1 */
711  OffsetTo<Coverage>
712		coverage;		/* Offset to Coverage table--from
713					 * beginning of table */
714  OffsetArrayOf<RuleSet>
715		ruleSet;		/* Array of RuleSet tables
716					 * ordered by Coverage Index */
717  public:
718  DEFINE_SIZE_ARRAY (6, ruleSet);
719};
720
721
722struct ContextFormat2
723{
724  friend struct Context;
725
726  private:
727
728  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
729  {
730    TRACE_CLOSURE ();
731    if (!(this+coverage).intersects (c->glyphs))
732      return;
733
734    const ClassDef &class_def = this+classDef;
735
736    struct ContextClosureLookupContext lookup_context = {
737      {intersects_class, closure_func},
738      NULL
739    };
740
741    unsigned int count = ruleSet.len;
742    for (unsigned int i = 0; i < count; i++)
743      if (class_def.intersects_class (c->glyphs, i)) {
744	const RuleSet &rule_set = this+ruleSet[i];
745	rule_set.closure (c, lookup_context);
746      }
747  }
748
749  inline bool would_apply (hb_would_apply_context_t *c) const
750  {
751    TRACE_WOULD_APPLY ();
752
753    const ClassDef &class_def = this+classDef;
754    unsigned int index = class_def (c->first);
755    const RuleSet &rule_set = this+ruleSet[index];
756    struct ContextApplyLookupContext lookup_context = {
757      {match_class, NULL},
758      &class_def
759    };
760    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
761  }
762
763  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
764  {
765    TRACE_APPLY ();
766    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
767    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
768
769    const ClassDef &class_def = this+classDef;
770    index = class_def (c->buffer->cur().codepoint);
771    const RuleSet &rule_set = this+ruleSet[index];
772    struct ContextApplyLookupContext lookup_context = {
773      {match_class, apply_func},
774      &class_def
775    };
776    return TRACE_RETURN (rule_set.apply (c, lookup_context));
777  }
778
779  inline bool sanitize (hb_sanitize_context_t *c) {
780    TRACE_SANITIZE ();
781    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
782  }
783
784  protected:
785  USHORT	format;			/* Format identifier--format = 2 */
786  OffsetTo<Coverage>
787		coverage;		/* Offset to Coverage table--from
788					 * beginning of table */
789  OffsetTo<ClassDef>
790		classDef;		/* Offset to glyph ClassDef table--from
791					 * beginning of table */
792  OffsetArrayOf<RuleSet>
793		ruleSet;		/* Array of RuleSet tables
794					 * ordered by class */
795  public:
796  DEFINE_SIZE_ARRAY (8, ruleSet);
797};
798
799
800struct ContextFormat3
801{
802  friend struct Context;
803
804  private:
805
806  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
807  {
808    TRACE_CLOSURE ();
809    if (!(this+coverage[0]).intersects (c->glyphs))
810      return;
811
812    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
813    struct ContextClosureLookupContext lookup_context = {
814      {intersects_coverage, closure_func},
815      this
816    };
817    context_closure_lookup (c,
818			    glyphCount, (const USHORT *) (coverage + 1),
819			    lookupCount, lookupRecord,
820			    lookup_context);
821  }
822
823  inline bool would_apply (hb_would_apply_context_t *c) const
824  {
825    TRACE_WOULD_APPLY ();
826
827    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
828    struct ContextApplyLookupContext lookup_context = {
829      {match_coverage, NULL},
830      this
831    };
832    return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
833  }
834
835  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
836  {
837    TRACE_APPLY ();
838    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
839    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
840
841    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
842    struct ContextApplyLookupContext lookup_context = {
843      {match_coverage, apply_func},
844      this
845    };
846    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
847  }
848
849  inline bool sanitize (hb_sanitize_context_t *c) {
850    TRACE_SANITIZE ();
851    if (!c->check_struct (this)) return TRACE_RETURN (false);
852    unsigned int count = glyphCount;
853    if (unlikely (!glyphCount)) return TRACE_RETURN (false);
854    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
855    for (unsigned int i = 0; i < count; i++)
856      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
857    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
858    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
859  }
860
861  protected:
862  USHORT	format;			/* Format identifier--format = 3 */
863  USHORT	glyphCount;		/* Number of glyphs in the input glyph
864					 * sequence */
865  USHORT	lookupCount;		/* Number of LookupRecords */
866  OffsetTo<Coverage>
867		coverage[VAR];		/* Array of offsets to Coverage
868					 * table in glyph sequence order */
869  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
870					 * design order */
871  public:
872  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
873};
874
875struct Context
876{
877  protected:
878
879  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
880  {
881    TRACE_CLOSURE ();
882    switch (u.format) {
883    case 1: u.format1.closure (c, closure_func); break;
884    case 2: u.format2.closure (c, closure_func); break;
885    case 3: u.format3.closure (c, closure_func); break;
886    default:                                     break;
887    }
888  }
889
890  inline const Coverage &get_coverage (void) const
891  {
892    switch (u.format) {
893    case 1: return this + u.format1.coverage;
894    case 2: return this + u.format2.coverage;
895    case 3: return this + u.format3.coverage[0];
896    default:return Null(Coverage);
897    }
898  }
899
900  inline bool would_apply (hb_would_apply_context_t *c) const
901  {
902    switch (u.format) {
903    case 1: return u.format1.would_apply (c);
904    case 2: return u.format2.would_apply (c);
905    case 3: return u.format3.would_apply (c);
906    default:return false;
907    }
908  }
909
910  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
911  {
912    TRACE_APPLY ();
913    switch (u.format) {
914    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
915    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
916    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
917    default:return TRACE_RETURN (false);
918    }
919  }
920
921  inline bool sanitize (hb_sanitize_context_t *c) {
922    TRACE_SANITIZE ();
923    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
924    switch (u.format) {
925    case 1: return TRACE_RETURN (u.format1.sanitize (c));
926    case 2: return TRACE_RETURN (u.format2.sanitize (c));
927    case 3: return TRACE_RETURN (u.format3.sanitize (c));
928    default:return TRACE_RETURN (true);
929    }
930  }
931
932  protected:
933  union {
934  USHORT		format;		/* Format identifier */
935  ContextFormat1	format1;
936  ContextFormat2	format2;
937  ContextFormat3	format3;
938  } u;
939};
940
941
942/* Chaining Contextual lookups */
943
944struct ChainContextClosureLookupContext
945{
946  ContextClosureFuncs funcs;
947  const void *intersects_data[3];
948};
949
950struct ChainContextApplyLookupContext
951{
952  ContextApplyFuncs funcs;
953  const void *match_data[3];
954};
955
956static inline void chain_context_closure_lookup (hb_closure_context_t *c,
957						 unsigned int backtrackCount,
958						 const USHORT backtrack[],
959						 unsigned int inputCount, /* Including the first glyph (not matched) */
960						 const USHORT input[], /* Array of input values--start with second glyph */
961						 unsigned int lookaheadCount,
962						 const USHORT lookahead[],
963						 unsigned int lookupCount,
964						 const LookupRecord lookupRecord[],
965						 ChainContextClosureLookupContext &lookup_context)
966{
967  if (intersects_array (c,
968			backtrackCount, backtrack,
969			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
970   && intersects_array (c,
971			inputCount ? inputCount - 1 : 0, input,
972			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
973  && intersects_array (c,
974		       lookaheadCount, lookahead,
975		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
976    closure_lookup (c,
977		    lookupCount, lookupRecord,
978		    lookup_context.funcs.closure);
979}
980
981static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
982						     unsigned int backtrackCount,
983						     const USHORT backtrack[],
984						     unsigned int inputCount, /* Including the first glyph (not matched) */
985						     const USHORT input[], /* Array of input values--start with second glyph */
986						     unsigned int lookaheadCount,
987						     const USHORT lookahead[],
988						     unsigned int lookupCount,
989						     const LookupRecord lookupRecord[],
990						     ChainContextApplyLookupContext &lookup_context)
991{
992  return !backtrackCount
993      && !lookaheadCount
994      && would_match_input (c,
995			    inputCount, input,
996			    lookup_context.funcs.match, lookup_context.match_data[1]);
997}
998
999static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1000					       unsigned int backtrackCount,
1001					       const USHORT backtrack[],
1002					       unsigned int inputCount, /* Including the first glyph (not matched) */
1003					       const USHORT input[], /* Array of input values--start with second glyph */
1004					       unsigned int lookaheadCount,
1005					       const USHORT lookahead[],
1006					       unsigned int lookupCount,
1007					       const LookupRecord lookupRecord[],
1008					       ChainContextApplyLookupContext &lookup_context)
1009{
1010  unsigned int lookahead_offset;
1011  return match_input (c,
1012		      inputCount, input,
1013		      lookup_context.funcs.match, lookup_context.match_data[1],
1014		      &lookahead_offset)
1015      && match_backtrack (c,
1016			  backtrackCount, backtrack,
1017			  lookup_context.funcs.match, lookup_context.match_data[0])
1018      && match_lookahead (c,
1019			  lookaheadCount, lookahead,
1020			  lookup_context.funcs.match, lookup_context.match_data[2],
1021			  lookahead_offset)
1022      && apply_lookup (c,
1023		       inputCount,
1024		       lookupCount, lookupRecord,
1025		       lookup_context.funcs.apply);
1026}
1027
1028struct ChainRule
1029{
1030  friend struct ChainRuleSet;
1031
1032  private:
1033
1034  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1035  {
1036    TRACE_CLOSURE ();
1037    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1038    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1039    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1040    chain_context_closure_lookup (c,
1041				  backtrack.len, backtrack.array,
1042				  input.len, input.array,
1043				  lookahead.len, lookahead.array,
1044				  lookup.len, lookup.array,
1045				  lookup_context);
1046  }
1047
1048  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1049  {
1050    TRACE_WOULD_APPLY ();
1051    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1052    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1053    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1054    return TRACE_RETURN (chain_context_would_apply_lookup (c,
1055							   backtrack.len, backtrack.array,
1056							   input.len, input.array,
1057							   lookahead.len, lookahead.array, lookup.len,
1058							   lookup.array, lookup_context));
1059  }
1060
1061  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1062  {
1063    TRACE_APPLY ();
1064    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1065    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1066    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1067    return TRACE_RETURN (chain_context_apply_lookup (c,
1068						     backtrack.len, backtrack.array,
1069						     input.len, input.array,
1070						     lookahead.len, lookahead.array, lookup.len,
1071						     lookup.array, lookup_context));
1072  }
1073
1074  public:
1075  inline bool sanitize (hb_sanitize_context_t *c) {
1076    TRACE_SANITIZE ();
1077    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1078    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1079    if (!input.sanitize (c)) return TRACE_RETURN (false);
1080    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1081    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1082    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1083    return TRACE_RETURN (lookup.sanitize (c));
1084  }
1085
1086  protected:
1087  ArrayOf<USHORT>
1088		backtrack;		/* Array of backtracking values
1089					 * (to be matched before the input
1090					 * sequence) */
1091  HeadlessArrayOf<USHORT>
1092		inputX;			/* Array of input values (start with
1093					 * second glyph) */
1094  ArrayOf<USHORT>
1095		lookaheadX;		/* Array of lookahead values's (to be
1096					 * matched after the input sequence) */
1097  ArrayOf<LookupRecord>
1098		lookupX;		/* Array of LookupRecords--in
1099					 * design order) */
1100  public:
1101  DEFINE_SIZE_MIN (8);
1102};
1103
1104struct ChainRuleSet
1105{
1106  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1107  {
1108    TRACE_CLOSURE ();
1109    unsigned int num_rules = rule.len;
1110    for (unsigned int i = 0; i < num_rules; i++)
1111      (this+rule[i]).closure (c, lookup_context);
1112  }
1113
1114  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1115  {
1116    TRACE_WOULD_APPLY ();
1117    unsigned int num_rules = rule.len;
1118    for (unsigned int i = 0; i < num_rules; i++)
1119      if ((this+rule[i]).would_apply (c, lookup_context))
1120        return TRACE_RETURN (true);
1121
1122    return TRACE_RETURN (false);
1123  }
1124
1125  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1126  {
1127    TRACE_APPLY ();
1128    unsigned int num_rules = rule.len;
1129    for (unsigned int i = 0; i < num_rules; i++)
1130      if ((this+rule[i]).apply (c, lookup_context))
1131        return TRACE_RETURN (true);
1132
1133    return TRACE_RETURN (false);
1134  }
1135
1136  inline bool sanitize (hb_sanitize_context_t *c) {
1137    TRACE_SANITIZE ();
1138    return TRACE_RETURN (rule.sanitize (c, this));
1139  }
1140
1141  protected:
1142  OffsetArrayOf<ChainRule>
1143		rule;			/* Array of ChainRule tables
1144					 * ordered by preference */
1145  public:
1146  DEFINE_SIZE_ARRAY (2, rule);
1147};
1148
1149struct ChainContextFormat1
1150{
1151  friend struct ChainContext;
1152
1153  private:
1154
1155  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1156  {
1157    TRACE_CLOSURE ();
1158    const Coverage &cov = (this+coverage);
1159
1160    struct ChainContextClosureLookupContext lookup_context = {
1161      {intersects_glyph, closure_func},
1162      {NULL, NULL, NULL}
1163    };
1164
1165    unsigned int count = ruleSet.len;
1166    for (unsigned int i = 0; i < count; i++)
1167      if (cov.intersects_coverage (c->glyphs, i)) {
1168	const ChainRuleSet &rule_set = this+ruleSet[i];
1169	rule_set.closure (c, lookup_context);
1170      }
1171  }
1172
1173  inline bool would_apply (hb_would_apply_context_t *c) const
1174  {
1175    TRACE_WOULD_APPLY ();
1176
1177    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->first)];
1178    struct ChainContextApplyLookupContext lookup_context = {
1179      {match_glyph, NULL},
1180      {NULL, NULL, NULL}
1181    };
1182    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1183  }
1184
1185  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1186  {
1187    TRACE_APPLY ();
1188    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1189    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1190
1191    const ChainRuleSet &rule_set = this+ruleSet[index];
1192    struct ChainContextApplyLookupContext lookup_context = {
1193      {match_glyph, apply_func},
1194      {NULL, NULL, NULL}
1195    };
1196    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1197  }
1198
1199  inline bool sanitize (hb_sanitize_context_t *c) {
1200    TRACE_SANITIZE ();
1201    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1202  }
1203
1204  protected:
1205  USHORT	format;			/* Format identifier--format = 1 */
1206  OffsetTo<Coverage>
1207		coverage;		/* Offset to Coverage table--from
1208					 * beginning of table */
1209  OffsetArrayOf<ChainRuleSet>
1210		ruleSet;		/* Array of ChainRuleSet tables
1211					 * ordered by Coverage Index */
1212  public:
1213  DEFINE_SIZE_ARRAY (6, ruleSet);
1214};
1215
1216struct ChainContextFormat2
1217{
1218  friend struct ChainContext;
1219
1220  private:
1221
1222  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1223  {
1224    TRACE_CLOSURE ();
1225    if (!(this+coverage).intersects (c->glyphs))
1226      return;
1227
1228    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1229    const ClassDef &input_class_def = this+inputClassDef;
1230    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1231
1232    struct ChainContextClosureLookupContext lookup_context = {
1233      {intersects_class, closure_func},
1234      {&backtrack_class_def,
1235       &input_class_def,
1236       &lookahead_class_def}
1237    };
1238
1239    unsigned int count = ruleSet.len;
1240    for (unsigned int i = 0; i < count; i++)
1241      if (input_class_def.intersects_class (c->glyphs, i)) {
1242	const ChainRuleSet &rule_set = this+ruleSet[i];
1243	rule_set.closure (c, lookup_context);
1244      }
1245  }
1246
1247  inline bool would_apply (hb_would_apply_context_t *c) const
1248  {
1249    TRACE_WOULD_APPLY ();
1250
1251    const ClassDef &input_class_def = this+inputClassDef;
1252
1253    unsigned int index = input_class_def (c->first);
1254    const ChainRuleSet &rule_set = this+ruleSet[index];
1255    struct ChainContextApplyLookupContext lookup_context = {
1256      {match_class, NULL},
1257      {NULL, &input_class_def, NULL}
1258    };
1259    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1260  }
1261
1262  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1263  {
1264    TRACE_APPLY ();
1265    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1266    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1267
1268    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1269    const ClassDef &input_class_def = this+inputClassDef;
1270    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1271
1272    index = input_class_def (c->buffer->cur().codepoint);
1273    const ChainRuleSet &rule_set = this+ruleSet[index];
1274    struct ChainContextApplyLookupContext lookup_context = {
1275      {match_class, apply_func},
1276      {&backtrack_class_def,
1277       &input_class_def,
1278       &lookahead_class_def}
1279    };
1280    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1281  }
1282
1283  inline bool sanitize (hb_sanitize_context_t *c) {
1284    TRACE_SANITIZE ();
1285    return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1286			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1287			 ruleSet.sanitize (c, this));
1288  }
1289
1290  protected:
1291  USHORT	format;			/* Format identifier--format = 2 */
1292  OffsetTo<Coverage>
1293		coverage;		/* Offset to Coverage table--from
1294					 * beginning of table */
1295  OffsetTo<ClassDef>
1296		backtrackClassDef;	/* Offset to glyph ClassDef table
1297					 * containing backtrack sequence
1298					 * data--from beginning of table */
1299  OffsetTo<ClassDef>
1300		inputClassDef;		/* Offset to glyph ClassDef
1301					 * table containing input sequence
1302					 * data--from beginning of table */
1303  OffsetTo<ClassDef>
1304		lookaheadClassDef;	/* Offset to glyph ClassDef table
1305					 * containing lookahead sequence
1306					 * data--from beginning of table */
1307  OffsetArrayOf<ChainRuleSet>
1308		ruleSet;		/* Array of ChainRuleSet tables
1309					 * ordered by class */
1310  public:
1311  DEFINE_SIZE_ARRAY (12, ruleSet);
1312};
1313
1314struct ChainContextFormat3
1315{
1316  friend struct ChainContext;
1317
1318  private:
1319
1320  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1321  {
1322    TRACE_CLOSURE ();
1323    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1324
1325    if (!(this+input[0]).intersects (c->glyphs))
1326      return;
1327
1328    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1329    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1330    struct ChainContextClosureLookupContext lookup_context = {
1331      {intersects_coverage, closure_func},
1332      {this, this, this}
1333    };
1334    chain_context_closure_lookup (c,
1335				  backtrack.len, (const USHORT *) backtrack.array,
1336				  input.len, (const USHORT *) input.array + 1,
1337				  lookahead.len, (const USHORT *) lookahead.array,
1338				  lookup.len, lookup.array,
1339				  lookup_context);
1340  }
1341
1342  inline const Coverage &get_coverage (void) const
1343  {
1344    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1345    return this+input[0];
1346  }
1347
1348  inline bool would_apply (hb_would_apply_context_t *c) const
1349  {
1350    TRACE_WOULD_APPLY ();
1351
1352    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1353    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1354    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1355    struct ChainContextApplyLookupContext lookup_context = {
1356      {match_coverage, NULL},
1357      {this, this, this}
1358    };
1359    return TRACE_RETURN (chain_context_would_apply_lookup (c,
1360							   backtrack.len, (const USHORT *) backtrack.array,
1361							   input.len, (const USHORT *) input.array + 1,
1362							   lookahead.len, (const USHORT *) lookahead.array,
1363							   lookup.len, lookup.array, lookup_context));
1364  }
1365
1366  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1367  {
1368    TRACE_APPLY ();
1369    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1370
1371    unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
1372    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1373
1374    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1375    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1376    struct ChainContextApplyLookupContext lookup_context = {
1377      {match_coverage, apply_func},
1378      {this, this, this}
1379    };
1380    return TRACE_RETURN (chain_context_apply_lookup (c,
1381						     backtrack.len, (const USHORT *) backtrack.array,
1382						     input.len, (const USHORT *) input.array + 1,
1383						     lookahead.len, (const USHORT *) lookahead.array,
1384						     lookup.len, lookup.array, lookup_context));
1385  }
1386
1387  inline bool sanitize (hb_sanitize_context_t *c) {
1388    TRACE_SANITIZE ();
1389    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1390    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1391    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1392    if (unlikely (!input.len)) return TRACE_RETURN (false);
1393    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1394    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1395    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1396    return TRACE_RETURN (lookup.sanitize (c));
1397  }
1398
1399  protected:
1400  USHORT	format;			/* Format identifier--format = 3 */
1401  OffsetArrayOf<Coverage>
1402		backtrack;		/* Array of coverage tables
1403					 * in backtracking sequence, in  glyph
1404					 * sequence order */
1405  OffsetArrayOf<Coverage>
1406		inputX		;	/* Array of coverage
1407					 * tables in input sequence, in glyph
1408					 * sequence order */
1409  OffsetArrayOf<Coverage>
1410		lookaheadX;		/* Array of coverage tables
1411					 * in lookahead sequence, in glyph
1412					 * sequence order */
1413  ArrayOf<LookupRecord>
1414		lookupX;		/* Array of LookupRecords--in
1415					 * design order) */
1416  public:
1417  DEFINE_SIZE_MIN (10);
1418};
1419
1420struct ChainContext
1421{
1422  protected:
1423
1424  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1425  {
1426    TRACE_CLOSURE ();
1427    switch (u.format) {
1428    case 1: u.format1.closure (c, closure_func); break;
1429    case 2: u.format2.closure (c, closure_func); break;
1430    case 3: u.format3.closure (c, closure_func); break;
1431    default:                                     break;
1432    }
1433  }
1434
1435  inline const Coverage &get_coverage (void) const
1436  {
1437    switch (u.format) {
1438    case 1: return this + u.format1.coverage;
1439    case 2: return this + u.format2.coverage;
1440    case 3: return u.format3.get_coverage ();
1441    default:return Null(Coverage);
1442    }
1443  }
1444
1445  inline bool would_apply (hb_would_apply_context_t *c) const
1446  {
1447    switch (u.format) {
1448    case 1: return u.format1.would_apply (c);
1449    case 2: return u.format2.would_apply (c);
1450    case 3: return u.format3.would_apply (c);
1451    default:return false;
1452    }
1453  }
1454
1455  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1456  {
1457    TRACE_APPLY ();
1458    switch (u.format) {
1459    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
1460    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
1461    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
1462    default:return TRACE_RETURN (false);
1463    }
1464  }
1465
1466  inline bool sanitize (hb_sanitize_context_t *c) {
1467    TRACE_SANITIZE ();
1468    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1469    switch (u.format) {
1470    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1471    case 2: return TRACE_RETURN (u.format2.sanitize (c));
1472    case 3: return TRACE_RETURN (u.format3.sanitize (c));
1473    default:return TRACE_RETURN (true);
1474    }
1475  }
1476
1477  protected:
1478  union {
1479  USHORT		format;	/* Format identifier */
1480  ChainContextFormat1	format1;
1481  ChainContextFormat2	format2;
1482  ChainContextFormat3	format3;
1483  } u;
1484};
1485
1486
1487struct ExtensionFormat1
1488{
1489  friend struct Extension;
1490
1491  protected:
1492  inline unsigned int get_type (void) const { return extensionLookupType; }
1493  inline unsigned int get_offset (void) const { return extensionOffset; }
1494
1495  inline bool sanitize (hb_sanitize_context_t *c) {
1496    TRACE_SANITIZE ();
1497    return TRACE_RETURN (c->check_struct (this));
1498  }
1499
1500  protected:
1501  USHORT	format;			/* Format identifier. Set to 1. */
1502  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
1503					 * by ExtensionOffset (i.e. the
1504					 * extension subtable). */
1505  ULONG		extensionOffset;	/* Offset to the extension subtable,
1506					 * of lookup type subtable. */
1507  public:
1508  DEFINE_SIZE_STATIC (8);
1509};
1510
1511struct Extension
1512{
1513  inline unsigned int get_type (void) const
1514  {
1515    switch (u.format) {
1516    case 1: return u.format1.get_type ();
1517    default:return 0;
1518    }
1519  }
1520  inline unsigned int get_offset (void) const
1521  {
1522    switch (u.format) {
1523    case 1: return u.format1.get_offset ();
1524    default:return 0;
1525    }
1526  }
1527
1528  inline bool sanitize (hb_sanitize_context_t *c) {
1529    TRACE_SANITIZE ();
1530    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1531    switch (u.format) {
1532    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1533    default:return TRACE_RETURN (true);
1534    }
1535  }
1536
1537  protected:
1538  union {
1539  USHORT		format;		/* Format identifier */
1540  ExtensionFormat1	format1;
1541  } u;
1542};
1543
1544
1545/*
1546 * GSUB/GPOS Common
1547 */
1548
1549struct GSUBGPOS
1550{
1551  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
1552  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
1553
1554  inline unsigned int get_script_count (void) const
1555  { return (this+scriptList).len; }
1556  inline const Tag& get_script_tag (unsigned int i) const
1557  { return (this+scriptList).get_tag (i); }
1558  inline unsigned int get_script_tags (unsigned int start_offset,
1559				       unsigned int *script_count /* IN/OUT */,
1560				       hb_tag_t     *script_tags /* OUT */) const
1561  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
1562  inline const Script& get_script (unsigned int i) const
1563  { return (this+scriptList)[i]; }
1564  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
1565  { return (this+scriptList).find_index (tag, index); }
1566
1567  inline unsigned int get_feature_count (void) const
1568  { return (this+featureList).len; }
1569  inline const Tag& get_feature_tag (unsigned int i) const
1570  { return (this+featureList).get_tag (i); }
1571  inline unsigned int get_feature_tags (unsigned int start_offset,
1572					unsigned int *feature_count /* IN/OUT */,
1573					hb_tag_t     *feature_tags /* OUT */) const
1574  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
1575  inline const Feature& get_feature (unsigned int i) const
1576  { return (this+featureList)[i]; }
1577  inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
1578  { return (this+featureList).find_index (tag, index); }
1579
1580  inline unsigned int get_lookup_count (void) const
1581  { return (this+lookupList).len; }
1582  inline const Lookup& get_lookup (unsigned int i) const
1583  { return (this+lookupList)[i]; }
1584
1585  inline bool sanitize (hb_sanitize_context_t *c) {
1586    TRACE_SANITIZE ();
1587    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
1588			 scriptList.sanitize (c, this) &&
1589			 featureList.sanitize (c, this) &&
1590			 lookupList.sanitize (c, this));
1591  }
1592
1593  protected:
1594  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
1595				 * to 0x00010000 */
1596  OffsetTo<ScriptList>
1597		scriptList;  	/* ScriptList table */
1598  OffsetTo<FeatureList>
1599		featureList; 	/* FeatureList table */
1600  OffsetTo<LookupList>
1601		lookupList; 	/* LookupList table */
1602  public:
1603  DEFINE_SIZE_STATIC (10);
1604};
1605
1606
1607
1608#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
1609