tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-aat-layout-morx-table.hh (45705B)


      1 /*
      2 * Copyright © 2017  Google, Inc.
      3 *
      4 *  This is part of HarfBuzz, a text shaping library.
      5 *
      6 * Permission is hereby granted, without written agreement and without
      7 * license or royalty fees, to use, copy, modify, and distribute this
      8 * software and its documentation for any purpose, provided that the
      9 * above copyright notice and the following two paragraphs appear in
     10 * all copies of this software.
     11 *
     12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16 * DAMAGE.
     17 *
     18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23 *
     24 * Google Author(s): Behdad Esfahbod
     25 */
     26 
     27 #ifndef HB_AAT_LAYOUT_MORX_TABLE_HH
     28 #define HB_AAT_LAYOUT_MORX_TABLE_HH
     29 
     30 #include "hb-open-type.hh"
     31 #include "hb-aat-layout-common.hh"
     32 #include "hb-ot-layout.hh"
     33 #include "hb-aat-map.hh"
     34 
     35 /*
     36 * morx -- Extended Glyph Metamorphosis
     37 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
     38 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
     39 */
     40 #define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
     41 #define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
     42 
     43 
     44 namespace AAT {
     45 
     46 using namespace OT;
     47 
     48 template <typename Types>
     49 struct RearrangementSubtable
     50 {
     51  typedef typename Types::HBUINT HBUINT;
     52 
     53  typedef void EntryData;
     54 
     55  enum Flags
     56  {
     57    MarkFirst		= 0x8000,	/* If set, make the current glyph the first
     58 				 * glyph to be rearranged. */
     59    DontAdvance		= 0x4000,	/* If set, don't advance to the next glyph
     60 				 * before going to the new state. This means
     61 				 * that the glyph index doesn't change, even
     62 				 * if the glyph at that index has changed. */
     63    MarkLast		= 0x2000,	/* If set, make the current glyph the last
     64 				 * glyph to be rearranged. */
     65    Reserved		= 0x1FF0,	/* These bits are reserved and should be set to 0. */
     66    Verb		= 0x000F,	/* The type of rearrangement specified. */
     67  };
     68 
     69  bool is_action_initiable (const Entry<EntryData> &entry) const
     70  {
     71    return (entry.flags & MarkFirst);
     72  }
     73  bool is_actionable (const Entry<EntryData> &entry) const
     74  {
     75    return (entry.flags & Verb);
     76  }
     77 
     78  struct driver_context_t
     79  {
     80    static constexpr bool in_place = true;
     81 
     82    driver_context_t (const RearrangementSubtable *table_) :
     83 ret (false),
     84 table (table_),
     85 start (0), end (0) {}
     86 
     87    void transition (hb_buffer_t *buffer,
     88 	     StateTableDriver<Types, EntryData, Flags> *driver,
     89 	     const Entry<EntryData> &entry)
     90    {
     91      unsigned int flags = entry.flags;
     92 
     93      if (flags & MarkFirst)
     94 start = buffer->idx;
     95 
     96      if (flags & MarkLast)
     97 end = hb_min (buffer->idx + 1, buffer->len);
     98 
     99      if ((flags & Verb) && start < end)
    100      {
    101 /* The following map has two nibbles, for start-side
    102  * and end-side. Values of 0,1,2 mean move that many
    103  * to the other side. Value of 3 means move 2 and
    104  * flip them. */
    105 const unsigned char map[16] =
    106 {
    107   0x00,	/* 0	no change */
    108   0x10,	/* 1	Ax => xA */
    109   0x01,	/* 2	xD => Dx */
    110   0x11,	/* 3	AxD => DxA */
    111   0x20,	/* 4	ABx => xAB */
    112   0x30,	/* 5	ABx => xBA */
    113   0x02,	/* 6	xCD => CDx */
    114   0x03,	/* 7	xCD => DCx */
    115   0x12,	/* 8	AxCD => CDxA */
    116   0x13,	/* 9	AxCD => DCxA */
    117   0x21,	/* 10	ABxD => DxAB */
    118   0x31,	/* 11	ABxD => DxBA */
    119   0x22,	/* 12	ABxCD => CDxAB */
    120   0x32,	/* 13	ABxCD => CDxBA */
    121   0x23,	/* 14	ABxCD => DCxAB */
    122   0x33,	/* 15	ABxCD => DCxBA */
    123 };
    124 
    125 unsigned int m = map[flags & Verb];
    126 unsigned int l = hb_min (2u, m >> 4);
    127 unsigned int r = hb_min (2u, m & 0x0F);
    128 bool reverse_l = 3 == (m >> 4);
    129 bool reverse_r = 3 == (m & 0x0F);
    130 
    131 if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
    132 {
    133   buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
    134   buffer->merge_clusters (start, end);
    135 
    136   hb_glyph_info_t *info = buffer->info;
    137   hb_glyph_info_t buf[4];
    138 
    139   hb_memcpy (buf, info + start, l * sizeof (buf[0]));
    140   hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
    141 
    142   if (l != r)
    143     memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
    144 
    145   hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
    146   hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
    147   if (reverse_l)
    148   {
    149     buf[0] = info[end - 1];
    150     info[end - 1] = info[end - 2];
    151     info[end - 2] = buf[0];
    152   }
    153   if (reverse_r)
    154   {
    155     buf[0] = info[start];
    156     info[start] = info[start + 1];
    157     info[start + 1] = buf[0];
    158   }
    159 }
    160      }
    161    }
    162 
    163    public:
    164    bool ret;
    165    const RearrangementSubtable *table;
    166    private:
    167    unsigned int start;
    168    unsigned int end;
    169  };
    170 
    171  bool apply (hb_aat_apply_context_t *c) const
    172  {
    173    TRACE_APPLY (this);
    174 
    175    driver_context_t dc (this);
    176 
    177    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
    178 
    179    driver.drive (&dc, c);
    180 
    181    return_trace (dc.ret);
    182  }
    183 
    184  bool sanitize (hb_sanitize_context_t *c) const
    185  {
    186    TRACE_SANITIZE (this);
    187    return_trace (machine.sanitize (c));
    188  }
    189 
    190  public:
    191  StateTable<Types, EntryData>	machine;
    192  public:
    193  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
    194 };
    195 
    196 template <typename Types>
    197 struct ContextualSubtable
    198 {
    199  typedef typename Types::HBUINT HBUINT;
    200 
    201  struct EntryData
    202  {
    203    HBUINT16	markIndex;	/* Index of the substitution table for the
    204 			 * marked glyph (use 0xFFFF for none). */
    205    HBUINT16	currentIndex;	/* Index of the substitution table for the
    206 			 * current glyph (use 0xFFFF for none). */
    207    public:
    208    DEFINE_SIZE_STATIC (4);
    209  };
    210 
    211  enum Flags
    212  {
    213    SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
    214    DontAdvance		= 0x4000,	/* If set, don't advance to the next glyph before
    215 				 * going to the new state. */
    216    Reserved		= 0x3FFF,	/* These bits are reserved and should be set to 0. */
    217  };
    218 
    219  bool is_action_initiable (const Entry<EntryData> &entry) const
    220  {
    221    return (entry.flags & SetMark);
    222  }
    223  bool is_actionable (const Entry<EntryData> &entry) const
    224  {
    225    return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
    226  }
    227 
    228  struct driver_context_t
    229  {
    230    static constexpr bool in_place = true;
    231 
    232    driver_context_t (const ContextualSubtable *table_,
    233 		     hb_aat_apply_context_t *c_) :
    234 ret (false),
    235 c (c_),
    236 table (table_),
    237 mark_set (false),
    238 mark (0),
    239 subs (table+table->substitutionTables) {}
    240 
    241    void transition (hb_buffer_t *buffer,
    242 	     StateTableDriver<Types, EntryData, Flags> *driver,
    243 	     const Entry<EntryData> &entry)
    244    {
    245      /* Looks like CoreText applies neither mark nor current substitution for
    246       * end-of-text if mark was not explicitly set. */
    247      if (buffer->idx == buffer->len && !mark_set)
    248 return;
    249 
    250      const HBGlyphID16 *replacement;
    251 
    252      replacement = nullptr;
    253      if (Types::extended)
    254      {
    255 if (entry.data.markIndex != 0xFFFF)
    256 {
    257   const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
    258   replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
    259 }
    260      }
    261      else
    262      {
    263 unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
    264 const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
    265 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
    266 if (!(replacement->sanitize (&c->sanitizer) &&
    267       hb_barrier () &&
    268       *replacement))
    269   replacement = nullptr;
    270      }
    271      if (replacement)
    272      {
    273 buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
    274 c->replace_glyph_inplace (mark, *replacement);
    275 ret = true;
    276      }
    277 
    278      replacement = nullptr;
    279      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
    280      if (Types::extended)
    281      {
    282 if (entry.data.currentIndex != 0xFFFF)
    283 {
    284   const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
    285   replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
    286 }
    287      }
    288      else
    289      {
    290 unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
    291 const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
    292 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
    293 if (!(replacement->sanitize (&c->sanitizer) &&
    294       hb_barrier () &&
    295       *replacement))
    296   replacement = nullptr;
    297      }
    298      if (replacement)
    299      {
    300 c->replace_glyph_inplace (idx, *replacement);
    301 ret = true;
    302      }
    303 
    304      if (entry.flags & SetMark)
    305      {
    306 mark_set = true;
    307 mark = buffer->idx;
    308      }
    309    }
    310 
    311    public:
    312    bool ret;
    313    hb_aat_apply_context_t *c;
    314    const ContextualSubtable *table;
    315    private:
    316    bool mark_set;
    317    unsigned int mark;
    318    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
    319  };
    320 
    321  bool apply (hb_aat_apply_context_t *c) const
    322  {
    323    TRACE_APPLY (this);
    324 
    325    driver_context_t dc (this, c);
    326 
    327    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
    328 
    329    driver.drive (&dc, c);
    330 
    331    return_trace (dc.ret);
    332  }
    333 
    334  bool sanitize (hb_sanitize_context_t *c) const
    335  {
    336    TRACE_SANITIZE (this);
    337 
    338    unsigned int num_entries = 0;
    339    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
    340    hb_barrier ();
    341 
    342    if (!Types::extended)
    343      return_trace (substitutionTables.sanitize (c, this, 0));
    344 
    345    unsigned int num_lookups = 0;
    346 
    347    const Entry<EntryData> *entries = machine.get_entries ();
    348    for (unsigned int i = 0; i < num_entries; i++)
    349    {
    350      const EntryData &data = entries[i].data;
    351 
    352      if (data.markIndex != 0xFFFF)
    353 num_lookups = hb_max (num_lookups, 1u + data.markIndex);
    354      if (data.currentIndex != 0xFFFF)
    355 num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
    356    }
    357 
    358    return_trace (substitutionTables.sanitize (c, this, num_lookups));
    359  }
    360 
    361  public:
    362  StateTable<Types, EntryData>
    363 	machine;
    364  protected:
    365  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
    366 	substitutionTables;
    367  public:
    368  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
    369 };
    370 
    371 
    372 template <bool extended>
    373 struct LigatureEntry;
    374 
    375 template <>
    376 struct LigatureEntry<true>
    377 {
    378 
    379  struct EntryData
    380  {
    381    HBUINT16	ligActionIndex;	/* Index to the first ligActionTable entry
    382 			 * for processing this group, if indicated
    383 			 * by the flags. */
    384    public:
    385    DEFINE_SIZE_STATIC (2);
    386  };
    387 
    388  enum Flags
    389  {
    390    SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
    391 				 * eventual processing. */
    392    DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
    393 				   next iteration. */
    394    PerformAction	= 0x2000,	/* Use the ligActionIndex to process a ligature
    395 				 * group. */
    396    Reserved		= 0x1FFF,	/* These bits are reserved and should be set to 0. */
    397  };
    398 
    399  static bool initiateAction (const Entry<EntryData> &entry)
    400  { return entry.flags & SetComponent; }
    401 
    402  static bool performAction (const Entry<EntryData> &entry)
    403  { return entry.flags & PerformAction; }
    404 
    405  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
    406  { return entry.data.ligActionIndex; }
    407 };
    408 template <>
    409 struct LigatureEntry<false>
    410 {
    411  typedef void EntryData;
    412 
    413  enum Flags
    414  {
    415    SetComponent	= 0x8000,	/* Push this glyph onto the component stack for
    416 				 * eventual processing. */
    417    DontAdvance		= 0x4000,	/* Leave the glyph pointer at this glyph for the
    418 				   next iteration. */
    419    Offset		= 0x3FFF,	/* Byte offset from beginning of subtable to the
    420 				 * ligature action list. This value must be a
    421 				 * multiple of 4. */
    422  };
    423 
    424  static bool initiateAction (const Entry<EntryData> &entry)
    425  { return entry.flags & SetComponent; }
    426 
    427  static bool performAction (const Entry<EntryData> &entry)
    428  { return entry.flags & Offset; }
    429 
    430  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
    431  { return entry.flags & Offset; }
    432 };
    433 
    434 
    435 template <typename Types>
    436 struct LigatureSubtable
    437 {
    438  typedef typename Types::HBUINT HBUINT;
    439 
    440  typedef LigatureEntry<Types::extended> LigatureEntryT;
    441  typedef typename LigatureEntryT::EntryData EntryData;
    442 
    443  enum Flags
    444  {
    445    DontAdvance	= LigatureEntryT::DontAdvance,
    446  };
    447 
    448  bool is_action_initiable (const Entry<EntryData> &entry) const
    449  {
    450    return LigatureEntryT::initiateAction (entry);
    451  }
    452  bool is_actionable (const Entry<EntryData> &entry) const
    453  {
    454    return LigatureEntryT::performAction (entry);
    455  }
    456 
    457  struct driver_context_t
    458  {
    459    static constexpr bool in_place = false;
    460    enum LigActionFlags
    461    {
    462      LigActionLast	= 0x80000000,	/* This is the last action in the list. This also
    463 				 * implies storage. */
    464      LigActionStore	= 0x40000000,	/* Store the ligature at the current cumulated index
    465 				 * in the ligature table in place of the marked
    466 				 * (i.e. currently-popped) glyph. */
    467      LigActionOffset	= 0x3FFFFFFF,	/* A 30-bit value which is sign-extended to 32-bits
    468 				 * and added to the glyph ID, resulting in an index
    469 				 * into the component table. */
    470    };
    471 
    472    driver_context_t (const LigatureSubtable *table_,
    473 	      hb_aat_apply_context_t *c_) :
    474 ret (false),
    475 c (c_),
    476 table (table_),
    477 ligAction (table+table->ligAction),
    478 component (table+table->component),
    479 ligature (table+table->ligature),
    480 match_length (0) {}
    481 
    482    void transition (hb_buffer_t *buffer,
    483 	     StateTableDriver<Types, EntryData, Flags> *driver,
    484 	     const Entry<EntryData> &entry)
    485    {
    486      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
    487      if (entry.flags & LigatureEntryT::SetComponent)
    488      {
    489 /* Never mark same index twice, in case DontAdvance was used... */
    490 if (unlikely (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len))
    491   match_length--;
    492 
    493 match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
    494 DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
    495      }
    496 
    497      if (LigatureEntryT::performAction (entry))
    498      {
    499 DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
    500 unsigned int end = buffer->out_len;
    501 
    502 if (unlikely (!match_length))
    503   return;
    504 
    505 if (buffer->idx >= buffer->len)
    506   return; /* TODO Work on previous instead? */
    507 
    508 unsigned int cursor = match_length;
    509 
    510 unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
    511 action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
    512 const HBUINT32 *actionData = &ligAction[action_idx];
    513 
    514 unsigned int ligature_idx = 0;
    515 unsigned int action;
    516 do
    517 {
    518   if (unlikely (!cursor))
    519   {
    520     /* Stack underflow.  Clear the stack. */
    521     DEBUG_MSG (APPLY, nullptr, "Stack underflow");
    522     match_length = 0;
    523     break;
    524   }
    525 
    526   DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
    527   if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
    528 
    529   if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
    530   hb_barrier ();
    531   action = *actionData;
    532 
    533   uint32_t uoffset = action & LigActionOffset;
    534   if (uoffset & 0x20000000)
    535     uoffset |= 0xC0000000; /* Sign-extend. */
    536   int32_t offset = (int32_t) uoffset;
    537   unsigned int component_idx = buffer->cur().codepoint + offset;
    538   component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
    539   const HBUINT16 &componentData = component[component_idx];
    540   if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
    541   hb_barrier ();
    542   ligature_idx += componentData;
    543 
    544   DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
    545 	     bool (action & LigActionStore),
    546 	     bool (action & LigActionLast));
    547   if (action & (LigActionStore | LigActionLast))
    548   {
    549     ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
    550     const HBGlyphID16 &ligatureData = ligature[ligature_idx];
    551     if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
    552     hb_barrier ();
    553     hb_codepoint_t lig = ligatureData;
    554 
    555     DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
    556     if (unlikely (!c->replace_glyph (lig))) return;
    557 
    558     unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
    559     /* Now go and delete all subsequent components. */
    560     while (match_length - 1u > cursor)
    561     {
    562       DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
    563       if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
    564       if (!c->delete_glyph ()) return;
    565     }
    566 
    567     if (unlikely (!buffer->move_to (lig_end))) return;
    568     buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
    569   }
    570 
    571   actionData++;
    572 }
    573 while (!(action & LigActionLast));
    574 if (unlikely (!buffer->move_to (end))) return;
    575      }
    576    }
    577 
    578    public:
    579    bool ret;
    580    hb_aat_apply_context_t *c;
    581    const LigatureSubtable *table;
    582    private:
    583    const UnsizedArrayOf<HBUINT32> &ligAction;
    584    const UnsizedArrayOf<HBUINT16> &component;
    585    const UnsizedArrayOf<HBGlyphID16> &ligature;
    586    unsigned int match_length;
    587    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
    588  };
    589 
    590  bool apply (hb_aat_apply_context_t *c) const
    591  {
    592    TRACE_APPLY (this);
    593 
    594    driver_context_t dc (this, c);
    595 
    596    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
    597 
    598    driver.drive (&dc, c);
    599 
    600    return_trace (dc.ret);
    601  }
    602 
    603  bool sanitize (hb_sanitize_context_t *c) const
    604  {
    605    TRACE_SANITIZE (this);
    606    /* The rest of array sanitizations are done at run-time. */
    607    return_trace (c->check_struct (this) && machine.sanitize (c) &&
    608 	  hb_barrier () &&
    609 	  ligAction && component && ligature);
    610  }
    611 
    612  public:
    613  StateTable<Types, EntryData>
    614 	machine;
    615  protected:
    616  NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
    617 	ligAction;	/* Offset to the ligature action table. */
    618  NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
    619 	component;	/* Offset to the component table. */
    620  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
    621 	ligature;	/* Offset to the actual ligature lists. */
    622  public:
    623  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
    624 };
    625 
    626 template <typename Types>
    627 struct NoncontextualSubtable
    628 {
    629  bool apply (hb_aat_apply_context_t *c) const
    630  {
    631    TRACE_APPLY (this);
    632 
    633    bool ret = false;
    634    unsigned int num_glyphs = c->face->get_num_glyphs ();
    635 
    636    hb_glyph_info_t *info = c->buffer->info;
    637    unsigned int count = c->buffer->len;
    638    // If there's only one range, we already checked the flag.
    639    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
    640    for (unsigned int i = 0; i < count; i++)
    641    {
    642      /* This block copied from StateTableDriver::drive. Keep in sync. */
    643      if (unlikely (last_range))
    644      {
    645 auto *range = last_range;
    646 {
    647   unsigned cluster = info[i].cluster;
    648   while (cluster < range->cluster_first)
    649     range--;
    650   while (cluster > range->cluster_last)
    651     range++;
    652 
    653   last_range = range;
    654 }
    655 if (!(range->flags & c->subtable_flags))
    656   continue;
    657      }
    658 
    659      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
    660      if (replacement)
    661      {
    662 c->replace_glyph_inplace (i, *replacement);
    663 ret = true;
    664      }
    665    }
    666 
    667    return_trace (ret);
    668  }
    669 
    670  template <typename set_t>
    671  void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs) const
    672  {
    673    substitute.collect_glyphs (glyphs, num_glyphs);
    674  }
    675 
    676  bool sanitize (hb_sanitize_context_t *c) const
    677  {
    678    TRACE_SANITIZE (this);
    679    return_trace (substitute.sanitize (c));
    680  }
    681 
    682  protected:
    683  Lookup<HBGlyphID16>	substitute;
    684  public:
    685  DEFINE_SIZE_MIN (2);
    686 };
    687 
    688 template <typename Types>
    689 struct InsertionSubtable
    690 {
    691  typedef typename Types::HBUINT HBUINT;
    692 
    693  struct EntryData
    694  {
    695    HBUINT16	currentInsertIndex;	/* Zero-based index into the insertion glyph table.
    696 				 * The number of glyphs to be inserted is contained
    697 				 * in the currentInsertCount field in the flags.
    698 				 * A value of 0xFFFF indicates no insertion is to
    699 				 * be done. */
    700    HBUINT16	markedInsertIndex;	/* Zero-based index into the insertion glyph table.
    701 				 * The number of glyphs to be inserted is contained
    702 				 * in the markedInsertCount field in the flags.
    703 				 * A value of 0xFFFF indicates no insertion is to
    704 				 * be done. */
    705    public:
    706    DEFINE_SIZE_STATIC (4);
    707  };
    708 
    709  enum Flags
    710  {
    711    SetMark		= 0x8000,     /* If set, mark the current glyph. */
    712    DontAdvance		= 0x4000,     /* If set, don't advance to the next glyph before
    713 			       * going to the new state.  This does not mean
    714 			       * that the glyph pointed to is the same one as
    715 			       * before. If you've made insertions immediately
    716 			       * downstream of the current glyph, the next glyph
    717 			       * processed would in fact be the first one
    718 			       * inserted. */
    719    CurrentIsKashidaLike= 0x2000,     /* If set, and the currentInsertList is nonzero,
    720 			       * then the specified glyph list will be inserted
    721 			       * as a kashida-like insertion, either before or
    722 			       * after the current glyph (depending on the state
    723 			       * of the currentInsertBefore flag). If clear, and
    724 			       * the currentInsertList is nonzero, then the
    725 			       * specified glyph list will be inserted as a
    726 			       * split-vowel-like insertion, either before or
    727 			       * after the current glyph (depending on the state
    728 			       * of the currentInsertBefore flag). */
    729    MarkedIsKashidaLike= 0x1000,      /* If set, and the markedInsertList is nonzero,
    730 			       * then the specified glyph list will be inserted
    731 			       * as a kashida-like insertion, either before or
    732 			       * after the marked glyph (depending on the state
    733 			       * of the markedInsertBefore flag). If clear, and
    734 			       * the markedInsertList is nonzero, then the
    735 			       * specified glyph list will be inserted as a
    736 			       * split-vowel-like insertion, either before or
    737 			       * after the marked glyph (depending on the state
    738 			       * of the markedInsertBefore flag). */
    739    CurrentInsertBefore= 0x0800,      /* If set, specifies that insertions are to be made
    740 			       * to the left of the current glyph. If clear,
    741 			       * they're made to the right of the current glyph. */
    742    MarkedInsertBefore= 0x0400,	      /* If set, specifies that insertions are to be
    743 			       * made to the left of the marked glyph. If clear,
    744 			       * they're made to the right of the marked glyph. */
    745    CurrentInsertCount= 0x3E0,	      /* This 5-bit field is treated as a count of the
    746 			       * number of glyphs to insert at the current
    747 			       * position. Since zero means no insertions, the
    748 			       * largest number of insertions at any given
    749 			       * current location is 31 glyphs. */
    750    MarkedInsertCount= 0x001F,	      /* This 5-bit field is treated as a count of the
    751 			       * number of glyphs to insert at the marked
    752 			       * position. Since zero means no insertions, the
    753 			       * largest number of insertions at any given
    754 			       * marked location is 31 glyphs. */
    755  };
    756 
    757  bool is_action_initiable (const Entry<EntryData> &entry) const
    758  {
    759    return (entry.flags & SetMark);
    760  }
    761  bool is_actionable (const Entry<EntryData> &entry) const
    762  {
    763    return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
    764    (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
    765  }
    766 
    767  struct driver_context_t
    768  {
    769    static constexpr bool in_place = false;
    770 
    771    driver_context_t (const InsertionSubtable *table_,
    772 	      hb_aat_apply_context_t *c_) :
    773 ret (false),
    774 c (c_),
    775 table (table_),
    776 mark (0),
    777 insertionAction (table+table->insertionAction) {}
    778 
    779    void transition (hb_buffer_t *buffer,
    780 	     StateTableDriver<Types, EntryData, Flags> *driver,
    781 	     const Entry<EntryData> &entry)
    782    {
    783      unsigned int flags = entry.flags;
    784 
    785      unsigned mark_loc = buffer->out_len;
    786 
    787      if (entry.data.markedInsertIndex != 0xFFFF)
    788      {
    789 unsigned int count = (flags & MarkedInsertCount);
    790 if (unlikely ((buffer->max_ops -= count) <= 0)) return;
    791 unsigned int start = entry.data.markedInsertIndex;
    792 const HBGlyphID16 *glyphs = &insertionAction[start];
    793 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
    794 hb_barrier ();
    795 
    796 bool before = flags & MarkedInsertBefore;
    797 
    798 unsigned int end = buffer->out_len;
    799 if (unlikely (!buffer->move_to (mark))) return;
    800 
    801 if (buffer->idx < buffer->len && !before)
    802   if (unlikely (!buffer->copy_glyph ())) return;
    803 /* TODO We ignore KashidaLike setting. */
    804 if (unlikely (!c->output_glyphs (count, glyphs))) return;
    805 ret = true;
    806 if (buffer->idx < buffer->len && !before)
    807   buffer->skip_glyph ();
    808 
    809 if (unlikely (!buffer->move_to (end + count))) return;
    810 
    811 buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
    812      }
    813 
    814      if (flags & SetMark)
    815 mark = mark_loc;
    816 
    817      if (entry.data.currentInsertIndex != 0xFFFF)
    818      {
    819 unsigned int count = (flags & CurrentInsertCount) >> 5;
    820 if (unlikely ((buffer->max_ops -= count) <= 0)) return;
    821 unsigned int start = entry.data.currentInsertIndex;
    822 const HBGlyphID16 *glyphs = &insertionAction[start];
    823 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
    824 hb_barrier ();
    825 
    826 bool before = flags & CurrentInsertBefore;
    827 
    828 unsigned int end = buffer->out_len;
    829 
    830 if (buffer->idx < buffer->len && !before)
    831   if (unlikely (!buffer->copy_glyph ())) return;
    832 /* TODO We ignore KashidaLike setting. */
    833 if (unlikely (!c->output_glyphs (count, glyphs))) return;
    834 ret = true;
    835 if (buffer->idx < buffer->len && !before)
    836   buffer->skip_glyph ();
    837 
    838 /* Humm. Not sure where to move to.  There's this wording under
    839  * DontAdvance flag:
    840  *
    841  * "If set, don't update the glyph index before going to the new state.
    842  * This does not mean that the glyph pointed to is the same one as
    843  * before. If you've made insertions immediately downstream of the
    844  * current glyph, the next glyph processed would in fact be the first
    845  * one inserted."
    846  *
    847  * This suggests that if DontAdvance is NOT set, we should move to
    848  * end+count.  If it *was*, then move to end, such that newly inserted
    849  * glyphs are now visible.
    850  *
    851  * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
    852  */
    853 if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
    854      }
    855    }
    856 
    857    public:
    858    bool ret;
    859    hb_aat_apply_context_t *c;
    860    const InsertionSubtable *table;
    861    private:
    862    unsigned int mark;
    863    const UnsizedArrayOf<HBGlyphID16> &insertionAction;
    864  };
    865 
    866  bool apply (hb_aat_apply_context_t *c) const
    867  {
    868    TRACE_APPLY (this);
    869 
    870    driver_context_t dc (this, c);
    871 
    872    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
    873 
    874    driver.drive (&dc, c);
    875 
    876    return_trace (dc.ret);
    877  }
    878 
    879  bool sanitize (hb_sanitize_context_t *c) const
    880  {
    881    TRACE_SANITIZE (this);
    882    /* The rest of array sanitizations are done at run-time. */
    883    return_trace (c->check_struct (this) && machine.sanitize (c) &&
    884 	  hb_barrier () &&
    885 	  insertionAction);
    886  }
    887 
    888  public:
    889  StateTable<Types, EntryData>
    890 	machine;
    891  protected:
    892  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
    893 	insertionAction;	/* Byte offset from stateHeader to the start of
    894 				 * the insertion glyph table. */
    895  public:
    896  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
    897 };
    898 
    899 
    900 struct Feature
    901 {
    902  bool sanitize (hb_sanitize_context_t *c) const
    903  {
    904    TRACE_SANITIZE (this);
    905    return_trace (c->check_struct (this));
    906  }
    907 
    908  public:
    909  HBUINT16	featureType;	/* The type of feature. */
    910  HBUINT16	featureSetting;	/* The feature's setting (aka selector). */
    911  HBUINT32	enableFlags;	/* Flags for the settings that this feature
    912 			 * and setting enables. */
    913  HBUINT32	disableFlags;	/* Complement of flags for the settings that this
    914 			 * feature and setting disable. */
    915 
    916  public:
    917  DEFINE_SIZE_STATIC (12);
    918 };
    919 
    920 
    921 struct hb_accelerate_subtables_context_t :
    922       hb_dispatch_context_t<hb_accelerate_subtables_context_t>
    923 {
    924  struct hb_applicable_t
    925  {
    926    friend struct hb_accelerate_subtables_context_t;
    927    friend struct hb_aat_layout_lookup_accelerator_t;
    928 
    929    public:
    930    hb_bit_set_t glyph_set;
    931    mutable hb_aat_class_cache_t class_cache;
    932 
    933    template <typename T>
    934    auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
    935    (
    936      obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_)
    937    )
    938 
    939    template <typename T>
    940    void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
    941    {
    942      obj_.collect_initial_glyphs (glyph_set, num_glyphs);
    943    }
    944 
    945    template <typename T>
    946    void init (const T &obj_, unsigned num_glyphs)
    947    {
    948      glyph_set.init ();
    949      init_ (obj_, num_glyphs, hb_prioritize);
    950      class_cache.clear ();
    951    }
    952 
    953    void
    954    fini ()
    955    {
    956      glyph_set.fini ();
    957    }
    958  };
    959 
    960  /* Dispatch interface. */
    961  template <typename T>
    962  return_t dispatch (const T &obj)
    963  {
    964    hb_applicable_t *entry = &array[i++];
    965 
    966    entry->init (obj, num_glyphs);
    967 
    968    return hb_empty_t ();
    969  }
    970  static return_t default_return_value () { return hb_empty_t (); }
    971 
    972  bool stop_sublookup_iteration (return_t r) const { return false; }
    973 
    974  hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
    975 			     hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
    976 			     array (array_), num_glyphs (num_glyphs_) {}
    977 
    978  hb_applicable_t *array;
    979  unsigned num_glyphs;
    980  unsigned i = 0;
    981 };
    982 
    983 struct hb_aat_layout_chain_accelerator_t
    984 {
    985  template <typename TChain>
    986  static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
    987  {
    988    unsigned count = chain.get_subtable_count ();
    989 
    990    unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) -
    991 	    HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
    992 	    count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
    993 
    994    /* The following is a calloc because when we are collecting subtables,
    995     * some of them might be invalid and hence not collect; as a result,
    996     * we might not fill in all the count entries of the subtables array.
    997     * Zeroing it allows the set digest to gatekeep it without having to
    998     * initialize it further. */
    999    auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
   1000    if (unlikely (!thiz))
   1001      return nullptr;
   1002 
   1003    thiz->count = count;
   1004 
   1005    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
   1006    chain.dispatch (&c_accelerate_subtables);
   1007 
   1008    return thiz;
   1009  }
   1010 
   1011  void destroy ()
   1012  {
   1013    for (unsigned i = 0; i < count; i++)
   1014      subtables[i].fini ();
   1015  }
   1016 
   1017  unsigned count;
   1018  hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
   1019 };
   1020 
   1021 template <typename Types>
   1022 struct ChainSubtable
   1023 {
   1024  typedef typename Types::HBUINT HBUINT;
   1025 
   1026  template <typename T>
   1027  friend struct Chain;
   1028 
   1029  unsigned int get_size () const     { return length; }
   1030  unsigned int get_type () const     { return coverage & 0xFF; }
   1031  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
   1032 
   1033  enum Coverage
   1034  {
   1035    Vertical		= 0x80,	/* If set, this subtable will only be applied
   1036 			 * to vertical text. If clear, this subtable
   1037 			 * will only be applied to horizontal text. */
   1038    Backwards		= 0x40,	/* If set, this subtable will process glyphs
   1039 			 * in descending order. If clear, it will
   1040 			 * process the glyphs in ascending order. */
   1041    AllDirections	= 0x20,	/* If set, this subtable will be applied to
   1042 			 * both horizontal and vertical text (i.e.
   1043 			 * the state of bit 0x80000000 is ignored). */
   1044    Logical		= 0x10,	/* If set, this subtable will process glyphs
   1045 			 * in logical order (or reverse logical order,
   1046 			 * depending on the value of bit 0x80000000). */
   1047  };
   1048  enum Type
   1049  {
   1050    Rearrangement	= 0,
   1051    Contextual		= 1,
   1052    Ligature		= 2,
   1053    Noncontextual	= 4,
   1054    Insertion		= 5
   1055  };
   1056 
   1057  template <typename context_t, typename ...Ts>
   1058  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   1059  {
   1060    unsigned int subtable_type = get_type ();
   1061    TRACE_DISPATCH (this, subtable_type);
   1062    switch (subtable_type) {
   1063    case Rearrangement:		return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
   1064    case Contextual:		return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
   1065    case Ligature:		return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
   1066    case Noncontextual:		return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
   1067    case Insertion:		return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
   1068    default:			return_trace (c->default_return_value ());
   1069    }
   1070  }
   1071 
   1072  bool apply (hb_aat_apply_context_t *c) const
   1073  {
   1074    TRACE_APPLY (this);
   1075    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
   1076    //hb_sanitize_with_object_t with (&c->sanitizer, this);
   1077    return_trace (dispatch (c));
   1078  }
   1079 
   1080  bool sanitize (hb_sanitize_context_t *c) const
   1081  {
   1082    TRACE_SANITIZE (this);
   1083    if (!(length.sanitize (c) &&
   1084   hb_barrier () &&
   1085   length >= min_size &&
   1086   c->check_range (this, length)))
   1087      return_trace (false);
   1088 
   1089    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
   1090    //hb_sanitize_with_object_t with (c, this);
   1091    return_trace (dispatch (c));
   1092  }
   1093 
   1094  protected:
   1095  HBUINT	length;		/* Total subtable length, including this header. */
   1096  HBUINT	coverage;	/* Coverage flags and subtable type. */
   1097  HBUINT32	subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
   1098  union {
   1099  RearrangementSubtable<Types>	rearrangement;
   1100  ContextualSubtable<Types>	contextual;
   1101  LigatureSubtable<Types>	ligature;
   1102  NoncontextualSubtable<Types>	noncontextual;
   1103  InsertionSubtable<Types>	insertion;
   1104  } u;
   1105  public:
   1106  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
   1107 };
   1108 
   1109 template <typename Types>
   1110 struct Chain
   1111 {
   1112  typedef typename Types::HBUINT HBUINT;
   1113 
   1114  unsigned get_subtable_count () const { return subtableCount; }
   1115 
   1116  hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
   1117  {
   1118    hb_mask_t flags = defaultFlags;
   1119    {
   1120      unsigned int count = featureCount;
   1121      for (unsigned i = 0; i < count; i++)
   1122      {
   1123 const Feature &feature = featureZ[i];
   1124 hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
   1125 hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
   1126      retry:
   1127 // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
   1128 // (The search here only looks at the type and setting fields of feature_info_t.)
   1129 hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
   1130 if (map->current_features.bsearch (info))
   1131 {
   1132   flags &= feature.disableFlags;
   1133   flags |= feature.enableFlags;
   1134 }
   1135 else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
   1136 {
   1137   /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
   1138   type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
   1139   setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
   1140   goto retry;
   1141 }
   1142 #ifndef HB_NO_AAT
   1143 else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
   1144 	 /* TODO: Rudimentary language matching. */
   1145 	 hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
   1146 {
   1147   flags &= feature.disableFlags;
   1148   flags |= feature.enableFlags;
   1149 }
   1150 #endif
   1151      }
   1152    }
   1153    return flags;
   1154  }
   1155 
   1156  void apply (hb_aat_apply_context_t *c,
   1157       const hb_aat_layout_chain_accelerator_t *accel) const
   1158  {
   1159    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
   1160    unsigned int count = subtableCount;
   1161    for (unsigned int i = 0; i < count; i++)
   1162    {
   1163      bool reverse;
   1164 
   1165      auto coverage = subtable->get_coverage ();
   1166 
   1167      hb_mask_t subtable_flags = subtable->subFeatureFlags;
   1168      if (hb_none (hb_iter (c->range_flags) |
   1169 	   hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
   1170 goto skip;
   1171 
   1172      if (!(coverage & ChainSubtable<Types>::AllDirections) &&
   1173   HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
   1174   bool (coverage & ChainSubtable<Types>::Vertical))
   1175 goto skip;
   1176 
   1177      c->subtable_flags = subtable_flags;
   1178      c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
   1179      c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
   1180 
   1181      if (!c->buffer_intersects_machine ())
   1182      {
   1183 (void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
   1184 goto skip;
   1185      }
   1186 
   1187      /* Buffer contents is always in logical direction.  Determine if
   1188       * we need to reverse before applying this subtable.  We reverse
   1189       * back after if we did reverse indeed.
   1190       *
   1191       * Quoting the spac:
   1192       * """
   1193       * Bits 28 and 30 of the coverage field control the order in which
   1194       * glyphs are processed when the subtable is run by the layout engine.
   1195       * Bit 28 is used to indicate if the glyph processing direction is
   1196       * the same as logical order or layout order. Bit 30 is used to
   1197       * indicate whether glyphs are processed forwards or backwards within
   1198       * that order.
   1199 
   1200 	Bit 30	Bit 28	Interpretation for Horizontal Text
   1201 	0	0	The subtable is processed in layout order
   1202 			(the same order as the glyphs, which is
   1203 			always left-to-right).
   1204 	1	0	The subtable is processed in reverse layout order
   1205 			(the order opposite that of the glyphs, which is
   1206 			always right-to-left).
   1207 	0	1	The subtable is processed in logical order
   1208 			(the same order as the characters, which may be
   1209 			left-to-right or right-to-left).
   1210 	1	1	The subtable is processed in reverse logical order
   1211 			(the order opposite that of the characters, which
   1212 			may be right-to-left or left-to-right).
   1213       */
   1214      reverse = coverage & ChainSubtable<Types>::Logical ?
   1215 	bool (coverage & ChainSubtable<Types>::Backwards) :
   1216 	bool (coverage & ChainSubtable<Types>::Backwards) !=
   1217 	HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
   1218 
   1219      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
   1220 goto skip;
   1221 
   1222      if (reverse != c->buffer_is_reversed)
   1223        c->reverse_buffer ();
   1224 
   1225      subtable->apply (c);
   1226 
   1227      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
   1228 
   1229      if (unlikely (!c->buffer->successful)) break;
   1230 
   1231    skip:
   1232      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
   1233      c->set_lookup_index (c->lookup_index + 1);
   1234    }
   1235    if (c->buffer_is_reversed)
   1236      c->reverse_buffer ();
   1237  }
   1238 
   1239  unsigned int get_size () const { return length; }
   1240 
   1241  template <typename context_t, typename ...Ts>
   1242  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   1243  {
   1244    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
   1245    unsigned int count = subtableCount;
   1246    for (unsigned int i = 0; i < count; i++)
   1247    {
   1248      typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
   1249      if (c->stop_sublookup_iteration (ret))
   1250 return ret;
   1251      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
   1252    }
   1253    return c->default_return_value ();
   1254  }
   1255 
   1256  bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
   1257  {
   1258    TRACE_SANITIZE (this);
   1259    if (!(length.sanitize (c) &&
   1260   hb_barrier () &&
   1261   length >= min_size &&
   1262   c->check_range (this, length)))
   1263      return_trace (false);
   1264 
   1265    if (!c->check_array (featureZ.arrayZ, featureCount))
   1266      return_trace (false);
   1267 
   1268    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
   1269    unsigned int count = subtableCount;
   1270    for (unsigned int i = 0; i < count; i++)
   1271    {
   1272      if (!subtable->sanitize (c))
   1273 return_trace (false);
   1274      hb_barrier ();
   1275      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
   1276    }
   1277 
   1278    if (version >= 3)
   1279    {
   1280      const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
   1281      if (!coverage->sanitize (c, count))
   1282        return_trace (false);
   1283    }
   1284 
   1285    return_trace (true);
   1286  }
   1287 
   1288  protected:
   1289  HBUINT32	defaultFlags;	/* The default specification for subtables. */
   1290  HBUINT32	length;		/* Total byte count, including this header. */
   1291  HBUINT	featureCount;	/* Number of feature subtable entries. */
   1292  HBUINT	subtableCount;	/* The number of subtables in the chain. */
   1293 
   1294  UnsizedArrayOf<Feature>	featureZ;	/* Features. */
   1295 /*ChainSubtable	firstSubtable;*//* Subtables. */
   1296 /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
   1297 
   1298  public:
   1299  DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
   1300 };
   1301 
   1302 
   1303 /*
   1304 * The 'mort'/'morx' Table
   1305 */
   1306 
   1307 template <typename T, typename Types, hb_tag_t TAG>
   1308 struct mortmorx
   1309 {
   1310  static constexpr hb_tag_t tableTag = TAG;
   1311 
   1312  bool has_data () const { return version != 0; }
   1313 
   1314  struct accelerator_t
   1315  {
   1316    accelerator_t (hb_face_t *face)
   1317    {
   1318      hb_sanitize_context_t sc;
   1319      this->table = sc.reference_table<T> (face);
   1320 
   1321      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
   1322      {
   1323        hb_blob_destroy (this->table.get_blob ());
   1324        this->table = hb_blob_get_empty ();
   1325      }
   1326 
   1327      this->chain_count = table->get_chain_count ();
   1328 
   1329      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
   1330      if (unlikely (!this->accels))
   1331      {
   1332 this->chain_count = 0;
   1333 this->table.destroy ();
   1334 this->table = hb_blob_get_empty ();
   1335      }
   1336    }
   1337    ~accelerator_t ()
   1338    {
   1339      for (unsigned int i = 0; i < this->chain_count; i++)
   1340      {
   1341 if (this->accels[i])
   1342   this->accels[i]->destroy ();
   1343 hb_free (this->accels[i]);
   1344      }
   1345      hb_free (this->accels);
   1346      this->table.destroy ();
   1347    }
   1348 
   1349    hb_blob_t *get_blob () const { return table.get_blob (); }
   1350 
   1351    template <typename Chain>
   1352    hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
   1353    {
   1354      if (unlikely (chain_index >= chain_count)) return nullptr;
   1355 
   1356    retry:
   1357      auto *accel = accels[chain_index].get_acquire ();
   1358      if (unlikely (!accel))
   1359      {
   1360 accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
   1361 if (unlikely (!accel))
   1362   return nullptr;
   1363 
   1364 if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
   1365 {
   1366   hb_free (accel);
   1367   goto retry;
   1368 }
   1369      }
   1370 
   1371      return accel;
   1372    }
   1373 
   1374    hb_blob_ptr_t<T> table;
   1375    unsigned int chain_count;
   1376    hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
   1377    hb_aat_scratch_t scratch;
   1378  };
   1379 
   1380 
   1381  void compile_flags (const hb_aat_map_builder_t *mapper,
   1382 	      hb_aat_map_t *map) const
   1383  {
   1384    const Chain<Types> *chain = &firstChain;
   1385    unsigned int count = chainCount;
   1386    if (unlikely (!map->chain_flags.resize (count)))
   1387      return;
   1388    for (unsigned int i = 0; i < count; i++)
   1389    {
   1390      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
   1391 						     mapper->range_first,
   1392 						     mapper->range_last});
   1393      chain = &StructAfter<Chain<Types>> (*chain);
   1394    }
   1395  }
   1396 
   1397  unsigned get_chain_count () const
   1398  {
   1399    return chainCount;
   1400  }
   1401  void apply (hb_aat_apply_context_t *c,
   1402       const hb_aat_map_t &map,
   1403       const accelerator_t &accel) const
   1404  {
   1405    if (unlikely (!c->buffer->successful)) return;
   1406 
   1407    c->buffer->unsafe_to_concat ();
   1408 
   1409    c->setup_buffer_glyph_set ();
   1410 
   1411    c->set_lookup_index (0);
   1412    const Chain<Types> *chain = &firstChain;
   1413    unsigned int count = chainCount;
   1414    for (unsigned int i = 0; i < count; i++)
   1415    {
   1416      auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
   1417      c->range_flags = &map.chain_flags[i];
   1418      chain->apply (c, chain_accel);
   1419      if (unlikely (!c->buffer->successful)) return;
   1420      chain = &StructAfter<Chain<Types>> (*chain);
   1421    }
   1422  }
   1423 
   1424  bool sanitize (hb_sanitize_context_t *c) const
   1425  {
   1426    TRACE_SANITIZE (this);
   1427    if (!(version.sanitize (c) &&
   1428   hb_barrier () &&
   1429   version &&
   1430   chainCount.sanitize (c)))
   1431      return_trace (false);
   1432 
   1433    const Chain<Types> *chain = &firstChain;
   1434    unsigned int count = chainCount;
   1435    for (unsigned int i = 0; i < count; i++)
   1436    {
   1437      if (!chain->sanitize (c, version))
   1438 return_trace (false);
   1439      hb_barrier ();
   1440      chain = &StructAfter<Chain<Types>> (*chain);
   1441    }
   1442 
   1443    return_trace (true);
   1444  }
   1445 
   1446  protected:
   1447  HBUINT16	version;	/* Version number of the glyph metamorphosis table.
   1448 			 * 1, 2, or 3. */
   1449  HBUINT16	unused;		/* Set to 0. */
   1450  HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
   1451 			 * table. */
   1452  Chain<Types>	firstChain;	/* Chains. */
   1453 
   1454  public:
   1455  DEFINE_SIZE_MIN (8);
   1456 };
   1457 
   1458 struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx>
   1459 {
   1460  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
   1461                                   hb_face_t *face) const;
   1462 };
   1463 
   1464 struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort>
   1465 {
   1466  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
   1467                                   hb_face_t *face) const;
   1468 };
   1469 
   1470 struct morx_accelerator_t : morx::accelerator_t {
   1471  morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
   1472 };
   1473 struct mort_accelerator_t : mort::accelerator_t {
   1474  mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
   1475 };
   1476 
   1477 
   1478 } /* namespace AAT */
   1479 
   1480 
   1481 #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */