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