Coverage Report

Created: 2025-10-10 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-ot-kern-table.hh
Line
Count
Source
1
/*
2
 * Copyright © 2017  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_OT_KERN_TABLE_HH
28
#define HB_OT_KERN_TABLE_HH
29
30
#include "hb-aat-layout-common.hh"
31
#include "hb-aat-layout-kerx-table.hh"
32
33
34
/*
35
 * kern -- Kerning
36
 * https://docs.microsoft.com/en-us/typography/opentype/spec/kern
37
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
38
 */
39
#define HB_OT_TAG_kern HB_TAG('k','e','r','n')
40
41
42
namespace OT {
43
44
45
template <typename KernSubTableHeader>
46
struct KernSubTableFormat3
47
{
48
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
49
0
  {
50
0
    hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
51
0
    hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
52
0
    hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
53
0
    hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
54
55
0
    unsigned int leftC = leftClass[left];
56
0
    unsigned int rightC = rightClass[right];
57
0
    if (unlikely (leftC >= leftClassCount || rightC >= rightClassCount))
58
0
      return 0;
59
0
    unsigned int i = leftC * rightClassCount + rightC;
60
0
    return kernValue[kernIndex[i]];
61
0
  }
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int) const
62
63
  bool apply (AAT::hb_aat_apply_context_t *c) const
64
0
  {
65
0
    TRACE_APPLY (this);
66
67
0
    if (!c->plan->requested_kerning)
68
0
      return false;
69
70
0
    if (header.coverage & header.Backwards)
71
0
      return false;
72
73
0
    hb_kern_machine_t<KernSubTableFormat3> machine (*this, header.coverage & header.CrossStream);
74
0
    machine.kern (c->font, c->buffer, c->plan->kern_mask);
75
76
0
    return_trace (true);
77
0
  }
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
78
79
  bool sanitize (hb_sanitize_context_t *c) const
80
0
  {
81
0
    TRACE_SANITIZE (this);
82
0
    return_trace (c->check_struct (this) &&
83
0
      hb_barrier () &&
84
0
      c->check_range (kernValueZ,
85
0
          kernValueCount * sizeof (FWORD) +
86
0
          glyphCount * 2 +
87
0
          leftClassCount * rightClassCount));
88
0
  }
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::KernSubTableFormat3<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const
89
90
  template <typename set_t>
91
  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
92
0
  {
93
0
    set_t set;
94
0
    if (likely (glyphCount))
95
0
    {
96
0
      left_set.add_range (0, num_glyphs - 1);
97
0
      right_set.add_range (0, num_glyphs - 1);
98
0
    }
99
0
  }
Unexecuted instantiation: void OT::KernSubTableFormat3<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void OT::KernSubTableFormat3<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
100
101
  protected:
102
  KernSubTableHeader
103
    header;
104
  HBUINT16  glyphCount; /* The number of glyphs in this font. */
105
  HBUINT8 kernValueCount; /* The number of kerning values. */
106
  HBUINT8 leftClassCount; /* The number of left-hand classes. */
107
  HBUINT8 rightClassCount;/* The number of right-hand classes. */
108
  HBUINT8 flags;    /* Set to zero (reserved for future use). */
109
  UnsizedArrayOf<FWORD>
110
    kernValueZ; /* The kerning values.
111
         * Length kernValueCount. */
112
#if 0
113
  UnsizedArrayOf<HBUINT8>
114
    leftClass;  /* The left-hand classes.
115
         * Length glyphCount. */
116
  UnsizedArrayOf<HBUINT8>
117
    rightClass; /* The right-hand classes.
118
         * Length glyphCount. */
119
  UnsizedArrayOf<HBUINT8>kernIndex;
120
        /* The indices into the kernValue array.
121
         * Length leftClassCount * rightClassCount */
122
#endif
123
  public:
124
  DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
125
};
126
127
template <typename KernSubTableHeader>
128
struct KernSubTable
129
{
130
1.00k
  unsigned int get_size () const { return u.header.length; }
OT::KernSubTable<OT::KernOTSubTableHeader>::get_size() const
Line
Count
Source
130
1.00k
  unsigned int get_size () const { return u.header.length; }
Unexecuted instantiation: OT::KernSubTable<OT::KernAATSubTableHeader>::get_size() const
131
162
  unsigned int get_type () const { return u.header.format; }
OT::KernSubTable<OT::KernOTSubTableHeader>::get_type() const
Line
Count
Source
131
162
  unsigned int get_type () const { return u.header.format; }
Unexecuted instantiation: OT::KernSubTable<OT::KernAATSubTableHeader>::get_type() const
132
133
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
134
0
  {
135
0
    switch (get_type ()) {
136
0
    /* This method hooks up to hb_font_t's get_h_kerning.  Only support Format0. */
137
0
    case 0: hb_barrier (); return u.format0.get_kerning (left, right);
138
0
    default:return 0;
139
0
    }
140
0
  }
Unexecuted instantiation: OT::KernSubTable<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: OT::KernSubTable<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int) const
141
142
  template <typename context_t, typename ...Ts>
