Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-gsub-table.hh
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010,2012,2013  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_GSUB_TABLE_HH
30 #define HB_OT_LAYOUT_GSUB_TABLE_HH
31
32 #include "hb-ot-layout-gsubgpos.hh"
33
34
35 namespace OT {
36
37
38 static inline void SingleSubst_serialize (hb_serialize_context_t *c,
39                                           hb_array_t<const GlyphID> glyphs,
40                                           hb_array_t<const GlyphID> substitutes);
41
42 struct SingleSubstFormat1
43 {
44   bool intersects (const hb_set_t *glyphs) const
45   { return (this+coverage).intersects (glyphs); }
46
47   void closure (hb_closure_context_t *c) const
48   {
49     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
50     {
51       /* TODO Switch to range-based API to work around malicious fonts.
52        * https://github.com/harfbuzz/harfbuzz/issues/363 */
53       hb_codepoint_t glyph_id = iter.get_glyph ();
54       if (c->glyphs->has (glyph_id))
55         c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
56     }
57   }
58
59   void collect_glyphs (hb_collect_glyphs_context_t *c) const
60   {
61     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
62     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
63     {
64       /* TODO Switch to range-based API to work around malicious fonts.
65        * https://github.com/harfbuzz/harfbuzz/issues/363 */
66       hb_codepoint_t glyph_id = iter.get_glyph ();
67       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
68     }
69   }
70
71   const Coverage &get_coverage () const { return this+coverage; }
72
73   bool would_apply (hb_would_apply_context_t *c) const
74   {
75     TRACE_WOULD_APPLY (this);
76     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
77   }
78
79   bool apply (hb_ot_apply_context_t *c) const
80   {
81     TRACE_APPLY (this);
82     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
83     unsigned int index = (this+coverage).get_coverage (glyph_id);
84     if (likely (index == NOT_COVERED)) return_trace (false);
85
86     /* According to the Adobe Annotated OpenType Suite, result is always
87      * limited to 16bit. */
88     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
89     c->replace_glyph (glyph_id);
90
91     return_trace (true);
92   }
93
94   bool serialize (hb_serialize_context_t *c,
95                   hb_array_t<const GlyphID> glyphs,
96                   int delta)
97   {
98     TRACE_SERIALIZE (this);
99     if (unlikely (!c->extend_min (*this))) return_trace (false);
100     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
101     deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
102     return_trace (true);
103   }
104
105   bool subset (hb_subset_context_t *c) const
106   {
107     TRACE_SUBSET (this);
108     const hb_set_t &glyphset = *c->plan->glyphset;
109     const hb_map_t &glyph_map = *c->plan->glyph_map;
110     hb_vector_t<GlyphID> from;
111     hb_vector_t<GlyphID> to;
112     hb_codepoint_t delta = deltaGlyphID;
113     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
114     {
115       if (!glyphset.has (iter.get_glyph ())) continue;
116       from.push ()->set (glyph_map[iter.get_glyph ()]);
117       to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
118     }
119     c->serializer->propagate_error (from, to);
120     SingleSubst_serialize (c->serializer, from, to);
121     return_trace (from.length);
122   }
123
124   bool sanitize (hb_sanitize_context_t *c) const
125   {
126     TRACE_SANITIZE (this);
127     return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
128   }
129
130   protected:
131   HBUINT16      format;                 /* Format identifier--format = 1 */
132   OffsetTo<Coverage>
133                 coverage;               /* Offset to Coverage table--from
134                                          * beginning of Substitution table */
135   HBINT16       deltaGlyphID;           /* Add to original GlyphID to get
136                                          * substitute GlyphID */
137   public:
138   DEFINE_SIZE_STATIC (6);
139 };
140
141 struct SingleSubstFormat2
142 {
143   bool intersects (const hb_set_t *glyphs) const
144   { return (this+coverage).intersects (glyphs); }
145
146   void closure (hb_closure_context_t *c) const
147   {
148     unsigned int count = substitute.len;
149     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
150     {
151       if (unlikely (iter.get_coverage () >= count))
152         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
153       if (c->glyphs->has (iter.get_glyph ()))
154         c->out->add (substitute[iter.get_coverage ()]);
155     }
156   }
157
158   void collect_glyphs (hb_collect_glyphs_context_t *c) const
159   {
160     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
161     unsigned int count = substitute.len;
162     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
163     {
164       if (unlikely (iter.get_coverage () >= count))
165         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
166       c->output->add (substitute[iter.get_coverage ()]);
167     }
168   }
169
170   const Coverage &get_coverage () const { return this+coverage; }
171
172   bool would_apply (hb_would_apply_context_t *c) const
173   {
174     TRACE_WOULD_APPLY (this);
175     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
176   }
177
178   bool apply (hb_ot_apply_context_t *c) const
179   {
180     TRACE_APPLY (this);
181     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
182     if (likely (index == NOT_COVERED)) return_trace (false);
183
184     if (unlikely (index >= substitute.len)) return_trace (false);
185
186     c->replace_glyph (substitute[index]);
187
188     return_trace (true);
189   }
190
191   bool serialize (hb_serialize_context_t *c,
192                   hb_array_t<const GlyphID> glyphs,
193                   hb_array_t<const GlyphID> substitutes)
194   {
195     TRACE_SERIALIZE (this);
196     if (unlikely (!c->extend_min (*this))) return_trace (false);
197     if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
198     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
199     return_trace (true);
200   }
201
202   bool subset (hb_subset_context_t *c) const
203   {
204     TRACE_SUBSET (this);
205     const hb_set_t &glyphset = *c->plan->glyphset;
206     const hb_map_t &glyph_map = *c->plan->glyph_map;
207     hb_vector_t<GlyphID> from;
208     hb_vector_t<GlyphID> to;
209     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
210     {
211       if (!glyphset.has (iter.get_glyph ())) continue;
212       from.push ()->set (glyph_map[iter.get_glyph ()]);
213       to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
214     }
215     c->serializer->propagate_error (from, to);
216     SingleSubst_serialize (c->serializer, from, to);
217     return_trace (from.length);
218   }
219
220   bool sanitize (hb_sanitize_context_t *c) const
221   {
222     TRACE_SANITIZE (this);
223     return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
224   }
225
226   protected:
227   HBUINT16      format;                 /* Format identifier--format = 2 */
228   OffsetTo<Coverage>
229                 coverage;               /* Offset to Coverage table--from
230                                          * beginning of Substitution table */
231   ArrayOf<GlyphID>
232                 substitute;             /* Array of substitute
233                                          * GlyphIDs--ordered by Coverage Index */
234   public:
235   DEFINE_SIZE_ARRAY (6, substitute);
236 };
237
238 struct SingleSubst
239 {
240   bool serialize (hb_serialize_context_t *c,
241                   hb_array_t<const GlyphID> glyphs,
242                   hb_array_t<const GlyphID> substitutes)
243   {
244     TRACE_SERIALIZE (this);
245     if (unlikely (!c->extend_min (u.format))) return_trace (false);
246     unsigned int format = 2;
247     int delta = 0;
248     if (glyphs.length)
249     {
250       format = 1;
251       /* TODO(serialize) check for wrap-around */
252       delta = substitutes[0] - glyphs[0];
253       for (unsigned int i = 1; i < glyphs.length; i++)
254         if (delta != (int) (substitutes[i] - glyphs[i])) {
255           format = 2;
256           break;
257         }
258     }
259     u.format.set (format);
260     switch (u.format) {
261     case 1: return_trace (u.format1.serialize (c, glyphs, delta));
262     case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
263     default:return_trace (false);
264     }
265   }
266
267   template <typename context_t>
268   typename context_t::return_t dispatch (context_t *c) const
269   {
270     TRACE_DISPATCH (this, u.format);
271     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
272     switch (u.format) {
273     case 1: return_trace (c->dispatch (u.format1));
274     case 2: return_trace (c->dispatch (u.format2));
275     default:return_trace (c->default_return_value ());
276     }
277   }
278
279   protected:
280   union {
281   HBUINT16              format;         /* Format identifier */
282   SingleSubstFormat1    format1;
283   SingleSubstFormat2    format2;
284   } u;
285 };
286
287 static inline void
288 SingleSubst_serialize (hb_serialize_context_t *c,
289                        hb_array_t<const GlyphID> glyphs,
290                        hb_array_t<const GlyphID> substitutes)
291 { c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
292
293 struct Sequence
294 {
295   void closure (hb_closure_context_t *c) const
296   {
297     unsigned int count = substitute.len;
298     for (unsigned int i = 0; i < count; i++)
299       c->out->add (substitute[i]);
300   }
301
302   void collect_glyphs (hb_collect_glyphs_context_t *c) const
303   { c->output->add_array (substitute.arrayZ, substitute.len); }
304
305   bool apply (hb_ot_apply_context_t *c) const
306   {
307     TRACE_APPLY (this);
308     unsigned int count = substitute.len;
309
310     /* Special-case to make it in-place and not consider this
311      * as a "multiplied" substitution. */
312     if (unlikely (count == 1))
313     {
314       c->replace_glyph (substitute.arrayZ[0]);
315       return_trace (true);
316     }
317     /* Spec disallows this, but Uniscribe allows it.
318      * https://github.com/harfbuzz/harfbuzz/issues/253 */
319     else if (unlikely (count == 0))
320     {
321       c->buffer->delete_glyph ();
322       return_trace (true);
323     }
324
325     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
326                          HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
327
328     for (unsigned int i = 0; i < count; i++) {
329       _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
330       c->output_glyph_for_component (substitute.arrayZ[i], klass);
331     }
332     c->buffer->skip_glyph ();
333
334     return_trace (true);
335   }
336
337   bool serialize (hb_serialize_context_t *c,
338                   hb_array_t<const GlyphID> glyphs)
339   {
340     TRACE_SERIALIZE (this);
341     return_trace (substitute.serialize (c, glyphs));
342   }
343
344   bool sanitize (hb_sanitize_context_t *c) const
345   {
346     TRACE_SANITIZE (this);
347     return_trace (substitute.sanitize (c));
348   }
349
350   protected:
351   ArrayOf<GlyphID>
352                 substitute;             /* String of GlyphIDs to substitute */
353   public:
354   DEFINE_SIZE_ARRAY (2, substitute);
355 };
356
357 struct MultipleSubstFormat1
358 {
359   bool intersects (const hb_set_t *glyphs) const
360   { return (this+coverage).intersects (glyphs); }
361
362   void closure (hb_closure_context_t *c) const
363   {
364     unsigned int count = sequence.len;
365     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
366     {
367       if (unlikely (iter.get_coverage () >= count))
368         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
369       if (c->glyphs->has (iter.get_glyph ()))
370         (this+sequence[iter.get_coverage ()]).closure (c);
371     }
372   }
373
374   void collect_glyphs (hb_collect_glyphs_context_t *c) const
375   {
376     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
377     unsigned int count = sequence.len;
378     for (unsigned int i = 0; i < count; i++)
379       (this+sequence[i]).collect_glyphs (c);
380   }
381
382   const Coverage &get_coverage () const { return this+coverage; }
383
384   bool would_apply (hb_would_apply_context_t *c) const
385   {
386     TRACE_WOULD_APPLY (this);
387     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
388   }
389
390   bool apply (hb_ot_apply_context_t *c) const
391   {
392     TRACE_APPLY (this);
393
394     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
395     if (likely (index == NOT_COVERED)) return_trace (false);
396
397     return_trace ((this+sequence[index]).apply (c));
398   }
399
400   bool serialize (hb_serialize_context_t *c,
401                   hb_array_t<const GlyphID> glyphs,
402                   hb_array_t<const unsigned int> substitute_len_list,
403                   hb_array_t<const GlyphID> substitute_glyphs_list)
404   {
405     TRACE_SERIALIZE (this);
406     if (unlikely (!c->extend_min (*this))) return_trace (false);
407     if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
408     for (unsigned int i = 0; i < glyphs.length; i++)
409     {
410       unsigned int substitute_len = substitute_len_list[i];
411       if (unlikely (!sequence[i].serialize (c, this)
412                                 .serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
413         return_trace (false);
414       substitute_glyphs_list += substitute_len;
415     }
416     return_trace (coverage.serialize (c, this).serialize (c, glyphs));
417   }
418
419   bool subset (hb_subset_context_t *c) const
420   {
421     TRACE_SUBSET (this);
422     // TODO(subset)
423     return_trace (false);
424   }
425
426   bool sanitize (hb_sanitize_context_t *c) const
427   {
428     TRACE_SANITIZE (this);
429     return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
430   }
431
432   protected:
433   HBUINT16      format;                 /* Format identifier--format = 1 */
434   OffsetTo<Coverage>
435                 coverage;               /* Offset to Coverage table--from
436                                          * beginning of Substitution table */
437   OffsetArrayOf<Sequence>
438                 sequence;               /* Array of Sequence tables
439                                          * ordered by Coverage Index */
440   public:
441   DEFINE_SIZE_ARRAY (6, sequence);
442 };
443
444 struct MultipleSubst
445 {
446   bool serialize (hb_serialize_context_t *c,
447                   hb_array_t<const GlyphID> glyphs,
448                   hb_array_t<const unsigned int> substitute_len_list,
449                   hb_array_t<const GlyphID> substitute_glyphs_list)
450   {
451     TRACE_SERIALIZE (this);
452     if (unlikely (!c->extend_min (u.format))) return_trace (false);
453     unsigned int format = 1;
454     u.format.set (format);
455     switch (u.format) {
456     case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
457     default:return_trace (false);
458     }
459   }
460
461   template <typename context_t>
462   typename context_t::return_t dispatch (context_t *c) const
463   {
464     TRACE_DISPATCH (this, u.format);
465     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
466     switch (u.format) {
467     case 1: return_trace (c->dispatch (u.format1));
468     default:return_trace (c->default_return_value ());
469     }
470   }
471
472   protected:
473   union {
474   HBUINT16              format;         /* Format identifier */
475   MultipleSubstFormat1  format1;
476   } u;
477 };
478
479 struct AlternateSet
480 {
481   void closure (hb_closure_context_t *c) const
482   {
483     unsigned int count = alternates.len;
484     for (unsigned int i = 0; i < count; i++)
485       c->out->add (alternates[i]);
486   }
487
488   void collect_glyphs (hb_collect_glyphs_context_t *c) const
489   { c->output->add_array (alternates.arrayZ, alternates.len); }
490
491   bool apply (hb_ot_apply_context_t *c) const
492   {
493     TRACE_APPLY (this);
494     unsigned int count = alternates.len;
495
496     if (unlikely (!count)) return_trace (false);
497
498     hb_mask_t glyph_mask = c->buffer->cur().mask;
499     hb_mask_t lookup_mask = c->lookup_mask;
500
501     /* Note: This breaks badly if two features enabled this lookup together. */
502     unsigned int shift = hb_ctz (lookup_mask);
503     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
504
505     /* If alt_index is MAX, randomize feature if it is the rand feature. */
506     if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
507       alt_index = c->random_number () % count + 1;
508
509     if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
510
511     c->replace_glyph (alternates[alt_index - 1]);
512
513     return_trace (true);
514   }
515
516   bool serialize (hb_serialize_context_t *c,
517                   hb_array_t<const GlyphID> glyphs)
518   {
519     TRACE_SERIALIZE (this);
520     return_trace (alternates.serialize (c, glyphs));
521   }
522
523   bool sanitize (hb_sanitize_context_t *c) const
524   {
525     TRACE_SANITIZE (this);
526     return_trace (alternates.sanitize (c));
527   }
528
529   protected:
530   ArrayOf<GlyphID>
531                 alternates;             /* Array of alternate GlyphIDs--in
532                                          * arbitrary order */
533   public:
534   DEFINE_SIZE_ARRAY (2, alternates);
535 };
536
537 struct AlternateSubstFormat1
538 {
539   bool intersects (const hb_set_t *glyphs) const
540   { return (this+coverage).intersects (glyphs); }
541
542   void closure (hb_closure_context_t *c) const
543   {
544     unsigned int count = alternateSet.len;
545     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
546     {
547       if (unlikely (iter.get_coverage () >= count))
548         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
549       if (c->glyphs->has (iter.get_glyph ()))
550         (this+alternateSet[iter.get_coverage ()]).closure (c);
551     }
552   }
553
554   void collect_glyphs (hb_collect_glyphs_context_t *c) const
555   {
556     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
557     unsigned int count = alternateSet.len;
558     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
559     {
560       if (unlikely (iter.get_coverage () >= count))
561         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
562       (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
563     }
564   }
565
566   const Coverage &get_coverage () const { return this+coverage; }
567
568   bool would_apply (hb_would_apply_context_t *c) const
569   {
570     TRACE_WOULD_APPLY (this);
571     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
572   }
573
574   bool apply (hb_ot_apply_context_t *c) const
575   {
576     TRACE_APPLY (this);
577
578     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
579     if (likely (index == NOT_COVERED)) return_trace (false);
580
581     return_trace ((this+alternateSet[index]).apply (c));
582   }
583
584   bool serialize (hb_serialize_context_t *c,
585                   hb_array_t<const GlyphID> glyphs,
586                   hb_array_t<const unsigned int> alternate_len_list,
587                   hb_array_t<const GlyphID> alternate_glyphs_list)
588   {
589     TRACE_SERIALIZE (this);
590     if (unlikely (!c->extend_min (*this))) return_trace (false);
591     if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
592     for (unsigned int i = 0; i < glyphs.length; i++)
593     {
594       unsigned int alternate_len = alternate_len_list[i];
595       if (unlikely (!alternateSet[i].serialize (c, this)
596                                     .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
597         return_trace (false);
598       alternate_glyphs_list += alternate_len;
599     }
600     return_trace (coverage.serialize (c, this).serialize (c, glyphs));
601   }
602
603   bool subset (hb_subset_context_t *c) const
604   {
605     TRACE_SUBSET (this);
606     // TODO(subset)
607     return_trace (false);
608   }
609
610   bool sanitize (hb_sanitize_context_t *c) const
611   {
612     TRACE_SANITIZE (this);
613     return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
614   }
615
616   protected:
617   HBUINT16      format;                 /* Format identifier--format = 1 */
618   OffsetTo<Coverage>
619                 coverage;               /* Offset to Coverage table--from
620                                          * beginning of Substitution table */
621   OffsetArrayOf<AlternateSet>
622                 alternateSet;           /* Array of AlternateSet tables
623                                          * ordered by Coverage Index */
624   public:
625   DEFINE_SIZE_ARRAY (6, alternateSet);
626 };
627
628 struct AlternateSubst
629 {
630   bool serialize (hb_serialize_context_t *c,
631                   hb_array_t<const GlyphID> glyphs,
632                   hb_array_t<const unsigned int> alternate_len_list,
633                   hb_array_t<const GlyphID> alternate_glyphs_list)
634   {
635     TRACE_SERIALIZE (this);
636     if (unlikely (!c->extend_min (u.format))) return_trace (false);
637     unsigned int format = 1;
638     u.format.set (format);
639     switch (u.format) {
640     case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
641     default:return_trace (false);
642     }
643   }
644
645   template <typename context_t>
646   typename context_t::return_t dispatch (context_t *c) const
647   {
648     TRACE_DISPATCH (this, u.format);
649     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
650     switch (u.format) {
651     case 1: return_trace (c->dispatch (u.format1));
652     default:return_trace (c->default_return_value ());
653     }
654   }
655
656   protected:
657   union {
658   HBUINT16              format;         /* Format identifier */
659   AlternateSubstFormat1 format1;
660   } u;
661 };
662
663
664 struct Ligature
665 {
666   bool intersects (const hb_set_t *glyphs) const
667   {
668     unsigned int count = component.lenP1;
669     for (unsigned int i = 1; i < count; i++)
670       if (!glyphs->has (component[i]))
671         return false;
672     return true;
673   }
674
675   void closure (hb_closure_context_t *c) const
676   {
677     unsigned int count = component.lenP1;
678     for (unsigned int i = 1; i < count; i++)
679       if (!c->glyphs->has (component[i]))
680         return;
681     c->out->add (ligGlyph);
682   }
683
684   void collect_glyphs (hb_collect_glyphs_context_t *c) const
685   {
686     c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
687     c->output->add (ligGlyph);
688   }
689
690   bool would_apply (hb_would_apply_context_t *c) const
691   {
692     TRACE_WOULD_APPLY (this);
693     if (c->len != component.lenP1)
694       return_trace (false);
695
696     for (unsigned int i = 1; i < c->len; i++)
697       if (likely (c->glyphs[i] != component[i]))
698         return_trace (false);
699
700     return_trace (true);
701   }
702
703   bool apply (hb_ot_apply_context_t *c) const
704   {
705     TRACE_APPLY (this);
706     unsigned int count = component.lenP1;
707
708     if (unlikely (!count)) return_trace (false);
709
710     /* Special-case to make it in-place and not consider this
711      * as a "ligated" substitution. */
712     if (unlikely (count == 1))
713     {
714       c->replace_glyph (ligGlyph);
715       return_trace (true);
716     }
717
718     unsigned int total_component_count = 0;
719
720     unsigned int match_length = 0;
721     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
722
723     if (likely (!match_input (c, count,
724                               &component[1],
725                               match_glyph,
726                               nullptr,
727                               &match_length,
728                               match_positions,
729                               &total_component_count)))
730       return_trace (false);
731
732     ligate_input (c,
733                   count,
734                   match_positions,
735                   match_length,
736                   ligGlyph,
737                   total_component_count);
738
739     return_trace (true);
740   }
741
742   bool serialize (hb_serialize_context_t *c,
743                   GlyphID ligature,
744                   hb_array_t<const GlyphID> components /* Starting from second */)
745   {
746     TRACE_SERIALIZE (this);
747     if (unlikely (!c->extend_min (*this))) return_trace (false);
748     ligGlyph = ligature;
749     if (unlikely (!component.serialize (c, components))) return_trace (false);
750     return_trace (true);
751   }
752
753   public:
754   bool sanitize (hb_sanitize_context_t *c) const
755   {
756     TRACE_SANITIZE (this);
757     return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
758   }
759
760   protected:
761   GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
762   HeadlessArrayOf<GlyphID>
763                 component;              /* Array of component GlyphIDs--start
764                                          * with the second  component--ordered
765                                          * in writing direction */
766   public:
767   DEFINE_SIZE_ARRAY (4, component);
768 };
769
770 struct LigatureSet
771 {
772   bool intersects (const hb_set_t *glyphs) const
773   {
774     unsigned int num_ligs = ligature.len;
775     for (unsigned int i = 0; i < num_ligs; i++)
776       if ((this+ligature[i]).intersects (glyphs))
777         return true;
778     return false;
779   }
780
781   void closure (hb_closure_context_t *c) const
782   {
783     unsigned int num_ligs = ligature.len;
784     for (unsigned int i = 0; i < num_ligs; i++)
785       (this+ligature[i]).closure (c);
786   }
787
788   void collect_glyphs (hb_collect_glyphs_context_t *c) const
789   {
790     unsigned int num_ligs = ligature.len;
791     for (unsigned int i = 0; i < num_ligs; i++)
792       (this+ligature[i]).collect_glyphs (c);
793   }
794
795   bool would_apply (hb_would_apply_context_t *c) const
796   {
797     TRACE_WOULD_APPLY (this);
798     unsigned int num_ligs = ligature.len;
799     for (unsigned int i = 0; i < num_ligs; i++)
800     {
801       const Ligature &lig = this+ligature[i];
802       if (lig.would_apply (c))
803         return_trace (true);
804     }
805     return_trace (false);
806   }
807
808   bool apply (hb_ot_apply_context_t *c) const
809   {
810     TRACE_APPLY (this);
811     unsigned int num_ligs = ligature.len;
812     for (unsigned int i = 0; i < num_ligs; i++)
813     {
814       const Ligature &lig = this+ligature[i];
815       if (lig.apply (c)) return_trace (true);
816     }
817
818     return_trace (false);
819   }
820
821   bool serialize (hb_serialize_context_t *c,
822                   hb_array_t<const GlyphID> ligatures,
823                   hb_array_t<const unsigned int> component_count_list,
824                   hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
825   {
826     TRACE_SERIALIZE (this);
827     if (unlikely (!c->extend_min (*this))) return_trace (false);
828     if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
829     for (unsigned int i = 0; i < ligatures.length; i++)
830     {
831       unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
832       if (unlikely (!ligature[i].serialize (c, this)
833                                 .serialize (c,
834                                             ligatures[i],
835                                             component_list.sub_array (0, component_count))))
836         return_trace (false);
837       component_list += component_count;
838     }
839     return_trace (true);
840   }
841
842   bool sanitize (hb_sanitize_context_t *c) const
843   {
844     TRACE_SANITIZE (this);
845     return_trace (ligature.sanitize (c, this));
846   }
847
848   protected:
849   OffsetArrayOf<Ligature>
850                 ligature;               /* Array LigatureSet tables
851                                          * ordered by preference */
852   public:
853   DEFINE_SIZE_ARRAY (2, ligature);
854 };
855
856 struct LigatureSubstFormat1
857 {
858   bool intersects (const hb_set_t *glyphs) const
859   {
860     unsigned int count = ligatureSet.len;
861     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
862     {
863       if (unlikely (iter.get_coverage () >= count))
864         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
865       if (glyphs->has (iter.get_glyph ()) &&
866           (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
867         return true;
868     }
869     return false;
870   }
871
872   void closure (hb_closure_context_t *c) const
873   {
874     unsigned int count = ligatureSet.len;
875     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
876     {
877       if (unlikely (iter.get_coverage () >= count))
878         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
879       if (c->glyphs->has (iter.get_glyph ()))
880         (this+ligatureSet[iter.get_coverage ()]).closure (c);
881     }
882   }
883
884   void collect_glyphs (hb_collect_glyphs_context_t *c) const
885   {
886     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
887     unsigned int count = ligatureSet.len;
888     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
889     {
890       if (unlikely (iter.get_coverage () >= count))
891         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
892       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
893     }
894   }
895
896   const Coverage &get_coverage () const { return this+coverage; }
897
898   bool would_apply (hb_would_apply_context_t *c) const
899   {
900     TRACE_WOULD_APPLY (this);
901     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
902     if (likely (index == NOT_COVERED)) return_trace (false);
903
904     const LigatureSet &lig_set = this+ligatureSet[index];
905     return_trace (lig_set.would_apply (c));
906   }
907
908   bool apply (hb_ot_apply_context_t *c) const
909   {
910     TRACE_APPLY (this);
911
912     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
913     if (likely (index == NOT_COVERED)) return_trace (false);
914
915     const LigatureSet &lig_set = this+ligatureSet[index];
916     return_trace (lig_set.apply (c));
917   }
918
919   bool serialize (hb_serialize_context_t *c,
920                   hb_array_t<const GlyphID> first_glyphs,
921                   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
922                   hb_array_t<const GlyphID> ligatures_list,
923                   hb_array_t<const unsigned int> component_count_list,
924                   hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
925   {
926     TRACE_SERIALIZE (this);
927     if (unlikely (!c->extend_min (*this))) return_trace (false);
928     if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
929     for (unsigned int i = 0; i < first_glyphs.length; i++)
930     {
931       unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
932       if (unlikely (!ligatureSet[i].serialize (c, this)
933                                    .serialize (c,
934                                                ligatures_list.sub_array (0, ligature_count),
935                                                component_count_list.sub_array (0, ligature_count),
936                                                component_list))) return_trace (false);
937       ligatures_list += ligature_count;
938       component_count_list += ligature_count;
939     }
940     return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
941   }
942
943   bool subset (hb_subset_context_t *c) const
944   {
945     TRACE_SUBSET (this);
946     // TODO(subset)
947     return_trace (false);
948   }
949
950   bool sanitize (hb_sanitize_context_t *c) const
951   {
952     TRACE_SANITIZE (this);
953     return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
954   }
955
956   protected:
957   HBUINT16      format;                 /* Format identifier--format = 1 */
958   OffsetTo<Coverage>
959                 coverage;               /* Offset to Coverage table--from
960                                          * beginning of Substitution table */
961   OffsetArrayOf<LigatureSet>
962                 ligatureSet;            /* Array LigatureSet tables
963                                          * ordered by Coverage Index */
964   public:
965   DEFINE_SIZE_ARRAY (6, ligatureSet);
966 };
967
968 struct LigatureSubst
969 {
970   bool serialize (hb_serialize_context_t *c,
971                   hb_array_t<const GlyphID> first_glyphs,
972                   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
973                   hb_array_t<const GlyphID> ligatures_list,
974                   hb_array_t<const unsigned int> component_count_list,
975                   hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
976   {
977     TRACE_SERIALIZE (this);
978     if (unlikely (!c->extend_min (u.format))) return_trace (false);
979     unsigned int format = 1;
980     u.format.set (format);
981     switch (u.format) {
982     case 1: return_trace (u.format1.serialize (c,
983                                                first_glyphs,
984                                                ligature_per_first_glyph_count_list,
985                                                ligatures_list,
986                                                component_count_list,
987                                                component_list));
988     default:return_trace (false);
989     }
990   }
991
992   template <typename context_t>
993   typename context_t::return_t dispatch (context_t *c) const
994   {
995     TRACE_DISPATCH (this, u.format);
996     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
997     switch (u.format) {
998     case 1: return_trace (c->dispatch (u.format1));
999     default:return_trace (c->default_return_value ());
1000     }
1001   }
1002
1003   protected:
1004   union {
1005   HBUINT16              format;         /* Format identifier */
1006   LigatureSubstFormat1  format1;
1007   } u;
1008 };
1009
1010
1011 struct ContextSubst : Context {};
1012
1013 struct ChainContextSubst : ChainContext {};
1014
1015 struct ExtensionSubst : Extension<ExtensionSubst>
1016 {
1017   typedef struct SubstLookupSubTable SubTable;
1018
1019   bool is_reverse () const;
1020 };
1021
1022
1023 struct ReverseChainSingleSubstFormat1
1024 {
1025   bool intersects (const hb_set_t *glyphs) const
1026   {
1027     if (!(this+coverage).intersects (glyphs))
1028       return false;
1029
1030     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1031
1032     unsigned int count;
1033
1034     count = backtrack.len;
1035     for (unsigned int i = 0; i < count; i++)
1036       if (!(this+backtrack[i]).intersects (glyphs))
1037         return false;
1038
1039     count = lookahead.len;
1040     for (unsigned int i = 0; i < count; i++)
1041       if (!(this+lookahead[i]).intersects (glyphs))
1042         return false;
1043
1044     return true;
1045   }
1046
1047   void closure (hb_closure_context_t *c) const
1048   {
1049     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1050
1051     unsigned int count;
1052
1053     count = backtrack.len;
1054     for (unsigned int i = 0; i < count; i++)
1055       if (!(this+backtrack[i]).intersects (c->glyphs))
1056         return;
1057
1058     count = lookahead.len;
1059     for (unsigned int i = 0; i < count; i++)
1060       if (!(this+lookahead[i]).intersects (c->glyphs))
1061         return;
1062
1063     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1064     count = substitute.len;
1065     for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1066     {
1067       if (unlikely (iter.get_coverage () >= count))
1068         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1069       if (c->glyphs->has (iter.get_glyph ()))
1070         c->out->add (substitute[iter.get_coverage ()]);
1071     }
1072   }
1073
1074   void collect_glyphs (hb_collect_glyphs_context_t *c) const
1075   {
1076     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1077
1078     unsigned int count;
1079
1080     count = backtrack.len;
1081     for (unsigned int i = 0; i < count; i++)
1082       if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
1083
1084     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1085     count = lookahead.len;
1086     for (unsigned int i = 0; i < count; i++)
1087       if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1088
1089     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1090     count = substitute.len;
1091     c->output->add_array (substitute.arrayZ, substitute.len);
1092   }
1093
1094   const Coverage &get_coverage () const { return this+coverage; }
1095
1096   bool would_apply (hb_would_apply_context_t *c) const
1097   {
1098     TRACE_WOULD_APPLY (this);
1099     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1100   }
1101
1102   bool apply (hb_ot_apply_context_t *c) const
1103   {
1104     TRACE_APPLY (this);
1105     if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
1106       return_trace (false); /* No chaining to this type */
1107
1108     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1109     if (likely (index == NOT_COVERED)) return_trace (false);
1110
1111     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1112     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1113
1114   unsigned int start_index = 0, end_index = 0;
1115     if (match_backtrack (c,
1116                          backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1117                          match_coverage, this,
1118                          &start_index) &&
1119         match_lookahead (c,
1120                          lookahead.len, (HBUINT16 *) lookahead.arrayZ,
1121                          match_coverage, this,
1122                          1, &end_index))
1123     {
1124       c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
1125       c->replace_glyph_inplace (substitute[index]);
1126       /* Note: We DON'T decrease buffer->idx.  The main loop does it
1127        * for us.  This is useful for preventing surprises if someone
1128        * calls us through a Context lookup. */
1129       return_trace (true);
1130     }
1131
1132     return_trace (false);
1133   }
1134
1135   bool subset (hb_subset_context_t *c) const
1136   {
1137     TRACE_SUBSET (this);
1138     // TODO(subset)
1139     return_trace (false);
1140   }
1141
1142   bool sanitize (hb_sanitize_context_t *c) const
1143   {
1144     TRACE_SANITIZE (this);
1145     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1146       return_trace (false);
1147     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1148     if (!lookahead.sanitize (c, this))
1149       return_trace (false);
1150     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1151     return_trace (substitute.sanitize (c));
1152   }
1153
1154   protected:
1155   HBUINT16      format;                 /* Format identifier--format = 1 */
1156   OffsetTo<Coverage>
1157                 coverage;               /* Offset to Coverage table--from
1158                                          * beginning of table */
1159   OffsetArrayOf<Coverage>
1160                 backtrack;              /* Array of coverage tables
1161                                          * in backtracking sequence, in glyph
1162                                          * sequence order */
1163   OffsetArrayOf<Coverage>
1164                 lookaheadX;             /* Array of coverage tables
1165                                          * in lookahead sequence, in glyph
1166                                          * sequence order */
1167   ArrayOf<GlyphID>
1168                 substituteX;            /* Array of substitute
1169                                          * GlyphIDs--ordered by Coverage Index */
1170   public:
1171   DEFINE_SIZE_MIN (10);
1172 };
1173
1174 struct ReverseChainSingleSubst
1175 {
1176   template <typename context_t>
1177   typename context_t::return_t dispatch (context_t *c) const
1178   {
1179     TRACE_DISPATCH (this, u.format);
1180     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1181     switch (u.format) {
1182     case 1: return_trace (c->dispatch (u.format1));
1183     default:return_trace (c->default_return_value ());
1184     }
1185   }
1186
1187   protected:
1188   union {
1189   HBUINT16                              format;         /* Format identifier */
1190   ReverseChainSingleSubstFormat1        format1;
1191   } u;
1192 };
1193
1194
1195
1196 /*
1197  * SubstLookup
1198  */
1199
1200 struct SubstLookupSubTable
1201 {
1202   friend struct Lookup;
1203   friend struct SubstLookup;
1204
1205   enum Type {
1206     Single              = 1,
1207     Multiple            = 2,
1208     Alternate           = 3,
1209     Ligature            = 4,
1210     Context             = 5,
1211     ChainContext        = 6,
1212     Extension           = 7,
1213     ReverseChainSingle  = 8
1214   };
1215
1216   template <typename context_t>
1217   typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1218   {
1219     TRACE_DISPATCH (this, lookup_type);
1220     switch (lookup_type) {
1221     case Single:                return_trace (u.single.dispatch (c));
1222     case Multiple:              return_trace (u.multiple.dispatch (c));
1223     case Alternate:             return_trace (u.alternate.dispatch (c));
1224     case Ligature:              return_trace (u.ligature.dispatch (c));
1225     case Context:               return_trace (u.context.dispatch (c));
1226     case ChainContext:          return_trace (u.chainContext.dispatch (c));
1227     case Extension:             return_trace (u.extension.dispatch (c));
1228     case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c));
1229     default:                    return_trace (c->default_return_value ());
1230     }
1231   }
1232
1233   protected:
1234   union {
1235   SingleSubst                   single;
1236   MultipleSubst                 multiple;
1237   AlternateSubst                alternate;
1238   LigatureSubst                 ligature;
1239   ContextSubst                  context;
1240   ChainContextSubst             chainContext;
1241   ExtensionSubst                extension;
1242   ReverseChainSingleSubst       reverseChainContextSingle;
1243   } u;
1244   public:
1245   DEFINE_SIZE_MIN (0);
1246 };
1247
1248
1249 struct SubstLookup : Lookup
1250 {
1251   typedef SubstLookupSubTable SubTable;
1252
1253   const SubTable& get_subtable (unsigned int i) const
1254   { return Lookup::get_subtable<SubTable> (i); }
1255
1256   static bool lookup_type_is_reverse (unsigned int lookup_type)
1257   { return lookup_type == SubTable::ReverseChainSingle; }
1258
1259   bool is_reverse () const
1260   {
1261     unsigned int type = get_type ();
1262     if (unlikely (type == SubTable::Extension))
1263       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1264     return lookup_type_is_reverse (type);
1265   }
1266
1267   bool apply (hb_ot_apply_context_t *c) const
1268   {
1269     TRACE_APPLY (this);
1270     return_trace (dispatch (c));
1271   }
1272
1273   bool intersects (const hb_set_t *glyphs) const
1274   {
1275     hb_intersects_context_t c (glyphs);
1276     return dispatch (&c);
1277   }
1278
1279   hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1280   {
1281     if (!c->should_visit_lookup (this_index))
1282       return hb_closure_context_t::default_return_value ();
1283
1284     c->set_recurse_func (dispatch_closure_recurse_func);
1285
1286     hb_closure_context_t::return_t ret = dispatch (c);
1287
1288     c->flush ();
1289
1290     return ret;
1291   }
1292
1293   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1294   {
1295     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1296     return dispatch (c);
1297   }
1298
1299   template <typename set_t>
1300   void add_coverage (set_t *glyphs) const
1301   {
1302     hb_add_coverage_context_t<set_t> c (glyphs);
1303     dispatch (&c);
1304   }
1305
1306   bool would_apply (hb_would_apply_context_t *c,
1307                     const hb_ot_layout_lookup_accelerator_t *accel) const
1308   {
1309     TRACE_WOULD_APPLY (this);
1310     if (unlikely (!c->len))  return_trace (false);
1311     if (!accel->may_have (c->glyphs[0]))  return_trace (false);
1312       return_trace (dispatch (c));
1313   }
1314
1315   static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
1316
1317   SubTable& serialize_subtable (hb_serialize_context_t *c,
1318                                        unsigned int i)
1319   { return get_subtables<SubTable> ()[i].serialize (c, this); }
1320
1321   bool serialize_single (hb_serialize_context_t *c,
1322                          uint32_t lookup_props,
1323                          hb_array_t<const GlyphID> glyphs,
1324                          hb_array_t<const GlyphID> substitutes)
1325   {
1326     TRACE_SERIALIZE (this);
1327     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
1328     return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
1329   }
1330
1331   bool serialize_multiple (hb_serialize_context_t *c,
1332                            uint32_t lookup_props,
1333                            hb_array_t<const GlyphID> glyphs,
1334                            hb_array_t<const unsigned int> substitute_len_list,
1335                            hb_array_t<const GlyphID> substitute_glyphs_list)
1336   {
1337     TRACE_SERIALIZE (this);
1338     if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
1339     return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
1340                                                                   glyphs,
1341                                                                   substitute_len_list,
1342                                                                   substitute_glyphs_list));
1343   }
1344
1345   bool serialize_alternate (hb_serialize_context_t *c,
1346                             uint32_t lookup_props,
1347                             hb_array_t<const GlyphID> glyphs,
1348                             hb_array_t<const unsigned int> alternate_len_list,
1349                             hb_array_t<const GlyphID> alternate_glyphs_list)
1350   {
1351     TRACE_SERIALIZE (this);
1352     if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
1353     return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
1354                                                                    glyphs,
1355                                                                    alternate_len_list,
1356                                                                    alternate_glyphs_list));
1357   }
1358
1359   bool serialize_ligature (hb_serialize_context_t *c,
1360                            uint32_t lookup_props,
1361                            hb_array_t<const GlyphID> first_glyphs,
1362                            hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
1363                            hb_array_t<const GlyphID> ligatures_list,
1364                            hb_array_t<const unsigned int> component_count_list,
1365                            hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
1366   {
1367     TRACE_SERIALIZE (this);
1368     if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
1369     return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
1370                                                                   first_glyphs,
1371                                                                   ligature_per_first_glyph_count_list,
1372                                                                   ligatures_list,
1373                                                                   component_count_list,
1374                                                                   component_list));
1375   }
1376
1377   template <typename context_t>
1378   static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1379
1380   static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1381   {
1382     if (!c->should_visit_lookup (lookup_index))
1383       return HB_VOID;
1384
1385     hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
1386
1387     /* While in theory we should flush here, it will cause timeouts because a recursive
1388      * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
1389      * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
1390     //c->flush ();
1391
1392     return ret;
1393   }
1394
1395   template <typename context_t>
1396   typename context_t::return_t dispatch (context_t *c) const
1397   { return Lookup::dispatch<SubTable> (c); }
1398
1399   bool subset (hb_subset_context_t *c) const
1400   { return Lookup::subset<SubTable> (c); }
1401
1402   bool sanitize (hb_sanitize_context_t *c) const
1403   { return Lookup::sanitize<SubTable> (c); }
1404 };
1405
1406 /*
1407  * GSUB -- Glyph Substitution
1408  * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
1409  */
1410
1411 struct GSUB : GSUBGPOS
1412 {
1413   static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
1414
1415   const SubstLookup& get_lookup (unsigned int i) const
1416   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1417
1418   bool subset (hb_subset_context_t *c) const
1419   { return GSUBGPOS::subset<SubstLookup> (c); }
1420
1421   bool sanitize (hb_sanitize_context_t *c) const
1422   { return GSUBGPOS::sanitize<SubstLookup> (c); }
1423
1424   HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
1425                                    hb_face_t *face) const;
1426
1427   typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
1428 };
1429
1430
1431 struct GSUB_accelerator_t : GSUB::accelerator_t {};
1432
1433
1434 /* Out-of-class implementation for methods recursing */
1435
1436 /*static*/ inline bool ExtensionSubst::is_reverse () const
1437 {
1438   unsigned int type = get_type ();
1439   if (unlikely (type == SubTable::Extension))
1440     return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
1441   return SubstLookup::lookup_type_is_reverse (type);
1442 }
1443
1444 template <typename context_t>
1445 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1446 {
1447   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1448   return l.dispatch (c);
1449 }
1450
1451 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
1452 {
1453   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1454   unsigned int saved_lookup_props = c->lookup_props;
1455   unsigned int saved_lookup_index = c->lookup_index;
1456   c->set_lookup_index (lookup_index);
1457   c->set_lookup_props (l.get_props ());
1458   bool ret = l.dispatch (c);
1459   c->set_lookup_index (saved_lookup_index);
1460   c->set_lookup_props (saved_lookup_props);
1461   return ret;
1462 }
1463
1464 } /* namespace OT */
1465
1466
1467 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */