Coverage Report

Created: 2026-11-10 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
Line
Count
Source
1
#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
2
#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
3
4
#include "MarkMarkPosFormat1.hh"
5
6
namespace OT {
7
namespace Layout {
8
namespace GPOS_impl {
9
10
template <typename Types>
11
struct MarkMarkPosFormat1_2
12
{
13
  protected:
14
  HBUINT16      format;                 /* Format identifier--format = 1 */
15
  typename Types::template LOffsetTo<Coverage>
16
                mark1Coverage;          /* Offset to Combining Mark1 Coverage
17
                                         * table--from beginning of MarkMarkPos
18
                                         * subtable */
19
  typename Types::template LOffsetTo<Coverage>
20
                mark2Coverage;          /* Offset to Combining Mark2 Coverage
21
                                         * table--from beginning of MarkMarkPos
22
                                         * subtable */
23
  HBUINT16      classCount;             /* Number of defined mark classes */
24
  typename Types::template LOffsetTo<MarkArray<Types>>
25
                mark1Array;             /* Offset to Mark1Array table--from
26
                                         * beginning of MarkMarkPos subtable */
27
  typename Types::template LOffsetTo<AnchorMatrix<Types, HBUINT16>>
28
                mark2Array;             /* Offset to Mark2Array table--from
29
                                         * beginning of MarkMarkPos subtable */
30
  public:
31
  DEFINE_SIZE_STATIC (4 + 4 * Types::LOffset::static_size);
32
33
  bool sanitize (hb_sanitize_context_t *c) const
34
0
  {
35
0
    TRACE_SANITIZE (this);
36
0
    return_trace (c->check_struct (this) &&
37
0
                  mark1Coverage.sanitize (c, this) &&
38
0
                  mark2Coverage.sanitize (c, this) &&
39
0
                  mark1Array.sanitize (c, this) &&
40
0
      hb_barrier () &&
41
0
                  mark2Array.sanitize (c, this, (unsigned int) classCount));
42
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::sanitize(hb_sanitize_context_t*) const
43
44
  bool intersects (const hb_set_t *glyphs) const
45
0
  {
46
0
    return (this+mark1Coverage).intersects (glyphs) &&
47
0
           (this+mark2Coverage).intersects (glyphs);
48
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::intersects(hb_set_t const*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::intersects(hb_set_t const*) const
49
50
0
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::closure_lookups(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::closure_lookups(OT::hb_closure_lookups_context_t*) const
51
52
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
53
0
  {
54
0
    (this+mark1Array).collect_variation_indices (c, this+mark1Coverage);
55
56
0
    hb_map_t klass_mapping;
57
0
    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
58
59
0
    hb_sorted_vector_t<unsigned> mark2_indexes;
60
0
    collect_anchor_indexes (this+mark2Coverage, (this+mark2Array).rows,
61
0
                            classCount, *c->glyph_set, klass_mapping,
62
0
                            mark2_indexes);
63
0
    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
64
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::collect_variation_indices(OT::hb_collect_variation_indices_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::collect_variation_indices(OT::hb_collect_variation_indices_context_t*) const
65
66
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
67
0
  {
68
0
    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
69
0
    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
70
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::collect_glyphs(OT::hb_collect_glyphs_context_t*) const
71
72
  void collect_second_glyphs (hb_set_digest_t *digest) const
73
0
  { (this+mark2Coverage).collect_coverage (digest); }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::collect_second_glyphs(hb_set_digest_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::collect_second_glyphs(hb_set_digest_t*) const
74
75
0
  const Coverage &get_coverage () const { return this+mark1Coverage; }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::get_coverage() const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::get_coverage() const
76
77
  bool apply (hb_ot_apply_context_t *c) const
78
0
  {
79
0
    TRACE_APPLY (this);
80
0
    hb_buffer_t *buffer = c->buffer;
81
0
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
82
0
    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
83
84
    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
85
0
    auto &skippy_iter = c->iter_input;
86
0
    skippy_iter.reset_fast (buffer->idx);
87
0
    skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
88
0
    unsigned unsafe_from;
89
0
    if (unlikely (!skippy_iter.prev (&unsafe_from)))
90
0
    {
91
0
      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
92
0
      return_trace (false);
93
0
    }
94
95
0
    if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
96
0
    {
97
0
      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
98
0
      return_trace (false);
99
0
    }
100
101
0
    unsigned int j = skippy_iter.idx;
102
103
0
    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
104
0
    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
105
0
    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
106
0
    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
107
108
0
    if (likely (id1 == id2))
109
0
    {
110
0
      if (id1 == 0) /* Marks belonging to the same base. */
111
0
        goto good;
112
0
      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
113
0
        goto good;
114
0
    }
115
0
    else
116
0
    {
117
      /* If ligature ids don't match, it may be the case that one of the marks
118
       * itself is a ligature.  In which case match. */
119
0
      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
120
0
        goto good;
121
0
    }
122
123
    /* Didn't match. */
124
0
    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
125
0
    return_trace (false);
126
127
0
    good:
128
0
    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
129
0
    if (mark2_index == NOT_COVERED)
130
0
    {
131
0
      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
132
0
      return_trace (false);
133
0
    }
134
135
0
    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
136
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::apply(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::apply(OT::hb_ot_apply_context_t*) const
137
138
  bool subset (hb_subset_context_t *c) const
139
0
  {
140
0
    TRACE_SUBSET (this);
141
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
142
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
143
144
0
    auto *out = c->serializer->start_embed (*this);
145
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
146
0
    out->format = format;
147
148
0
    hb_map_t klass_mapping;
149
0
    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
150
151
0
    if (!klass_mapping.get_population ()) return_trace (false);
152
0
    out->classCount = klass_mapping.get_population ();
153
154
0
    auto mark1_iter =
155
0
    + hb_zip (this+mark1Coverage, this+mark1Array)
156
0
    | hb_filter (glyphset, hb_first)
157
0
    ;
158
159
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
160
0
    + mark1_iter
161
0
    | hb_map (hb_first)
162
0
    | hb_map (glyph_map)
163
0
    | hb_sink (new_coverage)
164
0
    ;
165
166
0
    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
167
0
      return_trace (false);
168
169
0
    if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
170
0
                 (this+mark1Coverage).iter (),
171
0
                 &klass_mapping)))
172
0
      return_trace (false);
173
174
0
    new_coverage.reset ();
175
0
    hb_sorted_vector_t<unsigned> mark2_indexes;
176
0
    const auto &mark2_array = this+mark2Array;
177
0
    collect_subset_anchor_indexes (this+mark2Coverage, mark2_array.rows,
178
0
                                   classCount, mark2_array.matrixZ.arrayZ,
179
0
                                   glyphset, glyph_map, klass_mapping,
180
0
                                   new_coverage, mark2_indexes);
181
182
0
    if (!new_coverage) return_trace (false);
183
0
    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
184
0
      return_trace (false);
185
186
0
    return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
187
0
                new_coverage.length,
188
0
                mark2_indexes.iter ()));
189
190
0
  }
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes>::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::MediumTypes>::subset(hb_subset_context_t*) const
191
};
192
193
194
}
195
}
196
}
197
198
#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */