tor-browser

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

SingleSubstFormat1.hh (6996B)


      1 #ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
      2 #define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH
      3 
      4 #include "Common.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GSUB_impl {
      9 
     10 template <typename Types>
     11 struct SingleSubstFormat1_3
     12 {
     13  protected:
     14  HBUINT16      format;                 /* Format identifier--format = 1 */
     15  typename Types::template OffsetTo<Coverage>
     16                coverage;               /* Offset to Coverage table--from
     17                                         * beginning of Substitution table */
     18  typename Types::HBUINT
     19                deltaGlyphID;           /* Add to original GlyphID to get
     20                                         * substitute GlyphID, modulo 0x10000 */
     21 
     22  public:
     23  DEFINE_SIZE_STATIC (2 + 2 * Types::size);
     24 
     25  bool sanitize (hb_sanitize_context_t *c) const
     26  {
     27    TRACE_SANITIZE (this);
     28    return_trace (c->check_struct (this) &&
     29                  coverage.sanitize (c, this) &&
     30                  /* The coverage  table may use a range to represent a set
     31                   * of glyphs, which means a small number of bytes can
     32                   * generate a large glyph set. Manually modify the
     33                   * sanitizer max ops to take this into account.
     34                   *
     35                   * Note: This check *must* be right after coverage sanitize. */
     36                  c->check_ops ((this + coverage).get_population () >> 1));
     37  }
     38 
     39  hb_codepoint_t get_mask () const
     40  { return (1 << (8 * Types::size)) - 1; }
     41 
     42  bool intersects (const hb_set_t *glyphs) const
     43  { return (this+coverage).intersects (glyphs); }
     44 
     45  bool may_have_non_1to1 () const
     46  { return false; }
     47 
     48  void closure (hb_closure_context_t *c) const
     49  {
     50    hb_codepoint_t d = deltaGlyphID;
     51    hb_codepoint_t mask = get_mask ();
     52 
     53    /* Help fuzzer avoid this function as much. */
     54    unsigned pop = (this+coverage).get_population ();
     55    if (pop >= mask)
     56      return;
     57 
     58    hb_set_t intersection;
     59    (this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
     60 
     61    /* In degenerate fuzzer-found fonts, but not real fonts,
     62     * this table can keep adding new glyphs in each round of closure.
     63     * Refuse to close-over, if it maps glyph range to overlapping range. */
     64    hb_codepoint_t min_before = intersection.get_min ();
     65    hb_codepoint_t max_before = intersection.get_max ();
     66    hb_codepoint_t min_after = (min_before + d) & mask;
     67    hb_codepoint_t max_after = (max_before + d) & mask;
     68    if (intersection.get_population () == max_before - min_before + 1 &&
     69 ((min_before <= min_after && min_after <= max_before) ||
     70  (min_before <= max_after && max_after <= max_before)))
     71      return;
     72 
     73    + hb_iter (intersection)
     74    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     75    | hb_sink (c->output)
     76    ;
     77  }
     78 
     79  void closure_lookups (hb_closure_lookups_context_t *c) const {}
     80 
     81  void collect_glyphs (hb_collect_glyphs_context_t *c) const
     82  {
     83    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
     84    hb_codepoint_t d = deltaGlyphID;
     85    hb_codepoint_t mask = get_mask ();
     86 
     87    + hb_iter (this+coverage)
     88    | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
     89    | hb_sink (c->output)
     90    ;
     91  }
     92 
     93  const Coverage &get_coverage () const { return this+coverage; }
     94 
     95  bool would_apply (hb_would_apply_context_t *c) const
     96  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
     97 
     98  unsigned
     99  get_glyph_alternates (hb_codepoint_t  glyph_id,
    100                        unsigned        start_offset,
    101                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
    102                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
    103  {
    104    unsigned int index = (this+coverage).get_coverage (glyph_id);
    105    if (likely (index == NOT_COVERED))
    106    {
    107      if (alternate_count)
    108        *alternate_count = 0;
    109      return 0;
    110    }
    111 
    112    if (alternate_count && *alternate_count)
    113    {
    114      hb_codepoint_t d = deltaGlyphID;
    115      hb_codepoint_t mask = get_mask ();
    116 
    117      glyph_id = (glyph_id + d) & mask;
    118 
    119      *alternate_glyphs = glyph_id;
    120      *alternate_count = 1;
    121    }
    122 
    123    return 1;
    124  }
    125 
    126  void
    127  collect_glyph_alternates (hb_map_t  *alternate_count /* IN/OUT */,
    128 		    hb_map_t  *alternate_glyphs /* IN/OUT */) const
    129  {
    130    hb_codepoint_t d = deltaGlyphID;
    131    hb_codepoint_t mask = get_mask ();
    132 
    133    + hb_iter (this+coverage)
    134    | hb_map ([d, mask] (hb_codepoint_t g) { return hb_pair (g, (g + d) & mask); })
    135    | hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
    136 	{ _hb_collect_glyph_alternates_add (p.first, p.second,
    137 					    alternate_count, alternate_glyphs); })
    138    ;
    139  }
    140 
    141  bool apply (hb_ot_apply_context_t *c) const
    142  {
    143    TRACE_APPLY (this);
    144    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
    145    unsigned int index = (this+coverage).get_coverage (glyph_id);
    146    if (index == NOT_COVERED) return_trace (false);
    147 
    148    hb_codepoint_t d = deltaGlyphID;
    149    hb_codepoint_t mask = get_mask ();
    150 
    151    glyph_id = (glyph_id + d) & mask;
    152 
    153    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    154    {
    155      c->buffer->sync_so_far ();
    156      c->buffer->message (c->font,
    157 		  "replacing glyph at %u (single substitution)",
    158 		  c->buffer->idx);
    159    }
    160 
    161    c->replace_glyph (glyph_id);
    162 
    163    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    164    {
    165      c->buffer->message (c->font,
    166 		  "replaced glyph at %u (single substitution)",
    167 		  c->buffer->idx - 1u);
    168    }
    169 
    170    return_trace (true);
    171  }
    172 
    173  template<typename Iterator,
    174           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
    175  bool serialize (hb_serialize_context_t *c,
    176                  Iterator glyphs,
    177                  unsigned delta)
    178  {
    179    TRACE_SERIALIZE (this);
    180    if (unlikely (!c->extend_min (this))) return_trace (false);
    181    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
    182    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
    183    return_trace (true);
    184  }
    185 
    186  bool subset (hb_subset_context_t *c) const
    187  {
    188    TRACE_SUBSET (this);
    189    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    190    const hb_map_t &glyph_map = *c->plan->glyph_map;
    191 
    192    hb_codepoint_t d = deltaGlyphID;
    193    hb_codepoint_t mask = get_mask ();
    194 
    195    hb_set_t intersection;
    196    (this+coverage).intersect_set (glyphset, intersection);
    197 
    198    auto it =
    199    + hb_iter (intersection)
    200    | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
    201                                return hb_codepoint_pair_t (g,
    202                                                            (g + d) & mask); })
    203    | hb_filter (glyphset, hb_second)
    204    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
    205                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
    206    ;
    207 
    208    bool ret = bool (it);
    209    SingleSubst_serialize (c->serializer, it);
    210    return_trace (ret);
    211  }
    212 };
    213 
    214 }
    215 }
    216 }
    217 
    218 
    219 #endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */