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