tor-browser

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

Ligature.hh (5196B)


      1 #ifndef OT_LAYOUT_GSUB_LIGATURE_HH
      2 #define OT_LAYOUT_GSUB_LIGATURE_HH
      3 
      4 #include "Common.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GSUB_impl {
      9 
     10 template <typename Types>
     11 struct Ligature
     12 {
     13  public:
     14  typename Types::HBGlyphID
     15 	ligGlyph;               /* GlyphID of ligature to substitute */
     16  HeadlessArray16Of<typename Types::HBGlyphID>
     17 	component;              /* Array of component GlyphIDs--start
     18                                         * with the second  component--ordered
     19                                         * in writing direction */
     20  public:
     21  DEFINE_SIZE_ARRAY (Types::size + 2, component);
     22 
     23  bool sanitize (hb_sanitize_context_t *c) const
     24  {
     25    TRACE_SANITIZE (this);
     26    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
     27  }
     28 
     29  bool intersects (const hb_set_t *glyphs) const
     30  { return hb_all (component, glyphs); }
     31 
     32  bool intersects_lig_glyph (const hb_set_t *glyphs) const
     33  { return glyphs->has(ligGlyph); }
     34 
     35  void closure (hb_closure_context_t *c) const
     36  {
     37    if (!intersects (c->glyphs)) return;
     38    c->output->add (ligGlyph);
     39  }
     40 
     41  void collect_glyphs (hb_collect_glyphs_context_t *c) const
     42  {
     43    c->input->add_array (component.arrayZ, component.get_length ());
     44    c->output->add (ligGlyph);
     45  }
     46 
     47  template <typename set_t>
     48  void collect_second (set_t &s) const
     49  {
     50    if (unlikely (!component.get_length ()))
     51    {
     52      // A ligature without any components. Anything matches.
     53      s = set_t::full ();
     54      return;
     55    }
     56    s.add (component.arrayZ[0]);
     57  }
     58 
     59  bool would_apply (hb_would_apply_context_t *c) const
     60  {
     61    if (c->len != component.lenP1)
     62      return false;
     63 
     64    for (unsigned int i = 1; i < c->len; i++)
     65      if (likely (c->glyphs[i] != component[i]))
     66        return false;
     67 
     68    return true;
     69  }
     70 
     71  bool apply (hb_ot_apply_context_t *c) const
     72  {
     73    TRACE_APPLY (this);
     74    unsigned int count = component.lenP1;
     75 
     76    if (unlikely (!count)) return_trace (false);
     77 
     78    /* Special-case to make it in-place and not consider this
     79     * as a "ligated" substitution. */
     80    if (unlikely (count == 1))
     81    {
     82 
     83      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     84      {
     85 c->buffer->sync_so_far ();
     86 c->buffer->message (c->font,
     87 		    "replacing glyph at %u (ligature substitution)",
     88 		    c->buffer->idx);
     89      }
     90 
     91      c->replace_glyph (ligGlyph);
     92 
     93      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     94      {
     95 c->buffer->message (c->font,
     96 		    "replaced glyph at %u (ligature substitution)",
     97 		    c->buffer->idx - 1u);
     98      }
     99 
    100      return_trace (true);
    101    }
    102 
    103    unsigned int total_component_count = 0;
    104 
    105    if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
    106    unsigned int match_end = 0;
    107 
    108    if (likely (!match_input (c, count,
    109                              &component[1],
    110                              match_glyph,
    111                              nullptr,
    112                              &match_end,
    113                              &total_component_count)))
    114    {
    115      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
    116      return_trace (false);
    117    }
    118 
    119    unsigned pos = 0;
    120    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    121    {
    122      unsigned delta = c->buffer->sync_so_far ();
    123 
    124      pos = c->buffer->idx;
    125 
    126      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
    127      char *p = buf;
    128 
    129      match_end += delta;
    130      for (unsigned i = 0; i < count; i++)
    131      {
    132 c->match_positions[i] += delta;
    133 if (i)
    134   *p++ = ',';
    135 snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]);
    136 p += strlen(p);
    137      }
    138 
    139      c->buffer->message (c->font,
    140 		  "ligating glyphs at %s",
    141 		  buf);
    142    }
    143 
    144    ligate_input (c,
    145                  count,
    146                  match_end,
    147                  ligGlyph,
    148                  total_component_count);
    149 
    150    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    151    {
    152      c->buffer->sync_so_far ();
    153      c->buffer->message (c->font,
    154 		  "ligated glyph at %u",
    155 		  pos);
    156    }
    157 
    158    return_trace (true);
    159  }
    160 
    161  template <typename Iterator,
    162            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
    163  bool serialize (hb_serialize_context_t *c,
    164                  hb_codepoint_t ligature,
    165                  Iterator components /* Starting from second */)
    166  {
    167    TRACE_SERIALIZE (this);
    168    if (unlikely (!c->extend_min (this))) return_trace (false);
    169    ligGlyph = ligature;
    170    if (unlikely (!component.serialize (c, components))) return_trace (false);
    171    return_trace (true);
    172  }
    173 
    174  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
    175  {
    176    TRACE_SUBSET (this);
    177    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    178    const hb_map_t &glyph_map = *c->plan->glyph_map;
    179 
    180    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
    181    // Ensure Coverage table is always packed after this.
    182    c->serializer->add_virtual_link (coverage_idx);
    183 
    184    auto it =
    185      + hb_iter (component)
    186      | hb_map (glyph_map)
    187      ;
    188 
    189    auto *out = c->serializer->start_embed (*this);
    190    return_trace (out->serialize (c->serializer,
    191                                  glyph_map[ligGlyph],
    192                                  it));  }
    193 };
    194 
    195 
    196 }
    197 }
    198 }
    199 
    200 #endif  /* OT_LAYOUT_GSUB_LIGATURE_HH */