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