Home | History | Annotate | Download | only in src
      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     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 
     60   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 
     73   const Coverage &get_coverage () const { return this+coverage; }
     74 
     75   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 
     81   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 
     96   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 
    107   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 
    126   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 {
    145   bool intersects (const hb_set_t *glyphs) const
    146   { return (this+coverage).intersects (glyphs); }
    147 
    148   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 
    161   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 
    174   const Coverage &get_coverage () const { return this+coverage; }
    175 
    176   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 
    182   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 
    195   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 
    206   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 
    224   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 {
    244   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>
    272   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
    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 {
    299   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 
    307   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 
    313   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 
    345   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 
    352   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 {
    367   bool intersects (const hb_set_t *glyphs) const
    368   { return (this+coverage).intersects (glyphs); }
    369 
    370   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 
    383   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 
    392   const Coverage &get_coverage () const { return this+coverage; }
    393 
    394   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 
    400   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 
    410   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 
    429   bool subset (hb_subset_context_t *c) const
    430   {
    431     TRACE_SUBSET (this);
    432     // TODO(subset)
    433     return_trace (false);
    434   }
    435 
    436   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 {
    456   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>
    472   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 {
    491   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 
    499   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 
    505   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 
    530   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 
    537   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 {
    553   bool intersects (const hb_set_t *glyphs) const
    554   { return (this+coverage).intersects (glyphs); }
    555 
    556   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 
    569   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 
    582   const Coverage &get_coverage () const { return this+coverage; }
    583 
    584   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 
    590   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 
    600   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 
    619   bool subset (hb_subset_context_t *c) const
    620   {
    621     TRACE_SUBSET (this);
    622     // TODO(subset)
    623     return_trace (false);
    624   }
    625 
    626   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 {
    646   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>
    662   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 {
    682   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 
    691   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 
    701   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 
    708   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 
    721   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 
    760   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:
    772   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 {
    790   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 
    799   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 
    807   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 
    815   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 
    828   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 
    841   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 
    862   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 {
    878   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 
    892   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 
    905   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 
    918   const Coverage &get_coverage () const { return this+coverage; }
    919 
    920   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 
    930   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 
    941   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 
    967   bool subset (hb_subset_context_t *c) const
    968   {
    969     TRACE_SUBSET (this);
    970     // TODO(subset)
    971     return_trace (false);
    972   }
    973 
    974   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 {
    994   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>
   1017   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 {
   1049   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 
   1071   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 
   1099   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 
   1120   const Coverage &get_coverage () const { return this+coverage; }
   1121 
   1122   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 
   1128   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 
   1161   bool subset (hb_subset_context_t *c) const
   1162   {
   1163     TRACE_SUBSET (this);
   1164     // TODO(subset)
   1165     return_trace (false);
   1166   }
   1167 
   1168   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>
   1203   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>
   1243   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 
   1279   const SubTable& get_subtable (unsigned int i) const
   1280   { return Lookup::get_subtable<SubTable> (i); }
   1281 
   1282   static bool lookup_type_is_reverse (unsigned int lookup_type)
   1283   { return lookup_type == SubTable::ReverseChainSingle; }
   1284 
   1285   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 
   1293   bool apply (hb_ot_apply_context_t *c) const
   1294   {
   1295     TRACE_APPLY (this);
   1296     return_trace (dispatch (c));
   1297   }
   1298 
   1299   bool intersects (const hb_set_t *glyphs) const
   1300   {
   1301     hb_intersects_context_t c (glyphs);
   1302     return dispatch (&c);
   1303   }
   1304 
   1305   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 
   1320   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>
   1328   void add_coverage (set_t *glyphs) const
   1329   {
   1330     hb_add_coverage_context_t<set_t> c (glyphs);
   1331     dispatch (&c);
   1332   }
   1333 
   1334   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 
   1345   SubTable& serialize_subtable (hb_serialize_context_t *c,
   1346 				       unsigned int i)
   1347   { return get_subtables<SubTable> ()[i].serialize (c, this); }
   1348 
   1349   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 
   1359   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 
   1373   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 
   1387   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 
   1408   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>
   1424   typename context_t::return_t dispatch (context_t *c) const
   1425   { return Lookup::dispatch<SubTable> (c); }
   1426 
   1427   bool subset (hb_subset_context_t *c) const
   1428   { return Lookup::subset<SubTable> (c); }
   1429 
   1430   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 
   1443   const SubstLookup& get_lookup (unsigned int i) const
   1444   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
   1445 
   1446   bool subset (hb_subset_context_t *c) const
   1447   { return GSUBGPOS::subset<SubstLookup> (c); }
   1448 
   1449   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 
   1464 /*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>
   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 
   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