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