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