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_empty_t, 0>
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_empty_t (); }
default_return_valueOT::hb_closure_context_t68   static return_t default_return_value () { return hb_empty_t (); }
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 output[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, output);
118     hb_set_clear (output);
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, 0>
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_empty_t, 0>
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_empty_t (); }
default_return_valueOT::hb_collect_glyphs_context_t160   static return_t default_return_value () { return hb_empty_t (); }
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 	  if (match_glyph_data) 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 	  if (match_glyph_data) 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 (
487 #ifndef HB_NO_OT_LAYOUT
488 			      *face->table.GDEF->table
489 #else
490 			      Null(GDEF)
491 #endif
492 			     ),
493 			var_store (gdef.get_var_store ()),
494 			direction (buffer_->props.direction),
495 			lookup_mask (1),
496 			table_index (table_index_),
497 			lookup_index ((unsigned int) -1),
498 			lookup_props (0),
499 			nesting_level_left (HB_MAX_NESTING_LEVEL),
500 			debug_depth (0),
501 			has_glyph_classes (gdef.has_glyph_classes ()),
502 			auto_zwnj (true),
503 			auto_zwj (true),
504 			random (false),
505 			random_state (1) { init_iters (); }
506 
init_itersOT::hb_ot_apply_context_t507   void init_iters ()
508   {
509     iter_input.init (this, false);
510     iter_context.init (this, true);
511   }
512 
set_lookup_maskOT::hb_ot_apply_context_t513   void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
set_auto_zwjOT::hb_ot_apply_context_t514   void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
set_auto_zwnjOT::hb_ot_apply_context_t515   void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
set_randomOT::hb_ot_apply_context_t516   void set_random (bool random_) { random = random_; }
set_recurse_funcOT::hb_ot_apply_context_t517   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
set_lookup_indexOT::hb_ot_apply_context_t518   void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
set_lookup_propsOT::hb_ot_apply_context_t519   void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
520 
random_numberOT::hb_ot_apply_context_t521   uint32_t random_number ()
522   {
523     /* http://www.cplusplus.com/reference/random/minstd_rand/ */
524     random_state = random_state * 48271 % 2147483647;
525     return random_state;
526   }
527 
match_properties_markOT::hb_ot_apply_context_t528   bool match_properties_mark (hb_codepoint_t  glyph,
529 			      unsigned int    glyph_props,
530 			      unsigned int    match_props) const
531   {
532     /* If using mark filtering sets, the high short of
533      * match_props has the set index.
534      */
535     if (match_props & LookupFlag::UseMarkFilteringSet)
536       return gdef.mark_set_covers (match_props >> 16, glyph);
537 
538     /* The second byte of match_props has the meaning
539      * "ignore marks of attachment type different than
540      * the attachment type specified."
541      */
542     if (match_props & LookupFlag::MarkAttachmentType)
543       return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
544 
545     return true;
546   }
547 
check_glyph_propertyOT::hb_ot_apply_context_t548   bool check_glyph_property (const hb_glyph_info_t *info,
549 			     unsigned int  match_props) const
550   {
551     hb_codepoint_t glyph = info->codepoint;
552     unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
553 
554     /* Not covered, if, for example, glyph class is ligature and
555      * match_props includes LookupFlags::IgnoreLigatures
556      */
557     if (glyph_props & match_props & LookupFlag::IgnoreFlags)
558       return false;
559 
560     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
561       return match_properties_mark (glyph, glyph_props, match_props);
562 
563     return true;
564   }
565 
_set_glyph_propsOT::hb_ot_apply_context_t566   void _set_glyph_props (hb_codepoint_t glyph_index,
567 			  unsigned int class_guess = 0,
568 			  bool ligature = false,
569 			  bool component = false) const
570   {
571     unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
572 			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
573     add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
574     if (ligature)
575     {
576       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
577       /* In the only place that the MULTIPLIED bit is used, Uniscribe
578        * seems to only care about the "last" transformation between
579        * Ligature and Multiple substitutions.  Ie. if you ligate, expand,
580        * and ligate again, it forgives the multiplication and acts as
581        * if only ligation happened.  As such, clear MULTIPLIED bit.
582        */
583       add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
584     }
585     if (component)
586       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
587     if (likely (has_glyph_classes))
588       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
589     else if (class_guess)
590       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
591   }
592 
replace_glyphOT::hb_ot_apply_context_t593   void replace_glyph (hb_codepoint_t glyph_index) const
594   {
595     _set_glyph_props (glyph_index);
596     buffer->replace_glyph (glyph_index);
597   }
replace_glyph_inplaceOT::hb_ot_apply_context_t598   void replace_glyph_inplace (hb_codepoint_t glyph_index) const
599   {
600     _set_glyph_props (glyph_index);
601     buffer->cur().codepoint = glyph_index;
602   }
replace_glyph_with_ligatureOT::hb_ot_apply_context_t603   void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
604 					   unsigned int class_guess) const
605   {
606     _set_glyph_props (glyph_index, class_guess, true);
607     buffer->replace_glyph (glyph_index);
608   }
output_glyph_for_componentOT::hb_ot_apply_context_t609   void output_glyph_for_component (hb_codepoint_t glyph_index,
610 					  unsigned int class_guess) const
611   {
612     _set_glyph_props (glyph_index, class_guess, false, true);
613     buffer->output_glyph (glyph_index);
614   }
615 };
616 
617 
618 struct hb_get_subtables_context_t :
619        hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
620 {
621   template <typename Type>
apply_toOT::hb_get_subtables_context_t622   HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
623   {
624     const Type *typed_obj = (const Type *) obj;
625     return typed_obj->apply (c);
626   }
627 
628   typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
629 
630   struct hb_applicable_t
631   {
632     template <typename T>
initOT::hb_get_subtables_context_t::hb_applicable_t633     void init (const T &obj_, hb_apply_func_t apply_func_)
634     {
635       obj = &obj_;
636       apply_func = apply_func_;
637       digest.init ();
638       obj_.get_coverage ().add_coverage (&digest);
639     }
640 
applyOT::hb_get_subtables_context_t::hb_applicable_t641     bool apply (OT::hb_ot_apply_context_t *c) const
642     {
643       return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
644     }
645 
646     private:
647     const void *obj;
648     hb_apply_func_t apply_func;
649     hb_set_digest_t digest;
650   };
651 
652   typedef hb_vector_t<hb_applicable_t> array_t;
653 
654   /* Dispatch interface. */
get_nameOT::hb_get_subtables_context_t655   const char *get_name () { return "GET_SUBTABLES"; }
656   template <typename T>
dispatchOT::hb_get_subtables_context_t657   return_t dispatch (const T &obj)
658   {
659     hb_applicable_t *entry = array.push();
660     entry->init (obj, apply_to<T>);
661     return hb_empty_t ();
662   }
default_return_valueOT::hb_get_subtables_context_t663   static return_t default_return_value () { return hb_empty_t (); }
664 
hb_get_subtables_context_tOT::hb_get_subtables_context_t665   hb_get_subtables_context_t (array_t &array_) :
666 			      array (array_),
667 			      debug_depth (0) {}
668 
669   array_t &array;
670   unsigned int debug_depth;
671 };
672 
673 
674 
675 
676 typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
677 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
678 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
679 
680 struct ContextClosureFuncs
681 {
682   intersects_func_t intersects;
683 };
684 struct ContextCollectGlyphsFuncs
685 {
686   collect_glyphs_func_t collect;
687 };
688 struct ContextApplyFuncs
689 {
690   match_func_t match;
691 };
692 
693 
intersects_glyph(const hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)694 static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
695 {
696   return glyphs->has (value);
697 }
intersects_class(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)698 static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
699 {
700   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
701   return class_def.intersects_class (glyphs, value);
702 }
intersects_coverage(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)703 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
704 {
705   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
706   return (data+coverage).intersects (glyphs);
707 }
708 
intersects_array(const hb_set_t * glyphs,unsigned int count,const HBUINT16 values[],intersects_func_t intersects_func,const void * intersects_data)709 static inline bool intersects_array (const hb_set_t *glyphs,
710 				     unsigned int count,
711 				     const HBUINT16 values[],
712 				     intersects_func_t intersects_func,
713 				     const void *intersects_data)
714 {
715   for (const HBUINT16 &_ : + hb_iter (values, count))
716     if (intersects_func (glyphs, _, intersects_data)) return true;
717   return false;
718 }
719 
720 
collect_glyph(hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)721 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
722 {
723   glyphs->add (value);
724 }
collect_class(hb_set_t * glyphs,const HBUINT16 & value,const void * data)725 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
726 {
727   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
728   class_def.add_class (glyphs, value);
729 }
collect_coverage(hb_set_t * glyphs,const HBUINT16 & value,const void * data)730 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
731 {
732   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
733   (data+coverage).add_coverage (glyphs);
734 }
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)735 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
736 				  hb_set_t *glyphs,
737 				  unsigned int count,
738 				  const HBUINT16 values[],
739 				  collect_glyphs_func_t collect_func,
740 				  const void *collect_data)
741 {
742   return
743   + hb_iter (values, count)
744   | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
745   ;
746 }
747 
748 
match_glyph(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data HB_UNUSED)749 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
750 {
751   return glyph_id == value;
752 }
match_class(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)753 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
754 {
755   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
756   return class_def.get_class (glyph_id) == value;
757 }
match_coverage(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)758 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
759 {
760   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
761   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
762 }
763 
would_match_input(hb_would_apply_context_t * c,unsigned int count,const HBUINT16 input[],match_func_t match_func,const void * match_data)764 static inline bool would_match_input (hb_would_apply_context_t *c,
765 				      unsigned int count, /* Including the first glyph (not matched) */
766 				      const HBUINT16 input[], /* Array of input values--start with second glyph */
767 				      match_func_t match_func,
768 				      const void *match_data)
769 {
770   if (count != c->len)
771     return false;
772 
773   for (unsigned int i = 1; i < count; i++)
774     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
775       return false;
776 
777   return true;
778 }
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)779 static inline bool match_input (hb_ot_apply_context_t *c,
780 				unsigned int count, /* Including the first glyph (not matched) */
781 				const HBUINT16 input[], /* Array of input values--start with second glyph */
782 				match_func_t match_func,
783 				const void *match_data,
784 				unsigned int *end_offset,
785 				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
786 				unsigned int *p_total_component_count = nullptr)
787 {
788   TRACE_APPLY (nullptr);
789 
790   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
791 
792   hb_buffer_t *buffer = c->buffer;
793 
794   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
795   skippy_iter.reset (buffer->idx, count - 1);
796   skippy_iter.set_match_func (match_func, match_data, input);
797 
798   /*
799    * This is perhaps the trickiest part of OpenType...  Remarks:
800    *
801    * - If all components of the ligature were marks, we call this a mark ligature.
802    *
803    * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
804    *   it as a ligature glyph.
805    *
806    * - Ligatures cannot be formed across glyphs attached to different components
807    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
808    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
809    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
810    *   There are a couple of exceptions to this:
811    *
812    *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
813    *     assuming that the font designer knows what they are doing (otherwise it can
814    *     break Indic stuff when a matra wants to ligate with a conjunct,
815    *
816    *   o If two marks want to ligate and they belong to different components of the
817    *     same ligature glyph, and said ligature glyph is to be ignored according to
818    *     mark-filtering rules, then allow.
819    *     https://github.com/harfbuzz/harfbuzz/issues/545
820    */
821 
822   unsigned int total_component_count = 0;
823   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
824 
825   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
826   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
827 
828   enum {
829     LIGBASE_NOT_CHECKED,
830     LIGBASE_MAY_NOT_SKIP,
831     LIGBASE_MAY_SKIP
832   } ligbase = LIGBASE_NOT_CHECKED;
833 
834   match_positions[0] = buffer->idx;
835   for (unsigned int i = 1; i < count; i++)
836   {
837     if (!skippy_iter.next ()) return_trace (false);
838 
839     match_positions[i] = skippy_iter.idx;
840 
841     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
842     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
843 
844     if (first_lig_id && first_lig_comp)
845     {
846       /* If first component was attached to a previous ligature component,
847        * all subsequent components should be attached to the same ligature
848        * component, otherwise we shouldn't ligate them... */
849       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
850       {
851 	/* ...unless, we are attached to a base ligature and that base
852 	 * ligature is ignorable. */
853 	if (ligbase == LIGBASE_NOT_CHECKED)
854 	{
855 	  bool found = false;
856 	  const auto *out = buffer->out_info;
857 	  unsigned int j = buffer->out_len;
858 	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
859 	  {
860 	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
861 	    {
862 	      j--;
863 	      found = true;
864 	      break;
865 	    }
866 	    j--;
867 	  }
868 
869 	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
870 	    ligbase = LIGBASE_MAY_SKIP;
871 	  else
872 	    ligbase = LIGBASE_MAY_NOT_SKIP;
873 	}
874 
875 	if (ligbase == LIGBASE_MAY_NOT_SKIP)
876 	  return_trace (false);
877       }
878     }
879     else
880     {
881       /* If first component was NOT attached to a previous ligature component,
882        * all subsequent components should also NOT be attached to any ligature
883        * component, unless they are attached to the first component itself! */
884       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
885 	return_trace (false);
886     }
887 
888     total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
889   }
890 
891   *end_offset = skippy_iter.idx - buffer->idx + 1;
892 
893   if (p_total_component_count)
894     *p_total_component_count = total_component_count;
895 
896   return_trace (true);
897 }
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)898 static inline bool ligate_input (hb_ot_apply_context_t *c,
899 				 unsigned int count, /* Including the first glyph */
900 				 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
901 				 unsigned int match_length,
902 				 hb_codepoint_t lig_glyph,
903 				 unsigned int total_component_count)
904 {
905   TRACE_APPLY (nullptr);
906 
907   hb_buffer_t *buffer = c->buffer;
908 
909   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
910 
911   /* - If a base and one or more marks ligate, consider that as a base, NOT
912    *   ligature, such that all following marks can still attach to it.
913    *   https://github.com/harfbuzz/harfbuzz/issues/1109
914    *
915    * - If all components of the ligature were marks, we call this a mark ligature.
916    *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
917    *   the ligature to keep its old ligature id.  This will allow it to attach to
918    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
919    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
920    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
921    *   later, we don't want them to lose their ligature id/component, otherwise
922    *   GPOS will fail to correctly position the mark ligature on top of the
923    *   LAM,LAM,HEH ligature.  See:
924    *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
925    *
926    * - If a ligature is formed of components that some of which are also ligatures
927    *   themselves, and those ligature components had marks attached to *their*
928    *   components, we have to attach the marks to the new ligature component
929    *   positions!  Now *that*'s tricky!  And these marks may be following the
930    *   last component of the whole sequence, so we should loop forward looking
931    *   for them and update them.
932    *
933    *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
934    *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
935    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
936    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
937    *   the new ligature with a component value of 2.
938    *
939    *   This in fact happened to a font...  See:
940    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
941    */
942 
943   bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
944   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
945   for (unsigned int i = 1; i < count; i++)
946     if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
947     {
948       is_base_ligature = false;
949       is_mark_ligature = false;
950       break;
951     }
952   bool is_ligature = !is_base_ligature && !is_mark_ligature;
953 
954   unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
955   unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
956   unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
957   unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
958   unsigned int components_so_far = last_num_components;
959 
960   if (is_ligature)
961   {
962     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
963     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
964     {
965       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
966     }
967   }
968   c->replace_glyph_with_ligature (lig_glyph, klass);
969 
970   for (unsigned int i = 1; i < count; i++)
971   {
972     while (buffer->idx < match_positions[i] && buffer->successful)
973     {
974       if (is_ligature)
975       {
976 	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
977 	if (this_comp == 0)
978 	  this_comp = last_num_components;
979 	unsigned int new_lig_comp = components_so_far - last_num_components +
980 				    hb_min (this_comp, last_num_components);
981 	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
982       }
983       buffer->next_glyph ();
984     }
985 
986     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
987     last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
988     components_so_far += last_num_components;
989 
990     /* Skip the base glyph */
991     buffer->idx++;
992   }
993 
994   if (!is_mark_ligature && last_lig_id) {
995     /* Re-adjust components for any marks following. */
996     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
997       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
998 	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
999 	if (!this_comp)
1000 	  break;
1001 	unsigned int new_lig_comp = components_so_far - last_num_components +
1002 				    hb_min (this_comp, last_num_components);
1003 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1004       } else
1005 	break;
1006     }
1007   }
1008   return_trace (true);
1009 }
1010 
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)1011 static inline bool match_backtrack (hb_ot_apply_context_t *c,
1012 				    unsigned int count,
1013 				    const HBUINT16 backtrack[],
1014 				    match_func_t match_func,
1015 				    const void *match_data,
1016 				    unsigned int *match_start)
1017 {
1018   TRACE_APPLY (nullptr);
1019 
1020   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1021   skippy_iter.reset (c->buffer->backtrack_len (), count);
1022   skippy_iter.set_match_func (match_func, match_data, backtrack);
1023 
1024   for (unsigned int i = 0; i < count; i++)
1025     if (!skippy_iter.prev ())
1026       return_trace (false);
1027 
1028   *match_start = skippy_iter.idx;
1029 
1030   return_trace (true);
1031 }
1032 
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)1033 static inline bool match_lookahead (hb_ot_apply_context_t *c,
1034 				    unsigned int count,
1035 				    const HBUINT16 lookahead[],
1036 				    match_func_t match_func,
1037 				    const void *match_data,
1038 				    unsigned int offset,
1039 				    unsigned int *end_index)
1040 {
1041   TRACE_APPLY (nullptr);
1042 
1043   hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1044   skippy_iter.reset (c->buffer->idx + offset - 1, count);
1045   skippy_iter.set_match_func (match_func, match_data, lookahead);
1046 
1047   for (unsigned int i = 0; i < count; i++)
1048     if (!skippy_iter.next ())
1049       return_trace (false);
1050 
1051   *end_index = skippy_iter.idx + 1;
1052 
1053   return_trace (true);
1054 }
1055 
1056 
1057 
1058 struct LookupRecord
1059 {
sanitizeOT::LookupRecord1060   bool sanitize (hb_sanitize_context_t *c) const
1061   {
1062     TRACE_SANITIZE (this);
1063     return_trace (c->check_struct (this));
1064   }
1065 
1066   HBUINT16	sequenceIndex;		/* Index into current glyph
1067 					 * sequence--first glyph = 0 */
1068   HBUINT16	lookupListIndex;	/* Lookup to apply to that
1069 					 * position--zero--based */
1070   public:
1071   DEFINE_SIZE_STATIC (4);
1072 };
1073 
1074 template <typename context_t>
recurse_lookups(context_t * c,unsigned int lookupCount,const LookupRecord lookupRecord[])1075 static inline void recurse_lookups (context_t *c,
1076 				    unsigned int lookupCount,
1077 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1078 {
1079   for (unsigned int i = 0; i < lookupCount; i++)
1080     c->recurse (lookupRecord[i].lookupListIndex);
1081 }
1082 
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)1083 static inline bool apply_lookup (hb_ot_apply_context_t *c,
1084 				 unsigned int count, /* Including the first glyph */
1085 				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1086 				 unsigned int lookupCount,
1087 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1088 				 unsigned int match_length)
1089 {
1090   TRACE_APPLY (nullptr);
1091 
1092   hb_buffer_t *buffer = c->buffer;
1093   int end;
1094 
1095   /* All positions are distance from beginning of *output* buffer.
1096    * Adjust. */
1097   {
1098     unsigned int bl = buffer->backtrack_len ();
1099     end = bl + match_length;
1100 
1101     int delta = bl - buffer->idx;
1102     /* Convert positions to new indexing. */
1103     for (unsigned int j = 0; j < count; j++)
1104       match_positions[j] += delta;
1105   }
1106 
1107   for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1108   {
1109     unsigned int idx = lookupRecord[i].sequenceIndex;
1110     if (idx >= count)
1111       continue;
1112 
1113     /* Don't recurse to ourself at same position.
1114      * Note that this test is too naive, it doesn't catch longer loops. */
1115     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1116       continue;
1117 
1118     if (unlikely (!buffer->move_to (match_positions[idx])))
1119       break;
1120 
1121     if (unlikely (buffer->max_ops <= 0))
1122       break;
1123 
1124     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1125     if (!c->recurse (lookupRecord[i].lookupListIndex))
1126       continue;
1127 
1128     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1129     int delta = new_len - orig_len;
1130 
1131     if (!delta)
1132       continue;
1133 
1134     /* Recursed lookup changed buffer len.  Adjust.
1135      *
1136      * TODO:
1137      *
1138      * Right now, if buffer length increased by n, we assume n new glyphs
1139      * were added right after the current position, and if buffer length
1140      * was decreased by n, we assume n match positions after the current
1141      * one where removed.  The former (buffer length increased) case is
1142      * fine, but the decrease case can be improved in at least two ways,
1143      * both of which are significant:
1144      *
1145      *   - If recursed-to lookup is MultipleSubst and buffer length
1146      *     decreased, then it's current match position that was deleted,
1147      *     NOT the one after it.
1148      *
1149      *   - If buffer length was decreased by n, it does not necessarily
1150      *     mean that n match positions where removed, as there might
1151      *     have been marks and default-ignorables in the sequence.  We
1152      *     should instead drop match positions between current-position
1153      *     and current-position + n instead.
1154      *
1155      * It should be possible to construct tests for both of these cases.
1156      */
1157 
1158     end += delta;
1159     if (end <= int (match_positions[idx]))
1160     {
1161       /* End might end up being smaller than match_positions[idx] if the recursed
1162        * lookup ended up removing many items, more than we have had matched.
1163        * Just never rewind end back and get out of here.
1164        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1165       end = match_positions[idx];
1166       /* There can't be any further changes. */
1167       break;
1168     }
1169 
1170     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1171 
1172     if (delta > 0)
1173     {
1174       if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1175 	break;
1176     }
1177     else
1178     {
1179       /* NOTE: delta is negative. */
1180       delta = hb_max (delta, (int) next - (int) count);
1181       next -= delta;
1182     }
1183 
1184     /* Shift! */
1185     memmove (match_positions + next + delta, match_positions + next,
1186 	     (count - next) * sizeof (match_positions[0]));
1187     next += delta;
1188     count += delta;
1189 
1190     /* Fill in new entries. */
1191     for (unsigned int j = idx + 1; j < next; j++)
1192       match_positions[j] = match_positions[j - 1] + 1;
1193 
1194     /* And fixup the rest. */
1195     for (; next < count; next++)
1196       match_positions[next] += delta;
1197   }
1198 
1199   buffer->move_to (end);
1200 
1201   return_trace (true);
1202 }
1203 
1204 
1205 
1206 /* Contextual lookups */
1207 
1208 struct ContextClosureLookupContext
1209 {
1210   ContextClosureFuncs funcs;
1211   const void *intersects_data;
1212 };
1213 
1214 struct ContextCollectGlyphsLookupContext
1215 {
1216   ContextCollectGlyphsFuncs funcs;
1217   const void *collect_data;
1218 };
1219 
1220 struct ContextApplyLookupContext
1221 {
1222   ContextApplyFuncs funcs;
1223   const void *match_data;
1224 };
1225 
context_intersects(const hb_set_t * glyphs,unsigned int inputCount,const HBUINT16 input[],ContextClosureLookupContext & lookup_context)1226 static inline bool context_intersects (const hb_set_t *glyphs,
1227 				       unsigned int inputCount, /* Including the first glyph (not matched) */
1228 				       const HBUINT16 input[], /* Array of input values--start with second glyph */
1229 				       ContextClosureLookupContext &lookup_context)
1230 {
1231   return intersects_array (glyphs,
1232 			   inputCount ? inputCount - 1 : 0, input,
1233 			   lookup_context.funcs.intersects, lookup_context.intersects_data);
1234 }
1235 
context_closure_lookup(hb_closure_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextClosureLookupContext & lookup_context)1236 static inline void context_closure_lookup (hb_closure_context_t *c,
1237 					   unsigned int inputCount, /* Including the first glyph (not matched) */
1238 					   const HBUINT16 input[], /* Array of input values--start with second glyph */
1239 					   unsigned int lookupCount,
1240 					   const LookupRecord lookupRecord[],
1241 					   ContextClosureLookupContext &lookup_context)
1242 {
1243   if (context_intersects (c->glyphs,
1244 			  inputCount, input,
1245 			  lookup_context))
1246     recurse_lookups (c,
1247 		     lookupCount, lookupRecord);
1248 }
1249 
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)1250 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1251 						  unsigned int inputCount, /* Including the first glyph (not matched) */
1252 						  const HBUINT16 input[], /* Array of input values--start with second glyph */
1253 						  unsigned int lookupCount,
1254 						  const LookupRecord lookupRecord[],
1255 						  ContextCollectGlyphsLookupContext &lookup_context)
1256 {
1257   collect_array (c, c->input,
1258 		 inputCount ? inputCount - 1 : 0, input,
1259 		 lookup_context.funcs.collect, lookup_context.collect_data);
1260   recurse_lookups (c,
1261 		   lookupCount, lookupRecord);
1262 }
1263 
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)1264 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1265 					       unsigned int inputCount, /* Including the first glyph (not matched) */
1266 					       const HBUINT16 input[], /* Array of input values--start with second glyph */
1267 					       unsigned int lookupCount HB_UNUSED,
1268 					       const LookupRecord lookupRecord[] HB_UNUSED,
1269 					       ContextApplyLookupContext &lookup_context)
1270 {
1271   return would_match_input (c,
1272 			    inputCount, input,
1273 			    lookup_context.funcs.match, lookup_context.match_data);
1274 }
context_apply_lookup(hb_ot_apply_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextApplyLookupContext & lookup_context)1275 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1276 					 unsigned int inputCount, /* Including the first glyph (not matched) */
1277 					 const HBUINT16 input[], /* Array of input values--start with second glyph */
1278 					 unsigned int lookupCount,
1279 					 const LookupRecord lookupRecord[],
1280 					 ContextApplyLookupContext &lookup_context)
1281 {
1282   unsigned int match_length = 0;
1283   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1284   return match_input (c,
1285 		      inputCount, input,
1286 		      lookup_context.funcs.match, lookup_context.match_data,
1287 		      &match_length, match_positions)
1288       && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1289 	  apply_lookup (c,
1290 		       inputCount, match_positions,
1291 		       lookupCount, lookupRecord,
1292 		       match_length));
1293 }
1294 
1295 struct Rule
1296 {
intersectsOT::Rule1297   bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1298   {
1299     return context_intersects (glyphs,
1300 			       inputCount, inputZ.arrayZ,
1301 			       lookup_context);
1302   }
1303 
closureOT::Rule1304   void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1305   {
1306     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1307 						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1308     context_closure_lookup (c,
1309 			    inputCount, inputZ.arrayZ,
1310 			    lookupCount, lookupRecord.arrayZ,
1311 			    lookup_context);
1312   }
1313 
collect_glyphsOT::Rule1314   void collect_glyphs (hb_collect_glyphs_context_t *c,
1315 		       ContextCollectGlyphsLookupContext &lookup_context) const
1316   {
1317     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1318 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1319     context_collect_glyphs_lookup (c,
1320 				   inputCount, inputZ.arrayZ,
1321 				   lookupCount, lookupRecord.arrayZ,
1322 				   lookup_context);
1323   }
1324 
would_applyOT::Rule1325   bool would_apply (hb_would_apply_context_t *c,
1326 		    ContextApplyLookupContext &lookup_context) const
1327   {
1328     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1329 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1330     return context_would_apply_lookup (c,
1331 				       inputCount, inputZ.arrayZ,
1332 				       lookupCount, lookupRecord.arrayZ,
1333 				       lookup_context);
1334   }
1335 
applyOT::Rule1336   bool apply (hb_ot_apply_context_t *c,
1337 	      ContextApplyLookupContext &lookup_context) const
1338   {
1339     TRACE_APPLY (this);
1340     const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1341 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1342     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1343   }
1344 
1345   public:
sanitizeOT::Rule1346   bool sanitize (hb_sanitize_context_t *c) const
1347   {
1348     TRACE_SANITIZE (this);
1349     return_trace (inputCount.sanitize (c) &&
1350 		  lookupCount.sanitize (c) &&
1351 		  c->check_range (inputZ.arrayZ,
1352 				  inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
1353 				  LookupRecord::static_size * lookupCount));
1354   }
1355 
1356   protected:
1357   HBUINT16	inputCount;		/* Total number of glyphs in input
1358 					 * glyph sequence--includes the first
1359 					 * glyph */
1360   HBUINT16	lookupCount;		/* Number of LookupRecords */
1361   UnsizedArrayOf<HBUINT16>
1362  		inputZ;			/* Array of match inputs--start with
1363 					 * second glyph */
1364 /*UnsizedArrayOf<LookupRecord>
1365 		lookupRecordX;*/	/* Array of LookupRecords--in
1366 					 * design order */
1367   public:
1368   DEFINE_SIZE_ARRAY (4, inputZ);
1369 };
1370 
1371 struct RuleSet
1372 {
intersectsOT::RuleSet1373   bool intersects (const hb_set_t *glyphs,
1374 		   ContextClosureLookupContext &lookup_context) const
1375   {
1376     return
1377     + hb_iter (rule)
1378     | hb_map (hb_add (this))
1379     | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
1380     | hb_any
1381     ;
1382   }
1383 
closureOT::RuleSet1384   void closure (hb_closure_context_t *c,
1385 		ContextClosureLookupContext &lookup_context) const
1386   {
1387     return
1388     + hb_iter (rule)
1389     | hb_map (hb_add (this))
1390     | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
1391     ;
1392   }
1393 
collect_glyphsOT::RuleSet1394   void collect_glyphs (hb_collect_glyphs_context_t *c,
1395 		       ContextCollectGlyphsLookupContext &lookup_context) const
1396   {
1397     return
1398     + hb_iter (rule)
1399     | hb_map (hb_add (this))
1400     | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
1401     ;
1402   }
1403 
would_applyOT::RuleSet1404   bool would_apply (hb_would_apply_context_t *c,
1405 		    ContextApplyLookupContext &lookup_context) const
1406   {
1407     return
1408     + hb_iter (rule)
1409     | hb_map (hb_add (this))
1410     | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
1411     | hb_any
1412     ;
1413   }
1414 
applyOT::RuleSet1415   bool apply (hb_ot_apply_context_t *c,
1416 	      ContextApplyLookupContext &lookup_context) const
1417   {
1418     TRACE_APPLY (this);
1419     return_trace (
1420     + hb_iter (rule)
1421     | hb_map (hb_add (this))
1422     | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
1423     | hb_any
1424     )
1425     ;
1426   }
1427 
sanitizeOT::RuleSet1428   bool sanitize (hb_sanitize_context_t *c) const
1429   {
1430     TRACE_SANITIZE (this);
1431     return_trace (rule.sanitize (c, this));
1432   }
1433 
1434   protected:
1435   OffsetArrayOf<Rule>
1436 		rule;			/* Array of Rule tables
1437 					 * ordered by preference */
1438   public:
1439   DEFINE_SIZE_ARRAY (2, rule);
1440 };
1441 
1442 
1443 struct ContextFormat1
1444 {
intersectsOT::ContextFormat11445   bool intersects (const hb_set_t *glyphs) const
1446   {
1447     struct ContextClosureLookupContext lookup_context = {
1448       {intersects_glyph},
1449       nullptr
1450     };
1451 
1452     return
1453     + hb_zip (this+coverage, ruleSet)
1454     | hb_filter (*glyphs, hb_first)
1455     | hb_map (hb_second)
1456     | hb_map (hb_add (this))
1457     | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
1458     | hb_any
1459     ;
1460   }
1461 
closureOT::ContextFormat11462   void closure (hb_closure_context_t *c) const
1463   {
1464     struct ContextClosureLookupContext lookup_context = {
1465       {intersects_glyph},
1466       nullptr
1467     };
1468 
1469     + hb_zip (this+coverage, ruleSet)
1470     | hb_filter (*c->glyphs, hb_first)
1471     | hb_map (hb_second)
1472     | hb_map (hb_add (this))
1473     | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
1474     ;
1475   }
1476 
collect_glyphsOT::ContextFormat11477   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1478   {
1479     (this+coverage).add_coverage (c->input);
1480 
1481     struct ContextCollectGlyphsLookupContext lookup_context = {
1482       {collect_glyph},
1483       nullptr
1484     };
1485 
1486     + hb_iter (ruleSet)
1487     | hb_map (hb_add (this))
1488     | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
1489     ;
1490   }
1491 
would_applyOT::ContextFormat11492   bool would_apply (hb_would_apply_context_t *c) const
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 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     return
1560     + hb_enumerate (ruleSet)
1561     | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
1562 	      { return class_def.intersects_class (glyphs, p.first) &&
1563 		       (this+p.second).intersects (glyphs, lookup_context); })
1564     | hb_any
1565     ;
1566   }
1567 
closureOT::ContextFormat21568   void closure (hb_closure_context_t *c) const
1569   {
1570     if (!(this+coverage).intersects (c->glyphs))
1571       return;
1572 
1573     const ClassDef &class_def = this+classDef;
1574 
1575     struct ContextClosureLookupContext lookup_context = {
1576       {intersects_class},
1577       &class_def
1578     };
1579 
1580     return
1581     + hb_enumerate (ruleSet)
1582     | hb_filter ([&] (unsigned _)
1583 		 { return class_def.intersects_class (c->glyphs, _); },
1584 		 hb_first)
1585     | hb_map (hb_second)
1586     | hb_map (hb_add (this))
1587     | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
1588     ;
1589   }
1590 
collect_glyphsOT::ContextFormat21591   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1592   {
1593     (this+coverage).add_coverage (c->input);
1594 
1595     const ClassDef &class_def = this+classDef;
1596     struct ContextCollectGlyphsLookupContext lookup_context = {
1597       {collect_class},
1598       &class_def
1599     };
1600 
1601     + hb_iter (ruleSet)
1602     | hb_map (hb_add (this))
1603     | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
1604     ;
1605   }
1606 
would_applyOT::ContextFormat21607   bool would_apply (hb_would_apply_context_t *c) const
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 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     if (!(this+coverageZ[0]).intersects (c->glyphs))
1685       return;
1686 
1687     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1688     struct ContextClosureLookupContext lookup_context = {
1689       {intersects_coverage},
1690       this
1691     };
1692     context_closure_lookup (c,
1693 			    glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1694 			    lookupCount, lookupRecord,
1695 			    lookup_context);
1696   }
1697 
collect_glyphsOT::ContextFormat31698   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1699   {
1700     (this+coverageZ[0]).add_coverage (c->input);
1701 
1702     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1703     struct ContextCollectGlyphsLookupContext lookup_context = {
1704       {collect_coverage},
1705       this
1706     };
1707 
1708     context_collect_glyphs_lookup (c,
1709 				   glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1710 				   lookupCount, lookupRecord,
1711 				   lookup_context);
1712   }
1713 
would_applyOT::ContextFormat31714   bool would_apply (hb_would_apply_context_t *c) const
1715   {
1716     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1717     struct ContextApplyLookupContext lookup_context = {
1718       {match_coverage},
1719       this
1720     };
1721     return context_would_apply_lookup (c,
1722 				       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1723 				       lookupCount, lookupRecord,
1724 				       lookup_context);
1725   }
1726 
get_coverageOT::ContextFormat31727   const Coverage &get_coverage () const { return this+coverageZ[0]; }
1728 
applyOT::ContextFormat31729   bool apply (hb_ot_apply_context_t *c) const
1730   {
1731     TRACE_APPLY (this);
1732     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1733     if (likely (index == NOT_COVERED)) return_trace (false);
1734 
1735     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1736     struct ContextApplyLookupContext lookup_context = {
1737       {match_coverage},
1738       this
1739     };
1740     return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1741   }
1742 
subsetOT::ContextFormat31743   bool subset (hb_subset_context_t *c) const
1744   {
1745     TRACE_SUBSET (this);
1746     // TODO(subset)
1747     return_trace (false);
1748   }
1749 
sanitizeOT::ContextFormat31750   bool sanitize (hb_sanitize_context_t *c) const
1751   {
1752     TRACE_SANITIZE (this);
1753     if (!c->check_struct (this)) return_trace (false);
1754     unsigned int count = glyphCount;
1755     if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1756     if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
1757     for (unsigned int i = 0; i < count; i++)
1758       if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1759     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1760     return_trace (c->check_array (lookupRecord, lookupCount));
1761   }
1762 
1763   protected:
1764   HBUINT16	format;			/* Format identifier--format = 3 */
1765   HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
1766 					 * sequence */
1767   HBUINT16	lookupCount;		/* Number of LookupRecords */
1768   UnsizedArrayOf<OffsetTo<Coverage>>
1769 		coverageZ;		/* Array of offsets to Coverage
1770 					 * table in glyph sequence order */
1771 /*UnsizedArrayOf<LookupRecord>
1772 		lookupRecordX;*/	/* Array of LookupRecords--in
1773 					 * design order */
1774   public:
1775   DEFINE_SIZE_ARRAY (6, coverageZ);
1776 };
1777 
1778 struct Context
1779 {
1780   template <typename context_t, typename ...Ts>
dispatchOT::Context1781   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1782   {
1783     TRACE_DISPATCH (this, u.format);
1784     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1785     switch (u.format) {
1786     case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
1787     case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
1788     case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
1789     default:return_trace (c->default_return_value ());
1790     }
1791   }
1792 
1793   protected:
1794   union {
1795   HBUINT16		format;		/* Format identifier */
1796   ContextFormat1	format1;
1797   ContextFormat2	format2;
1798   ContextFormat3	format3;
1799   } u;
1800 };
1801 
1802 
1803 /* Chaining Contextual lookups */
1804 
1805 struct ChainContextClosureLookupContext
1806 {
1807   ContextClosureFuncs funcs;
1808   const void *intersects_data[3];
1809 };
1810 
1811 struct ChainContextCollectGlyphsLookupContext
1812 {
1813   ContextCollectGlyphsFuncs funcs;
1814   const void *collect_data[3];
1815 };
1816 
1817 struct ChainContextApplyLookupContext
1818 {
1819   ContextApplyFuncs funcs;
1820   const void *match_data[3];
1821 };
1822 
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)1823 static inline bool chain_context_intersects (const hb_set_t *glyphs,
1824 					     unsigned int backtrackCount,
1825 					     const HBUINT16 backtrack[],
1826 					     unsigned int inputCount, /* Including the first glyph (not matched) */
1827 					     const HBUINT16 input[], /* Array of input values--start with second glyph */
1828 					     unsigned int lookaheadCount,
1829 					     const HBUINT16 lookahead[],
1830 					     ChainContextClosureLookupContext &lookup_context)
1831 {
1832   return intersects_array (glyphs,
1833 			   backtrackCount, backtrack,
1834 			   lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1835       && intersects_array (glyphs,
1836 			   inputCount ? inputCount - 1 : 0, input,
1837 			   lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1838       && intersects_array (glyphs,
1839 			  lookaheadCount, lookahead,
1840 			  lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1841 }
1842 
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)1843 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1844 						 unsigned int backtrackCount,
1845 						 const HBUINT16 backtrack[],
1846 						 unsigned int inputCount, /* Including the first glyph (not matched) */
1847 						 const HBUINT16 input[], /* Array of input values--start with second glyph */
1848 						 unsigned int lookaheadCount,
1849 						 const HBUINT16 lookahead[],
1850 						 unsigned int lookupCount,
1851 						 const LookupRecord lookupRecord[],
1852 						 ChainContextClosureLookupContext &lookup_context)
1853 {
1854   if (chain_context_intersects (c->glyphs,
1855 				backtrackCount, backtrack,
1856 				inputCount, input,
1857 				lookaheadCount, lookahead,
1858 				lookup_context))
1859     recurse_lookups (c,
1860 		     lookupCount, lookupRecord);
1861 }
1862 
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)1863 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1864 							unsigned int backtrackCount,
1865 							const HBUINT16 backtrack[],
1866 							unsigned int inputCount, /* Including the first glyph (not matched) */
1867 							const HBUINT16 input[], /* Array of input values--start with second glyph */
1868 							unsigned int lookaheadCount,
1869 							const HBUINT16 lookahead[],
1870 							unsigned int lookupCount,
1871 							const LookupRecord lookupRecord[],
1872 							ChainContextCollectGlyphsLookupContext &lookup_context)
1873 {
1874   collect_array (c, c->before,
1875 		 backtrackCount, backtrack,
1876 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1877   collect_array (c, c->input,
1878 		 inputCount ? inputCount - 1 : 0, input,
1879 		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1880   collect_array (c, c->after,
1881 		 lookaheadCount, lookahead,
1882 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1883   recurse_lookups (c,
1884 		   lookupCount, lookupRecord);
1885 }
1886 
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)1887 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1888 						     unsigned int backtrackCount,
1889 						     const HBUINT16 backtrack[] HB_UNUSED,
1890 						     unsigned int inputCount, /* Including the first glyph (not matched) */
1891 						     const HBUINT16 input[], /* Array of input values--start with second glyph */
1892 						     unsigned int lookaheadCount,
1893 						     const HBUINT16 lookahead[] HB_UNUSED,
1894 						     unsigned int lookupCount HB_UNUSED,
1895 						     const LookupRecord lookupRecord[] HB_UNUSED,
1896 						     ChainContextApplyLookupContext &lookup_context)
1897 {
1898   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1899       && would_match_input (c,
1900 			    inputCount, input,
1901 			    lookup_context.funcs.match, lookup_context.match_data[1]);
1902 }
1903 
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)1904 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1905 					       unsigned int backtrackCount,
1906 					       const HBUINT16 backtrack[],
1907 					       unsigned int inputCount, /* Including the first glyph (not matched) */
1908 					       const HBUINT16 input[], /* Array of input values--start with second glyph */
1909 					       unsigned int lookaheadCount,
1910 					       const HBUINT16 lookahead[],
1911 					       unsigned int lookupCount,
1912 					       const LookupRecord lookupRecord[],
1913 					       ChainContextApplyLookupContext &lookup_context)
1914 {
1915   unsigned int start_index = 0, match_length = 0, end_index = 0;
1916   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1917   return match_input (c,
1918 		      inputCount, input,
1919 		      lookup_context.funcs.match, lookup_context.match_data[1],
1920 		      &match_length, match_positions)
1921       && match_backtrack (c,
1922 			  backtrackCount, backtrack,
1923 			  lookup_context.funcs.match, lookup_context.match_data[0],
1924 			  &start_index)
1925       && match_lookahead (c,
1926 			  lookaheadCount, lookahead,
1927 			  lookup_context.funcs.match, lookup_context.match_data[2],
1928 			  match_length, &end_index)
1929       && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1930 	  apply_lookup (c,
1931 			inputCount, match_positions,
1932 			lookupCount, lookupRecord,
1933 			match_length));
1934 }
1935 
1936 struct ChainRule
1937 {
intersectsOT::ChainRule1938   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1939   {
1940     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1941     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1942     return chain_context_intersects (glyphs,
1943 				     backtrack.len, backtrack.arrayZ,
1944 				     input.lenP1, input.arrayZ,
1945 				     lookahead.len, lookahead.arrayZ,
1946 				     lookup_context);
1947   }
1948 
closureOT::ChainRule1949   void closure (hb_closure_context_t *c,
1950 		ChainContextClosureLookupContext &lookup_context) const
1951   {
1952     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1953     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1954     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1955     chain_context_closure_lookup (c,
1956 				  backtrack.len, backtrack.arrayZ,
1957 				  input.lenP1, input.arrayZ,
1958 				  lookahead.len, lookahead.arrayZ,
1959 				  lookup.len, lookup.arrayZ,
1960 				  lookup_context);
1961   }
1962 
collect_glyphsOT::ChainRule1963   void collect_glyphs (hb_collect_glyphs_context_t *c,
1964 		       ChainContextCollectGlyphsLookupContext &lookup_context) const
1965   {
1966     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1967     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1968     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1969     chain_context_collect_glyphs_lookup (c,
1970 					 backtrack.len, backtrack.arrayZ,
1971 					 input.lenP1, input.arrayZ,
1972 					 lookahead.len, lookahead.arrayZ,
1973 					 lookup.len, lookup.arrayZ,
1974 					 lookup_context);
1975   }
1976 
would_applyOT::ChainRule1977   bool would_apply (hb_would_apply_context_t *c,
1978 		    ChainContextApplyLookupContext &lookup_context) const
1979   {
1980     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1981     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1982     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1983     return chain_context_would_apply_lookup (c,
1984 					     backtrack.len, backtrack.arrayZ,
1985 					     input.lenP1, input.arrayZ,
1986 					     lookahead.len, lookahead.arrayZ, lookup.len,
1987 					     lookup.arrayZ, lookup_context);
1988   }
1989 
applyOT::ChainRule1990   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1991   {
1992     TRACE_APPLY (this);
1993     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1994     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1995     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1996     return_trace (chain_context_apply_lookup (c,
1997 					      backtrack.len, backtrack.arrayZ,
1998 					      input.lenP1, input.arrayZ,
1999 					      lookahead.len, lookahead.arrayZ, lookup.len,
2000 					      lookup.arrayZ, lookup_context));
2001   }
2002 
2003   template<typename Iterator,
2004 	   hb_requires (hb_is_iterator (Iterator))>
serialize_arrayOT::ChainRule2005   void serialize_array (hb_serialize_context_t *c,
2006                         HBUINT16 len,
2007                         Iterator it) const
2008   {
2009     c->copy (len);
2010     for (const auto g : it)
2011     {
2012       HBUINT16 gid;
2013       gid = g;
2014       c->copy (gid);
2015     }
2016   }
2017 
copyOT::ChainRule2018   ChainRule* copy (hb_serialize_context_t *c,
2019 		   const hb_map_t *backtrack_map,
2020 		   const hb_map_t *input_map = nullptr,
2021 		   const hb_map_t *lookahead_map = nullptr) const
2022   {
2023     TRACE_SERIALIZE (this);
2024     auto *out = c->start_embed (this);
2025     if (unlikely (!out)) return_trace (nullptr);
2026 
2027     const hb_map_t *mapping = backtrack_map;
2028     serialize_array (c, backtrack.len, + backtrack.iter ()
2029 				       | hb_map (mapping));
2030 
2031     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2032     if (input_map) mapping = input_map;
2033     serialize_array (c, input.lenP1, + input.iter ()
2034 				     | hb_map (mapping));
2035 
2036     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2037     if (lookahead_map) mapping = lookahead_map;
2038     serialize_array (c, lookahead.len, + lookahead.iter ()
2039 				       | hb_map (mapping));
2040 
2041     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2042     c->copy (lookup);
2043 
2044     return_trace (out);
2045   }
2046 
subsetOT::ChainRule2047   bool subset (hb_subset_context_t *c,
2048                const hb_map_t *backtrack_map = nullptr,
2049                const hb_map_t *input_map = nullptr,
2050                const hb_map_t *lookahead_map = nullptr) const
2051   {
2052     TRACE_SUBSET (this);
2053 
2054     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2055     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2056 
2057     if (!backtrack_map)
2058     {
2059       const hb_set_t &glyphset = *c->plan->glyphset ();
2060       if (!hb_all (backtrack, glyphset) ||
2061           !hb_all (input, glyphset) ||
2062           !hb_all (lookahead, glyphset))
2063         return_trace (false);
2064 
2065       copy (c->serializer, c->plan->glyph_map);
2066     }
2067     else
2068     {
2069       if (!hb_all (backtrack, backtrack_map) ||
2070           !hb_all (input, input_map) ||
2071           !hb_all (lookahead, lookahead_map))
2072         return_trace (false);
2073 
2074       copy (c->serializer, backtrack_map, input_map, lookahead_map);
2075     }
2076 
2077     return_trace (true);
2078   }
2079 
sanitizeOT::ChainRule2080   bool sanitize (hb_sanitize_context_t *c) const
2081   {
2082     TRACE_SANITIZE (this);
2083     if (!backtrack.sanitize (c)) return_trace (false);
2084     const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2085     if (!input.sanitize (c)) return_trace (false);
2086     const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2087     if (!lookahead.sanitize (c)) return_trace (false);
2088     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2089     return_trace (lookup.sanitize (c));
2090   }
2091 
2092   protected:
2093   ArrayOf<HBUINT16>
2094 		backtrack;		/* Array of backtracking values
2095 					 * (to be matched before the input
2096 					 * sequence) */
2097   HeadlessArrayOf<HBUINT16>
2098 		inputX;			/* Array of input values (start with
2099 					 * second glyph) */
2100   ArrayOf<HBUINT16>
2101 		lookaheadX;		/* Array of lookahead values's (to be
2102 					 * matched after the input sequence) */
2103   ArrayOf<LookupRecord>
2104 		lookupX;		/* Array of LookupRecords--in
2105 					 * design order) */
2106   public:
2107   DEFINE_SIZE_MIN (8);
2108 };
2109 
2110 struct ChainRuleSet
2111 {
intersectsOT::ChainRuleSet2112   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
2113   {
2114     return
2115     + hb_iter (rule)
2116     | hb_map (hb_add (this))
2117     | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
2118     | hb_any
2119     ;
2120   }
closureOT::ChainRuleSet2121   void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2122   {
2123     return
2124     + hb_iter (rule)
2125     | hb_map (hb_add (this))
2126     | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
2127     ;
2128   }
2129 
collect_glyphsOT::ChainRuleSet2130   void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
2131   {
2132     return
2133     + hb_iter (rule)
2134     | hb_map (hb_add (this))
2135     | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
2136     ;
2137   }
2138 
would_applyOT::ChainRuleSet2139   bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2140   {
2141     return
2142     + hb_iter (rule)
2143     | hb_map (hb_add (this))
2144     | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
2145     | hb_any
2146     ;
2147   }
2148 
applyOT::ChainRuleSet2149   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2150   {
2151     TRACE_APPLY (this);
2152     return_trace (
2153     + hb_iter (rule)
2154     | hb_map (hb_add (this))
2155     | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
2156     | hb_any
2157     )
2158     ;
2159   }
2160 
subsetOT::ChainRuleSet2161   bool subset (hb_subset_context_t *c,
2162                const hb_map_t *backtrack_klass_map = nullptr,
2163                const hb_map_t *input_klass_map = nullptr,
2164                const hb_map_t *lookahead_klass_map = nullptr) const
2165   {
2166     TRACE_SUBSET (this);
2167 
2168     auto snap = c->serializer->snapshot ();
2169     auto *out = c->serializer->start_embed (*this);
2170     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2171 
2172     for (const OffsetTo<ChainRule>& _ : rule)
2173     {
2174       if (!_) continue;
2175       auto *o = out->rule.serialize_append (c->serializer);
2176       if (unlikely (!o)) continue;
2177 
2178       auto o_snap = c->serializer->snapshot ();
2179       if (!o->serialize_subset (c, _, this, out,
2180                                 backtrack_klass_map,
2181                                 input_klass_map,
2182                                 lookahead_klass_map))
2183       {
2184         out->rule.pop ();
2185         c->serializer->revert (o_snap);
2186       }
2187     }
2188 
2189     bool ret = bool (out->rule);
2190     if (!ret) c->serializer->revert (snap);
2191 
2192     return_trace (ret);
2193   }
2194 
sanitizeOT::ChainRuleSet2195   bool sanitize (hb_sanitize_context_t *c) const
2196   {
2197     TRACE_SANITIZE (this);
2198     return_trace (rule.sanitize (c, this));
2199   }
2200 
2201   protected:
2202   OffsetArrayOf<ChainRule>
2203 		rule;			/* Array of ChainRule tables
2204 					 * ordered by preference */
2205   public:
2206   DEFINE_SIZE_ARRAY (2, rule);
2207 };
2208 
2209 struct ChainContextFormat1
2210 {
intersectsOT::ChainContextFormat12211   bool intersects (const hb_set_t *glyphs) const
2212   {
2213     struct ChainContextClosureLookupContext lookup_context = {
2214       {intersects_glyph},
2215       {nullptr, nullptr, nullptr}
2216     };
2217 
2218     return
2219     + hb_zip (this+coverage, ruleSet)
2220     | hb_filter (*glyphs, hb_first)
2221     | hb_map (hb_second)
2222     | hb_map (hb_add (this))
2223     | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
2224     | hb_any
2225     ;
2226   }
2227 
closureOT::ChainContextFormat12228   void closure (hb_closure_context_t *c) const
2229   {
2230     struct ChainContextClosureLookupContext lookup_context = {
2231       {intersects_glyph},
2232       {nullptr, nullptr, nullptr}
2233     };
2234 
2235     + hb_zip (this+coverage, ruleSet)
2236     | hb_filter (*c->glyphs, hb_first)
2237     | hb_map (hb_second)
2238     | hb_map (hb_add (this))
2239     | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
2240     ;
2241   }
2242 
collect_glyphsOT::ChainContextFormat12243   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2244   {
2245     (this+coverage).add_coverage (c->input);
2246 
2247     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2248       {collect_glyph},
2249       {nullptr, nullptr, nullptr}
2250     };
2251 
2252     + hb_iter (ruleSet)
2253     | hb_map (hb_add (this))
2254     | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
2255     ;
2256   }
2257 
would_applyOT::ChainContextFormat12258   bool would_apply (hb_would_apply_context_t *c) const
2259   {
2260     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2261     struct ChainContextApplyLookupContext lookup_context = {
2262       {match_glyph},
2263       {nullptr, nullptr, nullptr}
2264     };
2265     return rule_set.would_apply (c, lookup_context);
2266   }
2267 
get_coverageOT::ChainContextFormat12268   const Coverage &get_coverage () const { return this+coverage; }
2269 
applyOT::ChainContextFormat12270   bool apply (hb_ot_apply_context_t *c) const
2271   {
2272     TRACE_APPLY (this);
2273     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2274     if (likely (index == NOT_COVERED)) return_trace (false);
2275 
2276     const ChainRuleSet &rule_set = this+ruleSet[index];
2277     struct ChainContextApplyLookupContext lookup_context = {
2278       {match_glyph},
2279       {nullptr, nullptr, nullptr}
2280     };
2281     return_trace (rule_set.apply (c, lookup_context));
2282   }
2283 
subsetOT::ChainContextFormat12284   bool subset (hb_subset_context_t *c) const
2285   {
2286     TRACE_SUBSET (this);
2287     const hb_set_t &glyphset = *c->plan->glyphset ();
2288     const hb_map_t &glyph_map = *c->plan->glyph_map;
2289 
2290     auto *out = c->serializer->start_embed (*this);
2291     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2292     out->format = format;
2293 
2294     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2295     + hb_zip (this+coverage, ruleSet)
2296     | hb_filter (glyphset, hb_first)
2297     | hb_filter (subset_offset_array (c, out->ruleSet, this, out), hb_second)
2298     | hb_map (hb_first)
2299     | hb_map (glyph_map)
2300     | hb_sink (new_coverage)
2301     ;
2302 
2303     out->coverage.serialize (c->serializer, out)
2304 		 .serialize (c->serializer, new_coverage.iter ());
2305     return_trace (bool (new_coverage));
2306   }
2307 
sanitizeOT::ChainContextFormat12308   bool sanitize (hb_sanitize_context_t *c) const
2309   {
2310     TRACE_SANITIZE (this);
2311     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2312   }
2313 
2314   protected:
2315   HBUINT16	format;			/* Format identifier--format = 1 */
2316   OffsetTo<Coverage>
2317 		coverage;		/* Offset to Coverage table--from
2318 					 * beginning of table */
2319   OffsetArrayOf<ChainRuleSet>
2320 		ruleSet;		/* Array of ChainRuleSet tables
2321 					 * ordered by Coverage Index */
2322   public:
2323   DEFINE_SIZE_ARRAY (6, ruleSet);
2324 };
2325 
2326 struct ChainContextFormat2
2327 {
intersectsOT::ChainContextFormat22328   bool intersects (const hb_set_t *glyphs) const
2329   {
2330     if (!(this+coverage).intersects (glyphs))
2331       return false;
2332 
2333     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2334     const ClassDef &input_class_def = this+inputClassDef;
2335     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2336 
2337     struct ChainContextClosureLookupContext lookup_context = {
2338       {intersects_class},
2339       {&backtrack_class_def,
2340        &input_class_def,
2341        &lookahead_class_def}
2342     };
2343 
2344     return
2345     + hb_enumerate (ruleSet)
2346     | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
2347 	      { return input_class_def.intersects_class (glyphs, p.first) &&
2348 		       (this+p.second).intersects (glyphs, lookup_context); })
2349     | hb_any
2350     ;
2351   }
closureOT::ChainContextFormat22352   void closure (hb_closure_context_t *c) const
2353   {
2354     if (!(this+coverage).intersects (c->glyphs))
2355       return;
2356 
2357     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2358     const ClassDef &input_class_def = this+inputClassDef;
2359     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2360 
2361     struct ChainContextClosureLookupContext lookup_context = {
2362       {intersects_class},
2363       {&backtrack_class_def,
2364        &input_class_def,
2365        &lookahead_class_def}
2366     };
2367 
2368     return
2369     + hb_enumerate (ruleSet)
2370     | hb_filter ([&] (unsigned _)
2371 		 { return input_class_def.intersects_class (c->glyphs, _); },
2372 		 hb_first)
2373     | hb_map (hb_second)
2374     | hb_map (hb_add (this))
2375     | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
2376     ;
2377   }
2378 
collect_glyphsOT::ChainContextFormat22379   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2380   {
2381     (this+coverage).add_coverage (c->input);
2382 
2383     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2384     const ClassDef &input_class_def = this+inputClassDef;
2385     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2386 
2387     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2388       {collect_class},
2389       {&backtrack_class_def,
2390        &input_class_def,
2391        &lookahead_class_def}
2392     };
2393 
2394     + hb_iter (ruleSet)
2395     | hb_map (hb_add (this))
2396     | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
2397     ;
2398   }
2399 
would_applyOT::ChainContextFormat22400   bool would_apply (hb_would_apply_context_t *c) const
2401   {
2402     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2403     const ClassDef &input_class_def = this+inputClassDef;
2404     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2405 
2406     unsigned int index = input_class_def.get_class (c->glyphs[0]);
2407     const ChainRuleSet &rule_set = this+ruleSet[index];
2408     struct ChainContextApplyLookupContext lookup_context = {
2409       {match_class},
2410       {&backtrack_class_def,
2411        &input_class_def,
2412        &lookahead_class_def}
2413     };
2414     return rule_set.would_apply (c, lookup_context);
2415   }
2416 
get_coverageOT::ChainContextFormat22417   const Coverage &get_coverage () const { return this+coverage; }
2418 
applyOT::ChainContextFormat22419   bool apply (hb_ot_apply_context_t *c) const
2420   {
2421     TRACE_APPLY (this);
2422     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2423     if (likely (index == NOT_COVERED)) return_trace (false);
2424 
2425     const ClassDef &backtrack_class_def = this+backtrackClassDef;
2426     const ClassDef &input_class_def = this+inputClassDef;
2427     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2428 
2429     index = input_class_def.get_class (c->buffer->cur().codepoint);
2430     const ChainRuleSet &rule_set = this+ruleSet[index];
2431     struct ChainContextApplyLookupContext lookup_context = {
2432       {match_class},
2433       {&backtrack_class_def,
2434        &input_class_def,
2435        &lookahead_class_def}
2436     };
2437     return_trace (rule_set.apply (c, lookup_context));
2438   }
2439 
subsetOT::ChainContextFormat22440   bool subset (hb_subset_context_t *c) const
2441   {
2442     TRACE_SUBSET (this);
2443     auto *out = c->serializer->start_embed (*this);
2444     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2445     out->format = format;
2446     out->coverage.serialize_subset (c, coverage, this, out);
2447 
2448     hb_map_t backtrack_klass_map;
2449     out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, out, &backtrack_klass_map);
2450 
2451     // subset inputClassDef based on glyphs survived in Coverage subsetting
2452     hb_map_t input_klass_map;
2453     out->inputClassDef.serialize_subset (c, inputClassDef, this, out, &input_klass_map);
2454 
2455     hb_map_t lookahead_klass_map;
2456     out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, out, &lookahead_klass_map);
2457 
2458     hb_vector_t<unsigned> rulesets;
2459     bool ret = true;
2460     for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
2461 					   | hb_filter (input_klass_map, hb_first)
2462 					   | hb_map (hb_second))
2463     {
2464       auto *o = out->ruleSet.serialize_append (c->serializer);
2465       if (unlikely (!o))
2466       {
2467         ret = false;
2468         break;
2469       }
2470       if (!o->serialize_subset (c, _, this, out,
2471                                 &backtrack_klass_map,
2472                                 &input_klass_map,
2473                                 &lookahead_klass_map))
2474       {
2475         rulesets.push (0);
2476       }
2477       else rulesets.push (1);
2478     }
2479 
2480     if (!ret) return_trace (ret);
2481 
2482     //prune empty trailing ruleSets
2483     unsigned count = rulesets.length;
2484     while (count > 0 && rulesets[count-1] == 0)
2485     {
2486       out->ruleSet.pop ();
2487       count--;
2488     }
2489 
2490     return_trace (bool (out->ruleSet));
2491   }
2492 
sanitizeOT::ChainContextFormat22493   bool sanitize (hb_sanitize_context_t *c) const
2494   {
2495     TRACE_SANITIZE (this);
2496     return_trace (coverage.sanitize (c, this) &&
2497 		  backtrackClassDef.sanitize (c, this) &&
2498 		  inputClassDef.sanitize (c, this) &&
2499 		  lookaheadClassDef.sanitize (c, this) &&
2500 		  ruleSet.sanitize (c, this));
2501   }
2502 
2503   protected:
2504   HBUINT16	format;			/* Format identifier--format = 2 */
2505   OffsetTo<Coverage>
2506 		coverage;		/* Offset to Coverage table--from
2507 					 * beginning of table */
2508   OffsetTo<ClassDef>
2509 		backtrackClassDef;	/* Offset to glyph ClassDef table
2510 					 * containing backtrack sequence
2511 					 * data--from beginning of table */
2512   OffsetTo<ClassDef>
2513 		inputClassDef;		/* Offset to glyph ClassDef
2514 					 * table containing input sequence
2515 					 * data--from beginning of table */
2516   OffsetTo<ClassDef>
2517 		lookaheadClassDef;	/* Offset to glyph ClassDef table
2518 					 * containing lookahead sequence
2519 					 * data--from beginning of table */
2520   OffsetArrayOf<ChainRuleSet>
2521 		ruleSet;		/* Array of ChainRuleSet tables
2522 					 * ordered by class */
2523   public:
2524   DEFINE_SIZE_ARRAY (12, ruleSet);
2525 };
2526 
2527 struct ChainContextFormat3
2528 {
intersectsOT::ChainContextFormat32529   bool intersects (const hb_set_t *glyphs) const
2530   {
2531     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2532 
2533     if (!(this+input[0]).intersects (glyphs))
2534       return false;
2535 
2536     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2537     struct ChainContextClosureLookupContext lookup_context = {
2538       {intersects_coverage},
2539       {this, this, this}
2540     };
2541     return chain_context_intersects (glyphs,
2542 				     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2543 				     input.len, (const HBUINT16 *) input.arrayZ + 1,
2544 				     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2545 				     lookup_context);
2546   }
2547 
closureOT::ChainContextFormat32548   void closure (hb_closure_context_t *c) const
2549   {
2550     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2551 
2552     if (!(this+input[0]).intersects (c->glyphs))
2553       return;
2554 
2555     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2556     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2557     struct ChainContextClosureLookupContext lookup_context = {
2558       {intersects_coverage},
2559       {this, this, this}
2560     };
2561     chain_context_closure_lookup (c,
2562 				  backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2563 				  input.len, (const HBUINT16 *) input.arrayZ + 1,
2564 				  lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2565 				  lookup.len, lookup.arrayZ,
2566 				  lookup_context);
2567   }
2568 
collect_glyphsOT::ChainContextFormat32569   void collect_glyphs (hb_collect_glyphs_context_t *c) const
2570   {
2571     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2572 
2573     (this+input[0]).add_coverage (c->input);
2574 
2575     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2576     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2577     struct ChainContextCollectGlyphsLookupContext lookup_context = {
2578       {collect_coverage},
2579       {this, this, this}
2580     };
2581     chain_context_collect_glyphs_lookup (c,
2582 					 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2583 					 input.len, (const HBUINT16 *) input.arrayZ + 1,
2584 					 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2585 					 lookup.len, lookup.arrayZ,
2586 					 lookup_context);
2587   }
2588 
would_applyOT::ChainContextFormat32589   bool would_apply (hb_would_apply_context_t *c) const
2590   {
2591     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2592     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2593     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2594     struct ChainContextApplyLookupContext lookup_context = {
2595       {match_coverage},
2596       {this, this, this}
2597     };
2598     return chain_context_would_apply_lookup (c,
2599 					     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2600 					     input.len, (const HBUINT16 *) input.arrayZ + 1,
2601 					     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2602 					     lookup.len, lookup.arrayZ, lookup_context);
2603   }
2604 
get_coverageOT::ChainContextFormat32605   const Coverage &get_coverage () const
2606   {
2607     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2608     return this+input[0];
2609   }
2610 
applyOT::ChainContextFormat32611   bool apply (hb_ot_apply_context_t *c) const
2612   {
2613     TRACE_APPLY (this);
2614     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2615 
2616     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2617     if (likely (index == NOT_COVERED)) return_trace (false);
2618 
2619     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2620     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2621     struct ChainContextApplyLookupContext lookup_context = {
2622       {match_coverage},
2623       {this, this, this}
2624     };
2625     return_trace (chain_context_apply_lookup (c,
2626 					      backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2627 					      input.len, (const HBUINT16 *) input.arrayZ + 1,
2628 					      lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2629 					      lookup.len, lookup.arrayZ, lookup_context));
2630   }
2631 
2632   template<typename Iterator,
2633 	   hb_requires (hb_is_iterator (Iterator))>
serialize_coverage_offsetsOT::ChainContextFormat32634   bool serialize_coverage_offsets (hb_subset_context_t *c,
2635                                    Iterator it,
2636 				   const void* src_base,
2637 				   const void* dst_base) const
2638   {
2639     TRACE_SERIALIZE (this);
2640     auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
2641 
2642     if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
2643 
2644     + it
2645     | hb_apply (subset_offset_array (c, *out, src_base, dst_base))
2646     ;
2647 
2648     return_trace (out->len);
2649   }
2650 
subsetOT::ChainContextFormat32651   bool subset (hb_subset_context_t *c) const
2652   {
2653     TRACE_SUBSET (this);
2654 
2655     auto *out = c->serializer->start_embed (this);
2656     if (unlikely (!out)) return_trace (false);
2657     if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
2658 
2659     if (!serialize_coverage_offsets (c, backtrack.iter (), this, out))
2660       return_trace (false);
2661 
2662     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2663     if (!serialize_coverage_offsets (c, input.iter (), this, out))
2664       return_trace (false);
2665 
2666     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2667     if (!serialize_coverage_offsets (c, lookahead.iter (), this, out))
2668       return_trace (false);
2669 
2670     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2671     return_trace (c->serializer->copy (lookup));
2672   }
2673 
sanitizeOT::ChainContextFormat32674   bool sanitize (hb_sanitize_context_t *c) const
2675   {
2676     TRACE_SANITIZE (this);
2677     if (!backtrack.sanitize (c, this)) return_trace (false);
2678     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2679     if (!input.sanitize (c, this)) return_trace (false);
2680     if (!input.len) return_trace (false); /* To be consistent with Context. */
2681     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2682     if (!lookahead.sanitize (c, this)) return_trace (false);
2683     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2684     return_trace (lookup.sanitize (c));
2685   }
2686 
2687   protected:
2688   HBUINT16	format;			/* Format identifier--format = 3 */
2689   OffsetArrayOf<Coverage>
2690 		backtrack;		/* Array of coverage tables
2691 					 * in backtracking sequence, in  glyph
2692 					 * sequence order */
2693   OffsetArrayOf<Coverage>
2694 		inputX		;	/* Array of coverage
2695 					 * tables in input sequence, in glyph
2696 					 * sequence order */
2697   OffsetArrayOf<Coverage>
2698 		lookaheadX;		/* Array of coverage tables
2699 					 * in lookahead sequence, in glyph
2700 					 * sequence order */
2701   ArrayOf<LookupRecord>
2702 		lookupX;		/* Array of LookupRecords--in
2703 					 * design order) */
2704   public:
2705   DEFINE_SIZE_MIN (10);
2706 };
2707 
2708 struct ChainContext
2709 {
2710   template <typename context_t, typename ...Ts>
dispatchOT::ChainContext2711   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2712   {
2713     TRACE_DISPATCH (this, u.format);
2714     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2715     switch (u.format) {
2716     case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
2717     case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
2718     case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
2719     default:return_trace (c->default_return_value ());
2720     }
2721   }
2722 
2723   protected:
2724   union {
2725   HBUINT16		format;	/* Format identifier */
2726   ChainContextFormat1	format1;
2727   ChainContextFormat2	format2;
2728   ChainContextFormat3	format3;
2729   } u;
2730 };
2731 
2732 
2733 template <typename T>
2734 struct ExtensionFormat1
2735 {
get_typeOT::ExtensionFormat12736   unsigned int get_type () const { return extensionLookupType; }
2737 
2738   template <typename X>
get_subtableOT::ExtensionFormat12739   const X& get_subtable () const
2740   { return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
2741 
2742   template <typename context_t, typename ...Ts>
dispatchOT::ExtensionFormat12743   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2744   {
2745     TRACE_DISPATCH (this, format);
2746     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2747     return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
2748   }
2749 
2750   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
sanitizeOT::ExtensionFormat12751   bool sanitize (hb_sanitize_context_t *c) const
2752   {
2753     TRACE_SANITIZE (this);
2754     return_trace (c->check_struct (this) &&
2755 		  extensionLookupType != T::SubTable::Extension);
2756   }
2757 
2758   protected:
2759   HBUINT16	format;			/* Format identifier. Set to 1. */
2760   HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
2761 					 * by ExtensionOffset (i.e. the
2762 					 * extension subtable). */
2763   Offset32	extensionOffset;	/* Offset to the extension subtable,
2764 					 * of lookup type subtable. */
2765   public:
2766   DEFINE_SIZE_STATIC (8);
2767 };
2768 
2769 template <typename T>
2770 struct Extension
2771 {
get_typeOT::Extension2772   unsigned int get_type () const
2773   {
2774     switch (u.format) {
2775     case 1: return u.format1.get_type ();
2776     default:return 0;
2777     }
2778   }
2779   template <typename X>
get_subtableOT::Extension2780   const X& get_subtable () const
2781   {
2782     switch (u.format) {
2783     case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2784     default:return Null(typename T::SubTable);
2785     }
2786   }
2787 
2788   template <typename context_t, typename ...Ts>
dispatchOT::Extension2789   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2790   {
2791     TRACE_DISPATCH (this, u.format);
2792     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2793     switch (u.format) {
2794     case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
2795     default:return_trace (c->default_return_value ());
2796     }
2797   }
2798 
2799   protected:
2800   union {
2801   HBUINT16		format;		/* Format identifier */
2802   ExtensionFormat1<T>	format1;
2803   } u;
2804 };
2805 
2806 
2807 /*
2808  * GSUB/GPOS Common
2809  */
2810 
2811 struct hb_ot_layout_lookup_accelerator_t
2812 {
2813   template <typename TLookup>
initOT::hb_ot_layout_lookup_accelerator_t2814   void init (const TLookup &lookup)
2815   {
2816     digest.init ();
2817     lookup.add_coverage (&digest);
2818 
2819     subtables.init ();
2820     OT::hb_get_subtables_context_t c_get_subtables (subtables);
2821     lookup.dispatch (&c_get_subtables);
2822   }
finiOT::hb_ot_layout_lookup_accelerator_t2823   void fini () { subtables.fini (); }
2824 
may_haveOT::hb_ot_layout_lookup_accelerator_t2825   bool may_have (hb_codepoint_t g) const
2826   { return digest.may_have (g); }
2827 
applyOT::hb_ot_layout_lookup_accelerator_t2828   bool apply (hb_ot_apply_context_t *c) const
2829   {
2830     for (unsigned int i = 0; i < subtables.length; i++)
2831       if (subtables[i].apply (c))
2832 	return true;
2833     return false;
2834   }
2835 
2836   private:
2837   hb_set_digest_t digest;
2838   hb_get_subtables_context_t::array_t subtables;
2839 };
2840 
2841 struct GSUBGPOS
2842 {
has_dataOT::GSUBGPOS2843   bool has_data () const { return version.to_int (); }
get_script_countOT::GSUBGPOS2844   unsigned int get_script_count () const
2845   { return (this+scriptList).len; }
get_script_tagOT::GSUBGPOS2846   const Tag& get_script_tag (unsigned int i) const
2847   { return (this+scriptList).get_tag (i); }
get_script_tagsOT::GSUBGPOS2848   unsigned int get_script_tags (unsigned int start_offset,
2849 				unsigned int *script_count /* IN/OUT */,
2850 				hb_tag_t     *script_tags /* OUT */) const
2851   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
get_scriptOT::GSUBGPOS2852   const Script& get_script (unsigned int i) const
2853   { return (this+scriptList)[i]; }
find_script_indexOT::GSUBGPOS2854   bool find_script_index (hb_tag_t tag, unsigned int *index) const
2855   { return (this+scriptList).find_index (tag, index); }
2856 
get_feature_countOT::GSUBGPOS2857   unsigned int get_feature_count () const
2858   { return (this+featureList).len; }
get_feature_tagOT::GSUBGPOS2859   hb_tag_t get_feature_tag (unsigned int i) const
2860   { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
get_feature_tagsOT::GSUBGPOS2861   unsigned int get_feature_tags (unsigned int start_offset,
2862 				 unsigned int *feature_count /* IN/OUT */,
2863 				 hb_tag_t     *feature_tags /* OUT */) const
2864   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
get_featureOT::GSUBGPOS2865   const Feature& get_feature (unsigned int i) const
2866   { return (this+featureList)[i]; }
find_feature_indexOT::GSUBGPOS2867   bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2868   { return (this+featureList).find_index (tag, index); }
2869 
get_lookup_countOT::GSUBGPOS2870   unsigned int get_lookup_count () const
2871   { return (this+lookupList).len; }
get_lookupOT::GSUBGPOS2872   const Lookup& get_lookup (unsigned int i) const
2873   { return (this+lookupList)[i]; }
2874 
find_variations_indexOT::GSUBGPOS2875   bool find_variations_index (const int *coords, unsigned int num_coords,
2876 			      unsigned int *index) const
2877   {
2878 #ifdef HB_NOVAR
2879     return false;
2880 #endif
2881     return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2882 	    .find_index (coords, num_coords, index);
2883   }
get_feature_variationOT::GSUBGPOS2884   const Feature& get_feature_variation (unsigned int feature_index,
2885 					unsigned int variations_index) const
2886   {
2887 #ifndef HB_NO_VAR
2888     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2889 	version.to_int () >= 0x00010001u)
2890     {
2891       const Feature *feature = (this+featureVars).find_substitute (variations_index,
2892 								   feature_index);
2893       if (feature)
2894 	return *feature;
2895     }
2896 #endif
2897     return get_feature (feature_index);
2898   }
2899 
2900   template <typename TLookup>
subsetOT::GSUBGPOS2901   bool subset (hb_subset_context_t *c) const
2902   {
2903     TRACE_SUBSET (this);
2904     auto *out = c->serializer->embed (*this);
2905     if (unlikely (!out)) return_trace (false);
2906 
2907     out->scriptList.serialize_subset (c, scriptList, this, out);
2908     out->featureList.serialize_subset (c, featureList, this, out);
2909 
2910     typedef OffsetListOf<TLookup> TLookupList;
2911     /* TODO Use intersects() to count how many subtables survive? */
2912     CastR<OffsetTo<TLookupList>> (out->lookupList)
2913       .serialize_subset (c,
2914 			 CastR<OffsetTo<TLookupList>> (lookupList),
2915 			 this,
2916 			 out);
2917 
2918 #ifndef HB_NO_VAR
2919     if (version.to_int () >= 0x00010001u)
2920      out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
2921 #endif
2922 
2923     return_trace (true);
2924   }
2925 
get_sizeOT::GSUBGPOS2926   unsigned int get_size () const
2927   {
2928     return min_size +
2929 	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2930   }
2931 
2932   template <typename TLookup>
sanitizeOT::GSUBGPOS2933   bool sanitize (hb_sanitize_context_t *c) const
2934   {
2935     TRACE_SANITIZE (this);
2936     typedef OffsetListOf<TLookup> TLookupList;
2937     if (unlikely (!(version.sanitize (c) &&
2938 		    likely (version.major == 1) &&
2939 		    scriptList.sanitize (c, this) &&
2940 		    featureList.sanitize (c, this) &&
2941 		    CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this))))
2942       return_trace (false);
2943 
2944 #ifndef HB_NO_VAR
2945     if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
2946       return_trace (false);
2947 #endif
2948 
2949     return_trace (true);
2950   }
2951 
2952   template <typename T>
2953   struct accelerator_t
2954   {
initOT::GSUBGPOS::accelerator_t2955     void init (hb_face_t *face)
2956     {
2957       this->table = hb_sanitize_context_t().reference_table<T> (face);
2958       if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
2959       {
2960 	hb_blob_destroy (this->table.get_blob ());
2961 	this->table = hb_blob_get_empty ();
2962       }
2963 
2964       this->lookup_count = table->get_lookup_count ();
2965 
2966       this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2967       if (unlikely (!this->accels))
2968 	this->lookup_count = 0;
2969 
2970       for (unsigned int i = 0; i < this->lookup_count; i++)
2971 	this->accels[i].init (table->get_lookup (i));
2972     }
2973 
finiOT::GSUBGPOS::accelerator_t2974     void fini ()
2975     {
2976       for (unsigned int i = 0; i < this->lookup_count; i++)
2977 	this->accels[i].fini ();
2978       free (this->accels);
2979       this->table.destroy ();
2980     }
2981 
2982     hb_blob_ptr_t<T> table;
2983     unsigned int lookup_count;
2984     hb_ot_layout_lookup_accelerator_t *accels;
2985   };
2986 
2987   protected:
2988   FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
2989 				 * to 0x00010000u */
2990   OffsetTo<ScriptList>
2991 		scriptList;  	/* ScriptList table */
2992   OffsetTo<FeatureList>
2993 		featureList; 	/* FeatureList table */
2994   OffsetTo<LookupList>
2995 		lookupList; 	/* LookupList table */
2996   LOffsetTo<FeatureVariations>
2997 		featureVars;	/* Offset to Feature Variations
2998 				   table--from beginning of table
2999 				 * (may be NULL).  Introduced
3000 				 * in version 0x00010001. */
3001   public:
3002   DEFINE_SIZE_MIN (10);
3003 };
3004 
3005 
3006 } /* namespace OT */
3007 
3008 
3009 #endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
3010