tor-browser

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

AlternateSet.hh (4065B)


      1 #ifndef OT_LAYOUT_GSUB_ALTERNATESET_HH
      2 #define OT_LAYOUT_GSUB_ALTERNATESET_HH
      3 
      4 #include "Common.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GSUB_impl {
      9 
     10 template <typename Types>
     11 struct AlternateSet
     12 {
     13  protected:
     14  Array16Of<typename Types::HBGlyphID>
     15                alternates;             /* Array of alternate GlyphIDs--in
     16                                         * arbitrary order */
     17  public:
     18  DEFINE_SIZE_ARRAY (2, alternates);
     19 
     20  bool sanitize (hb_sanitize_context_t *c) const
     21  {
     22    TRACE_SANITIZE (this);
     23    return_trace (alternates.sanitize (c));
     24  }
     25 
     26  bool intersects (const hb_set_t *glyphs) const
     27  { return hb_any (alternates, glyphs); }
     28 
     29  void closure (hb_closure_context_t *c) const
     30  { c->output->add_array (alternates.arrayZ, alternates.len); }
     31 
     32  void collect_glyphs (hb_collect_glyphs_context_t *c) const
     33  { c->output->add_array (alternates.arrayZ, alternates.len); }
     34 
     35  bool apply (hb_ot_apply_context_t *c) const
     36  {
     37    TRACE_APPLY (this);
     38    unsigned int count = alternates.len;
     39 
     40    if (unlikely (!count)) return_trace (false);
     41 
     42    hb_mask_t glyph_mask = c->buffer->cur().mask;
     43    hb_mask_t lookup_mask = c->lookup_mask;
     44 
     45    /* Note: This breaks badly if two features enabled this lookup together. */
     46    unsigned int shift = hb_ctz (lookup_mask);
     47    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
     48 
     49    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
     50    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
     51    {
     52      /* Maybe we can do better than unsafe-to-break all; but since we are
     53       * changing random state, it would be hard to track that.  Good 'nough. */
     54      c->buffer->unsafe_to_break (0, c->buffer->len);
     55      alt_index = c->random_number () % count + 1;
     56    }
     57 
     58    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
     59 
     60    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     61    {
     62      c->buffer->sync_so_far ();
     63      c->buffer->message (c->font,
     64 		  "replacing glyph at %u (alternate substitution)",
     65 		  c->buffer->idx);
     66    }
     67 
     68    c->replace_glyph (alternates[alt_index - 1]);
     69 
     70    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     71    {
     72      c->buffer->message (c->font,
     73 		  "replaced glyph at %u (alternate substitution)",
     74 		  c->buffer->idx - 1u);
     75    }
     76 
     77    return_trace (true);
     78  }
     79 
     80  unsigned
     81  get_alternates (unsigned        start_offset,
     82                  unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
     83                  hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
     84  {
     85    if (alternates.len && alternate_count)
     86    {
     87      + alternates.as_array ().sub_array (start_offset, alternate_count)
     88      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
     89      ;
     90    }
     91    return alternates.len;
     92  }
     93 
     94  void
     95  collect_alternates (hb_codepoint_t gid,
     96 	      hb_map_t  *alternate_count /* IN/OUT */,
     97 	      hb_map_t  *alternate_glyphs /* IN/OUT */) const
     98  {
     99    + hb_enumerate (alternates)
    100    | hb_map ([gid] (hb_pair_t<unsigned, hb_codepoint_t> _) { return hb_pair (gid + (_.first << 24), _.second); })
    101    | hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
    102 	{ _hb_collect_glyph_alternates_add (p.first, p.second,
    103 					    alternate_count, alternate_glyphs); })
    104    ;
    105  }
    106 
    107  template <typename Iterator,
    108            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
    109  bool serialize (hb_serialize_context_t *c,
    110                  Iterator alts)
    111  {
    112    TRACE_SERIALIZE (this);
    113    return_trace (alternates.serialize (c, alts));
    114  }
    115 
    116  bool subset (hb_subset_context_t *c) const
    117  {
    118    TRACE_SUBSET (this);
    119    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    120    const hb_map_t &glyph_map = *c->plan->glyph_map;
    121 
    122    auto it =
    123      + hb_iter (alternates)
    124      | hb_filter (glyphset)
    125      | hb_map (glyph_map)
    126      ;
    127 
    128    auto *out = c->serializer->start_embed (*this);
    129    return_trace (out->serialize (c->serializer, it) &&
    130                  out->alternates);
    131  }
    132 };
    133 
    134 }
    135 }
    136 }
    137 
    138 
    139 #endif /* OT_LAYOUT_GSUB_ALTERNATESET_HH */