Coverage Report

Created: 2025-07-18 07:04

/src/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
Line
Count
Source (jump to first uncovered line)
1
#ifndef OT_LAYOUT_GPOS_PAIRSET_HH
2
#define OT_LAYOUT_GPOS_PAIRSET_HH
3
4
#include "PairValueRecord.hh"
5
6
namespace OT {
7
namespace Layout {
8
namespace GPOS_impl {
9
10
11
template <typename Types>
12
struct PairSet : ValueBase
13
{
14
  template <typename Types2>
15
  friend struct PairPosFormat1_3;
16
17
  using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
18
19
  protected:
20
  HBUINT16              len;    /* Number of PairValueRecords */
21
  PairValueRecord       firstPairValueRecord;
22
                                /* Array of PairValueRecords--ordered
23
                                 * by GlyphID of the second glyph */
24
  public:
25
  DEFINE_SIZE_MIN (2);
26
27
  static unsigned get_size (unsigned len1, unsigned len2)
28
360k
  {
29
360k
    return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
30
360k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::get_size(unsigned int, unsigned int)
Line
Count
Source
28
340k
  {
29
340k
    return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
30
340k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::get_size(unsigned int, unsigned int)
Line
Count
Source
28
19.3k
  {
29
19.3k
    return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
30
19.3k
  }
31
  static unsigned get_size (const ValueFormat valueFormats[2])
32
49.7k
  {
33
49.7k
    unsigned len1 = valueFormats[0].get_len ();
34
49.7k
    unsigned len2 = valueFormats[1].get_len ();
35
49.7k
    return get_size (len1, len2);
36
49.7k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::get_size(OT::Layout::GPOS_impl::ValueFormat const*)
Line
Count
Source
32
44.5k
  {
33
44.5k
    unsigned len1 = valueFormats[0].get_len ();
34
44.5k
    unsigned len2 = valueFormats[1].get_len ();
35
44.5k
    return get_size (len1, len2);
36
44.5k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::get_size(OT::Layout::GPOS_impl::ValueFormat const*)
Line
Count
Source
32
5.21k
  {
33
5.21k
    unsigned len1 = valueFormats[0].get_len ();
34
5.21k
    unsigned len2 = valueFormats[1].get_len ();
35
5.21k
    return get_size (len1, len2);
36
5.21k
  }
37
38
  struct sanitize_closure_t
39
  {
40
    const ValueFormat *valueFormats;
41
    unsigned int len1; /* valueFormats[0].get_len() */
42
    unsigned int stride; /* bytes */
43
  };
44
45
  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
46
583k
  {
47
583k
    TRACE_SANITIZE (this);
48
583k
    if (!(c->check_struct (this) &&
49
583k
    hb_barrier () &&
50
583k
          c->check_range (&firstPairValueRecord,
51
565k
                          len,
52
565k
                          closure->stride))) return_trace (false);
53
541k
    hb_barrier ();
54
55
541k
    unsigned int count = len;
56
541k
    const PairValueRecord *record = &firstPairValueRecord;
57
541k
    return_trace (c->lazy_some_gpos ||
58
583k
      (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
59
583k
                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
60
583k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::sanitize(hb_sanitize_context_t*, OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::sanitize_closure_t const*) const
Line
Count
Source
46
567k
  {
47
567k
    TRACE_SANITIZE (this);
48
567k
    if (!(c->check_struct (this) &&
49
567k
    hb_barrier () &&
50
567k
          c->check_range (&firstPairValueRecord,
51
553k
                          len,
52
553k
                          closure->stride))) return_trace (false);
53
530k
    hb_barrier ();
54
55
530k
    unsigned int count = len;
56
530k
    const PairValueRecord *record = &firstPairValueRecord;
57
530k
    return_trace (c->lazy_some_gpos ||
58
567k
      (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
59
567k
                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
60
567k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::sanitize(hb_sanitize_context_t*, OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::sanitize_closure_t const*) const
Line
Count
Source
46
16.3k
  {
47
16.3k
    TRACE_SANITIZE (this);
48
16.3k
    if (!(c->check_struct (this) &&
49
16.3k
    hb_barrier () &&
50
16.3k
          c->check_range (&firstPairValueRecord,
51
12.2k
                          len,
52
12.2k
                          closure->stride))) return_trace (false);
53
11.1k
    hb_barrier ();
54
55
11.1k
    unsigned int count = len;
56
11.1k
    const PairValueRecord *record = &firstPairValueRecord;
57
11.1k
    return_trace (c->lazy_some_gpos ||
58
16.3k
      (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
59
16.3k
                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
60
16.3k
  }
61
62
  bool intersects (const hb_set_t *glyphs,
63
                   const ValueFormat *valueFormats) const
64
45.2k
  {
65
45.2k
    unsigned record_size = get_size (valueFormats);
66
67
45.2k
    const PairValueRecord *record = &firstPairValueRecord;
68
45.2k
    unsigned int count = len;
69
105k
    for (unsigned int i = 0; i < count; i++)
70
78.1k
    {
71
78.1k
      if (glyphs->has (record->secondGlyph))
72
18.3k
        return true;
73
59.8k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
74
59.8k
    }
75
26.9k
    return false;
76
45.2k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::intersects(hb_set_t const*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
64
40.5k
  {
65
40.5k
    unsigned record_size = get_size (valueFormats);
66
67
40.5k
    const PairValueRecord *record = &firstPairValueRecord;
68
40.5k
    unsigned int count = len;
69
47.6k
    for (unsigned int i = 0; i < count; i++)
70
23.5k
    {
71
23.5k
      if (glyphs->has (record->secondGlyph))
72
16.4k
        return true;
73
7.10k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
74
7.10k
    }
75
24.1k
    return false;
76
40.5k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::intersects(hb_set_t const*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
64
4.64k
  {
65
4.64k
    unsigned record_size = get_size (valueFormats);
66
67
4.64k
    const PairValueRecord *record = &firstPairValueRecord;
68
4.64k
    unsigned int count = len;
69
57.4k
    for (unsigned int i = 0; i < count; i++)
70
54.6k
    {
71
54.6k
      if (glyphs->has (record->secondGlyph))
72
1.90k
        return true;
73
52.7k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
74
52.7k
    }
75
2.74k
    return false;
76
4.64k
  }
77
78
  void collect_glyphs (hb_collect_glyphs_context_t *c,
79
                       const ValueFormat *valueFormats) const
80
0
  {
81
0
    unsigned record_size = get_size (valueFormats);
82
83
0
    const PairValueRecord *record = &firstPairValueRecord;
84
0
    c->input->add_array (&record->secondGlyph, len, record_size);
85
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*, OT::Layout::GPOS_impl::ValueFormat const*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*, OT::Layout::GPOS_impl::ValueFormat const*) const
86
87
  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
88
                                  const ValueFormat *valueFormats) const
89
1.44k
  {
90
1.44k
    unsigned record_size = get_size (valueFormats);
91
92
1.44k
    const PairValueRecord *record = &firstPairValueRecord;
93
1.44k
    unsigned count = len;
94
748k
    for (unsigned i = 0; i < count; i++)
95
746k
    {
96
746k
      if (c->glyph_set->has (record->secondGlyph))
97
527k
      { record->collect_variation_indices (c, valueFormats, this); }
98
99
746k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
100
746k
    }
101
1.44k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::collect_variation_indices(OT::hb_collect_variation_indices_context_t*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
89
1.16k
  {
90
1.16k
    unsigned record_size = get_size (valueFormats);
91
92
1.16k
    const PairValueRecord *record = &firstPairValueRecord;
93
1.16k
    unsigned count = len;
94
746k
    for (unsigned i = 0; i < count; i++)
95
745k
    {
96
745k
      if (c->glyph_set->has (record->secondGlyph))
97
526k
      { record->collect_variation_indices (c, valueFormats, this); }
98
99
745k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
100
745k
    }
101
1.16k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::collect_variation_indices(OT::hb_collect_variation_indices_context_t*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
89
282
  {
90
282
    unsigned record_size = get_size (valueFormats);
91
92
282
    const PairValueRecord *record = &firstPairValueRecord;
93
282
    unsigned count = len;
94
2.06k
    for (unsigned i = 0; i < count; i++)
95
1.77k
    {
96
1.77k
      if (c->glyph_set->has (record->secondGlyph))
97
893
      { record->collect_variation_indices (c, valueFormats, this); }
98
99
1.77k
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
100
1.77k
    }
101
282
  }
102
103
  bool apply (hb_ot_apply_context_t *c,
104
              const ValueFormat *valueFormats,
105
              unsigned int pos) const
106
0
  {
107
0
    TRACE_APPLY (this);
108
0
    hb_buffer_t *buffer = c->buffer;
109
0
    unsigned int len1 = valueFormats[0].get_len ();
110
0
    unsigned int len2 = valueFormats[1].get_len ();
111
0
    unsigned record_size = get_size (len1, len2);
112
113
0
    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
114
0
                                                &firstPairValueRecord,
115
0
                                                len,
116
0
                                                record_size);
117
0
    if (record)
118
0
    {
119
0
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
120
0
      {
121
0
  c->buffer->message (c->font,
122
0
          "try kerning glyphs at %u,%u",
123
0
          c->buffer->idx, pos);
124
0
      }
125
126
0
      bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
127
0
      bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
128
129
0
      if (applied_first || applied_second)
130
0
  if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
131
0
  {
132
0
    c->buffer->message (c->font,
133
0
            "kerned glyphs at %u,%u",
134
0
            c->buffer->idx, pos);
135
0
  }
136
137
0
      if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
138
0
      {
139
0
  c->buffer->message (c->font,
140
0
          "tried kerning glyphs at %u,%u",
141
0
          c->buffer->idx, pos);
142
0
      }
143
144
0
      if (applied_first || applied_second)
145
0
        buffer->unsafe_to_break (buffer->idx, pos + 1);
146
147
0
      if (len2)
148
0
      {
149
0
  pos++;
150
      // https://github.com/harfbuzz/harfbuzz/issues/3824
151
      // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
152
0
      buffer->unsafe_to_break (buffer->idx, pos + 1);
153
0
      }
154
155
0
      buffer->idx = pos;
156
0
      return_trace (true);
157
0
    }
158
0
    buffer->unsafe_to_concat (buffer->idx, pos + 1);
159
0
    return_trace (false);
160
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::apply(OT::hb_ot_apply_context_t*, OT::Layout::GPOS_impl::ValueFormat const*, unsigned int) const
Unexecuted instantiation: OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::apply(OT::hb_ot_apply_context_t*, OT::Layout::GPOS_impl::ValueFormat const*, unsigned int) const
161
162
  bool subset (hb_subset_context_t *c,
163
               const ValueFormat valueFormats[2],
164
               const ValueFormat newFormats[2]) const
165
227k
  {
166
227k
    TRACE_SUBSET (this);
167
227k
    auto snap = c->serializer->snapshot ();
168
169
227k
    auto *out = c->serializer->start_embed (*this);
170
227k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
171
227k
    out->len = 0;
172
173
227k
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
174
227k
    const hb_map_t &glyph_map = *c->plan->glyph_map;
175
176
227k
    unsigned len1 = valueFormats[0].get_len ();
177
227k
    unsigned len2 = valueFormats[1].get_len ();
178
227k
    unsigned record_size = get_size (len1, len2);
179
180
227k
    typename PairValueRecord::context_t context =
181
227k
    {
182
227k
      this,
183
227k
      valueFormats,
184
227k
      newFormats,
185
227k
      len1,
186
227k
      &glyph_map,
187
227k
      &c->plan->layout_variation_idx_delta_map
188
227k
    };
189
190
227k
    const PairValueRecord *record = &firstPairValueRecord;
191
227k
    unsigned count = len, num = 0;
192
211M
    for (unsigned i = 0; i < count; i++)
193
211M
    {
194
211M
      if (glyphset.has (record->secondGlyph)
195
211M
         && record->subset (c, &context)) num++;
196
211M
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
197
211M
    }
198
199
227k
    out->len = num;
200
227k
    if (!num) c->serializer->revert (snap);
201
227k
    return_trace (num);
202
227k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::SmallTypes>::subset(hb_subset_context_t*, OT::Layout::GPOS_impl::ValueFormat const*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
165
225k
  {
166
225k
    TRACE_SUBSET (this);
167
225k
    auto snap = c->serializer->snapshot ();
168
169
225k
    auto *out = c->serializer->start_embed (*this);
170
225k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
171
225k
    out->len = 0;
172
173
225k
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
174
225k
    const hb_map_t &glyph_map = *c->plan->glyph_map;
175
176
225k
    unsigned len1 = valueFormats[0].get_len ();
177
225k
    unsigned len2 = valueFormats[1].get_len ();
178
225k
    unsigned record_size = get_size (len1, len2);
179
180
225k
    typename PairValueRecord::context_t context =
181
225k
    {
182
225k
      this,
183
225k
      valueFormats,
184
225k
      newFormats,
185
225k
      len1,
186
225k
      &glyph_map,
187
225k
      &c->plan->layout_variation_idx_delta_map
188
225k
    };
189
190
225k
    const PairValueRecord *record = &firstPairValueRecord;
191
225k
    unsigned count = len, num = 0;
192
210M
    for (unsigned i = 0; i < count; i++)
193
210M
    {
194
210M
      if (glyphset.has (record->secondGlyph)
195
210M
         && record->subset (c, &context)) num++;
196
210M
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
197
210M
    }
198
199
225k
    out->len = num;
200
225k
    if (!num) c->serializer->revert (snap);
201
225k
    return_trace (num);
202
225k
  }
OT::Layout::GPOS_impl::PairSet<OT::Layout::MediumTypes>::subset(hb_subset_context_t*, OT::Layout::GPOS_impl::ValueFormat const*, OT::Layout::GPOS_impl::ValueFormat const*) const
Line
Count
Source
165
2.17k
  {
166
2.17k
    TRACE_SUBSET (this);
167
2.17k
    auto snap = c->serializer->snapshot ();
168
169
2.17k
    auto *out = c->serializer->start_embed (*this);
170
2.17k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
171
2.17k
    out->len = 0;
172
173
2.17k
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
174
2.17k
    const hb_map_t &glyph_map = *c->plan->glyph_map;
175
176
2.17k
    unsigned len1 = valueFormats[0].get_len ();
177
2.17k
    unsigned len2 = valueFormats[1].get_len ();
178
2.17k
    unsigned record_size = get_size (len1, len2);
179
180
2.17k
    typename PairValueRecord::context_t context =
181
2.17k
    {
182
2.17k
      this,
183
2.17k
      valueFormats,
184
2.17k
      newFormats,
185
2.17k
      len1,
186
2.17k
      &glyph_map,
187
2.17k
      &c->plan->layout_variation_idx_delta_map
188
2.17k
    };
189
190
2.17k
    const PairValueRecord *record = &firstPairValueRecord;
191
2.17k
    unsigned count = len, num = 0;
192
1.06M
    for (unsigned i = 0; i < count; i++)
193
1.06M
    {
194
1.06M
      if (glyphset.has (record->secondGlyph)
195
1.06M
         && record->subset (c, &context)) num++;
196
1.06M
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
197
1.06M
    }
198
199
2.17k
    out->len = num;
200
2.17k
    if (!num) c->serializer->revert (snap);
201
2.17k
    return_trace (num);
202
2.17k
  }
203
};
204
205
206
}
207
}
208
}
209
210
#endif  // OT_LAYOUT_GPOS_PAIRSET_HH