tor-browser

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

GDEF.hh (31999B)


      1 /*
      2 * Copyright © 2007,2008,2009  Red Hat, Inc.
      3 * Copyright © 2010,2011,2012  Google, Inc.
      4 *
      5 *  This is part of HarfBuzz, a text shaping library.
      6 *
      7 * Permission is hereby granted, without written agreement and without
      8 * license or royalty fees, to use, copy, modify, and distribute this
      9 * software and its documentation for any purpose, provided that the
     10 * above copyright notice and the following two paragraphs appear in
     11 * all copies of this software.
     12 *
     13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17 * DAMAGE.
     18 *
     19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24 *
     25 * Red Hat Author(s): Behdad Esfahbod
     26 * Google Author(s): Behdad Esfahbod
     27 */
     28 
     29 #ifndef OT_LAYOUT_GDEF_GDEF_HH
     30 #define OT_LAYOUT_GDEF_GDEF_HH
     31 
     32 #include "../../../hb-ot-var-common.hh"
     33 
     34 #include "../../../hb-font.hh"
     35 #include "../../../hb-cache.hh"
     36 
     37 
     38 namespace OT {
     39 
     40 
     41 /*
     42 * Attachment List Table
     43 */
     44 
     45 /* Array of contour point indices--in increasing numerical order */
     46 struct AttachPoint : Array16Of<HBUINT16>
     47 {
     48  bool subset (hb_subset_context_t *c) const
     49  {
     50    TRACE_SUBSET (this);
     51    auto *out = c->serializer->start_embed (*this);
     52    return_trace (out->serialize (c->serializer, + iter ()));
     53  }
     54 };
     55 
     56 struct AttachList
     57 {
     58  unsigned int get_attach_points (hb_codepoint_t glyph_id,
     59 			  unsigned int start_offset,
     60 			  unsigned int *point_count /* IN/OUT */,
     61 			  unsigned int *point_array /* OUT */) const
     62  {
     63    unsigned int index = (this+coverage).get_coverage (glyph_id);
     64    if (index == NOT_COVERED)
     65    {
     66      if (point_count)
     67 *point_count = 0;
     68      return 0;
     69    }
     70 
     71    const AttachPoint &points = this+attachPoint[index];
     72 
     73    if (point_count)
     74    {
     75      + points.as_array ().sub_array (start_offset, point_count)
     76      | hb_sink (hb_array (point_array, *point_count))
     77      ;
     78    }
     79 
     80    return points.len;
     81  }
     82 
     83  bool subset (hb_subset_context_t *c) const
     84  {
     85    TRACE_SUBSET (this);
     86    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     87    const hb_map_t &glyph_map = *c->plan->glyph_map;
     88 
     89    auto *out = c->serializer->start_embed (*this);
     90    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     91 
     92    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
     93    + hb_zip (this+coverage, attachPoint)
     94    | hb_filter (glyphset, hb_first)
     95    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
     96    | hb_map (hb_first)
     97    | hb_map (glyph_map)
     98    | hb_sink (new_coverage)
     99    ;
    100    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
    101    return_trace (bool (new_coverage));
    102  }
    103 
    104  bool sanitize (hb_sanitize_context_t *c) const
    105  {
    106    TRACE_SANITIZE (this);
    107    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
    108  }
    109 
    110  protected:
    111  Offset16To<Coverage>
    112 	coverage;		/* Offset to Coverage table -- from
    113 				 * beginning of AttachList table */
    114  Array16OfOffset16To<AttachPoint>
    115 	attachPoint;		/* Array of AttachPoint tables
    116 				 * in Coverage Index order */
    117  public:
    118  DEFINE_SIZE_ARRAY (4, attachPoint);
    119 };
    120 
    121 /*
    122 * Ligature Caret Table
    123 */
    124 
    125 struct CaretValueFormat1
    126 {
    127  friend struct CaretValue;
    128  bool subset (hb_subset_context_t *c) const
    129  {
    130    TRACE_SUBSET (this);
    131    auto *out = c->serializer->embed (this);
    132    if (unlikely (!out)) return_trace (false);
    133    return_trace (true);
    134  }
    135 
    136  private:
    137  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
    138  {
    139    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
    140  }
    141 
    142  bool sanitize (hb_sanitize_context_t *c) const
    143  {
    144    TRACE_SANITIZE (this);
    145    return_trace (c->check_struct (this));
    146  }
    147 
    148  protected:
    149  HBUINT16	caretValueFormat;	/* Format identifier--format = 1 */
    150  FWORD		coordinate;		/* X or Y value, in design units */
    151  public:
    152  DEFINE_SIZE_STATIC (4);
    153 };
    154 
    155 struct CaretValueFormat2
    156 {
    157  friend struct CaretValue;
    158  bool subset (hb_subset_context_t *c) const
    159  {
    160    TRACE_SUBSET (this);
    161    auto *out = c->serializer->embed (this);
    162    if (unlikely (!out)) return_trace (false);
    163    return_trace (true);
    164  }
    165 
    166  private:
    167  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
    168  {
    169    hb_position_t x, y;
    170    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
    171    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
    172  }
    173 
    174  bool sanitize (hb_sanitize_context_t *c) const
    175  {
    176    TRACE_SANITIZE (this);
    177    return_trace (c->check_struct (this));
    178  }
    179 
    180  protected:
    181  HBUINT16	caretValueFormat;	/* Format identifier--format = 2 */
    182  HBUINT16	caretValuePoint;	/* Contour point index on glyph */
    183  public:
    184  DEFINE_SIZE_STATIC (4);
    185 };
    186 
    187 struct CaretValueFormat3
    188 {
    189  friend struct CaretValue;
    190 
    191  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
    192 			 const ItemVariationStore &var_store) const
    193  {
    194    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
    195    font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
    196    font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
    197  }
    198 
    199  bool subset (hb_subset_context_t *c) const
    200  {
    201    TRACE_SUBSET (this);
    202    auto *out = c->serializer->start_embed (*this);
    203    if (!c->serializer->embed (caretValueFormat)) return_trace (false);
    204    if (!c->serializer->embed (coordinate)) return_trace (false);
    205 
    206    unsigned varidx = (this+deviceTable).get_variation_index ();
    207    hb_pair_t<unsigned, int> *new_varidx_delta;
    208    if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
    209      uint32_t new_varidx = hb_first (*new_varidx_delta);
    210      int delta = hb_second (*new_varidx_delta);
    211      if (delta != 0)
    212      {
    213        if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
    214          return_trace (false);
    215      }
    216 
    217      if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
    218        return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
    219    }
    220 
    221    if (!c->serializer->embed (deviceTable))
    222      return_trace (false);
    223 
    224    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
    225 					   hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
    226  }
    227 
    228  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
    229  { (this+deviceTable).collect_variation_indices (c); }
    230 
    231  bool sanitize (hb_sanitize_context_t *c) const
    232  {
    233    TRACE_SANITIZE (this);
    234    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
    235  }
    236 
    237  protected:
    238  HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
    239  FWORD		coordinate;		/* X or Y value, in design units */
    240  Offset16To<Device>
    241 	deviceTable;		/* Offset to Device table for X or Y
    242 				 * value--from beginning of CaretValue
    243 				 * table */
    244  public:
    245  DEFINE_SIZE_STATIC (6);
    246 };
    247 
    248 struct CaretValue
    249 {
    250  hb_position_t get_caret_value (hb_font_t *font,
    251 			 hb_direction_t direction,
    252 			 hb_codepoint_t glyph_id,
    253 			 const ItemVariationStore &var_store) const
    254  {
    255    switch (u.format.v) {
    256    case 1: return u.format1.get_caret_value (font, direction);
    257    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
    258    case 3: return u.format3.get_caret_value (font, direction, var_store);
    259    default:return 0;
    260    }
    261  }
    262 
    263  template <typename context_t, typename ...Ts>
    264  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
    265  {
    266    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
    267    TRACE_DISPATCH (this, u.format.v);
    268    switch (u.format.v) {
    269    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
    270    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
    271    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
    272    default:return_trace (c->default_return_value ());
    273    }
    274  }
    275 
    276  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
    277  {
    278    switch (u.format.v) {
    279    case 1:
    280    case 2:
    281      return;
    282    case 3:
    283      u.format3.collect_variation_indices (c);
    284      return;
    285    default: return;
    286    }
    287  }
    288 
    289  bool sanitize (hb_sanitize_context_t *c) const
    290  {
    291    TRACE_SANITIZE (this);
    292    if (!u.format.v.sanitize (c)) return_trace (false);
    293    hb_barrier ();
    294    switch (u.format.v) {
    295    case 1: return_trace (u.format1.sanitize (c));
    296    case 2: return_trace (u.format2.sanitize (c));
    297    case 3: return_trace (u.format3.sanitize (c));
    298    default:return_trace (true);
    299    }
    300  }
    301 
    302  protected:
    303  union {
    304  struct { HBUINT16 v; }	format;		/* Format identifier */
    305  CaretValueFormat1	format1;
    306  CaretValueFormat2	format2;
    307  CaretValueFormat3	format3;
    308  } u;
    309  public:
    310  DEFINE_SIZE_UNION (2, format.v);
    311 };
    312 
    313 struct LigGlyph
    314 {
    315  unsigned get_lig_carets (hb_font_t            *font,
    316 		   hb_direction_t        direction,
    317 		   hb_codepoint_t        glyph_id,
    318 		   const ItemVariationStore &var_store,
    319 		   unsigned              start_offset,
    320 		   unsigned             *caret_count /* IN/OUT */,
    321 		   hb_position_t        *caret_array /* OUT */) const
    322  {
    323    if (caret_count)
    324    {
    325      + carets.as_array ().sub_array (start_offset, caret_count)
    326      | hb_map (hb_add (this))
    327      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
    328      | hb_sink (hb_array (caret_array, *caret_count))
    329      ;
    330    }
    331 
    332    return carets.len;
    333  }
    334 
    335  bool subset (hb_subset_context_t *c) const
    336  {
    337    TRACE_SUBSET (this);
    338    auto *out = c->serializer->start_embed (*this);
    339    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    340 
    341    + hb_iter (carets)
    342    | hb_apply (subset_offset_array (c, out->carets, this))
    343    ;
    344 
    345    return_trace (bool (out->carets));
    346  }
    347 
    348  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
    349  {
    350    for (const Offset16To<CaretValue>& offset : carets.iter ())
    351      (this+offset).collect_variation_indices (c);
    352  }
    353 
    354  bool sanitize (hb_sanitize_context_t *c) const
    355  {
    356    TRACE_SANITIZE (this);
    357    return_trace (carets.sanitize (c, this));
    358  }
    359 
    360  protected:
    361  Array16OfOffset16To<CaretValue>
    362 	carets;			/* Offset array of CaretValue tables
    363 				 * --from beginning of LigGlyph table
    364 				 * --in increasing coordinate order */
    365  public:
    366  DEFINE_SIZE_ARRAY (2, carets);
    367 };
    368 
    369 struct LigCaretList
    370 {
    371  unsigned int get_lig_carets (hb_font_t *font,
    372 		       hb_direction_t direction,
    373 		       hb_codepoint_t glyph_id,
    374 		       const ItemVariationStore &var_store,
    375 		       unsigned int start_offset,
    376 		       unsigned int *caret_count /* IN/OUT */,
    377 		       hb_position_t *caret_array /* OUT */) const
    378  {
    379    unsigned int index = (this+coverage).get_coverage (glyph_id);
    380    if (index == NOT_COVERED)
    381    {
    382      if (caret_count)
    383 *caret_count = 0;
    384      return 0;
    385    }
    386    const LigGlyph &lig_glyph = this+ligGlyph[index];
    387    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
    388  }
    389 
    390  bool subset (hb_subset_context_t *c) const
    391  {
    392    TRACE_SUBSET (this);
    393    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    394    const hb_map_t &glyph_map = *c->plan->glyph_map;
    395 
    396    auto *out = c->serializer->start_embed (*this);
    397    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    398 
    399    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
    400    + hb_zip (this+coverage, ligGlyph)
    401    | hb_filter (glyphset, hb_first)
    402    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
    403    | hb_map (hb_first)
    404    | hb_map (glyph_map)
    405    | hb_sink (new_coverage)
    406    ;
    407    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
    408    return_trace (bool (new_coverage));
    409  }
    410 
    411  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
    412  {
    413    + hb_zip (this+coverage, ligGlyph)
    414    | hb_filter (c->glyph_set, hb_first)
    415    | hb_map (hb_second)
    416    | hb_map (hb_add (this))
    417    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
    418    ;
    419  }
    420 
    421  bool sanitize (hb_sanitize_context_t *c) const
    422  {
    423    TRACE_SANITIZE (this);
    424    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
    425  }
    426 
    427  protected:
    428  Offset16To<Coverage>
    429 	coverage;		/* Offset to Coverage table--from
    430 				 * beginning of LigCaretList table */
    431  Array16OfOffset16To<LigGlyph>
    432 	ligGlyph;		/* Array of LigGlyph tables
    433 				 * in Coverage Index order */
    434  public:
    435  DEFINE_SIZE_ARRAY (4, ligGlyph);
    436 };
    437 
    438 
    439 struct MarkGlyphSetsFormat1
    440 {
    441  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
    442  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
    443 
    444  void collect_used_mark_sets (const hb_set_t& glyph_set,
    445                               hb_set_t& used_mark_sets /* OUT */) const
    446  {
    447    unsigned i = 0;
    448    for (const auto &offset : coverage)
    449     {
    450       const auto &cov = this+offset;
    451       if (cov.intersects (&glyph_set))
    452         used_mark_sets.add (i);
    453 
    454       i++;
    455     }
    456  }
    457 
    458  template <typename set_t>
    459  void collect_coverage (hb_vector_t<set_t> &sets) const
    460  {
    461     for (const auto &offset : coverage)
    462     {
    463       const auto &cov = this+offset;
    464       cov.collect_coverage (sets.push ());
    465     }
    466  }
    467 
    468  bool subset (hb_subset_context_t *c) const
    469  {
    470    TRACE_SUBSET (this);
    471    auto *out = c->serializer->start_embed (*this);
    472    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    473    out->format = format;
    474 
    475    bool ret = true;
    476    for (const Offset32To<Coverage>& offset : coverage.iter ())
    477    {
    478      auto snap = c->serializer->snapshot ();
    479      auto *o = out->coverage.serialize_append (c->serializer);
    480      if (unlikely (!o))
    481      {
    482 ret = false;
    483 break;
    484      }
    485 
    486      //skip empty coverage
    487      c->serializer->push ();
    488      bool res = false;
    489      if (offset) res = c->dispatch (this+offset);
    490      if (!res)
    491      {
    492        c->serializer->pop_discard ();
    493        c->serializer->revert (snap);
    494        (out->coverage.len)--;
    495        continue;
    496      }
    497      c->serializer->add_link (*o, c->serializer->pop_pack ());
    498    }
    499 
    500    return_trace (ret && out->coverage.len);
    501  }
    502 
    503  bool sanitize (hb_sanitize_context_t *c) const
    504  {
    505    TRACE_SANITIZE (this);
    506    return_trace (coverage.sanitize (c, this));
    507  }
    508 
    509  protected:
    510  HBUINT16	format;			/* Format identifier--format = 1 */
    511  Array16Of<Offset32To<Coverage>>
    512 	coverage;		/* Array of long offsets to mark set
    513 				 * coverage tables */
    514  public:
    515  DEFINE_SIZE_ARRAY (4, coverage);
    516 };
    517 
    518 struct MarkGlyphSets
    519 {
    520  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
    521  {
    522    switch (u.format.v) {
    523    case 1: return u.format1.covers (set_index, glyph_id);
    524    default:return false;
    525    }
    526  }
    527 
    528  template <typename set_t>
    529  void collect_coverage (hb_vector_t<set_t> &sets) const
    530  {
    531    switch (u.format.v) {
    532    case 1: u.format1.collect_coverage (sets); return;
    533    default:return;
    534    }
    535  }
    536 
    537  void collect_used_mark_sets (const hb_set_t& glyph_set,
    538                               hb_set_t& used_mark_sets /* OUT */) const
    539  {
    540    switch (u.format.v) {
    541    case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
    542    default:return;
    543    }
    544  }
    545 
    546  bool subset (hb_subset_context_t *c) const
    547  {
    548    TRACE_SUBSET (this);
    549    switch (u.format.v) {
    550    case 1: return_trace (u.format1.subset (c));
    551    default:return_trace (false);
    552    }
    553  }
    554 
    555  bool sanitize (hb_sanitize_context_t *c) const
    556  {
    557    TRACE_SANITIZE (this);
    558    if (!u.format.v.sanitize (c)) return_trace (false);
    559    hb_barrier ();
    560    switch (u.format.v) {
    561    case 1: return_trace (u.format1.sanitize (c));
    562    default:return_trace (true);
    563    }
    564  }
    565 
    566  protected:
    567  union {
    568  struct { HBUINT16 v; }	format;		/* Format identifier */
    569  MarkGlyphSetsFormat1	format1;
    570  } u;
    571  public:
    572  DEFINE_SIZE_UNION (2, format.v);
    573 };
    574 
    575 
    576 /*
    577 * GDEF -- Glyph Definition
    578 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
    579 */
    580 
    581 
    582 template <typename Types>
    583 struct GDEFVersion1_2
    584 {
    585  friend struct GDEF;
    586 
    587  protected:
    588  FixedVersion<>version;		/* Version of the GDEF table--currently
    589 				 * 0x00010003u */
    590  typename Types::template OffsetTo<ClassDef>
    591 	glyphClassDef;		/* Offset to class definition table
    592 				 * for glyph type--from beginning of
    593 				 * GDEF header (may be Null) */
    594  typename Types::template OffsetTo<AttachList>
    595 	attachList;		/* Offset to list of glyphs with
    596 				 * attachment points--from beginning
    597 				 * of GDEF header (may be Null) */
    598  typename Types::template OffsetTo<LigCaretList>
    599 	ligCaretList;		/* Offset to list of positioning points
    600 				 * for ligature carets--from beginning
    601 				 * of GDEF header (may be Null) */
    602  typename Types::template OffsetTo<ClassDef>
    603 	markAttachClassDef;	/* Offset to class definition table for
    604 				 * mark attachment type--from beginning
    605 				 * of GDEF header (may be Null) */
    606  typename Types::template OffsetTo<MarkGlyphSets>
    607 	markGlyphSetsDef;	/* Offset to the table of mark set
    608 				 * definitions--from beginning of GDEF
    609 				 * header (may be NULL).  Introduced
    610 				 * in version 0x00010002. */
    611  Offset32To<ItemVariationStore>
    612 	varStore;		/* Offset to the table of Item Variation
    613 				 * Store--from beginning of GDEF
    614 				 * header (may be NULL).  Introduced
    615 				 * in version 0x00010003. */
    616  public:
    617  DEFINE_SIZE_MIN (4 + 4 * Types::size);
    618 
    619  unsigned int get_size () const
    620  {
    621    return min_size +
    622    (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
    623    (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
    624  }
    625 
    626  bool sanitize (hb_sanitize_context_t *c) const
    627  {
    628    TRACE_SANITIZE (this);
    629    return_trace (version.sanitize (c) &&
    630 	  glyphClassDef.sanitize (c, this) &&
    631 	  attachList.sanitize (c, this) &&
    632 	  ligCaretList.sanitize (c, this) &&
    633 	  markAttachClassDef.sanitize (c, this) &&
    634 	  hb_barrier () &&
    635 	  ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
    636 	  ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
    637  }
    638 
    639  static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
    640                                                hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
    641  {
    642    /* varidx_map is empty which means varstore is empty after instantiation,
    643     * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
    644     * varidx_map doesn't have original varidx, indicating delta row is all
    645     * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
    646    for (auto _ : layout_variation_idx_delta_map.iter_ref ())
    647    {
    648      /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
    649       * varidx is used as key of varidx_map during instantiation */
    650      uint32_t varidx = _.second.first;
    651      uint32_t *new_varidx;
    652      if (varidx_map.has (varidx, &new_varidx))
    653        _.second.first = *new_varidx;
    654      else
    655        _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
    656    }
    657  }
    658 
    659  bool subset (hb_subset_context_t *c) const
    660  {
    661    TRACE_SUBSET (this);
    662    auto *out = c->serializer->start_embed (*this);
    663    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    664 
    665    // Push var store first (if it's needed) so that it's last in the
    666    // serialization order. Some font consumers assume that varstore runs to
    667    // the end of the GDEF table.
    668    // See: https://github.com/harfbuzz/harfbuzz/issues/4636
    669    auto snapshot_version0 = c->serializer->snapshot ();
    670    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
    671      return_trace (false);
    672 
    673    bool subset_varstore = false;
    674    unsigned varstore_index = (unsigned) -1;
    675    auto snapshot_version2 = c->serializer->snapshot ();
    676    if (version.to_int () >= 0x00010003u && hb_barrier ())
    677    {
    678      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
    679      if (c->plan->all_axes_pinned)
    680        out->varStore = 0;
    681      else if (c->plan->normalized_coords)
    682      {
    683        if (varStore)
    684        {
    685          item_variations_t item_vars;
    686          if (item_vars.instantiate (this+varStore, c->plan, true, true,
    687                                     c->plan->gdef_varstore_inner_maps.as_array ())) {
    688            subset_varstore = out->varStore.serialize_serialize (c->serializer,
    689                                                                 item_vars.has_long_word (),
    690                                                                 c->plan->axis_tags,
    691                                                                 item_vars.get_region_list (),
    692                                                                 item_vars.get_vardata_encodings ());
    693            varstore_index = c->serializer->last_added_child_index();
    694          }
    695          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
    696                                            c->plan->layout_variation_idx_delta_map);
    697        }
    698      }
    699      else
    700      {
    701        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
    702        varstore_index = c->serializer->last_added_child_index();
    703      }
    704    }
    705 
    706    out->version.major = version.major;
    707    out->version.minor = version.minor;
    708 
    709    if (!subset_varstore && version.to_int () >= 0x00010002u) {
    710      c->serializer->revert (snapshot_version2);
    711    }
    712 
    713    bool subset_markglyphsetsdef = false;
    714    if (version.to_int () >= 0x00010002u && hb_barrier ())
    715    {
    716      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
    717    }
    718 
    719    if (subset_varstore)
    720    {
    721      out->version.minor = 3;
    722      c->plan->has_gdef_varstore = true;
    723    } else if (subset_markglyphsetsdef) {
    724      out->version.minor = 2;      
    725    } else  {
    726      out->version.minor = 0;
    727      c->serializer->revert (snapshot_version0);
    728    }
    729 
    730    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
    731    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
    732    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
    733    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
    734 
    735    if (subset_varstore && varstore_index != (unsigned) -1) {
    736      c->serializer->repack_last(varstore_index);
    737    }
    738 
    739    return_trace (subset_glyphclassdef || subset_attachlist ||
    740 	  subset_ligcaretlist || subset_markattachclassdef ||
    741 	  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
    742 	  (out->version.to_int () >= 0x00010003u && subset_varstore));
    743  }
    744 };
    745 
    746 struct GDEF
    747 {
    748  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
    749 
    750  enum GlyphClasses {
    751    UnclassifiedGlyph	= 0,
    752    BaseGlyph		= 1,
    753    LigatureGlyph	= 2,
    754    MarkGlyph		= 3,
    755    ComponentGlyph	= 4
    756  };
    757 
    758  unsigned int get_size () const
    759  {
    760    switch (u.version.major) {
    761    case 1: return u.version1.get_size ();
    762 #ifndef HB_NO_BEYOND_64K
    763    case 2: return u.version2.get_size ();
    764 #endif
    765    default: return u.version.static_size;
    766    }
    767  }
    768 
    769  bool sanitize (hb_sanitize_context_t *c) const
    770  {
    771    TRACE_SANITIZE (this);
    772    if (unlikely (!u.version.sanitize (c))) return_trace (false);
    773    hb_barrier ();
    774    switch (u.version.major) {
    775    case 1: return_trace (u.version1.sanitize (c));
    776 #ifndef HB_NO_BEYOND_64K
    777    case 2: return_trace (u.version2.sanitize (c));
    778 #endif
    779    default: return_trace (true);
    780    }
    781  }
    782 
    783  bool subset (hb_subset_context_t *c) const
    784  {
    785    switch (u.version.major) {
    786    case 1: return u.version1.subset (c);
    787 #ifndef HB_NO_BEYOND_64K
    788    case 2: return u.version2.subset (c);
    789 #endif
    790    default: return false;
    791    }
    792  }
    793 
    794  bool has_glyph_classes () const
    795  {
    796    switch (u.version.major) {
    797    case 1: return u.version1.glyphClassDef != 0;
    798 #ifndef HB_NO_BEYOND_64K
    799    case 2: return u.version2.glyphClassDef != 0;
    800 #endif
    801    default: return false;
    802    }
    803  }
    804  const ClassDef &get_glyph_class_def () const
    805  {
    806    switch (u.version.major) {
    807    case 1: return this+u.version1.glyphClassDef;
    808 #ifndef HB_NO_BEYOND_64K
    809    case 2: return this+u.version2.glyphClassDef;
    810 #endif
    811    default: return Null(ClassDef);
    812    }
    813  }
    814  bool has_attach_list () const
    815  {
    816    switch (u.version.major) {
    817    case 1: return u.version1.attachList != 0;
    818 #ifndef HB_NO_BEYOND_64K
    819    case 2: return u.version2.attachList != 0;
    820 #endif
    821    default: return false;
    822    }
    823  }
    824  const AttachList &get_attach_list () const
    825  {
    826    switch (u.version.major) {
    827    case 1: return this+u.version1.attachList;
    828 #ifndef HB_NO_BEYOND_64K
    829    case 2: return this+u.version2.attachList;
    830 #endif
    831    default: return Null(AttachList);
    832    }
    833  }
    834  bool has_lig_carets () const
    835  {
    836    switch (u.version.major) {
    837    case 1: return u.version1.ligCaretList != 0;
    838 #ifndef HB_NO_BEYOND_64K
    839    case 2: return u.version2.ligCaretList != 0;
    840 #endif
    841    default: return false;
    842    }
    843  }
    844  const LigCaretList &get_lig_caret_list () const
    845  {
    846    switch (u.version.major) {
    847    case 1: return this+u.version1.ligCaretList;
    848 #ifndef HB_NO_BEYOND_64K
    849    case 2: return this+u.version2.ligCaretList;
    850 #endif
    851    default: return Null(LigCaretList);
    852    }
    853  }
    854  bool has_mark_attachment_types () const
    855  {
    856    switch (u.version.major) {
    857    case 1: return u.version1.markAttachClassDef != 0;
    858 #ifndef HB_NO_BEYOND_64K
    859    case 2: return u.version2.markAttachClassDef != 0;
    860 #endif
    861    default: return false;
    862    }
    863  }
    864  const ClassDef &get_mark_attach_class_def () const
    865  {
    866    switch (u.version.major) {
    867    case 1: return this+u.version1.markAttachClassDef;
    868 #ifndef HB_NO_BEYOND_64K
    869    case 2: return this+u.version2.markAttachClassDef;
    870 #endif
    871    default: return Null(ClassDef);
    872    }
    873  }
    874  bool has_mark_glyph_sets () const
    875  {
    876    switch (u.version.major) {
    877    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
    878 #ifndef HB_NO_BEYOND_64K
    879    case 2: return u.version2.markGlyphSetsDef != 0;
    880 #endif
    881    default: return false;
    882    }
    883  }
    884  const MarkGlyphSets &get_mark_glyph_sets () const
    885  {
    886    switch (u.version.major) {
    887    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
    888 #ifndef HB_NO_BEYOND_64K
    889    case 2: return this+u.version2.markGlyphSetsDef;
    890 #endif
    891    default: return Null(MarkGlyphSets);
    892    }
    893  }
    894  bool has_var_store () const
    895  {
    896    switch (u.version.major) {
    897    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
    898 #ifndef HB_NO_BEYOND_64K
    899    case 2: return u.version2.varStore != 0;
    900 #endif
    901    default: return false;
    902    }
    903  }
    904  const ItemVariationStore &get_var_store () const
    905  {
    906    switch (u.version.major) {
    907    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
    908 #ifndef HB_NO_BEYOND_64K
    909    case 2: return this+u.version2.varStore;
    910 #endif
    911    default: return Null(ItemVariationStore);
    912    }
    913  }
    914 
    915 
    916  bool has_data () const { return u.version.to_int (); }
    917  unsigned int get_glyph_class (hb_codepoint_t glyph) const
    918  { return get_glyph_class_def ().get_class (glyph); }
    919  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
    920  { get_glyph_class_def ().collect_class (glyphs, klass); }
    921 
    922  unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
    923  { return get_mark_attach_class_def ().get_class (glyph); }
    924 
    925  unsigned int get_attach_points (hb_codepoint_t glyph_id,
    926 			  unsigned int start_offset,
    927 			  unsigned int *point_count /* IN/OUT */,
    928 			  unsigned int *point_array /* OUT */) const
    929  { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
    930 
    931  unsigned int get_lig_carets (hb_font_t *font,
    932 		       hb_direction_t direction,
    933 		       hb_codepoint_t glyph_id,
    934 		       unsigned int start_offset,
    935 		       unsigned int *caret_count /* IN/OUT */,
    936 		       hb_position_t *caret_array /* OUT */) const
    937  { return get_lig_caret_list ().get_lig_carets (font,
    938 					 direction, glyph_id, get_var_store(),
    939 					 start_offset, caret_count, caret_array); }
    940 
    941  bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
    942  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
    943 
    944  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    945   * glyph class and other bits, and high 8-bit the mark attachment type (if any).
    946   * Not to be confused with lookup_props which is very similar. */
    947  unsigned int get_glyph_props (hb_codepoint_t glyph) const
    948  {
    949    unsigned int klass = get_glyph_class (glyph);
    950 
    951    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
    952    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
    953    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
    954 
    955    switch (klass) {
    956    default:			return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
    957    case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
    958    case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
    959    case MarkGlyph:
    960   klass = get_mark_attachment_type (glyph);
    961   return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
    962    }
    963  }
    964 
    965  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
    966 			   hb_face_t *face) const;
    967 
    968  struct accelerator_t
    969  {
    970    accelerator_t (hb_face_t *face)
    971    {
    972      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
    973      if (unlikely (table->is_blocklisted (table.get_blob (), face)))
    974      {
    975 hb_blob_destroy (table.get_blob ());
    976 table = hb_blob_get_empty ();
    977      }
    978 
    979 #ifndef HB_NO_GDEF_CACHE
    980      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
    981 #endif
    982    }
    983    ~accelerator_t () { table.destroy (); }
    984 
    985    unsigned int get_glyph_props (hb_codepoint_t glyph) const
    986    {
    987      unsigned v;
    988 
    989 #ifndef HB_NO_GDEF_CACHE
    990      if (glyph_props_cache.get (glyph, &v))
    991        return v;
    992 #endif
    993 
    994      v = table->get_glyph_props (glyph);
    995 
    996 #ifndef HB_NO_GDEF_CACHE
    997      if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
    998 glyph_props_cache.set (glyph, v);
    999 #endif
   1000 
   1001      return v;
   1002 
   1003    }
   1004 
   1005    bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   1006    {
   1007      return
   1008 #ifndef HB_NO_GDEF_CACHE
   1009      mark_glyph_sets[set_index].may_have (glyph_id)
   1010 #else
   1011      table->mark_set_covers (set_index, glyph_id)
   1012 #endif
   1013      ;
   1014    }
   1015 
   1016    hb_blob_ptr_t<GDEF> table;
   1017 #ifndef HB_NO_GDEF_CACHE
   1018    hb_vector_t<hb_bit_set_t> mark_glyph_sets;
   1019    mutable hb_cache_t<21, 3> glyph_props_cache;
   1020    static_assert (sizeof (glyph_props_cache) == 512, "");
   1021 #endif
   1022  };
   1023 
   1024  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   1025  { get_lig_caret_list ().collect_variation_indices (c); }
   1026 
   1027  protected:
   1028  union {
   1029  FixedVersion<>		version;	/* Version identifier */
   1030  GDEFVersion1_2<SmallTypes>	version1;
   1031 #ifndef HB_NO_BEYOND_64K
   1032  GDEFVersion1_2<MediumTypes>	version2;
   1033 #endif
   1034  } u;
   1035  public:
   1036  DEFINE_SIZE_MIN (4);
   1037 };
   1038 
   1039 struct GDEF_accelerator_t : GDEF::accelerator_t {
   1040  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
   1041 };
   1042 
   1043 } /* namespace OT */
   1044 
   1045 
   1046 #endif /* OT_LAYOUT_GDEF_GDEF_HH */