143
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
144
54
  {
145
54
    unsigned int subtable_type = get_type ();
146
54
    TRACE_DISPATCH (this, subtable_type);
147
54
    switch (subtable_type) {
148
54
    case 0: return_trace (c->dispatch (u.format0));
149
0
#ifndef HB_NO_AAT_SHAPE
150
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
151
0
#endif
152
0
    case 2: return_trace (c->dispatch (u.format2));
153
0
#ifndef HB_NO_AAT_SHAPE
154
0
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
155
0
#endif
156
0
    default:  return_trace (c->default_return_value ());
157
54
    }
158
54
  }
Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t OT::KernSubTable<OT::KernOTSubTableHeader>::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t OT::KernSubTable<OT::KernAATSubTableHeader>::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
hb_sanitize_context_t::return_t OT::KernSubTable<OT::KernOTSubTableHeader>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
144
54
  {
145
54
    unsigned int subtable_type = get_type ();
146
54
    TRACE_DISPATCH (this, subtable_type);
147
54
    switch (subtable_type) {
148
54
    case 0: return_trace (c->dispatch (u.format0));
149
0
#ifndef HB_NO_AAT_SHAPE
150
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
151
0
#endif
152
0
    case 2: return_trace (c->dispatch (u.format2));
153
0
#ifndef HB_NO_AAT_SHAPE
154
0
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
155
0
#endif
156
0
    default:  return_trace (c->default_return_value ());
157
54
    }
158
54
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::KernSubTable<OT::KernAATSubTableHeader>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
159
160
  template <typename set_t>
161
  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
162
54
  {
163
54
    unsigned int subtable_type = get_type ();
164
54
    switch (subtable_type) {
165
54
    case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
166
0
    case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
167
0
    case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
168
0
    case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return;
169
0
    default:  return;
170
54
    }
171
54
  }
void OT::KernSubTable<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Line
Count
Source
162
54
  {
163
54
    unsigned int subtable_type = get_type ();
164
54
    switch (subtable_type) {
165
54
    case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
166
0
    case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
167
0
    case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
168
0
    case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return;
169
0
    default:  return;
170
54
    }
171
54
  }
Unexecuted instantiation: void OT::KernSubTable<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
172
173
  bool sanitize (hb_sanitize_context_t *c) const
174
54
  {
175
54
    TRACE_SANITIZE (this);
176
54
    if (unlikely (!(u.header.sanitize (c) &&
177
54
        hb_barrier () &&
178
54
        u.header.length >= u.header.min_size &&
179
54
        c->check_range (this, u.header.length)))) return_trace (false);
180
181
54
    return_trace (dispatch (c));
182
54
  }
OT::KernSubTable<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
174
54
  {
175
54
    TRACE_SANITIZE (this);
176
54
    if (unlikely (!(u.header.sanitize (c) &&
177
54
        hb_barrier () &&
178
54
        u.header.length >= u.header.min_size &&
179
54
        c->check_range (this, u.header.length)))) return_trace (false);
180
181
54
    return_trace (dispatch (c));
182
54
  }
Unexecuted instantiation: OT::KernSubTable<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const
183
184
  public:
185
  union {
186
  KernSubTableHeader        header;
187
  AAT::KerxSubTableFormat0<KernSubTableHeader>  format0;
188
  AAT::KerxSubTableFormat1<KernSubTableHeader>  format1;
189
  AAT::KerxSubTableFormat2<KernSubTableHeader>  format2;
190
  KernSubTableFormat3<KernSubTableHeader> format3;
191
  } u;
192
  public:
193
  DEFINE_SIZE_MIN (KernSubTableHeader::static_size);
194
};
195
196
197
struct KernOTSubTableHeader
198
{
199
  static constexpr bool apple = false;
200
  typedef AAT::ObsoleteTypes Types;
201
202
0
  unsigned   tuple_count () const { return 0; }
203
807
  bool     is_horizontal () const { return (coverage & Horizontal); }
204
205
  enum Coverage
206
  {
207
    Horizontal  = 0x01u,
208
    Minimum = 0x02u,
209
    CrossStream = 0x04u,
210
    Override  = 0x08u,
211
212
    /* Not supported: */
213
    Backwards = 0x00u,
214
    Variation = 0x00u,
215
  };
216
217
  bool sanitize (hb_sanitize_context_t *c) const
218
108
  {
219
108
    TRACE_SANITIZE (this);
220
108
    return_trace (c->check_struct (this));
221
108
  }
222
223
  public:
224
  HBUINT16  versionZ; /* Unused. */
225
  HBUINT16  length;   /* Length of the subtable (including this header). */
226
  HBUINT8 format;   /* Subtable format. */
227
  HBUINT8 coverage; /* Coverage bits. */
228
  public:
229
  DEFINE_SIZE_STATIC (6);
230
};
231
232
struct KernOT : AAT::KerxTable<KernOT>
233
{
234
  friend struct AAT::KerxTable<KernOT>;
235
236
  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
237
  static constexpr unsigned minVersion = 0u;
238
239
  typedef KernOTSubTableHeader SubTableHeader;
240
  typedef SubTableHeader::Types Types;
241
  typedef KernSubTable<SubTableHeader> SubTable;
242
243
  protected:
244
  HBUINT16  version;  /* Version--0x0000u */
245
  HBUINT16  tableCount; /* Number of subtables in the kerning table. */
246
  SubTable  firstSubTable;  /* Subtables. */
247
  public:
248
  DEFINE_SIZE_MIN (4);
249
};
250
251
252
struct KernAATSubTableHeader
253
{
254
  static constexpr bool apple = true;
255
  typedef AAT::ObsoleteTypes Types;
256
257
0
  unsigned   tuple_count () const { return 0; }
258
0
  bool     is_horizontal () const { return !(coverage & Vertical); }
259
260
  enum Coverage
261
  {
262
    Vertical  = 0x80u,
263
    CrossStream = 0x40u,
264
    Variation = 0x20u,
265
266
    /* Not supported: */
267
    Backwards = 0x00u,
268
  };
269
270
  bool sanitize (hb_sanitize_context_t *c) const
271
0
  {
272
0
    TRACE_SANITIZE (this);
273
0
    return_trace (c->check_struct (this));
274
0
  }
275
276
  public:
277
  HBUINT32  length;   /* Length of the subtable (including this header). */
278
  HBUINT8 coverage; /* Coverage bits. */
279
  HBUINT8 format;   /* Subtable format. */
280
  HBUINT16  tupleIndex; /* The tuple index (used for variations fonts).
281
         * This value specifies which tuple this subtable covers.
282
         * Note: We don't implement. */
283
  public:
284
  DEFINE_SIZE_STATIC (8);
285
};
286
287
struct KernAAT : AAT::KerxTable<KernAAT>
288
{
289
  friend struct AAT::KerxTable<KernAAT>;
290
291
  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
292
  static constexpr unsigned minVersion = 0x00010000u;
293
294
  typedef KernAATSubTableHeader SubTableHeader;
295
  typedef SubTableHeader::Types Types;
296
  typedef KernSubTable<SubTableHeader> SubTable;
297
298
  protected:
299
  HBUINT32  version;  /* Version--0x00010000u */
300
  HBUINT32  tableCount; /* Number of subtables in the kerning table. */
301
  SubTable  firstSubTable;  /* Subtables. */
302
  public:
303
  DEFINE_SIZE_MIN (8);
304
};
305
306
struct kern
307
{
308
  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
309
310
2.00k
  bool     has_data () const { return u.version32; }
311
1.99k
  unsigned get_type () const { return u.major; }
312
313
  bool has_state_machine () const
314
15
  {
315
15
    switch (get_type ()) {
316
15
    case 0: hb_barrier (); return u.ot.has_state_machine ();
317
0
#ifndef HB_NO_AAT_SHAPE
318
0
    case 1: hb_barrier (); return u.aat.has_state_machine ();
319
0
#endif
320
0
    default:return false;
321
15
    }
322
15
  }
323
324
  bool has_cross_stream () const
325
0
  {
326
0
    switch (get_type ()) {
327
0
    case 0: hb_barrier (); return u.ot.has_cross_stream ();
328
0
#ifndef HB_NO_AAT_SHAPE
329
0
    case 1: hb_barrier (); return u.aat.has_cross_stream ();
330
0
#endif
331
0
    default:return false;
332
0
    }
333
0
  }
334
335
  int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
336
0
  {
337
0
    switch (get_type ()) {
338
0
    case 0: hb_barrier (); return u.ot.get_h_kerning (left, right);
339
0
#ifndef HB_NO_AAT_SHAPE
340
0
    case 1: hb_barrier (); return u.aat.get_h_kerning (left, right);
341
0
#endif
342
0
    default:return 0;
343
0
    }
344
0
  }
345
346
  bool apply (AAT::hb_aat_apply_context_t *c,
347
        const AAT::kern_accelerator_data_t &accel_data) const
348
219
  { return dispatch (c, accel_data); }
349
350
  template <typename context_t, typename ...Ts>
351
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
352
234
  {
353
234
    unsigned int subtable_type = get_type ();
354
234
    TRACE_DISPATCH (this, subtable_type);
355
234
    switch (subtable_type) {
356
234
    case 0: return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...));
357
0
#ifndef HB_NO_AAT_SHAPE
358
0
    case 1: return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...));
