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