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