Coverage Report

Created: 2025-08-29 06:28

/src/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
Line
Count
Source (jump to first uncovered line)
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
0
  {
25
0
    TRACE_SANITIZE (this);
26
0
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
27
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::sanitize(hb_sanitize_context_t*) const
28
29
  bool intersects (const hb_set_t *glyphs) const
30
0
  { return hb_all (component, glyphs); }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::intersects(hb_set_t const*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::intersects(hb_set_t const*) const
31
32
  bool intersects_lig_glyph (const hb_set_t *glyphs) const
33
0
  { return glyphs->has(ligGlyph); }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::intersects_lig_glyph(hb_set_t const*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::intersects_lig_glyph(hb_set_t const*) const
34
35
  void closure (hb_closure_context_t *c) const
36
0
  {
37
0
    if (!intersects (c->glyphs)) return;
38
0
    c->output->add (ligGlyph);
39
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::closure(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::closure(OT::hb_closure_context_t*) const
40
41
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
42
0
  {
43
0
    c->input->add_array (component.arrayZ, component.get_length ());
44
0
    c->output->add (ligGlyph);
45
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
46
47
  template <typename set_t>
48
  void collect_second (set_t &s) const
49
0
  {
50
0
    if (unlikely (!component.get_length ()))
51
0
    {
52
      // A ligature without any components. Anything matches.
53
0
      s = set_t::full ();
54
0
      return;
55
0
    }
56
0
    s.add (component.arrayZ[0]);
57
0
  }
Unexecuted instantiation: void OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::collect_second<hb_set_digest_t>(hb_set_digest_t&) const
Unexecuted instantiation: void OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::collect_second<hb_set_digest_t>(hb_set_digest_t&) const
58
59
  bool would_apply (hb_would_apply_context_t *c) const
60
0
  {
61
0
    if (c->len != component.lenP1)
62
0
      return false;
63
64
0
    for (unsigned int i = 1; i < c->len; i++)
65
0
      if (likely (c->glyphs[i] != component[i]))
66
0
        return false;
67
68
0
    return true;
69
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::would_apply(OT::hb_would_apply_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::would_apply(OT::hb_would_apply_context_t*) const
70
71
  bool apply (hb_ot_apply_context_t *c) const
72
0
  {
73
0
    TRACE_APPLY (this);
74
0
    unsigned int count = component.lenP1;
75
76
0
    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
0
    if (unlikely (count == 1))
81
0
    {
82
83
0
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
84
0
      {
85
0
  c->buffer->sync_so_far ();
86
0
  c->buffer->message (c->font,
87
0
          "replacing glyph at %u (ligature substitution)",
88
0
          c->buffer->idx);
89
0
      }
90
91
0
      c->replace_glyph (ligGlyph);
92
93
0
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
94
0
      {
95
0
  c->buffer->message (c->font,
96
0
          "replaced glyph at %u (ligature substitution)",
97
0
          c->buffer->idx - 1u);
98
0
      }
99
100
0
      return_trace (true);
101
0
    }
102
103
0
    unsigned int total_component_count = 0;
104
105
0
    if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
106
0
    unsigned int match_end = 0;
107
108
0
    if (likely (!match_input (c, count,
109
0
                              &component[1],
110
0
                              match_glyph,
111
0
                              nullptr,
112
0
                              &match_end,
113
0
                              &total_component_count)))
114
0
    {
115
0
      c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
116
0
      return_trace (false);
117
0
    }
118
119
0
    unsigned pos = 0;
120
0
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
121
0
    {
122
0
      unsigned delta = c->buffer->sync_so_far ();
123
124
0
      pos = c->buffer->idx;
125
126
0
      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
127
0
      char *p = buf;
128
129
0
      match_end += delta;
130
0
      for (unsigned i = 0; i < count; i++)
131
0
      {
132
0
  c->match_positions[i] += delta;
133
0
  if (i)
134
0
    *p++ = ',';
135
0
  snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]);
136
0
  p += strlen(p);
137
0
      }
138
139
0
      c->buffer->message (c->font,
140
0
        "ligating glyphs at %s",
141
0
        buf);
142
0
    }
143
144
0
    ligate_input (c,
145
0
                  count,
146
0
                  match_end,
147
0
                  ligGlyph,
148
0
                  total_component_count);
149
150
0
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
151
0
    {
152
0
      c->buffer->sync_so_far ();
153
0
      c->buffer->message (c->font,
154
0
        "ligated glyph at %u",
155
0
        pos);
156
0
    }
157
158
0
    return_trace (true);
159
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::apply(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::apply(OT::hb_ot_apply_context_t*) const
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
0
  {
167
0
    TRACE_SERIALIZE (this);
168
0
    if (unlikely (!c->extend_min (this))) return_trace (false);
169
0
    ligGlyph = ligature;
170
0
    if (unlikely (!component.serialize (c, components))) return_trace (false);
171
0
    return_trace (true);
172
0
  }
Unexecuted instantiation: _ZN2OT6Layout9GSUB_impl8LigatureINS0_10SmallTypesEE9serializeI10hb_array_tIKNS_11HBGlyphID16EETnPN12hb_enable_ifIXsr15hb_is_source_ofIT_jEE5valueEvE4typeELPv0EEEbP22hb_serialize_context_tjSB_
Unexecuted instantiation: _ZN2OT6Layout9GSUB_impl8LigatureINS0_10SmallTypesEE9serializeI13hb_map_iter_tI10hb_array_tIKNS_11HBGlyphID16EERK8hb_map_tL24hb_function_sortedness_t0ELPv0EETnPN12hb_enable_ifIXsr15hb_is_source_ofIT_jEE5valueEvE4typeELSF_0EEEbP22hb_serialize_context_tjSI_
Unexecuted instantiation: _ZN2OT6Layout9GSUB_impl8LigatureINS0_11MediumTypesEE9serializeI13hb_map_iter_tI10hb_array_tIKNS_11HBGlyphID24EERK8hb_map_tL24hb_function_sortedness_t0ELPv0EETnPN12hb_enable_ifIXsr15hb_is_source_ofIT_jEE5valueEvE4typeELSF_0EEEbP22hb_serialize_context_tjSI_
173
174
  bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
175
0
  {
176
0
    TRACE_SUBSET (this);
177
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
178
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
179
0
180
0
    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
181
0
    // Ensure Coverage table is always packed after this.
182
0
    c->serializer->add_virtual_link (coverage_idx);
183
0
184
0
    auto it =
185
0
      + hb_iter (component)
186
0
      | hb_map (glyph_map)
187
0
      ;
188
0
189
0
    auto *out = c->serializer->start_embed (*this);
190
0
    return_trace (out->serialize (c->serializer,
191
0
                                  glyph_map[ligGlyph],
192
0
                                  it));  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::SmallTypes>::subset(hb_subset_context_t*, unsigned int) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Ligature<OT::Layout::MediumTypes>::subset(hb_subset_context_t*, unsigned int) const
193
};
194
195
196
}
197
}
198
}
199
200
#endif  /* OT_LAYOUT_GSUB_LIGATURE_HH */