Coverage Report

Created: 2025-10-28 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
Line
Count
Source
1
#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
2
#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
3
4
#include "LigatureArray.hh"
5
6
namespace OT {
7
namespace Layout {
8
namespace GPOS_impl {
9
10
11
template <typename Types>
12
struct MarkLigPosFormat1_2
13
{
14
  protected:
15
  HBUINT16      format;                 /* Format identifier--format = 1 */
16
  typename Types::template OffsetTo<Coverage>
17
                markCoverage;           /* Offset to Mark Coverage table--from
18
                                         * beginning of MarkLigPos subtable */
19
  typename Types::template OffsetTo<Coverage>
20
                ligatureCoverage;       /* Offset to Ligature Coverage
21
                                         * table--from beginning of MarkLigPos
22
                                         * subtable */
23
  HBUINT16      classCount;             /* Number of defined mark classes */
24
  typename Types::template OffsetTo<MarkArray>
25
                markArray;              /* Offset to MarkArray table--from
26
                                         * beginning of MarkLigPos subtable */
27
  typename Types::template OffsetTo<LigatureArray>
28
                ligatureArray;          /* Offset to LigatureArray table--from
29
                                         * beginning of MarkLigPos subtable */
30
  public:
31
  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
32
33
  bool sanitize (hb_sanitize_context_t *c) const
34
29
  {
35
29
    TRACE_SANITIZE (this);
36
29
    return_trace (c->check_struct (this) &&
37
29
                  markCoverage.sanitize (c, this) &&
38
29
                  ligatureCoverage.sanitize (c, this) &&
39
29
                  markArray.sanitize (c, this) &&
40
29
                  ligatureArray.sanitize (c, this, (unsigned int) classCount));
41
29
  }
42
43
  bool intersects (const hb_set_t *glyphs) const
44
0
  {
45
0
    return (this+markCoverage).intersects (glyphs) &&
46
0
           (this+ligatureCoverage).intersects (glyphs);
47
0
  }
48
49
0
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
50
51
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
52
0
  {
53
0
    + hb_zip (this+markCoverage, this+markArray)
54
0
    | hb_filter (c->glyph_set, hb_first)
55
0
    | hb_map (hb_second)
56
0
    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
57
0
    ;
58
0
59
0
    hb_map_t klass_mapping;
60
0
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
61
0
62
0
    unsigned ligcount = (this+ligatureArray).len;
63
0
    auto lig_iter =
64
0
    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
65
0
    | hb_filter (c->glyph_set, hb_first)
66
0
    | hb_map (hb_second)
67
0
    ;
68
0
69
0
    const LigatureArray& lig_array = this+ligatureArray;
70
0
    for (const unsigned i : lig_iter)
71
0
    {
72
0
      hb_sorted_vector_t<unsigned> lig_indexes;
73
0
      unsigned row_count = lig_array[i].rows;
74
0
      for (unsigned row : + hb_range (row_count))
75
0
      {
76
0
        + hb_range ((unsigned) classCount)
77
0
        | hb_filter (klass_mapping)
78
0
        | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
79
0
        | hb_sink (lig_indexes)
80
0
        ;
81
0
      }
82
0
83
0
      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
84
0
    }
85
0
  }
86
87
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
88
0
  {
89
0
    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
90
0
    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
91
0
  }
92
93
13
  const Coverage &get_coverage () const { return this+markCoverage; }
94
95
  bool apply (hb_ot_apply_context_t *c) const
96
0
  {
97
0
    TRACE_APPLY (this);
98
0
    hb_buffer_t *buffer = c->buffer;
99
0
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
100
0
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
101
102
    /* Now we search backwards for a non-mark glyph */
103
104
0
    auto &skippy_iter = c->iter_input;
105
0
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
106
107
0
    if (c->last_base_until > buffer->idx)
108
0
    {
109
0
      c->last_base_until = 0;
110
0
      c->last_base = -1;
111
0
    }
112
0
    unsigned j;
113
0
    for (j = buffer->idx; j > c->last_base_until; j--)
114
0
    {
115
0
      auto match = skippy_iter.match (buffer->info[j - 1]);
116
0
      if (match == skippy_iter.MATCH)
117
0
      {
118
0
  c->last_base = (signed) j - 1;
119
0
  break;
120
0
      }
121
0
    }
122
0
    c->last_base_until = buffer->idx;
123
0
    if (c->last_base == -1)
124
0
    {
125
0
      buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
126
0
      return_trace (false);
127
0
    }
128
129
0
    unsigned idx = (unsigned) c->last_base;
130
131
    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
132
    //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
133
134
0
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[idx].codepoint);
135
0
    if (lig_index == NOT_COVERED)
136
0
    {
137
0
      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
138
0
      return_trace (false);
139
0
    }
140
141
0
    const LigatureArray& lig_array = this+ligatureArray;
142
0
    const LigatureAttach& lig_attach = lig_array[lig_index];
143
144
    /* Find component to attach to */
145
0
    unsigned int comp_count = lig_attach.rows;
146
0
    if (unlikely (!comp_count))
147
0
    {
148
0
      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
149
0
      return_trace (false);
150
0
    }
151
152
    /* We must now check whether the ligature ID of the current mark glyph
153
     * is identical to the ligature ID of the found ligature.  If yes, we
154
     * can directly use the component index.  If not, we attach the mark
155
     * glyph to the last component of the ligature. */
156
0
    unsigned int comp_index;
157
0
    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
158
0
    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
159
0
    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
160
0
    if (lig_id && lig_id == mark_id && mark_comp > 0)
161
0
      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
162
0
    else
163
0
      comp_index = comp_count - 1;
164
165
0
    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
166
0
  }
167
168
  bool subset (hb_subset_context_t *c) const
169
0
  {
170
0
    TRACE_SUBSET (this);
171
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
172
0
    const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
173
0
174
0
    auto *out = c->serializer->start_embed (*this);
175
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
176
0
    out->format = format;
177
0
178
0
    hb_map_t klass_mapping;
179
0
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
180
0
181
0
    if (!klass_mapping.get_population ()) return_trace (false);
182
0
    out->classCount = klass_mapping.get_population ();
183
0
184
0
    auto mark_iter =
185
0
    + hb_zip (this+markCoverage, this+markArray)
186
0
    | hb_filter (glyphset, hb_first)
187
0
    ;
188
0
189
0
    auto new_mark_coverage =
190
0
    + mark_iter
191
0
    | hb_map_retains_sorting (hb_first)
192
0
    | hb_map_retains_sorting (glyph_map)
193
0
    ;
194
0
195
0
    if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
196
0
      return_trace (false);
197
0
198
0
    if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
199
0
                (this+markCoverage).iter (),
200
0
                &klass_mapping)))
201
0
      return_trace (false);
202
0
203
0
    hb_sorted_vector_t<hb_codepoint_t> new_lig_coverage;
204
0
    if (!out->ligatureArray.serialize_subset (c, ligatureArray, this,
205
0
                hb_iter (this+ligatureCoverage),
206
0
                classCount, &klass_mapping, new_lig_coverage))
207
0
      return_trace (false);
208
0
209
0
    return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ()));
210
0
  }
211
212
};
213
214
}
215
}
216
}
217
218
#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */