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