359
0
#endif
360
0
    default:  return_trace (c->default_return_value ());
361
234
    }
362
234
  }
AAT::hb_aat_apply_context_t::return_t OT::kern::dispatch<AAT::hb_aat_apply_context_t, AAT::kern_accelerator_data_t const&>(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const
Line
Count
Source
352
219
  {
353
219
    unsigned int subtable_type = get_type ();
354
219
    TRACE_DISPATCH (this, subtable_type);
355
219
    switch (subtable_type) {
356
219
    case 0: return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...));
357
0
#ifndef HB_NO_AAT_SHAPE
358
0
    case 1: return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...));
359
0
#endif
360
0
    default:  return_trace (c->default_return_value ());
361
219
    }
362
219
  }
hb_sanitize_context_t::return_t OT::kern::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
352
15
  {
353
15
    unsigned int subtable_type = get_type ();
354
15
    TRACE_DISPATCH (this, subtable_type);
355
15
    switch (subtable_type) {
356
15
    case 0: return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...));
357
0
#ifndef HB_NO_AAT_SHAPE
358
0
    case 1: return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...));
359
0
#endif
360
0
    default:  return_trace (c->default_return_value ());
361
15
    }
362
15
  }
363
364
  bool sanitize (hb_sanitize_context_t *c) const
