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