Coverage Report

Created: 2026-11-12 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
Line
Count
Source
1
#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
2
#define OT_LAYOUT_GSUB_SEQUENCE_HH
3
4
#include "Common.hh"
5
6
namespace OT {
7
namespace Layout {
8
namespace GSUB_impl {
9
10
template <typename Types>
11
struct Sequence
12
{
13
  protected:
14
  Array16Of<typename Types::HBGlyphID>
15
                substitute;             /* String of GlyphIDs to substitute */
16
  public:
17
  DEFINE_SIZE_ARRAY (2, substitute);
18
19
  bool sanitize (hb_sanitize_context_t *c) const
20
48.1k
  {
21
48.1k
    TRACE_SANITIZE (this);
22
48.1k
    return_trace (substitute.sanitize (c));
23
48.1k
  }
OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
20
47.8k
  {
21
47.8k
    TRACE_SANITIZE (this);
22
47.8k
    return_trace (substitute.sanitize (c));
23
47.8k
  }
OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
20
385
  {
21
385
    TRACE_SANITIZE (this);
22
385
    return_trace (substitute.sanitize (c));
23
385
  }
24
25
  bool intersects (const hb_set_t *glyphs) const
26
0
  { return hb_all (substitute, glyphs); }
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::intersects(hb_set_t const*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::intersects(hb_set_t const*) const
27
28
  void closure (hb_closure_context_t *c) const
29
0
  {
30
0
    if (unlikely (!c->spend_budget (HB_BUDGET_1, substitute.len))) return;
31
0
    c->output->add_array (substitute.arrayZ, substitute.len);
32
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::closure(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::closure(OT::hb_closure_context_t*) const
33
34
  void depend (hb_depend_context_t *c, hb_codepoint_t source) const
35
0
  {
36
0
    + hb_iter (substitute)
37
0
    | hb_apply ([&] (const hb_codepoint_t &target) { c->depend_data->add_gsub_lookup (source, c->lookup_index, target); })
38
0
    ;
39
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::depend(OT::hb_depend_context_t*, unsigned int) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::depend(OT::hb_depend_context_t*, unsigned int) const
40
41
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
42
0
  { c->output->add_array (substitute.arrayZ, substitute.len); }
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
43
44
  bool apply (hb_ot_apply_context_t *c) const
45
4.51M
  {
46
4.51M
    TRACE_APPLY (this);
47
4.51M
    unsigned int count = substitute.len;
48
49
    /* Special-case to make it in-place and not consider this
50
     * as a "multiplied" substitution. */
51
4.51M
    if (unlikely (count == 1))
52
1.67k
    {
53
1.67k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
54
0
      {
55
0
  c->buffer->sync_so_far ();
56
0
  c->buffer->message (c->font,
57
0
          "replacing glyph at %u (multiple substitution)",
58
0
          c->buffer->idx);
59
0
      }
60
61
1.67k
      c->replace_glyph (substitute.arrayZ[0]);
62
63
1.67k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
64
0
      {
65
0
  c->buffer->message (c->font,
66
0
          "replaced glyph at %u (multiple substitution)",
67
0
          c->buffer->idx - 1u);
68
0
      }
69
70
1.67k
      return_trace (true);
71
1.67k
    }
72
    /* Spec disallows this, but Uniscribe allows it.
73
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
74
4.51M
    else if (unlikely (count == 0))
75
1.77M
    {
76
1.77M
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
77
0
      {
78
0
  c->buffer->sync_so_far ();
79
0
  c->buffer->message (c->font,
80
0
          "deleting glyph at %u (multiple substitution)",
81
0
          c->buffer->idx);
82
0
      }
83
84
1.77M
      c->buffer->delete_glyph ();
85
86
1.77M
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
87
0
      {
88
0
  c->buffer->sync_so_far ();
89
0
  c->buffer->message (c->font,
90
0
          "deleted glyph at %u (multiple substitution)",
91
0
          c->buffer->idx);
92
0
      }
93
94
1.77M
      return_trace (true);
95
1.77M
    }
96
97
2.73M
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
98
0
    {
99
0
      c->buffer->sync_so_far ();
100
0
      c->buffer->message (c->font,
101
0
        "multiplying glyph at %u",
102
0
        c->buffer->idx);
103
0
    }
104
105
2.73M
    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
106
2.71M
                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
107
2.73M
    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
108
109
72.9M
    for (unsigned int i = 0; i < count; i++)
110
70.1M
    {
111
      /* If is attached to a ligature, don't disturb that.
112
       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
113
70.1M
      if (!lig_id)
114
68.8M
        _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
115
70.1M
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
116
70.1M
    }
117
2.73M
    c->buffer->skip_glyph ();
118
119
2.73M
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
120
0
    {
121
0
      c->buffer->sync_so_far ();
122
123
0
      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
124
0
      char *p = buf;
125
126
0
      for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
127
0
      {
128
0
  if (buf < p && sizeof(buf) - 1u > unsigned (p - buf))
129
0
    *p++ = ',';
130
0
  snprintf (p, sizeof(buf) - (p - buf), "%u", i);
131
0
  p += strlen(p);
132
0
      }
133
134
0
      c->buffer->message (c->font,
135
0
        "multiplied glyphs at %s",
136
0
        buf);
137
0
    }
138
139
2.73M
    return_trace (true);
140
4.51M
  }
OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::apply(OT::hb_ot_apply_context_t*) const
Line
Count
Source
45
4.50M
  {
46
4.50M
    TRACE_APPLY (this);
47
4.50M
    unsigned int count = substitute.len;
48
49
    /* Special-case to make it in-place and not consider this
50
     * as a "multiplied" substitution. */
51
4.50M
    if (unlikely (count == 1))
52
666
    {
53
666
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
54
0
      {
55
0
  c->buffer->sync_so_far ();
56
0
  c->buffer->message (c->font,
57
0
          "replacing glyph at %u (multiple substitution)",
58
0
          c->buffer->idx);
59
0
      }
60
61
666
      c->replace_glyph (substitute.arrayZ[0]);
62
63
666
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
64
0
      {
65
0
  c->buffer->message (c->font,
66
0
          "replaced glyph at %u (multiple substitution)",
67
0
          c->buffer->idx - 1u);
68
0
      }
69
70
666
      return_trace (true);
71
666
    }
72
    /* Spec disallows this, but Uniscribe allows it.
73
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
74
4.50M
    else if (unlikely (count == 0))
75
1.77M
    {
76
1.77M
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
77
0
      {
78
0
  c->buffer->sync_so_far ();
79
0
  c->buffer->message (c->font,
80
0
          "deleting glyph at %u (multiple substitution)",
81
0
          c->buffer->idx);
82
0
      }
83
84
1.77M
      c->buffer->delete_glyph ();
85
86
1.77M
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
87
0
      {
88
0
  c->buffer->sync_so_far ();
89
0
  c->buffer->message (c->font,
90
0
          "deleted glyph at %u (multiple substitution)",
91
0
          c->buffer->idx);
92
0
      }
93
94
1.77M
      return_trace (true);
95
1.77M
    }
96
97
2.73M
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
98
0
    {
99
0
      c->buffer->sync_so_far ();
100
0
      c->buffer->message (c->font,
101
0
        "multiplying glyph at %u",
102
0
        c->buffer->idx);
103
0
    }
104
105
2.73M
    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
106
2.70M
                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
107
2.73M
    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
108
109
72.1M
    for (unsigned int i = 0; i < count; i++)
110
69.3M
    {
111
      /* If is attached to a ligature, don't disturb that.
112
       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
113
69.3M
      if (!lig_id)
114
68.0M
        _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
115
69.3M
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
116
69.3M
    }
117
2.73M
    c->buffer->skip_glyph ();
118
119
2.73M
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
120
0
    {
121
0
      c->buffer->sync_so_far ();
122
123
0
      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
124
0
      char *p = buf;
125
126
0
      for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
127
0
      {
128
0
  if (buf < p && sizeof(buf) - 1u > unsigned (p - buf))
129
0
    *p++ = ',';
130
0
  snprintf (p, sizeof(buf) - (p - buf), "%u", i);
131
0
  p += strlen(p);
132
0
      }
133
134
0
      c->buffer->message (c->font,
135
0
        "multiplied glyphs at %s",
136
0
        buf);
137
0
    }
138
139
2.73M
    return_trace (true);
140
4.50M
  }
OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::apply(OT::hb_ot_apply_context_t*) const
Line
Count
Source
45
7.11k
  {
46
7.11k
    TRACE_APPLY (this);
47
7.11k
    unsigned int count = substitute.len;
48
49
    /* Special-case to make it in-place and not consider this
50
     * as a "multiplied" substitution. */
51
7.11k
    if (unlikely (count == 1))
52
1.00k
    {
53
1.00k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
54
0
      {
55
0
  c->buffer->sync_so_far ();
56
0
  c->buffer->message (c->font,
57
0
          "replacing glyph at %u (multiple substitution)",
58
0
          c->buffer->idx);
59
0
      }
60
61
1.00k
      c->replace_glyph (substitute.arrayZ[0]);
62
63
1.00k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
64
0
      {
65
0
  c->buffer->message (c->font,
66
0
          "replaced glyph at %u (multiple substitution)",
67
0
          c->buffer->idx - 1u);
68
0
      }
69
70
1.00k
      return_trace (true);
71
1.00k
    }
72
    /* Spec disallows this, but Uniscribe allows it.
73
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
74
6.11k
    else if (unlikely (count == 0))
75
2.43k
    {
76
2.43k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
77
0
      {
78
0
  c->buffer->sync_so_far ();
79
0
  c->buffer->message (c->font,
80
0
          "deleting glyph at %u (multiple substitution)",
81
0
          c->buffer->idx);
82
0
      }
83
84
2.43k
      c->buffer->delete_glyph ();
85
86
2.43k
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
87
0
      {
88
0
  c->buffer->sync_so_far ();
89
0
  c->buffer->message (c->font,
90
0
          "deleted glyph at %u (multiple substitution)",
91
0
          c->buffer->idx);
92
0
      }
93
94
2.43k
      return_trace (true);
95
2.43k
    }
96
97
3.67k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
98
0
    {
99
0
      c->buffer->sync_so_far ();
100
0
      c->buffer->message (c->font,
101
0
        "multiplying glyph at %u",
102
0
        c->buffer->idx);
103
0
    }
104
105
3.67k
    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
106
3.67k
                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
107
3.67k
    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
108
109
818k
    for (unsigned int i = 0; i < count; i++)
110
814k
    {
111
      /* If is attached to a ligature, don't disturb that.
112
       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
113
814k
      if (!lig_id)
114
791k
        _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
115
814k
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
116
814k
    }
117
3.67k
    c->buffer->skip_glyph ();
118
119
3.67k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
120
0
    {
121
0
      c->buffer->sync_so_far ();
122
123
0
      char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
124
0
      char *p = buf;
125
126
0
      for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
127
0
      {
128
0
  if (buf < p && sizeof(buf) - 1u > unsigned (p - buf))
129
0
    *p++ = ',';
130
0
  snprintf (p, sizeof(buf) - (p - buf), "%u", i);
131
0
  p += strlen(p);
132
0
      }
133
134
0
      c->buffer->message (c->font,
135
0
        "multiplied glyphs at %s",
136
0
        buf);
137
0
    }
138
139
3.67k
    return_trace (true);
140
7.11k
  }
141
142
  template <typename Iterator,
143
            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
144
  bool serialize (hb_serialize_context_t *c,
145
                  Iterator subst)
146
0
  {
147
0
    TRACE_SERIALIZE (this);
148
0
    return_trace (substitute.serialize (c, subst));
149
0
  }
Unexecuted instantiation: _ZN2OT6Layout9GSUB_impl8SequenceINS0_10SmallTypesEE9serializeI13hb_map_iter_tI10hb_array_tIKNS_11HBGlyphID16EERK8hb_map_tL24hb_function_sortedness_t0ELPv0EETnPNSt3__19enable_ifIXsr15hb_is_source_ofIT_jEE5valueEvE4typeELSF_0EEEbP22hb_serialize_context_tSJ_
Unexecuted instantiation: _ZN2OT6Layout9GSUB_impl8SequenceINS0_11MediumTypesEE9serializeI13hb_map_iter_tI10hb_array_tIKNS_11HBGlyphID24EERK8hb_map_tL24hb_function_sortedness_t0ELPv0EETnPNSt3__19enable_ifIXsr15hb_is_source_ofIT_jEE5valueEvE4typeELSF_0EEEbP22hb_serialize_context_tSJ_
150
151
  bool subset (hb_subset_context_t *c) const
152
0
  {
153
0
    TRACE_SUBSET (this);
154
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
155
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
156
0
157
0
    if (!intersects (&glyphset)) return_trace (false);
158
0
159
0
    auto it =
160
0
    + hb_iter (substitute)
161
0
    | hb_map (glyph_map)
162
0
    ;
163
0
164
0
    auto *out = c->serializer->start_embed (*this);
165
0
    return_trace (out->serialize (c->serializer, it));
166
0
  }
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::SmallTypes>::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::Layout::GSUB_impl::Sequence<OT::Layout::MediumTypes>::subset(hb_subset_context_t*) const
167
};
168
169
170
}
171
}
172
}
173
174
175
#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */