• 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_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_HH
31 
32 #include "hb.hh"
33 #include "hb-buffer.hh"
34 #include "hb-map.hh"
35 #include "hb-set.hh"
36 #include "hb-ot-map.hh"
37 #include "hb-ot-layout-common.hh"
38 #include "hb-ot-layout-gdef-table.hh"
39 
40 
41 namespace OT {
42 
43 
44 struct hb_intersects_context_t :
45        hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
46 {
get_nameOT::hb_intersects_context_t47   const char *get_name () { return "INTERSECTS"; }
48   template <typename T>
dispatchOT::hb_intersects_context_t49   return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
default_return_valueOT::hb_intersects_context_t50   static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_intersects_context_t51   bool stop_sublookup_iteration (return_t r) const { return r; }
52 
53   const hb_set_t *glyphs;
54   unsigned int debug_depth;
55 
hb_intersects_context_tOT::hb_intersects_context_t56   hb_intersects_context_t (const hb_set_t *glyphs_) :
57 			     glyphs (glyphs_),
58 			     debug_depth (0) {}
59 };
60 
61 struct hb_closure_context_t :
62        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
63 {
get_nameOT::hb_closure_context_t64   const char *get_name () { return "CLOSURE"; }
65   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
66   template <typename T>
dispatchOT::hb_closure_context_t67   return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
default_return_valueOT::hb_closure_context_t68   static return_t default_return_value () { return HB_VOID; }
recurseOT::hb_closure_context_t69   void recurse (unsigned int lookup_index)
70   {
71     if (unlikely (nesting_level_left == 0 || !recurse_func))
72       return;
73 
74     nesting_level_left--;
75     recurse_func (this, lookup_index);
76     nesting_level_left++;
77   }
78 
should_visit_lookupOT::hb_closure_context_t79   bool should_visit_lookup (unsigned int lookup_index)
80   {
81     if (is_lookup_done (lookup_index))
82       return false;
83     done_lookups->set (lookup_index, glyphs->get_population ());
84     return true;
85   }
86 
is_lookup_doneOT::hb_closure_context_t87   bool is_lookup_done (unsigned int lookup_index)
88   {
89     /* Have we visited this lookup with the current set of glyphs? */
90     return done_lookups->get (lookup_index) == glyphs->get_population ();
91   }
92 
93   hb_face_t *face;
94   hb_set_t *glyphs;
95   hb_set_t out[1];
96   recurse_func_t recurse_func;
97   unsigned int nesting_level_left;
98   unsigned int debug_depth;
99 
hb_closure_context_tOT::hb_closure_context_t100   hb_closure_context_t (hb_face_t *face_,
101 			hb_set_t *glyphs_,
102 			hb_map_t *done_lookups_,
103 			unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
104 			  face (face_),
105 			  glyphs (glyphs_),
106 			  recurse_func (nullptr),
107 			  nesting_level_left (nesting_level_left_),
108 			  debug_depth (0),
109 			  done_lookups (done_lookups_) {}
110 
~hb_closure_context_tOT::hb_closure_context_t111   ~hb_closure_context_t () { flush (); }
112 
set_recurse_funcOT::hb_closure_context_t113   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
114 
flushOT::hb_closure_context_t115   void flush ()
116   {
117     hb_set_union (glyphs, out);
118     hb_set_clear (out);
119   }
120 
121   private:
122   hb_map_t *done_lookups;
123 };
124 
125 
126 struct hb_would_apply_context_t :
127        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
128 {
get_nameOT::hb_would_apply_context_t129   const char *get_name () { return "WOULD_APPLY"; }
130   template <typename T>
dispatchOT::hb_would_apply_context_t131   return_t dispatch (const T &obj) { return obj.would_apply (this); }
default_return_valueOT::hb_would_apply_context_t132   static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_would_apply_context_t133   bool stop_sublookup_iteration (return_t r) const { return r; }
134 
135   hb_face_t *face;
136   const hb_codepoint_t *glyphs;
137   unsigned int len;
138   bool zero_context;
139   unsigned int debug_depth;
140 
hb_would_apply_context_tOT::hb_would_apply_context_t141   hb_would_apply_context_t (hb_face_t *face_,
142 			    const hb_codepoint_t *glyphs_,
143 			    unsigned int len_,
144 			    bool zero_context_) :
145 			      face (face_),
146 			      glyphs (glyphs_),
147 			      len (len_),
148 			      zero_context (zero_context_),
149 			      debug_depth (0) {}
150 };
151 
152 
153 struct hb_collect_glyphs_context_t :
154        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
155 {
get_nameOT::hb_collect_glyphs_context_t156   const char *get_name () { return "COLLECT_GLYPHS"; }
157   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
158   template <typename T>
dispatchOT::hb_collect_glyphs_context_t159   return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
default_return_valueOT::hb_collect_glyphs_context_t160   static return_t default_return_value () { return HB_VOID; }
recurseOT::hb_collect_glyphs_context_t161   void recurse (unsigned int lookup_index)
162   {
163     if (unlikely (nesting_level_left == 0 || !recurse_func))
164       return;
165 
166     /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
167      * past the previous check.  For GSUB, we only want to collect the output
168      * glyphs in the recursion.  If output is not requested, we can go home now.
169      *
170      * Note further, that the above is not exactly correct.  A recursed lookup
171      * is allowed to match input that is not matched in the context, but that's
172      * not how most fonts are built.  It's possible to relax that and recurse
173      * with all sets here if it proves to be an issue.
174      */
175 
176     if (output == hb_set_get_empty ())
177       return;
178 
179     /* Return if new lookup was recursed to before. */
180     if (recursed_lookups->has (lookup_index))
181       return;
182 
183     hb_set_t *old_before = before;
184     hb_set_t *old_input  = input;
185     hb_set_t *old_after  = after;
186     before = input = after = hb_set_get_empty ();
187 
188     nesting_level_left--;
189     recurse_func (this, lookup_index);
190     nesting_level_left++;
191 
192     before = old_before;
193     input  = old_input;
194     after  = old_after;
195 
196     recursed_lookups->add (lookup_index);
197   }
198 
199   hb_face_t *face;
200   hb_set_t *before;
201   hb_set_t *input;
202   hb_set_t *after;
203   hb_set_t *output;
204   recurse_func_t recurse_func;
205   hb_set_t *recursed_lookups;
206   unsigned int nesting_level_left;
207   unsigned int debug_depth;
208 
hb_collect_glyphs_context_tOT::hb_collect_glyphs_context_t209   hb_collect_glyphs_context_t (hb_face_t *face_,
210 			       hb_set_t  *glyphs_before, /* OUT.  May be NULL */
211 			       hb_set_t  *glyphs_input,  /* OUT.  May be NULL */
212 			       hb_set_t  *glyphs_after,  /* OUT.  May be NULL */
213 			       hb_set_t  *glyphs_output, /* OUT.  May be NULL */
214 			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
215 			      face (face_),
216 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
217 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
218 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
219 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
220 			      recurse_func (nullptr),
221 			      recursed_lookups (hb_set_create ()),
222 			      nesting_level_left (nesting_level_left_),
223 			      debug_depth (0) {}
~hb_collect_glyphs_context_tOT::hb_collect_glyphs_context_t224   ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
225 
set_recurse_funcOT::hb_collect_glyphs_context_t226   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
227 };
228 
229 
230 
231 template <typename set_t>
232 struct hb_add_coverage_context_t :
233        hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
234 {
get_nameOT::hb_add_coverage_context_t235   const char *get_name () { return "GET_COVERAGE"; }
236   typedef const Coverage &return_t;
237   template <typename T>
dispatchOT::hb_add_coverage_context_t238   return_t dispatch (const T &obj) { return obj.get_coverage (); }
default_return_valueOT::hb_add_coverage_context_t239   static return_t default_return_value () { return Null(Coverage); }
stop_sublookup_iterationOT::hb_add_coverage_context_t240   bool stop_sublookup_iteration (return_t r) const
241   {
242     r.add_coverage (set);
243     return false;
244   }
245 
hb_add_coverage_context_tOT::hb_add_coverage_context_t246   hb_add_coverage_context_t (set_t *set_) :
247 			    set (set_),
248 			    debug_depth (0) {}
249 
250   set_t *set;
251   unsigned int debug_depth;
252 };
253 
254 
255 struct hb_ot_apply_context_t :
256        hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
257 {
258   struct matcher_t
259   {
matcher_tOT::hb_ot_apply_context_t::matcher_t260     matcher_t () :
261 	     lookup_props (0),
262 	     ignore_zwnj (false),
263 	     ignore_zwj (false),
264 	     mask (-1),
265 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
266 	     syllable arg1(0),
267 #undef arg1
268 	     match_func (nullptr),
269 	     match_data (nullptr) {}
270 
271     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
272 
set_ignore_zwnjOT::hb_ot_apply_context_t::matcher_t273     void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
set_ignore_zwjOT::hb_ot_apply_context_t::matcher_t274     void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
set_lookup_propsOT::hb_ot_apply_context_t::matcher_t275     void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
set_maskOT::hb_ot_apply_context_t::matcher_t276     void set_mask (hb_mask_t mask_) { mask = mask_; }
set_syllableOT::hb_ot_apply_context_t::matcher_t277     void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
set_match_funcOT::hb_ot_apply_context_t::matcher_t278     void set_match_func (match_func_t match_func_,
279 				const void *match_data_)
280     { match_func = match_func_; match_data = match_data_; }
281 
282     enum may_match_t {
283       MATCH_NO,
284       MATCH_YES,
285       MATCH_MAYBE
286     };
287 
may_matchOT::hb_ot_apply_context_t::matcher_t288     may_match_t may_match (const hb_glyph_info_t &info,
289 				  const HBUINT16        *glyph_data) const
290     {
291       if (!(info.mask & mask) ||
292 	  (syllable && syllable != info.syllable ()))
293 	return MATCH_NO;
294 
295       if (match_func)
296 	return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
297 
298       return MATCH_MAYBE;
299     }
300 
301     enum may_skip_t {
302       SKIP_NO,
303       SKIP_YES,
304       SKIP_MAYBE
305     };
306 
may_skipOT::hb_ot_apply_context_t::matcher_t307     may_skip_t may_skip (const hb_ot_apply_context_t *c,
308 			 const hb_glyph_info_t       &info) const
309     {
310       if (!c->check_glyph_property (&info, lookup_props))
311 	return SKIP_YES;
312 
313       if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
314 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
315 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
316 	return SKIP_MAYBE;
317 
318       return SKIP_NO;
319     }
320 
321     protected:
322     unsigned int lookup_props;
323     bool ignore_zwnj;
324     bool ignore_zwj;
325     hb_mask_t mask;
326     uint8_t syllable;
327     match_func_t match_func;
328     const void *match_data;
329   };
330 
331   struct skipping_iterator_t
332   {
initOT::hb_ot_apply_context_t::skipping_iterator_t333     void init (hb_ot_apply_context_t *c_, bool context_match = false)
334     {
335       c = c_;
336       match_glyph_data = nullptr;
337       matcher.set_match_func (nullptr, nullptr);
338       matcher.set_lookup_props (c->lookup_props);
339       /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
340       matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
341       /* Ignore ZWJ if we are matching context, or asked to. */
342       matcher.set_ignore_zwj  (context_match || c->auto_zwj);
343       matcher.set_mask (context_match ? -1 : c->lookup_mask);
344     }
set_lookup_propsOT::hb_ot_apply_context_t::skipping_iterator_t345     void set_lookup_props (unsigned int lookup_props)
346     {
347       matcher.set_lookup_props (lookup_props);
348     }
set_match_funcOT::hb_ot_apply_context_t::skipping_iterator_t349     void set_match_func (matcher_t::match_func_t match_func_,
350 			 const void *match_data_,
351 			 const HBUINT16 glyph_data[])
352     {
353       matcher.set_match_func (match_func_, match_data_);
354       match_glyph_data = glyph_data;
355     }
356 
resetOT::hb_ot_apply_context_t::skipping_iterator_t357     void reset (unsigned int start_index_,
358 		       unsigned int num_items_)
359     {
360       idx = start_index_;
361       num_items = num_items_;
362       end = c->buffer->len;
363       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
364     }
365 
rejectOT::hb_ot_apply_context_t::skipping_iterator_t366     void reject () { num_items++; match_glyph_data--; }
367 
368     matcher_t::may_skip_t
may_skipOT::hb_ot_apply_context_t::skipping_iterator_t369     may_skip (const hb_glyph_info_t &info) const
370     { return matcher.may_skip (c, info); }
371 
nextOT::hb_ot_apply_context_t::skipping_iterator_t372     bool next ()
373     {
374       assert (num_items > 0);
375       while (idx + num_items < end)
376       {
377 	idx++;
378 	const hb_glyph_info_t &info = c->buffer->info[idx];
379 
380 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
381 	if (unlikely (skip == matcher_t::SKIP_YES))
382 	  continue;
383 
384 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
385 	if (match == matcher_t::MATCH_YES ||
386 	    (match == matcher_t::MATCH_MAYBE &&
387 	     skip == matcher_t::SKIP_NO))
388 	{
389 	  num_items--;
390 	  match_glyph_data++;
391 	  return true;
392 	}
393 
394 	if (skip == matcher_t::SKIP_NO)
395 	  return false;
396       }
397       return false;
398     }
prevOT::hb_ot_apply_context_t::skipping_iterator_t399     bool prev ()
400     {
401       assert (num_items > 0);
402       while (idx > num_items - 1)
403       {
404 	idx--;
405 	const hb_glyph_info_t &info = c->buffer->out_info[idx];
406 
407 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
408 	if (unlikely (skip == matcher_t::SKIP_YES))
409 	  continue;
410 
411 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
412 	if (match == matcher_t::MATCH_YES ||
413 	    (match == matcher_t::MATCH_MAYBE &&
414 	     skip == matcher_t::SKIP_NO))
415 	{
416 	  num_items--;
417 	  match_glyph_data++;
418 	  return true;
419 	}
420 
421 	if (skip == matcher_t::SKIP_NO)
422 	  return false;
423       }
424       return false;
425     }
426 
427     unsigned int idx;
428     protected:
429     hb_ot_apply_context_t *c;
430     matcher_t matcher;
431     const HBUINT16 *match_glyph_data;
432 
433     unsigned int num_items;
434     unsigned int end;
435   };
436 
437 
get_nameOT::hb_ot_apply_context_t438   const char *get_name () { return "APPLY"; }
439   typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
440   template <typename T>
dispatchOT::hb_ot_apply_context_t441   return_t dispatch (const T &obj) { return obj.apply (this); }
default_return_valueOT::hb_ot_apply_context_t442   static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_ot_apply_context_t443   bool stop_sublookup_iteration (return_t r) const { return r; }
recurseOT::hb_ot_apply_context_t444   return_t recurse (unsigned int sub_lookup_index)
445   {
446     if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
447       return default_return_value ();
448 
449     nesting_level_left--;
450     bool ret = recurse_func (this, sub_lookup_index);
451     nesting_level_left++;
452     return ret;
453   }
454 
455   skipping_iterator_t iter_input, iter_context;
456 
457   hb_font_t *font;
458   hb_face_t *face;
459   hb_buffer_t *buffer;
460   recurse_func_t recurse_func;
461   const GDEF &gdef;
462   const VariationStore &var_store;
463 
464   hb_direction_t direction;
465   hb_mask_t lookup_mask;
466   unsigned int table_index; /* GSUB/GPOS */
467   unsigned int lookup_index;
468   unsigned int lookup_props;
469   unsigned int nesting_level_left;
470   unsigned int debug_depth;
471 
472   bool has_glyph_classes;
473   bool auto_zwnj;
474   bool auto_zwj;
475   bool random;
476 
477   uint32_t random_state;
478 
479 
hb_ot_apply_context_tOT::hb_ot_apply_context_t480   hb_ot_apply_context_t (unsigned int table_index_,
481 		      hb_font_t *font_,
482 		      hb_buffer_t *buffer_) :
483 			iter_input (), iter_context (),
484 			font (font_), face (font->face), buffer (buffer_),
485 			recurse_func (nullptr),
486 			gdef (*face->table.GDEF->table),
487 			var_store (gdef.get_var_store ()),
488 			direction (buffer_->props.direction),
489 			lookup_mask (1),
490 			table_index (table_index_),
491 			lookup_index ((unsigned int) -1),
492 			lookup_props (0),
493 			nesting_level_left (HB_MAX_NESTING_LEVEL),
494 			debug_depth (0),
495 			has_glyph_classes (gdef.has_glyph_classes ()),
496 			auto_zwnj (true),
497 			auto_zwj (true),
498 			random (false),
499 			random_state (1) { init_iters (); }
500 
init_itersOT::hb_ot_apply_context_t501   void init_iters ()
502   {
503     iter_input.init (this, false);
504     iter_context.init (this, true);
505   }
506 
set_lookup_maskOT::hb_ot_apply_context_t507   void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
set_auto_zwjOT::hb_ot_apply_context_t508   void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
set_auto_zwnjOT::hb_ot_apply_context_t509   void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
set_randomOT::hb_ot_apply_context_t510   void set_random (bool random_) { random = random_; }
set_recurse_funcOT::hb_ot_apply_context_t511   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
set_lookup_indexOT::hb_ot_apply_context_t512   void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
set_lookup_propsOT::hb_ot_apply_context_t513   void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
514 
random_numberOT::hb_ot_apply_context_t515   uint32_t random_number ()
516   {
517     /* http://www.cplusplus.com/reference/random/minstd_rand/ */
518     random_state = random_state * 48271 % 2147483647;
519     return random_state;
520   }
521 
match_properties_markOT::hb_ot_apply_context_t522   bool match_properties_mark (hb_codepoint_t  glyph,
523 			      unsigned int    glyph_props,
524 			      unsigned int    match_props) const
525   {
526     /* If using mark filtering sets, the high short of
527      * match_props has the set index.
528      */
529     if (match_props & LookupFlag::UseMarkFilteringSet)
530       return gdef.mark_set_covers (match_props >> 16, glyph);
531 
532     /* The second byte of match_props has the meaning
533      * "ignore marks of attachment type different than
534      * the attachment type specified."
535      */
536     if (match_props & LookupFlag::MarkAttachmentType)
537       return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
538 
539     return true;
540   }
541 
check_glyph_propertyOT::hb_ot_apply_context_t542   bool check_glyph_property (const hb_glyph_info_t *info,
543 			     unsigned int  match_props) const
544   {
545     hb_codepoint_t glyph = info->codepoint;
546     unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
547 
548     /* Not covered, if, for example, glyph class is ligature and
549      * match_props includes LookupFlags::IgnoreLigatures
550      */
551     if (glyph_props & match_props & LookupFlag::IgnoreFlags)
552       return false;
553 
554     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
555       return match_properties_mark (glyph, glyph_props, match_props);
556 
557     return true;
558   }
559 
_set_glyph_propsOT::hb_ot_apply_context_t560   void _set_glyph_props (hb_codepoint_t glyph_index,
561 			  unsigned int class_guess = 0,
562 			  bool ligature = false,
563 			  bool component = false) const
564   {
565     unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
566 			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
567     add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
568     if (ligature)
569     {
570       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
571       /* In the only place that the MULTIPLIED bit is used, Uniscribe
572        * seems to only care about the "last" transformation between
573        * Ligature and Multiple substitutions.  Ie. if you ligate, expand,
574        * and ligate again, it forgives the multiplication and acts as
575        * if only ligation happened.  As such, clear MULTIPLIED bit.
576        */
577       add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
578     }
579     if (component)
580       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
581     if (likely (has_glyph_classes))
582       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
583     else if (class_guess)
584       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
585   }
586 
replace_glyphOT::hb_ot_apply_context_t587   void replace_glyph (hb_codepoint_t glyph_index) const
588   {
589     _set_glyph_props (glyph_index);
590     buffer->replace_glyph (glyph_index);
591   }
replace_glyph_inplaceOT::hb_ot_apply_context_t592   void replace_glyph_inplace (hb_codepoint_t glyph_index) const
593   {
594     _set_glyph_props (glyph_index);
595     buffer->cur().codepoint = glyph_index;
596   }
replace_glyph_with_ligatureOT::hb_ot_apply_context_t597   void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
598 					   unsigned int class_guess) const
599   {
600     _set_glyph_props (glyph_index, class_guess, true);
601     buffer->replace_glyph (glyph_index);
602   }
output_glyph_for_componentOT::hb_ot_apply_context_t603   void output_glyph_for_component (hb_codepoint_t glyph_index,
604 					  unsigned int class_guess) const
605   {
606     _set_glyph_props (glyph_index, class_guess, false, true);
607     buffer->output_glyph (glyph_index);
608   }
609 };
610 
611 
612 struct hb_get_subtables_context_t :
613        hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
614 {
615   template <typename Type>
apply_toOT::hb_get_subtables_context_t616   static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
617   {
618     const Type *typed_obj = (const Type *) obj;
619     return typed_obj->apply (c);
620   }
621 
622   typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
623 
624   struct hb_applicable_t
625   {
626     template <typename T>
initOT::hb_get_subtables_context_t::hb_applicable_t627     void init (const T &obj_, hb_apply_func_t apply_func_)
628     {
629       obj = &obj_;
630       apply_func = apply_func_;
631       digest.init ();
632       obj_.get_coverage ().add_coverage (&digest);
633     }
634 
applyOT::hb_get_subtables_context_t::hb_applicable_t635     bool apply (OT::hb_ot_apply_context_t *c) const
636     {
637       return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
638     }
639 
640     private:
641     const void *obj;
642     hb_apply_func_t apply_func;
643     hb_set_digest_t digest;
644   };
645 
646   typedef hb_vector_t<hb_applicable_t, 2> array_t;
647 
648   /* Dispatch interface. */
get_nameOT::hb_get_subtables_context_t649   const char *get_name () { return "GET_SUBTABLES"; }
650   template <typename T>
dispatchOT::hb_get_subtables_context_t651   return_t dispatch (const T &obj)
652   {
653     hb_applicable_t *entry = array.push();
654     entry->init (obj, apply_to<T>);
655     return HB_VOID;
656   }
default_return_valueOT::hb_get_subtables_context_t657   static return_t default_return_value () { return HB_VOID; }
658 
hb_get_subtables_context_tOT::hb_get_subtables_context_t659   hb_get_subtables_context_t (array_t &array_) :
660 			      array (array_),
661 			      debug_depth (0) {}
662 
663   array_t &array;
664   unsigned int debug_depth;
665 };
666 
667 
668 
669 
670 typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
671 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
672 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
673 
674 struct ContextClosureFuncs
675 {
676   intersects_func_t intersects;
677 };
678 struct ContextCollectGlyphsFuncs
679 {
680   collect_glyphs_func_t collect;
681 };
682 struct ContextApplyFuncs
683 {
684   match_func_t match;
685 };
686 
687 
intersects_glyph(const hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)688 static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
689 {
690   return glyphs->has (value);
691 }
intersects_class(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)692 static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
693 {
694   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
695   return class_def.intersects_class (glyphs, value);
696 }
intersects_coverage(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)697 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
698 {
699   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
700   return (data+coverage).intersects (glyphs);
701 }
702 
intersects_array(const hb_set_t * glyphs,unsigned int count,const HBUINT16 values[],intersects_func_t intersects_func,const void * intersects_data)703 static inline bool intersects_array (const hb_set_t *glyphs,
704 				     unsigned int count,
705 				     const HBUINT16 values[],
706 				     intersects_func_t intersects_func,
707 				     const void *intersects_data)
708 {
709   for (unsigned int i = 0; i < count; i++)
710     if (likely (!intersects_func (glyphs, values[i], intersects_data)))
711       return false;
712   return true;
713 }
714 
715 
collect_glyph(hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)716 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
717 {
718   glyphs->add (value);
719 }
collect_class(hb_set_t * glyphs,const HBUINT16 & value,const void * data)720 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
721 {
722   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
723   class_def.add_class (glyphs, value);
724 }
collect_coverage(hb_set_t * glyphs,const HBUINT16 & value,const void * data)725 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
726 {
727   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
728   (data+coverage).add_coverage (glyphs);
729 }
collect_array(hb_collect_glyphs_context_t * c HB_UNUSED,hb_set_t * glyphs,unsigned int count,const HBUINT16 values[],collect_glyphs_func_t collect_func,const void * collect_data)730 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
731 				  hb_set_t *glyphs,
732 				  unsigned int count,
733 				  const HBUINT16 values[],
734 				  collect_glyphs_func_t collect_func,
735 				  const void *collect_data)
736 {
737   for (unsigned int i = 0; i < count; i++)
738     collect_func (glyphs, values[i], collect_data);
739 }
740 
741 
match_glyph(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data HB_UNUSED)742 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
743 {
744   return glyph_id == value;
745 }
match_class(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)746 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
747 {
748   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
749   return class_def.get_class (glyph_id) == value;
750 }
match_coverage(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)751 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
752 {
753   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
754   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
755 }
756 
would_match_input(hb_would_apply_context_t * c,unsigned int count,const HBUINT16 input[],match_func_t match_func,const void * match_data)757 static inline bool would_match_input (hb_would_apply_context_t *c,
758 				      unsigned int count, /* Including the first glyph (not matched) */
759 				      const HBUINT16 input[], /* Array of input values--start with second glyph */
760 				      match_func_t match_func,
761 				      const void *match_data)
762 {
763   if (count != c->len)
764     return false;
765 
766   for (unsigned int i = 1; i < count; i++)
767     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
768       return false;
769 
770   return true;
771 }
match_input(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 input[],match_func_t match_func,const void * match_data,unsigned int * end_offset,unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],unsigned int * p_total_component_count=nullptr)772 static inline bool match_input (hb_ot_apply_context_t *c,
773 				unsigned int count, /* Including the first glyph (not matched) */
774 				const HBUINT16 input[], /* Array of input values--start with second glyph */
775 				match_func_t match_func,
776 				const void *match_data,
777 				unsigned int *end_offset,
778 				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
779 				unsigned int *p_total_component_count = nullptr)
780 {
781   TRACE_APPLY (nullptr);
782 
783   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
784 
785   hb_buffer_t *buffer = c->buffer;
786 
787   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
788   skippy_iter.reset (buffer->idx, count - 1);
789   skippy_iter.set_match_func (match_func, match_data, input);
790 
791   /*
792    * This is perhaps the trickiest part of OpenType...  Remarks:
793    *
794    * - If all components of the ligature were marks, we call this a mark ligature.
795    *
796    * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
797    *   it as a ligature glyph.
798    *
799    * - Ligatures cannot be formed across glyphs attached to different components
800    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
801    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
802    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
803    *   There are a couple of exceptions to this:
804    *
805    *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
806    *     assuming that the font designer knows what they are doing (otherwise it can
807    *     break Indic stuff when a matra wants to ligate with a conjunct,
808    *
809    *   o If two marks want to ligate and they belong to different components of the
810    *     same ligature glyph, and said ligature glyph is to be ignored according to
811    *     mark-filtering rules, then allow.
812    *     https://github.com/harfbuzz/harfbuzz/issues/545
813    */
814 
815   unsigned int total_component_count = 0;
816   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
817 
818   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
819   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
820 
821   enum {
822     LIGBASE_NOT_CHECKED,
823     LIGBASE_MAY_NOT_SKIP,
824     LIGBASE_MAY_SKIP
825   } ligbase = LIGBASE_NOT_CHECKED;
826 
827   match_positions[0] = buffer->idx;
828   for (unsigned int i = 1; i < count; i++)
829   {
830     if (!skippy_iter.next ()) return_trace (false);
831 
832     match_positions[i] = skippy_iter.idx;
833 
834     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
835     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
836 
837     if (first_lig_id && first_lig_comp)
838     {
839       /* If first component was attached to a previous ligature component,
840        * all subsequent components should be attached to the same ligature
841        * component, otherwise we shouldn't ligate them... */
842       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
843       {
844 	/* ...unless, we are attached to a base ligature and that base
845 	 * ligature is ignorable. */
846 	if (ligbase == LIGBASE_NOT_CHECKED)
847 	{
848 	  bool found = false;
849 	  const hb_glyph_info_t *out = buffer->out_info;
850 	  unsigned int j = buffer->out_len;
851 	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
852 	  {
853 	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
854 	    {
855 	      j--;
856 	      found = true;
857 	      break;
858 	    }
859 	    j--;
860 	  }
861 
862 	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
863 	    ligbase = LIGBASE_MAY_SKIP;
864 	  else
865 	    ligbase = LIGBASE_MAY_NOT_SKIP;
866 	}
867 
868 	if (ligbase == LIGBASE_MAY_NOT_SKIP)
869 	  return_trace (false);
870       }
871     }
872     else
873     {
874       /* If first component was NOT attached to a previous ligature component,
875        * all subsequent components should also NOT be attached to any ligature
876        * component, unless they are attached to the first component itself! */
877       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
878 	return_trace (false);
879     }
880 
881     total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
882   }
883 
884   *end_offset = skippy_iter.idx - buffer->idx + 1;
885 
886   if (p_total_component_count)
887     *p_total_component_count = total_component_count;
888 
889   return_trace (true);
890 }
ligate_input(hb_ot_apply_context_t * c,unsigned int count,const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],unsigned int match_length,hb_codepoint_t lig_glyph,unsigned int total_component_count)891 static inline bool ligate_input (hb_ot_apply_context_t *c,
892 				 unsigned int count, /* Including the first glyph */
893 				 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
894 				 unsigned int match_length,
895 				 hb_codepoint_t lig_glyph,
896 				 unsigned int total_component_count)
897 {
898   TRACE_APPLY (nullptr);
899 
900   hb_buffer_t *buffer = c->buffer;
901 
902   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
903 
904   /* - If a base and one or more marks ligate, consider that as a base, NOT
905    *   ligature, such that all following marks can still attach to it.
906    *   https://github.com/harfbuzz/harfbuzz/issues/1109
907    *
908    * - If all components of the ligature were marks, we call this a mark ligature.
909    *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
910    *   the ligature to keep its old ligature id.  This will allow it to attach to
911    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
912    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
913    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
914    *   later, we don't want them to lose their ligature id/component, otherwise
915    *   GPOS will fail to correctly position the mark ligature on top of the
916    *   LAM,LAM,HEH ligature.  See:
917    *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
918    *
919    * - If a ligature is formed of components that some of which are also ligatures
920    *   themselves, and those ligature components had marks attached to *their*
921    *   components, we have to attach the marks to the new ligature component
922    *   positions!  Now *that*'s tricky!  And these marks may be following the
923    *   last component of the whole sequence, so we should loop forward looking
924    *   for them and update them.
925    *
926    *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
927    *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
928    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
929    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
930    *   the new ligature with a component value of 2.
931    *
932    *   This in fact happened to a font...  See:
933    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
934    */
935 
936   bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
937   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
938   for (unsigned int i = 1; i < count; i++)
939     if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
940     {
941       is_base_ligature = false;
942       is_mark_ligature = false;
943       break;
944     }
945   bool is_ligature = !is_base_ligature && !is_mark_ligature;
946 
947   unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
948   unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
949   unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
950   unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
951   unsigned int components_so_far = last_num_components;
952 
953   if (is_ligature)
954   {
955     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
956     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
957     {
958       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
959     }
960   }
961   c->replace_glyph_with_ligature (lig_glyph, klass);
962 
963   for (unsigned int i = 1; i < count; i++)
964   {
965     while (buffer->idx < match_positions[i] && buffer->successful)
966     {
967       if (is_ligature)
968       {
969 	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
970 	if (this_comp == 0)
971 	  this_comp = last_num_components;
972 	unsigned int new_lig_comp = components_so_far - last_num_components +
973 				    MIN (this_comp, last_num_components);
974 	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
975       }
976       buffer->next_glyph ();
977     }
978 
979     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
980     last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
981     components_so_far += last_num_components;
982 
983     /* Skip the base glyph */
984     buffer->idx++;
985   }
986 
987   if (!is_mark_ligature && last_lig_id) {
988     /* Re-adjust components for any marks following. */
989     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
990       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
991 	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
992 	if (!this_comp)
993 	  break;
994 	unsigned int new_lig_comp = components_so_far - last_num_components +
995 				    MIN (this_comp, last_num_components);
996 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
997       } else
998 	break;
999     }
1000   }
1001   return_trace (true);
1002 }
1003 
match_backtrack(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 backtrack[],match_func_t match_func,const void * match_data,unsigned int * match_start)1004 static inline bool match_backtrack (hb_ot_apply_context_t *c,
1005 				    unsigned int count,
1006 				    const HBUINT16 backtrack[],
1007 				    match_func_t match_func,
1008 				    const void *match_data,
1009 				    unsigned int *match_start)
1010 {
1011   TRACE_APPLY (nullptr);
1012 
1013   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1014   skippy_iter.reset (c->buffer->backtrack_len (), count);
1015   skippy_iter.set_match_func (match_func, match_data, backtrack);
1016 
1017   for (unsigned int i = 0; i < count; i++)
1018     if (!skippy_iter.prev ())
1019       return_trace (false);
1020 
1021   *match_start = skippy_iter.idx;
1022 
1023   return_trace (true);
1024 }
1025 
match_lookahead(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 lookahead[],match_func_t match_func,const void * match_data,unsigned int offset,unsigned int * end_index)1026 static inline bool match_lookahead (hb_ot_apply_context_t *c,
1027 				    unsigned int count,
1028 				    const HBUINT16 lookahead[],
1029 				    match_func_t match_func,
1030 				    const void *match_data,
1031 				    unsigned int offset,
1032 				    unsigned int *end_index)
1033 {
1034   TRACE_APPLY (nullptr);
1035 
1036   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1037   skippy_iter.reset (c->buffer->idx + offset - 1, count);
1038   skippy_iter.set_match_func (match_func, match_data, lookahead);
1039 
1040   for (unsigned int i = 0; i < count; i++)
1041     if (!skippy_iter.next ())
1042       return_trace (false);
1043 
1044   *end_index = skippy_iter.idx + 1;
1045 
1046   return_trace (true);
1047 }
1048 
1049 
1050 
1051 struct LookupRecord
1052 {
sanitizeOT::LookupRecord1053   bool sanitize (hb_sanitize_context_t *c) const
1054   {
1055     TRACE_SANITIZE (this);
1056     return_trace (c->check_struct (this));
1057   }
1058 
1059   HBUINT16	sequenceIndex;		/* Index into current glyph
1060 					 * sequence--first glyph = 0 */
1061   HBUINT16	lookupListIndex;	/* Lookup to apply to that
1062 					 * position--zero--based */
1063   public:
1064   DEFINE_SIZE_STATIC (4);
1065 };
1066 
1067 template <typename context_t>
recurse_lookups(context_t * c,unsigned int lookupCount,const LookupRecord lookupRecord[])1068 static inline void recurse_lookups (context_t *c,
1069 				    unsigned int lookupCount,
1070 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1071 {
1072   for (unsigned int i = 0; i < lookupCount; i++)
1073     c->recurse (lookupRecord[i].lookupListIndex);
1074 }
1075 
apply_lookup(hb_ot_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)1076 static inline bool apply_lookup (hb_ot_apply_context_t *c,
1077 				 unsigned int count, /* Including the first glyph */
1078 				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1079 				 unsigned int lookupCount,
1080 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1081 				 unsigned int match_length)
1082 {
1083   TRACE_APPLY (nullptr);
1084 
1085   hb_buffer_t *buffer = c->buffer;
1086   int end;
1087 
1088   /* All positions are distance from beginning of *output* buffer.
1089    * Adjust. */
1090   {
1091     unsigned int bl = buffer->backtrack_len ();
1092     end = bl + match_length;
1093 
1094     int delta = bl - buffer->idx;
1095     /* Convert positions to new indexing. */
1096     for (unsigned int j = 0; j < count; j++)
1097       match_positions[j] += delta;
1098   }
1099 
1100   for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1101   {
1102     unsigned int idx = lookupRecord[i].sequenceIndex;
1103     if (idx >= count)
1104       continue;
1105 
1106     /* Don't recurse to ourself at same position.
1107      * Note that this test is too naive, it doesn't catch longer loops. */
1108     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1109       continue;
1110 
1111     if (unlikely (!buffer->move_to (match_positions[idx])))
1112       break;
1113 
1114     if (unlikely (buffer->max_ops <= 0))
1115       break;
1116 
1117     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1118     if (!c->recurse (lookupRecord[i].lookupListIndex))
1119       continue;
1120 
1121     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1122     int delta = new_len - orig_len;
1123 
1124     if (!delta)
1125       continue;
1126 
1127     /* Recursed lookup changed buffer len.  Adjust.
1128      *
1129      * TODO:
1130      *
1131      * Right now, if buffer length increased by n, we assume n new glyphs
1132      * were added right after the current position, and if buffer length
1133      * was decreased by n, we assume n match positions after the current
1134      * one where removed.  The former (buffer length increased) case is
1135      * fine, but the decrease case can be improved in at least two ways,
1136      * both of which are significant:
1137      *
1138      *   - If recursed-to lookup is MultipleSubst and buffer length
1139      *     decreased, then it's current match position that was deleted,
1140      *     NOT the one after it.
1141      *
1142      *   - If buffer length was decreased by n, it does not necessarily
1143      *     mean that n match positions where removed, as there might
1144      *     have been marks and default-ignorables in the sequence.  We
1145      *     should instead drop match positions between current-position
1146      *     and current-position + n instead.
1147      *
1148      * It should be possible to construct tests for both of these cases.
1149      */
1150 
1151     end += delta;
1152     if (end <= int (match_positions[idx]))
1153     {
1154       /* End might end up being smaller than match_positions[idx] if the recursed
1155        * lookup ended up removing many items, more than we have had matched.
1156        * Just never rewind end back and get out of here.
1157        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1158       end = match_positions[idx];
1159       /* There can't be any further changes. */
1160       break;
1161     }
1162 
1163     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1164 
1165     if (delta > 0)
1166     {
1167       if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1168 	break;
1169     }
1170     else
1171     {
1172       /* NOTE: delta is negative. */
1173       delta = MAX (delta, (int) next - (int) count);
1174       next -= delta;
1175     }
1176 
1177     /* Shift! */
1178     memmove (match_positions + next + delta, match_positions + next,
1179 	     (count - next) * sizeof (match_positions[0]));
1180     next += delta;
1181     count += delta;
1182 
1183     /* Fill in new entries. */
1184     for (unsigned int j = idx + 1; j < next; j++)
1185       match_positions[j] = match_positions[j - 1] + 1;
1186 
1187     /* And fixup the rest. */
1188     for (; next < count; next++)
1189       match_positions[next] += delta;
1190   }
1191 
1192   buffer->move_to (end);
1193 
1194   return_trace (true);
1195 }
1196 
1197 
1198 
1199 /* Contextual lookups */
1200 
1201 struct ContextClosureLookupContext
1202 {
1203   ContextClosureFuncs funcs;
1204   const void *intersects_data;
1205 };
1206 
1207 struct ContextCollectGlyphsLookupContext
1208 {
1209   ContextCollectGlyphsFuncs funcs;
1210   const void *collect_data;
1211 };
1212 
1213 struct ContextApplyLookupContext
1214 {
1215   ContextApplyFuncs funcs;
1216   const void *match_data;
1217 };
1218 
context_intersects(const hb_set_t * glyphs,unsigned int inputCount,const HBUINT16 input[],ContextClosureLookupContext & lookup_context)1219 static inline bool context_intersects (const hb_set_t *glyphs,
1220 				       unsigned int inputCount, /* Including the first glyph (not matched) */
1221 				       const HBUINT16 input[], /* Array of input values--start with second glyph */
1222 				       ContextClosureLookupContext &lookup_context)
1223 {
1224   return intersects_array (glyphs,
1225 			   inputCount ? inputCount - 1 : 0, input,
1226 			   lookup_context.funcs.intersects, lookup_context.intersects_data);
1227 }
1228 
context_closure_lookup(hb_closure_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextClosureLookupContext & lookup_context)1229 static inline void context_closure_lookup (hb_closure_context_t *c,
1230 					   unsigned int inputCount, /* Including the first glyph (not matched) */
1231 					   const HBUINT16 input[], /* Array of input values--start with second glyph */
1232 					   unsigned int lookupCount,
1233 					   const LookupRecord lookupRecord[],
1234 					   ContextClosureLookupContext &lookup_context)
1235 {
1236   if (context_intersects (c->glyphs,
1237 			  inputCount, input,
1238 			  lookup_context))
1239     recurse_lookups (c,
1240 		     lookupCount, lookupRecord);
1241 }
1242 
context_collect_glyphs_lookup(hb_collect_glyphs_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextCollectGlyphsLookupContext & lookup_context)1243 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1244 						  unsigned int inputCount, /* Including the first glyph (not matched) */
1245 						  const HBUINT16 input[], /* Array of input values--start with second glyph */
1246 						  unsigned int lookupCount,
1247 						  const LookupRecord lookupRecord[],
1248 						  ContextCollectGlyphsLookupContext &lookup_context)
1249 {
1250   collect_array (c, c->input,
1251 		 inputCount ? inputCount - 1 : 0, input,
1252 		 lookup_context.funcs.collect, lookup_context.collect_data);
1253   recurse_lookups (c,
1254 		   lookupCount, lookupRecord);
1255 }
1256 
context_would_apply_lookup(hb_would_apply_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount HB_UNUSED,const LookupRecord lookupRecord[]HB_UNUSED,ContextApplyLookupContext & lookup_context)1257 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1258 					       unsigned int inputCount, /* Including the first glyph (not matched) */
1259 					       const HBUINT16 input[], /* Array of input values--start with second glyph */
1260 					       unsigned int lookupCount HB_UNUSED,
1261 					       const LookupRecord lookupRecord[] HB_UNUSED,
1262 					       ContextApplyLookupContext &lookup_context)
1263 {
1264   return would_match_input (c,
1265 			    inputCount, input,
1266 			    lookup_context.funcs.match, lookup_context.match_data);
1267 }
context_apply_lookup(hb_ot_apply_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextApplyLookupContext & lookup_context)1268 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1269 					 unsigned int inputCount, /* Including the first glyph (not matched) */
1270 					 const HBUINT16 input[], /* Array of input values--start with second glyph */
1271 					 unsigned int lookupCount,
1272 					 const LookupRecord lookupRecord[],
1273 					 ContextApplyLookupContext &lookup_context)
1274 {
1275   unsigned int match_length = 0;
1276   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1277   return match_input (c,
1278 		      inputCount, input,
1279 		      lookup_context.funcs.match, lookup_context.match_data,
1280 		      &match_length, match_positions)
1281       && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1282 	  apply_lookup (c,
1283 		       inputCount, match_positions,
1284 		       lookupCount, lookupRecord,
1285 		       match_length));
1286 }
1287 
1288 struct Rule
1289 {
intersectsOT::Rule1290   bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1291   {
1292     return context_intersects (glyphs,
1293 			       inputCount, inputZ.arrayZ,
1294 			       lookup_context);
1295   }
1296 
closureOT::Rule1297   void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1298   {
1299     TRACE_CLOSURE (this);
1300     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1301 						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1302     context_closure_lookup (c,
1303 			    inputCount, inputZ.arrayZ,
1304 			    lookupCount, lookupRecord.arrayZ,
1305 			    lookup_context);
1306   }
1307 
collect_glyphsOT::Rule1308   void collect_glyphs (hb_collect_glyphs_context_t *c,
1309 		       ContextCollectGlyphsLookupContext &lookup_context) const
1310   {
1311     TRACE_COLLECT_GLYPHS (this);
1312     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1313 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1314     context_collect_glyphs_lookup (c,
1315 				   inputCount, inputZ.arrayZ,
1316 				   lookupCount, lookupRecord.arrayZ,
1317 				   lookup_context);
1318   }
1319 
would_applyOT::Rule1320   bool would_apply (hb_would_apply_context_t *c,
1321 		    ContextApplyLookupContext &lookup_context) const
1322   {
1323     TRACE_WOULD_APPLY (this);
1324     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1325 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1326     return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1327   }
1328 
applyOT::Rule1329   bool apply (hb_ot_apply_context_t *c,
1330 	      ContextApplyLookupContext &lookup_context) const
1331   {
1332     TRACE_APPLY (this);
1333     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1334 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1335     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1336   }
1337 
1338   public:
sanitizeOT::Rule1339   bool sanitize (hb_sanitize_context_t *c) const
1340   {
1341     TRACE_SANITIZE (this);
1342     return_trace (inputCount.sanitize (c) &&
1343 		  lookupCount.sanitize (c) &&
1344 		  c->check_range (inputZ.arrayZ,
1345 				  inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
1346 				  LookupRecord::static_size * lookupCount));
1347   }
1348 
1349   protected:
1350   HBUINT16	inputCount;		/* Total number of glyphs in input
1351 					 * glyph sequence--includes the first
1352 					 * glyph */
1353   HBUINT16	lookupCount;		/* Number of LookupRecords */
1354   UnsizedArrayOf<HBUINT16>
1355  		inputZ;			/* Array of match inputs--start with
1356 					 * second glyph */
1357 /*UnsizedArrayOf<LookupRecord>
1358 		lookupRecordX;*/	/* Array of LookupRecords--in
1359 					 * design order */
1360   public:
1361   DEFINE_SIZE_ARRAY (4, inputZ);
1362 };
1363 
1364 struct RuleSet
1365 {
intersectsOT::RuleSet1366   bool intersects (const hb_set_t *glyphs,
1367 		   ContextClosureLookupContext &lookup_context) const
1368   {
1369     unsigned int num_rules = rule.len;
1370     for (unsigned int i = 0; i < num_rules; i++)
1371       if ((this+rule[i]).intersects (glyphs, lookup_context))
1372 	return true;
1373     return false;
1374   }
1375 
closureOT::RuleSet1376   void closure (hb_closure_context_t *c,
1377 		ContextClosureLookupContext &lookup_context) const
1378   {
1379     TRACE_CLOSURE (this);
1380     unsigned int num_rules = rule.len;
1381     for (unsigned int i = 0; i < num_rules; i++)
1382       (this+rule[i]).closure (c, lookup_context);
1383   }
1384 
collect_glyphsOT::RuleSet1385   void collect_glyphs (hb_collect_glyphs_context_t *c,
1386 		       ContextCollectGlyphsLookupContext &lookup_context) const
1387   {
1388     TRACE_COLLECT_GLYPHS (this);
1389     unsigned int num_rules = rule.len;
1390     for (unsigned int i = 0; i < num_rules; i++)
1391       (this+rule[i]).collect_glyphs (c, lookup_context);
1392   }
1393 
would_applyOT::RuleSet1394   bool would_apply (hb_would_apply_context_t *c,
1395 		    ContextApplyLookupContext &lookup_context) const
1396   {
1397     TRACE_WOULD_APPLY (this);
1398     unsigned int num_rules = rule.len;
1399     for (unsigned int i = 0; i < num_rules; i++)
1400     {
1401       if ((this+rule[i]).would_apply (c, lookup_context))
1402 	return_trace (true);
1403     }
1404     return_trace (false);
1405   }
1406 
applyOT::RuleSet1407   bool apply (hb_ot_apply_context_t *c,
1408 	      ContextApplyLookupContext &lookup_context) const
1409   {
1410     TRACE_APPLY (this);
1411     unsigned int num_rules = rule.len;
1412     for (unsigned int i = 0; i < num_rules; i++)
1413     {
1414       if ((this+rule[i]).apply (c, lookup_context))
1415 	return_trace (true);
1416     }
1417     return_trace (false);
1418   }
1419 
sanitizeOT::RuleSet1420   bool sanitize (hb_sanitize_context_t *c) const
1421   {
1422     TRACE_SANITIZE (this);
1423     return_trace (rule.sanitize (c, this));
1424   }
1425 
1426   protected:
1427   OffsetArrayOf<Rule>
1428 		rule;			/* Array of Rule tables
1429 					 * ordered by preference */
1430   public:
1431   DEFINE_SIZE_ARRAY (2, rule);
1432 };
1433 
1434 
1435 struct ContextFormat1
1436 {
intersectsOT::ContextFormat11437   bool intersects (const hb_set_t *glyphs) const
1438   {
1439     struct ContextClosureLookupContext lookup_context = {
1440       {intersects_glyph},
1441       nullptr
1442     };
1443 
1444     unsigned int count = ruleSet.len;
1445     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1446     {
1447       if (unlikely (iter.get_coverage () >= count))
1448 	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1449       if (glyphs->has (iter.get_glyph ()) &&
1450 	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
1451 	return true;
1452     }
1453     return false;
1454   }
1455 
closureOT::ContextFormat11456   void closure (hb_closure_context_t *c) const
1457   {
1458     TRACE_CLOSURE (this);
1459 
1460     struct ContextClosureLookupContext lookup_context = {
1461       {intersects_glyph},
1462       nullptr
1463     };
1464 
1465     unsigned int count = ruleSet.len;
1466     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1467     {
1468       if (unlikely (iter.get_coverage () >= count))
1469 	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1470       if (c->glyphs->has (iter.get_glyph ()))
1471 	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
1472     }
1473   }
1474 
collect_glyphsOT::ContextFormat11475   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1476   {
1477     TRACE_COLLECT_GLYPHS (this);
1478     (this+coverage).add_coverage (c->input);
1479 
1480     struct ContextCollectGlyphsLookupContext lookup_context = {
1481       {collect_glyph},
1482       nullptr
1483     };
1484 
1485     unsigned int count = ruleSet.len;
1486     for (unsigned int i = 0; i < count; i++)
1487       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1488   }
1489 
would_applyOT::ContextFormat11490   bool would_apply (hb_would_apply_context_t *c) const
1491   {
1492     TRACE_WOULD_APPLY (this);
1493 
1494     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1495     struct ContextApplyLookupContext lookup_context = {
1496       {match_glyph},
1497       nullptr
1498     };
1499     return_trace (rule_set.would_apply (c, lookup_context));
1500   }
1501 
get_coverageOT::ContextFormat11502   const Coverage &get_coverage () const { return this+coverage; }
1503 
applyOT::ContextFormat11504   bool apply (hb_ot_apply_context_t *c) const
1505   {
1506     TRACE_APPLY (this);
1507     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1508     if (likely (index == NOT_COVERED))
1509       return_trace (false);
1510 
1511     const RuleSet &rule_set = this+ruleSet[index];
1512     struct ContextApplyLookupContext lookup_context = {
1513       {match_glyph},
1514       nullptr
1515     };
1516     return_trace (rule_set.apply (c, lookup_context));
1517   }
1518 
subsetOT::ContextFormat11519   bool subset (hb_subset_context_t *c) const
1520   {
1521     TRACE_SUBSET (this);
1522     // TODO(subset)
1523     return_trace (false);
1524   }
1525 
sanitizeOT::ContextFormat11526   bool sanitize (hb_sanitize_context_t *c) const
1527   {
1528     TRACE_SANITIZE (this);
1529     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1530   }
1531 
1532   protected:
1533   HBUINT16	format;			/* Format identifier--format = 1 */
1534   OffsetTo<Coverage>
1535 		coverage;		/* Offset to Coverage table--from
1536 					 * beginning of table */
1537   OffsetArrayOf<RuleSet>
1538 		ruleSet;		/* Array of RuleSet tables
1539 					 * ordered by Coverage Index */
1540   public:
1541   DEFINE_SIZE_ARRAY (6, ruleSet);
1542 };
1543 
1544 
1545 struct ContextFormat2
1546 {
intersectsOT::ContextFormat21547   bool intersects (const hb_set_t *glyphs) const
1548   {
1549     if (!(this+coverage).intersects (glyphs))
1550       return false;
1551 
1552     const ClassDef &class_def = this+classDef;
1553 
1554     struct ContextClosureLookupContext lookup_context = {
1555       {intersects_class},
1556       &class_def
1557     };
1558 
1559     unsigned int count = ruleSet.len;
1560     for (unsigned int i = 0; i < count; i++)
1561       if (class_def.intersects_class (glyphs, i) &&
1562 	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
1563 	return true;
1564 
1565     return false;
1566   }
1567 
closureOT::ContextFormat21568   void closure (hb_closure_context_t *c) const
1569   {
1570     TRACE_CLOSURE (this);
1571     if (!(this+coverage).intersects (c->glyphs))
1572       return;
1573 
1574     const ClassDef &class_def = this+classDef;
1575 
1576     struct ContextClosureLookupContext lookup_context = {
1577       {intersects_class},
1578       &class_def
1579     };
1580 
1581     unsigned int count = ruleSet.len;
1582     for (unsigned int i = 0; i < count; i++)
1583       if (class_def.intersects_class (c->glyphs, i)) {
1584 	const RuleSet &rule_set = this+ruleSet[i];
1585 	rule_set.closure (c, lookup_context);
1586       }
1587   }
1588 
collect_glyphsOT::ContextFormat21589   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1590   {
1591     TRACE_COLLECT_GLYPHS (this);
1592     (this+coverage).add_coverage (c->input);
1593 
1594     const ClassDef &class_def = this+classDef;
1595     struct ContextCollectGlyphsLookupContext lookup_context = {
1596       {collect_class},
1597       &class_def
1598     };
1599 
1600     unsigned int count = ruleSet.len;
1601     for (unsigned int i = 0; i < count; i++)
1602       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1603   }
1604 
would_applyOT::ContextFormat21605   bool would_apply (hb_would_apply_context_t *c) const
1606   {
1607     TRACE_WOULD_APPLY (this);
1608 
1609     const ClassDef &class_def = this+classDef;
1610     unsigned int index = class_def.get_class (c->glyphs[0]);
1611     const RuleSet &rule_set = this+ruleSet[index];
1612     struct ContextApplyLookupContext lookup_context = {
1613       {match_class},
1614       &class_def
1615     };
1616     return_trace (rule_set.would_apply (c, lookup_context));
1617   }
1618 
get_coverageOT::ContextFormat21619   const Coverage &get_coverage () const { return this+coverage; }
1620 
applyOT::ContextFormat21621   bool apply (hb_ot_apply_context_t *c) const
1622   {
1623     TRACE_APPLY (this);
1624     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1625     if (likely (index == NOT_COVERED)) return_trace (false);
1626 
1627     const ClassDef &class_def = this+classDef;
1628     index = class_def.get_class (c->buffer->cur().codepoint);
1629     const RuleSet &rule_set = this+ruleSet[index];
1630     struct ContextApplyLookupContext lookup_context = {
1631       {match_class},
1632       &class_def
1633     };
1634     return_trace (rule_set.apply (c, lookup_context));
1635   }
1636 
subsetOT::ContextFormat21637   bool subset (hb_subset_context_t *c) const
1638   {
1639     TRACE_SUBSET (this);
1640     // TODO(subset)
1641     return_trace (false);
1642   }
1643 
sanitizeOT::ContextFormat21644   bool sanitize (hb_sanitize_context_t *c) const
1645   {
1646     TRACE_SANITIZE (this);
1647     return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1648   }
1649 
1650   protected:
1651   HBUINT16	format;			/* Format identifier--format = 2 */
1652   OffsetTo<Coverage>
1653 		coverage;		/* Offset to Coverage table--from
1654 					 * beginning of table */
1655   OffsetTo<ClassDef>
1656 		classDef;		/* Offset to glyph ClassDef table--from
1657 					 * beginning of table */
1658   OffsetArrayOf<RuleSet>
1659 		ruleSet;		/* Array of RuleSet tables
1660 					 * ordered by class */
1661   public:
1662   DEFINE_SIZE_ARRAY (8, ruleSet);
1663 };
1664 
1665 
1666 struct ContextFormat3
1667 {
intersectsOT::ContextFormat31668   bool intersects (const hb_set_t *glyphs) const
1669   {
1670     if (!(this+coverageZ[0]).intersects (glyphs))
1671       return false;
1672 
1673     struct ContextClosureLookupContext lookup_context = {
1674       {intersects_coverage},
1675       this
1676     };
1677     return context_intersects (glyphs,
1678 			       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1679 			       lookup_context);
1680   }
1681 
closureOT::ContextFormat31682   void closure (hb_closure_context_t *c) const
1683   {
1684     TRACE_CLOSURE (this);
1685     if (!(this+coverageZ[0]).intersects (c->glyphs))
1686       return;
1687 
1688     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1689     struct ContextClosureLookupContext lookup_context = {
1690       {intersects_coverage},
1691       this
1692     };
1693     context_closure_lookup (c,
1694 			    glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1695 			    lookupCount, lookupRecord,
1696 			    lookup_context);
1697   }
1698 
collect_glyphsOT::ContextFormat31699   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1700   {
1701     TRACE_COLLECT_GLYPHS (this);
1702     (this+coverageZ[0]).add_coverage (c->input);
1703 
1704     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1705     struct ContextCollectGlyphsLookupContext lookup_context = {
1706       {collect_coverage},
1707       this
1708     };
1709 
1710     context_collect_glyphs_lookup (c,
1711 				   glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1712 				   lookupCount, lookupRecord,
1713 				   lookup_context);
1714   }
1715 
would_applyOT::ContextFormat31716   bool would_apply (hb_would_apply_context_t *c) const
1717   {
1718     TRACE_WOULD_APPLY (this);
1719 
1720     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1721     struct ContextApplyLookupContext lookup_context = {
1722       {match_coverage},
1723       this
1724     };
1725     return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1726   }
1727 
get_coverageOT::ContextFormat31728   const Coverage &get_coverage () const { return this+coverageZ[0]; }
1729 
applyOT::ContextFormat31730   bool apply (hb_ot_apply_context_t *c) const
1731   {
1732     TRACE_APPLY (this);
1733     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1734     if (likely (index == NOT_COVERED)) return_trace (false);
1735 
1736     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1737     struct ContextApplyLookupContext lookup_context = {
1738       {match_coverage},
1739       this
1740     };
1741     return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1742   }
1743 
subsetOT::ContextFormat31744   bool subset (hb_subset_context_t *c) const
1745   {
1746     TRACE_SUBSET (this);
1747     // TODO(subset)
1748     return_trace (false);
1749   }
1750 
sanitizeOT::ContextFormat31751   bool sanitize (hb_sanitize_context_t *c) const
1752   {
1753     TRACE_SANITIZE (this);
1754     if (!c->check_struct (this)) return_trace (false);
1755     unsigned int count = glyphCount;
1756     if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1757     if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
1758     for (unsigned int i = 0; i < count; i++)
1759       if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1760     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1761     return_trace (c->check_array (lookupRecord, lookupCount));
1762   }
1763 
1764   protected:
1765   HBUINT16	format;			/* Format identifier--format = 3 */
1766   HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
1767 					 * sequence */
1768   HBUINT16	lookupCount;		/* Number of LookupRecords */
1769   UnsizedArrayOf<OffsetTo<Coverage> >
1770 		coverageZ;		/* Array of offsets to Coverage
1771 					 * table in glyph sequence order */
1772 /*UnsizedArrayOf<LookupRecord>
1773 		lookupRecordX;*/	/* Array of LookupRecords--in
1774 					 * design order */
1775   public:
1776   DEFINE_SIZE_ARRAY (6, coverageZ);
1777 };
1778 
1779 struct Context
1780 {
1781   template <typename context_t>
dispatchOT::Context1782   typename context_t::return_t dispatch (context_t *c) const
1783   {
1784     TRACE_DISPATCH (this, u.format);
1785     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1786     switch (u.format) {
1787     case 1: return_trace (c->dispatch (u.format1));
1788     case 2: return_trace (c->dispatch (u.format2));
1789     case 3: return_trace (c->dispatch (u.format3));
1790     default:return_trace (c->default_return_value ());
1791     }
1792   }
1793 
1794   protected:
1795   union {
1796   HBUINT16		format;		/* Format identifier */
1797   ContextFormat1	format1;
1798   ContextFormat2	format2;
1799   ContextFormat3	format3;
1800   } u;
1801 };
1802 
1803 
1804 /* Chaining Contextual lookups */
1805 
1806 struct ChainContextClosureLookupContext
1807 {
1808   ContextClosureFuncs funcs;
1809   const void *intersects_data[3];
1810 };
1811 
1812 struct ChainContextCollectGlyphsLookupContext
1813 {
1814   ContextCollectGlyphsFuncs funcs;
1815   const void *collect_data[3];
1816 };
1817 
1818 struct ChainContextApplyLookupContext
1819 {
1820   ContextApplyFuncs funcs;
1821   const void *match_data[3];
1822 };
1823 
chain_context_intersects(const hb_set_t * glyphs,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],ChainContextClosureLookupContext & lookup_context)1824 static inline bool chain_context_intersects (const hb_set_t *glyphs,
1825 					     unsigned int backtrackCount,
1826 					     const HBUINT16 backtrack[],
1827 					     unsigned int inputCount, /* Including the first glyph (not matched) */
1828 					     const HBUINT16 input[], /* Array of input values--start with second glyph */
1829 					     unsigned int lookaheadCount,
1830 					     const HBUINT16 lookahead[],
1831 					     ChainContextClosureLookupContext &lookup_context)
1832 {
1833   return intersects_array (glyphs,
1834 			   backtrackCount, backtrack,
1835 			   lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1836       && intersects_array (glyphs,
1837 			   inputCount ? inputCount - 1 : 0, input,
1838 			   lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1839       && intersects_array (glyphs,
1840 			  lookaheadCount, lookahead,
1841 			  lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1842 }
1843 
chain_context_closure_lookup(hb_closure_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextClosureLookupContext & lookup_context)1844 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1845 						 unsigned int backtrackCount,
1846 						 const HBUINT16 backtrack[],
1847 						 unsigned int inputCount, /* Including the first glyph (not matched) */
1848 						 const HBUINT16 input[], /* Array of input values--start with second glyph */
1849 						 unsigned int lookaheadCount,
1850 						 const HBUINT16 lookahead[],
1851 						 unsigned int lookupCount,
1852 						 const LookupRecord lookupRecord[],
1853 						 ChainContextClosureLookupContext &lookup_context)
1854 {
1855   if (chain_context_intersects (c->glyphs,
1856 				backtrackCount, backtrack,
1857 				inputCount, input,
1858 				lookaheadCount, lookahead,
1859 				lookup_context))
1860     recurse_lookups (c,
1861 		     lookupCount, lookupRecord);
1862 }
1863 
chain_context_collect_glyphs_lookup(hb_collect_glyphs_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextCollectGlyphsLookupContext & lookup_context)1864 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1865 							unsigned int backtrackCount,
1866 							const HBUINT16 backtrack[],
1867 							unsigned int inputCount, /* Including the first glyph (not matched) */
1868 							const HBUINT16 input[], /* Array of input values--start with second glyph */
1869 							unsigned int lookaheadCount,
1870 							const HBUINT16 lookahead[],
1871 							unsigned int lookupCount,
1872 							const LookupRecord lookupRecord[],
1873 							ChainContextCollectGlyphsLookupContext &lookup_context)
1874 {
1875   collect_array (c, c->before,
1876 		 backtrackCount, backtrack,
1877 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1878   collect_array (c, c->input,
1879 		 inputCount ? inputCount - 1 : 0, input,
1880 		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1881   collect_array (c, c->after,
1882 		 lookaheadCount, lookahead,
1883 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1884   recurse_lookups (c,
1885 		   lookupCount, lookupRecord);
1886 }
1887 
chain_context_would_apply_lookup(hb_would_apply_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[]HB_UNUSED,unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[]HB_UNUSED,unsigned int lookupCount HB_UNUSED,const LookupRecord lookupRecord[]HB_UNUSED,ChainContextApplyLookupContext & lookup_context)1888 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1889 						     unsigned int backtrackCount,
1890 						     const HBUINT16 backtrack[] HB_UNUSED,
1891 						     unsigned int inputCount, /* Including the first glyph (not matched) */
1892 						     const HBUINT16 input[], /* Array of input values--start with second glyph */
1893 						     unsigned int lookaheadCount,
1894 						     const HBUINT16 lookahead[] HB_UNUSED,
1895 						     unsigned int lookupCount HB_UNUSED,
1896 						     const LookupRecord lookupRecord[] HB_UNUSED,
1897 						     ChainContextApplyLookupContext &lookup_context)
1898 {
1899   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1900       && would_match_input (c,
1901 			    inputCount, input,
1902 			    lookup_context.funcs.match, lookup_context.match_data[1]);
1903 }
1904 
chain_context_apply_lookup(hb_ot_apply_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextApplyLookupContext & lookup_context)1905 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1906 					       unsigned int backtrackCount,
1907 					       const HBUINT16 backtrack[],
1908 					       unsigned int inputCount, /* Including the first glyph (not matched) */
1909 					       const HBUINT16 input[], /* Array of input values--start with second glyph */
1910 					       unsigned int lookaheadCount,
1911 					       const HBUINT16 lookahead[],
1912 					       unsigned int lookupCount,
1913 					       const LookupRecord lookupRecord[],
1914 					       ChainContextApplyLookupContext &lookup_context)
1915 {
1916   unsigned int start_index = 0, match_length = 0, end_index = 0;
1917   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1918   return match_input (c,
1919 		      inputCount, input,
1920 		      lookup_context.funcs.match, lookup_context.match_data[1],
1921 		      &match_length, match_positions)
1922       && match_backtrack (c,
1923 			  backtrackCount, backtrack,
1924 			  lookup_context.funcs.match, lookup_context.match_data[0],
1925 			  &start_index)
1926       && match_lookahead (c,
1927 			  lookaheadCount, lookahead,
1928 			  lookup_context.funcs.match, lookup_context.match_data[2],
1929 			  match_length, &end_index)
1930       && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1931 	  apply_lookup (c,
1932 			inputCount, match_positions,
1933 			lookupCount, lookupRecord,
1934 			match_length));
1935 }
1936 
1937 struct ChainRule
1938 {
intersectsOT::ChainRule1939   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1940   {
1941     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1942     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1943     return chain_context_intersects (glyphs,
1944 				     backtrack.len, backtrack.arrayZ,
1945 				     input.lenP1, input.arrayZ,
1946 				     lookahead.len, lookahead.arrayZ,
1947 				     lookup_context);
1948   }
1949 
closureOT::ChainRule1950   void closure (hb_closure_context_t *c,
1951 		ChainContextClosureLookupContext &lookup_context) const
1952   {
1953     TRACE_CLOSURE (this);
1954     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1955     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1956     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1957     chain_context_closure_lookup (c,
1958 				  backtrack.len, backtrack.arrayZ,
1959 				  input.lenP1, input.arrayZ,
1960 				  lookahead.len, lookahead.arrayZ,
1961 				  lookup.len, lookup.arrayZ,
1962 				  lookup_context);
1963   }
1964 
collect_glyphsOT::ChainRule1965   void collect_glyphs (hb_collect_glyphs_context_t *c,
1966 		       ChainContextCollectGlyphsLookupContext &lookup_context) const
1967   {
1968     TRACE_COLLECT_GLYPHS (this);
1969     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1970     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1971     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1972     chain_context_collect_glyphs_lookup (c,
1973 					 backtrack.len, backtrack.arrayZ,
1974 					 input.lenP1, input.arrayZ,
1975 					 lookahead.len, lookahead.arrayZ,
1976 					 lookup.len, lookup.arrayZ,
1977 					 lookup_context);
1978   }
1979 
would_applyOT::ChainRule1980   bool would_apply (hb_would_apply_context_t *c,
1981 		    ChainContextApplyLookupContext &lookup_context) const
1982   {
1983     TRACE_WOULD_APPLY (this);
1984     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1985     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1986     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1987     return_trace (chain_context_would_apply_lookup (c,
1988 						    backtrack.len, backtrack.arrayZ,
1989 						    input.lenP1, input.arrayZ,
1990 						    lookahead.len, lookahead.arrayZ, lookup.len,
1991 						    lookup.arrayZ, lookup_context));
1992   }
1993 
applyOT::ChainRule1994   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1995   {
1996     TRACE_APPLY (this);
1997     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1998     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1999     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2000     return_trace (chain_context_apply_lookup (c,
2001 					      backtrack.len, backtrack.arrayZ,
2002 					      input.lenP1, input.arrayZ,
2003 					      lookahead.len, lookahead.arrayZ, lookup.len,
2004 					      lookup.arrayZ, lookup_context));
2005   }
2006 
sanitizeOT::ChainRule2007   bool sanitize (hb_sanitize_context_t *c) const
2008   {
2009     TRACE_SANITIZE (this);
2010     if (!backtrack.sanitize (c)) return_trace (false);
2011     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
2012     if (!input.sanitize (c)) return_trace (false);
2013     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
2014     if (!lookahead.sanitize (c)) return_trace (false);
2015     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2016     return_trace (lookup.sanitize (c));
2017   }
2018 
2019   protected:
2020   ArrayOf<HBUINT16>
2021 		backtrack;		/* Array of backtracking values
2022 					 * (to be matched before the input
2023 					 * sequence) */
2024   HeadlessArrayOf<HBUINT16>
2025 		inputX;			/* Array of input values (start with
2026 					 * second glyph) */
2027   ArrayOf<HBUINT16>
2028 		lookaheadX;		/* Array of lookahead values's (to be
2029 					 * matched after the input sequence) */
2030   ArrayOf<LookupRecord>
2031 		lookupX;		/* Array of LookupRecords--in
2032 					 * design order) */
2033   public:
2034   DEFINE_SIZE_MIN (8);
2035 };
2036 
2037 struct ChainRuleSet
2038 {
intersectsOT::ChainRuleSet2039   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
2040   {
2041     unsigned int num_rules = rule.len;
2042     for (unsigned int i = 0; i < num_rules; i++)
2043       if ((this+rule[i]).intersects (glyphs, lookup_context))
2044 	return true;
2045     return false;
2046   }
closureOT::ChainRuleSet2047   void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2048   {
2049     TRACE_CLOSURE (this);
2050     unsigned int num_rules = rule.len;
2051     for (unsigned int i = 0; i < num_rules; i++)
2052       (this+rule[i]).closure (c, lookup_context);
2053   }
2054 
collect_glyphsOT::ChainRuleSet2055   void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
2056   {
2057     TRACE_COLLECT_GLYPHS (this);
2058     unsigned int num_rules = rule.len;
2059     for (unsigned int i = 0; i < num_rules; i++)
2060       (this+rule[i]).collect_glyphs (c, lookup_context);
2061   }
2062 
would_applyOT::ChainRuleSet2063   bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2064   {
2065     TRACE_WOULD_APPLY (this);
2066     unsigned int num_rules = rule.len;
2067     for (unsigned int i = 0; i < num_rules; i++)
2068       if ((this+rule[i]).would_apply (c, lookup_context))
2069 	return_trace (true);
2070 
2071     return_trace (false);
2072   }
2073 
applyOT::ChainRuleSet2074   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2075   {
2076     TRACE_APPLY (this);
2077     unsigned int num_rules = rule.len;
2078     for (unsigned int i = 0; i < num_rules; i++)
2079       if ((this+rule[i]).apply (c, lookup_context))
2080 	return_trace (true);
2081 
2082     return_trace (false);
2083   }
2084 
sanitizeOT::ChainRuleSet2085   bool sanitize (hb_sanitize_context_t *c) const
2086   {
2087     TRACE_SANITIZE (this);
2088     return_trace (rule.sanitize (c, this));
2089   }
2090 
2091   protected:
2092   OffsetArrayOf<ChainRule>
2093 		rule;			/* Array of ChainRule tables
2094 					 * ordered by preference */
2095   public:
2096   DEFINE_SIZE_ARRAY (2, rule);
2097 };
2098 
2099 struct ChainContextFormat1
2100 {
intersectsOT::ChainContextFormat12101   bool intersects (const hb_set_t *glyphs) const
2102   {
2103     struct ChainContextClosureLookupContext lookup_context = {
2104       {intersects_glyph},
2105       {nullptr, nullptr, nullptr}
2106     };
2107 
2108     unsigned int count = ruleSet.len;
2109     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2110     {
2111       if (unlikely (iter.get_coverage () >= count))
2112 	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2113       if (glyphs->has (iter.get_glyph ()) &&
2114 	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
2115 	return true;
2116     }
2117     return false;
2118   }
2119 
closureOT::ChainContextFormat12120   void closure (hb_closure_context_t *c) const
2121   {
2122     TRACE_CLOSURE (this);
2123 
2124     struct ChainContextClosureLookupContext lookup_context = {
2125       {intersects_glyph},
2126       {nullptr, nullptr, nullptr}
2127     };
2128 
2129     unsigned int count = ruleSet.len;
2130     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2131     {
2132       if (unlikely (iter.get_coverage () >= count))
2133 	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2134       if (c->glyphs->has (iter.get_glyph ()))
2135 	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
2136     }
2137   }
2138 
collect_glyphsOT::ChainContextFormat12139   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2140   {
2141     TRACE_COLLECT_GLYPHS (this);
2142     (this+coverage).add_coverage (c->input);
2143 
2144     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2145       {collect_glyph},
2146       {nullptr, nullptr, nullptr}
2147     };
2148 
2149     unsigned int count = ruleSet.len;
2150     for (unsigned int i = 0; i < count; i++)
2151       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2152   }
2153 
would_applyOT::ChainContextFormat12154   bool would_apply (hb_would_apply_context_t *c) const
2155   {
2156     TRACE_WOULD_APPLY (this);
2157 
2158     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2159     struct ChainContextApplyLookupContext lookup_context = {
2160       {match_glyph},
2161       {nullptr, nullptr, nullptr}
2162     };
2163     return_trace (rule_set.would_apply (c, lookup_context));
2164   }
2165 
get_coverageOT::ChainContextFormat12166   const Coverage &get_coverage () const { return this+coverage; }
2167 
applyOT::ChainContextFormat12168   bool apply (hb_ot_apply_context_t *c) const
2169   {
2170     TRACE_APPLY (this);
2171     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2172     if (likely (index == NOT_COVERED)) return_trace (false);
2173 
2174     const ChainRuleSet &rule_set = this+ruleSet[index];
2175     struct ChainContextApplyLookupContext lookup_context = {
2176       {match_glyph},
2177       {nullptr, nullptr, nullptr}
2178     };
2179     return_trace (rule_set.apply (c, lookup_context));
2180   }
2181 
subsetOT::ChainContextFormat12182   bool subset (hb_subset_context_t *c) const
2183   {
2184     TRACE_SUBSET (this);
2185     // TODO(subset)
2186     return_trace (false);
2187   }
2188 
sanitizeOT::ChainContextFormat12189   bool sanitize (hb_sanitize_context_t *c) const
2190   {
2191     TRACE_SANITIZE (this);
2192     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2193   }
2194 
2195   protected:
2196   HBUINT16	format;			/* Format identifier--format = 1 */
2197   OffsetTo<Coverage>
2198 		coverage;		/* Offset to Coverage table--from
2199 					 * beginning of table */
2200   OffsetArrayOf<ChainRuleSet>
2201 		ruleSet;		/* Array of ChainRuleSet tables
2202 					 * ordered by Coverage Index */
2203   public:
2204   DEFINE_SIZE_ARRAY (6, ruleSet);
2205 };
2206 
2207 struct ChainContextFormat2
2208 {
intersectsOT::ChainContextFormat22209   bool intersects (const hb_set_t *glyphs) const
2210   {
2211     if (!(this+coverage).intersects (glyphs))
2212       return false;
2213 
2214     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2215     const ClassDef &input_class_def = this+inputClassDef;
2216     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2217 
2218     struct ChainContextClosureLookupContext lookup_context = {
2219       {intersects_class},
2220       {&backtrack_class_def,
2221        &input_class_def,
2222        &lookahead_class_def}
2223     };
2224 
2225     unsigned int count = ruleSet.len;
2226     for (unsigned int i = 0; i < count; i++)
2227       if (input_class_def.intersects_class (glyphs, i) &&
2228 	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
2229 	return true;
2230 
2231     return false;
2232   }
closureOT::ChainContextFormat22233   void closure (hb_closure_context_t *c) const
2234   {
2235     TRACE_CLOSURE (this);
2236     if (!(this+coverage).intersects (c->glyphs))
2237       return;
2238 
2239     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2240     const ClassDef &input_class_def = this+inputClassDef;
2241     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2242 
2243     struct ChainContextClosureLookupContext lookup_context = {
2244       {intersects_class},
2245       {&backtrack_class_def,
2246        &input_class_def,
2247        &lookahead_class_def}
2248     };
2249 
2250     unsigned int count = ruleSet.len;
2251     for (unsigned int i = 0; i < count; i++)
2252       if (input_class_def.intersects_class (c->glyphs, i)) {
2253 	const ChainRuleSet &rule_set = this+ruleSet[i];
2254 	rule_set.closure (c, lookup_context);
2255       }
2256   }
2257 
collect_glyphsOT::ChainContextFormat22258   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2259   {
2260     TRACE_COLLECT_GLYPHS (this);
2261     (this+coverage).add_coverage (c->input);
2262 
2263     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2264     const ClassDef &input_class_def = this+inputClassDef;
2265     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2266 
2267     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2268       {collect_class},
2269       {&backtrack_class_def,
2270        &input_class_def,
2271        &lookahead_class_def}
2272     };
2273 
2274     unsigned int count = ruleSet.len;
2275     for (unsigned int i = 0; i < count; i++)
2276       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2277   }
2278 
would_applyOT::ChainContextFormat22279   bool would_apply (hb_would_apply_context_t *c) const
2280   {
2281     TRACE_WOULD_APPLY (this);
2282 
2283     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2284     const ClassDef &input_class_def = this+inputClassDef;
2285     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2286 
2287     unsigned int index = input_class_def.get_class (c->glyphs[0]);
2288     const ChainRuleSet &rule_set = this+ruleSet[index];
2289     struct ChainContextApplyLookupContext lookup_context = {
2290       {match_class},
2291       {&backtrack_class_def,
2292        &input_class_def,
2293        &lookahead_class_def}
2294     };
2295     return_trace (rule_set.would_apply (c, lookup_context));
2296   }
2297 
get_coverageOT::ChainContextFormat22298   const Coverage &get_coverage () const { return this+coverage; }
2299 
applyOT::ChainContextFormat22300   bool apply (hb_ot_apply_context_t *c) const
2301   {
2302     TRACE_APPLY (this);
2303     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2304     if (likely (index == NOT_COVERED)) return_trace (false);
2305 
2306     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2307     const ClassDef &input_class_def = this+inputClassDef;
2308     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2309 
2310     index = input_class_def.get_class (c->buffer->cur().codepoint);
2311     const ChainRuleSet &rule_set = this+ruleSet[index];
2312     struct ChainContextApplyLookupContext lookup_context = {
2313       {match_class},
2314       {&backtrack_class_def,
2315        &input_class_def,
2316        &lookahead_class_def}
2317     };
2318     return_trace (rule_set.apply (c, lookup_context));
2319   }
2320 
subsetOT::ChainContextFormat22321   bool subset (hb_subset_context_t *c) const
2322   {
2323     TRACE_SUBSET (this);
2324     // TODO(subset)
2325     return_trace (false);
2326   }
2327 
sanitizeOT::ChainContextFormat22328   bool sanitize (hb_sanitize_context_t *c) const
2329   {
2330     TRACE_SANITIZE (this);
2331     return_trace (coverage.sanitize (c, this) &&
2332 		  backtrackClassDef.sanitize (c, this) &&
2333 		  inputClassDef.sanitize (c, this) &&
2334 		  lookaheadClassDef.sanitize (c, this) &&
2335 		  ruleSet.sanitize (c, this));
2336   }
2337 
2338   protected:
2339   HBUINT16	format;			/* Format identifier--format = 2 */
2340   OffsetTo<Coverage>
2341 		coverage;		/* Offset to Coverage table--from
2342 					 * beginning of table */
2343   OffsetTo<ClassDef>
2344 		backtrackClassDef;	/* Offset to glyph ClassDef table
2345 					 * containing backtrack sequence
2346 					 * data--from beginning of table */
2347   OffsetTo<ClassDef>
2348 		inputClassDef;		/* Offset to glyph ClassDef
2349 					 * table containing input sequence
2350 					 * data--from beginning of table */
2351   OffsetTo<ClassDef>
2352 		lookaheadClassDef;	/* Offset to glyph ClassDef table
2353 					 * containing lookahead sequence
2354 					 * data--from beginning of table */
2355   OffsetArrayOf<ChainRuleSet>
2356 		ruleSet;		/* Array of ChainRuleSet tables
2357 					 * ordered by class */
2358   public:
2359   DEFINE_SIZE_ARRAY (12, ruleSet);
2360 };
2361 
2362 struct ChainContextFormat3
2363 {
intersectsOT::ChainContextFormat32364   bool intersects (const hb_set_t *glyphs) const
2365   {
2366     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2367 
2368     if (!(this+input[0]).intersects (glyphs))
2369       return false;
2370 
2371     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2372     struct ChainContextClosureLookupContext lookup_context = {
2373       {intersects_coverage},
2374       {this, this, this}
2375     };
2376     return chain_context_intersects (glyphs,
2377 				     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2378 				     input.len, (const HBUINT16 *) input.arrayZ + 1,
2379 				     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2380 				     lookup_context);
2381   }
2382 
closureOT::ChainContextFormat32383   void closure (hb_closure_context_t *c) const
2384   {
2385     TRACE_CLOSURE (this);
2386     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2387 
2388     if (!(this+input[0]).intersects (c->glyphs))
2389       return;
2390 
2391     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2392     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2393     struct ChainContextClosureLookupContext lookup_context = {
2394       {intersects_coverage},
2395       {this, this, this}
2396     };
2397     chain_context_closure_lookup (c,
2398 				  backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2399 				  input.len, (const HBUINT16 *) input.arrayZ + 1,
2400 				  lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2401 				  lookup.len, lookup.arrayZ,
2402 				  lookup_context);
2403   }
2404 
collect_glyphsOT::ChainContextFormat32405   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2406   {
2407     TRACE_COLLECT_GLYPHS (this);
2408     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2409 
2410     (this+input[0]).add_coverage (c->input);
2411 
2412     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2413     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2414     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2415       {collect_coverage},
2416       {this, this, this}
2417     };
2418     chain_context_collect_glyphs_lookup (c,
2419 					 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2420 					 input.len, (const HBUINT16 *) input.arrayZ + 1,
2421 					 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2422 					 lookup.len, lookup.arrayZ,
2423 					 lookup_context);
2424   }
2425 
would_applyOT::ChainContextFormat32426   bool would_apply (hb_would_apply_context_t *c) const
2427   {
2428     TRACE_WOULD_APPLY (this);
2429 
2430     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2431     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2432     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2433     struct ChainContextApplyLookupContext lookup_context = {
2434       {match_coverage},
2435       {this, this, this}
2436     };
2437     return_trace (chain_context_would_apply_lookup (c,
2438 						    backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2439 						    input.len, (const HBUINT16 *) input.arrayZ + 1,
2440 						    lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2441 						    lookup.len, lookup.arrayZ, lookup_context));
2442   }
2443 
get_coverageOT::ChainContextFormat32444   const Coverage &get_coverage () const
2445   {
2446     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2447     return this+input[0];
2448   }
2449 
applyOT::ChainContextFormat32450   bool apply (hb_ot_apply_context_t *c) const
2451   {
2452     TRACE_APPLY (this);
2453     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2454 
2455     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2456     if (likely (index == NOT_COVERED)) return_trace (false);
2457 
2458     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2459     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2460     struct ChainContextApplyLookupContext lookup_context = {
2461       {match_coverage},
2462       {this, this, this}
2463     };
2464     return_trace (chain_context_apply_lookup (c,
2465 					      backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2466 					      input.len, (const HBUINT16 *) input.arrayZ + 1,
2467 					      lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2468 					      lookup.len, lookup.arrayZ, lookup_context));
2469   }
2470 
subsetOT::ChainContextFormat32471   bool subset (hb_subset_context_t *c) const
2472   {
2473     TRACE_SUBSET (this);
2474     // TODO(subset)
2475     return_trace (false);
2476   }
2477 
sanitizeOT::ChainContextFormat32478   bool sanitize (hb_sanitize_context_t *c) const
2479   {
2480     TRACE_SANITIZE (this);
2481     if (!backtrack.sanitize (c, this)) return_trace (false);
2482     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2483     if (!input.sanitize (c, this)) return_trace (false);
2484     if (!input.len) return_trace (false); /* To be consistent with Context. */
2485     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2486     if (!lookahead.sanitize (c, this)) return_trace (false);
2487     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2488     return_trace (lookup.sanitize (c));
2489   }
2490 
2491   protected:
2492   HBUINT16	format;			/* Format identifier--format = 3 */
2493   OffsetArrayOf<Coverage>
2494 		backtrack;		/* Array of coverage tables
2495 					 * in backtracking sequence, in  glyph
2496 					 * sequence order */
2497   OffsetArrayOf<Coverage>
2498 		inputX		;	/* Array of coverage
2499 					 * tables in input sequence, in glyph
2500 					 * sequence order */
2501   OffsetArrayOf<Coverage>
2502 		lookaheadX;		/* Array of coverage tables
2503 					 * in lookahead sequence, in glyph
2504 					 * sequence order */
2505   ArrayOf<LookupRecord>
2506 		lookupX;		/* Array of LookupRecords--in
2507 					 * design order) */
2508   public:
2509   DEFINE_SIZE_MIN (10);
2510 };
2511 
2512 struct ChainContext
2513 {
2514   template <typename context_t>
dispatchOT::ChainContext2515   typename context_t::return_t dispatch (context_t *c) const
2516   {
2517     TRACE_DISPATCH (this, u.format);
2518     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2519     switch (u.format) {
2520     case 1: return_trace (c->dispatch (u.format1));
2521     case 2: return_trace (c->dispatch (u.format2));
2522     case 3: return_trace (c->dispatch (u.format3));
2523     default:return_trace (c->default_return_value ());
2524     }
2525   }
2526 
2527   protected:
2528   union {
2529   HBUINT16		format;	/* Format identifier */
2530   ChainContextFormat1	format1;
2531   ChainContextFormat2	format2;
2532   ChainContextFormat3	format3;
2533   } u;
2534 };
2535 
2536 
2537 template <typename T>
2538 struct ExtensionFormat1
2539 {
get_typeOT::ExtensionFormat12540   unsigned int get_type () const { return extensionLookupType; }
2541 
2542   template <typename X>
get_subtableOT::ExtensionFormat12543   const X& get_subtable () const
2544   {
2545     unsigned int offset = extensionOffset;
2546     if (unlikely (!offset)) return Null(typename T::SubTable);
2547     return StructAtOffset<typename T::SubTable> (this, offset);
2548   }
2549 
2550   template <typename context_t>
dispatchOT::ExtensionFormat12551   typename context_t::return_t dispatch (context_t *c) const
2552   {
2553     TRACE_DISPATCH (this, format);
2554     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2555     return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
2556   }
2557 
2558   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
sanitizeOT::ExtensionFormat12559   bool sanitize (hb_sanitize_context_t *c) const
2560   {
2561     TRACE_SANITIZE (this);
2562     return_trace (c->check_struct (this) &&
2563 		  extensionOffset != 0 &&
2564 		  extensionLookupType != T::SubTable::Extension);
2565   }
2566 
2567   protected:
2568   HBUINT16	format;			/* Format identifier. Set to 1. */
2569   HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
2570 					 * by ExtensionOffset (i.e. the
2571 					 * extension subtable). */
2572   HBUINT32	extensionOffset;	/* Offset to the extension subtable,
2573 					 * of lookup type subtable. */
2574   public:
2575   DEFINE_SIZE_STATIC (8);
2576 };
2577 
2578 template <typename T>
2579 struct Extension
2580 {
get_typeOT::Extension2581   unsigned int get_type () const
2582   {
2583     switch (u.format) {
2584     case 1: return u.format1.get_type ();
2585     default:return 0;
2586     }
2587   }
2588   template <typename X>
get_subtableOT::Extension2589   const X& get_subtable () const
2590   {
2591     switch (u.format) {
2592     case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2593     default:return Null(typename T::SubTable);
2594     }
2595   }
2596 
2597   template <typename context_t>
dispatchOT::Extension2598   typename context_t::return_t dispatch (context_t *c) const
2599   {
2600     TRACE_DISPATCH (this, u.format);
2601     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2602     switch (u.format) {
2603     case 1: return_trace (u.format1.dispatch (c));
2604     default:return_trace (c->default_return_value ());
2605     }
2606   }
2607 
2608   protected:
2609   union {
2610   HBUINT16		format;		/* Format identifier */
2611   ExtensionFormat1<T>	format1;
2612   } u;
2613 };
2614 
2615 
2616 /*
2617  * GSUB/GPOS Common
2618  */
2619 
2620 struct hb_ot_layout_lookup_accelerator_t
2621 {
2622   template <typename TLookup>
initOT::hb_ot_layout_lookup_accelerator_t2623   void init (const TLookup &lookup)
2624   {
2625     digest.init ();
2626     lookup.add_coverage (&digest);
2627 
2628     subtables.init ();
2629     OT::hb_get_subtables_context_t c_get_subtables (subtables);
2630     lookup.dispatch (&c_get_subtables);
2631   }
finiOT::hb_ot_layout_lookup_accelerator_t2632   void fini () { subtables.fini (); }
2633 
may_haveOT::hb_ot_layout_lookup_accelerator_t2634   bool may_have (hb_codepoint_t g) const
2635   { return digest.may_have (g); }
2636 
applyOT::hb_ot_layout_lookup_accelerator_t2637   bool apply (hb_ot_apply_context_t *c) const
2638   {
2639     for (unsigned int i = 0; i < subtables.len; i++)
2640       if (subtables[i].apply (c))
2641 	return true;
2642     return false;
2643   }
2644 
2645   private:
2646   hb_set_digest_t digest;
2647   hb_get_subtables_context_t::array_t subtables;
2648 };
2649 
2650 struct GSUBGPOS
2651 {
has_dataOT::GSUBGPOS2652   bool has_data () const { return version.to_int (); }
get_script_countOT::GSUBGPOS2653   unsigned int get_script_count () const
2654   { return (this+scriptList).len; }
get_script_tagOT::GSUBGPOS2655   const Tag& get_script_tag (unsigned int i) const
2656   { return (this+scriptList).get_tag (i); }
get_script_tagsOT::GSUBGPOS2657   unsigned int get_script_tags (unsigned int start_offset,
2658 				unsigned int *script_count /* IN/OUT */,
2659 				hb_tag_t     *script_tags /* OUT */) const
2660   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
get_scriptOT::GSUBGPOS2661   const Script& get_script (unsigned int i) const
2662   { return (this+scriptList)[i]; }
find_script_indexOT::GSUBGPOS2663   bool find_script_index (hb_tag_t tag, unsigned int *index) const
2664   { return (this+scriptList).find_index (tag, index); }
2665 
get_feature_countOT::GSUBGPOS2666   unsigned int get_feature_count () const
2667   { return (this+featureList).len; }
get_feature_tagOT::GSUBGPOS2668   hb_tag_t get_feature_tag (unsigned int i) const
2669   { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
get_feature_tagsOT::GSUBGPOS2670   unsigned int get_feature_tags (unsigned int start_offset,
2671 				 unsigned int *feature_count /* IN/OUT */,
2672 				 hb_tag_t     *feature_tags /* OUT */) const
2673   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
get_featureOT::GSUBGPOS2674   const Feature& get_feature (unsigned int i) const
2675   { return (this+featureList)[i]; }
find_feature_indexOT::GSUBGPOS2676   bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2677   { return (this+featureList).find_index (tag, index); }
2678 
get_lookup_countOT::GSUBGPOS2679   unsigned int get_lookup_count () const
2680   { return (this+lookupList).len; }
get_lookupOT::GSUBGPOS2681   const Lookup& get_lookup (unsigned int i) const
2682   { return (this+lookupList)[i]; }
2683 
find_variations_indexOT::GSUBGPOS2684   bool find_variations_index (const int *coords, unsigned int num_coords,
2685 			      unsigned int *index) const
2686   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2687 	   .find_index (coords, num_coords, index); }
get_feature_variationOT::GSUBGPOS2688   const Feature& get_feature_variation (unsigned int feature_index,
2689 					       unsigned int variations_index) const
2690   {
2691     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2692 	version.to_int () >= 0x00010001u)
2693     {
2694       const Feature *feature = (this+featureVars).find_substitute (variations_index,
2695 								   feature_index);
2696       if (feature)
2697 	return *feature;
2698     }
2699     return get_feature (feature_index);
2700   }
2701 
2702   template <typename TLookup>
subsetOT::GSUBGPOS2703   bool subset (hb_subset_context_t *c) const
2704   {
2705     TRACE_SUBSET (this);
2706     struct GSUBGPOS *out = c->serializer->embed (*this);
2707     if (unlikely (!out)) return_trace (false);
2708 
2709     out->scriptList.serialize_subset (c, this+scriptList, out);
2710     out->featureList.serialize_subset (c, this+featureList, out);
2711 
2712     typedef OffsetListOf<TLookup> TLookupList;
2713     /* TODO Use intersects() to count how many subtables survive? */
2714     CastR<OffsetTo<TLookupList> > (out->lookupList)
2715       .serialize_subset (c,
2716 			 this+CastR<const OffsetTo<TLookupList> > (lookupList),
2717 			 out);
2718 
2719     if (version.to_int () >= 0x00010001u)
2720      out->featureVars.serialize_subset (c, this+featureVars, out);
2721 
2722     return_trace (true);
2723   }
2724 
get_sizeOT::GSUBGPOS2725   unsigned int get_size () const
2726   {
2727     return min_size +
2728 	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2729   }
2730 
2731   template <typename TLookup>
sanitizeOT::GSUBGPOS2732   bool sanitize (hb_sanitize_context_t *c) const
2733   {
2734     TRACE_SANITIZE (this);
2735     typedef OffsetListOf<TLookup> TLookupList;
2736     return_trace (version.sanitize (c) &&
2737 		  likely (version.major == 1) &&
2738 		  scriptList.sanitize (c, this) &&
2739 		  featureList.sanitize (c, this) &&
2740 		  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
2741 		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2742   }
2743 
2744   template <typename T>
2745   struct accelerator_t
2746   {
initOT::GSUBGPOS::accelerator_t2747     void init (hb_face_t *face)
2748     {
2749       this->table = hb_sanitize_context_t().reference_table<T> (face);
2750       if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
2751       {
2752 	hb_blob_destroy (this->table.get_blob ());
2753 	this->table = hb_blob_get_empty ();
2754       }
2755 
2756       this->lookup_count = table->get_lookup_count ();
2757 
2758       this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2759       if (unlikely (!this->accels))
2760 	this->lookup_count = 0;
2761 
2762       for (unsigned int i = 0; i < this->lookup_count; i++)
2763 	this->accels[i].init (table->get_lookup (i));
2764     }
2765 
finiOT::GSUBGPOS::accelerator_t2766     void fini ()
2767     {
2768       for (unsigned int i = 0; i < this->lookup_count; i++)
2769 	this->accels[i].fini ();
2770       free (this->accels);
2771       this->table.destroy ();
2772     }
2773 
2774     hb_blob_ptr_t<T> table;
2775     unsigned int lookup_count;
2776     hb_ot_layout_lookup_accelerator_t *accels;
2777   };
2778 
2779   protected:
2780   FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
2781 				 * to 0x00010000u */
2782   OffsetTo<ScriptList>
2783 		scriptList;  	/* ScriptList table */
2784   OffsetTo<FeatureList>
2785 		featureList; 	/* FeatureList table */
2786   OffsetTo<LookupList>
2787 		lookupList; 	/* LookupList table */
2788   LOffsetTo<FeatureVariations>
2789 		featureVars;	/* Offset to Feature Variations
2790 				   table--from beginning of table
2791 				 * (may be NULL).  Introduced
2792 				 * in version 0x00010001. */
2793   public:
2794   DEFINE_SIZE_MIN (10);
2795 };
2796 
2797 
2798 } /* namespace OT */
2799 
2800 
2801 #endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
2802