365
15
  {
366
15
    TRACE_SANITIZE (this);
367
15
    if (!u.version32.sanitize (c)) return_trace (false);
368
15
    hb_barrier ();
369
15
    return_trace (dispatch (c));
370
15
  }
371
372
  AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
373
1.75k
  {
374
1.75k
    switch (get_type ()) {
375
1.75k
    case 0: hb_barrier (); return u.ot.create_accelerator_data (num_glyphs);
376
0
#ifndef HB_NO_AAT_SHAPE
377
0
    case 1: hb_barrier (); return u.aat.create_accelerator_data (num_glyphs);
378
0
#endif
379
0
    default:return AAT::kern_accelerator_data_t ();
380
1.75k
    }
381
1.75k
  }
382
383
  struct accelerator_t
384
  {
385
    accelerator_t (hb_face_t *face)
386
1.75k
    {
387
1.75k
      hb_sanitize_context_t sc;
388
1.75k
      this->table = sc.reference_table<kern> (face);
389
1.75k
      this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
390
1.75k
    }
391
    ~accelerator_t ()
392
1.75k
    {
393
1.75k
      this->table.destroy ();
394
1.75k
    }
395
396
219
    hb_blob_t *get_blob () const { return table.get_blob (); }
397
398
    bool apply (AAT::hb_aat_apply_context_t *c) const
399
219
    {
400
219
      return table->apply (c, accel_data);
401
219
    }
402
403
    hb_blob_ptr_t<kern> table;
404
    AAT::kern_accelerator_data_t accel_data;
405
    AAT::hb_aat_scratch_t scratch;
406
  };
407
408
  protected:
409
  union {
410
  HBUINT32    version32;
411
  HBUINT16    major;
412
  KernOT    ot;
413
#ifndef HB_NO_AAT_SHAPE
414
  KernAAT   aat;
415
#endif
416
  } u;
417
  public:
418
  DEFINE_SIZE_UNION (4, version32);
419
};
420
421
struct kern_accelerator_t : kern::accelerator_t {
422
1.75k
  kern_accelerator_t (hb_face_t *face) : kern::accelerator_t (face) {}
423
};
424
425
} /* namespace OT */
426
427
428
#endif /* HB_OT_KERN_TABLE_HH */