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