Coverage Report

Created: 2025-11-04 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-aat-layout-kerx-table.hh
Line
Count
Source
1
/*
2
 * Copyright © 2018  Ebrahim Byagowi
3
 * Copyright © 2018  Google, Inc.
4
 *
5
 *  This is part of HarfBuzz, a text shaping library.
6
 *
7
 * Permission is hereby granted, without written agreement and without
8
 * license or royalty fees, to use, copy, modify, and distribute this
9
 * software and its documentation for any purpose, provided that the
10
 * above copyright notice and the following two paragraphs appear in
11
 * all copies of this software.
12
 *
13
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
 * DAMAGE.
18
 *
19
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
 *
25
 * Google Author(s): Behdad Esfahbod
26
 */
27
28
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
29
#define HB_AAT_LAYOUT_KERX_TABLE_HH
30
31
#include "hb-kern.hh"
32
#include "hb-aat-layout-ankr-table.hh"
33
#include "hb-set-digest.hh"
34
35
/*
36
 * kerx -- Extended Kerning
37
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
38
 */
39
#define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
40
41
42
namespace AAT {
43
44
using namespace OT;
45
46
47
static inline int
48
kerxTupleKern (int value,
49
         unsigned int tupleCount,
50
         const void *base,
51
         hb_aat_apply_context_t *c)
52
0
{
53
0
  if (likely (!tupleCount || !c)) return value;
54
55
0
  unsigned int offset = value;
56
0
  const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
57
0
  if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
58
0
  hb_barrier ();
59
0
  return *pv;
60
0
}
Unexecuted instantiation: hb-ot-face.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: hb-aat-layout.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: hb-ot-layout.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*)
61
62
63
struct hb_glyph_pair_t
64
{
65
  hb_codepoint_t left;
66
  hb_codepoint_t right;
67
};
68
69
struct KernPair
70
{
71
0
  int get_kerning () const { return value; }
72
73
  int cmp (const hb_glyph_pair_t &o) const
74
0
  {
75
0
    int ret = left.cmp (o.left);
76
0
    if (ret) return ret;
77
0
    return right.cmp (o.right);
78
0
  }
79
80
  bool sanitize (hb_sanitize_context_t *c) const
81
0
  {
82
0
    TRACE_SANITIZE (this);
83
0
    return_trace (c->check_struct (this));
84
0
  }
85
86
  public:
87
  HBGlyphID16 left;
88
  HBGlyphID16 right;
89
  FWORD   value;
90
  public:
91
  DEFINE_SIZE_STATIC (6);
92
};
93
94
template <typename KernSubTableHeader>
95
struct KerxSubTableFormat0
96
{
97
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
98
       hb_aat_apply_context_t *c = nullptr) const
99
0
  {
100
0
    hb_glyph_pair_t pair = {left, right};
101
0
    int v = pairs.bsearch (pair).get_kerning ();
102
0
    return kerxTupleKern (v, header.tuple_count (), this, c);
103
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
104
105
  bool apply (hb_aat_apply_context_t *c) const
106
0
  {
107
0
    TRACE_APPLY (this);
108
109
0
    if (!c->plan->requested_kerning)
110
0
      return_trace (false);
111
112
0
    if (header.coverage & header.Backwards)
113
0
      return_trace (false);
114
115
0
    accelerator_t accel (*this, c);
116
0
    hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
117
0
    machine.kern (c->font, c->buffer, c->plan->kern_mask);
118
119
0
    return_trace (true);
120
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
121
122
  template <typename set_t>
123
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
124
63
  {
125
63
    for (const KernPair& pair : pairs)
126
485k
    {
127
485k
      first_set.add (pair.left);
128
485k
      second_set.add (pair.right);
129
485k
    }
130
63
  }
Unexecuted instantiation: void AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
void AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Line
Count
Source
124
63
  {
125
63
    for (const KernPair& pair : pairs)
126
485k
    {
127
485k
      first_set.add (pair.left);
128
485k
      second_set.add (pair.right);
129
485k
    }
130
63
  }
Unexecuted instantiation: void AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
131
132
  struct accelerator_t
133
  {
134
    const KerxSubTableFormat0 &table;
135
    hb_aat_apply_context_t *c;
136
137
    accelerator_t (const KerxSubTableFormat0 &table_,
138
       hb_aat_apply_context_t *c_) :
139
0
         table (table_), c (c_) {}
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
140
141
    int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
142
0
    {
143
0
      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
144
0
      return table.get_kerning (left, right, c);
145
0
    }
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
146
  };
147
148
149
  bool sanitize (hb_sanitize_context_t *c) const
150
63
  {
151
63
    TRACE_SANITIZE (this);
152
63
    return_trace (likely (pairs.sanitize (c)));
153
63
  }
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const
AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
150
63
  {
151
63
    TRACE_SANITIZE (this);
152
63
    return_trace (likely (pairs.sanitize (c)));
153
63
  }
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const
154
155
  protected:
156
  KernSubTableHeader  header;
157
  BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT>
158
      pairs;  /* Sorted kern records. */
159
  public:
160
  DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs);
161
};
162
163
164
template <bool extended>
165
struct Format1Entry;
166
167
template <>
168
struct Format1Entry<true>
169
{
170
  enum Flags
171
  {
172
    Push    = 0x8000, /* If set, push this glyph on the kerning stack. */
173
    DontAdvance   = 0x4000, /* If set, don't advance to the next glyph
174
           * before going to the new state. */
175
    Reset   = 0x2000, /* If set, reset the kerning data (clear the stack) */
176
    Reserved    = 0x1FFF, /* Not used; set to 0. */
177
  };
178
179
  struct EntryData
180
  {
181
    HBUINT16  kernActionIndex;/* Index into the kerning value array. If
182
         * this index is 0xFFFF, then no kerning
183
         * is to be performed. */
184
    public:
185
    DEFINE_SIZE_STATIC (2);
186
  };
187
188
  static bool initiateAction (const Entry<EntryData> &entry)
189
0
  { return entry.flags & Push; }
190
191
  static bool performAction (const Entry<EntryData> &entry)
192
0
  { return entry.data.kernActionIndex != 0xFFFF; }
193
194
  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
195
0
  { return entry.data.kernActionIndex; }
196
};
197
template <>
198
struct Format1Entry<false>
199
{
200
  enum Flags
201
  {
202
    Push    = 0x8000, /* If set, push this glyph on the kerning stack. */
203
    DontAdvance   = 0x4000, /* If set, don't advance to the next glyph
204
           * before going to the new state. */
205
    Offset    = 0x3FFF, /* Byte offset from beginning of subtable to the
206
           * value table for the glyphs on the kerning stack. */
207
208
    Reset   = 0x0000, /* Not supported? */
209
  };
210
211
  typedef void EntryData;
212
213
  static bool initiateAction (const Entry<EntryData> &entry)
214
0
  { return entry.flags & Push; }
215
216
  static bool performAction (const Entry<EntryData> &entry)
217
0
  { return entry.flags & Offset; }
218
219
  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
220
0
  { return entry.flags & Offset; }
221
};
222
223
template <typename KernSubTableHeader>
224
struct KerxSubTableFormat1
225
{
226
  typedef typename KernSubTableHeader::Types Types;
227
  typedef typename Types::HBUINT HBUINT;
228
229
  typedef Format1Entry<Types::extended> Format1EntryT;
230
  typedef typename Format1EntryT::EntryData EntryData;
231
232
  enum Flags
233
  {
234
    DontAdvance = Format1EntryT::DontAdvance,
235
  };
236
237
  bool is_action_initiable (const Entry<EntryData> &entry) const
238
0
  {
239
0
    return Format1EntryT::initiateAction (entry);
240
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::is_action_initiable(AAT::Entry<AAT::Format1Entry<true>::EntryData> const&) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::is_action_initiable(AAT::Entry<void> const&) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::is_action_initiable(AAT::Entry<void> const&) const
241
  bool is_actionable (const Entry<EntryData> &entry) const
242
0
  {
243
0
    return Format1EntryT::performAction (entry);
244
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::is_actionable(AAT::Entry<AAT::Format1Entry<true>::EntryData> const&) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::is_actionable(AAT::Entry<void> const&) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::is_actionable(AAT::Entry<void> const&) const
245
246
  struct driver_context_t
247
  {
248
    static constexpr bool in_place = true;
249
250
    driver_context_t (const KerxSubTableFormat1 *table_,
251
          hb_aat_apply_context_t *c_) :
252
0
  c (c_),
253
0
  table (table_),
254
  /* Apparently the offset kernAction is from the beginning of the state-machine,
255
   * similar to offsets in morx table, NOT from beginning of this table, like
256
   * other subtables in kerx.  Discovered via testing. */
257
0
  kernAction (&table->machine + table->kernAction),
258
0
  depth (0),
259
0
  crossStream (table->header.coverage & table->header.CrossStream) {}
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader> const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader> const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader> const*, AAT::hb_aat_apply_context_t*)
260
261
    void transition (hb_buffer_t *buffer,
262
         StateTableDriver<Types, EntryData, Flags> *driver,
263
         const Entry<EntryData> &entry)
264
0
    {
265
0
      unsigned int flags = entry.flags;
266
267
0
      if (flags & Format1EntryT::Reset)
268
0
  depth = 0;
269
270
0
      if (flags & Format1EntryT::Push)
271
0
      {
272
0
  if (likely (depth < ARRAY_LENGTH (stack)))
273
0
    stack[depth++] = buffer->idx;
274
0
  else
275
0
    depth = 0; /* Probably not what CoreText does, but better? */
276
0
      }
277
278
0
      if (Format1EntryT::performAction (entry) && depth)
279
0
      {
280
0
  unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
281
282
0
  unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
283
0
  kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
284
0
  const FWORD *actions = &kernAction[kern_idx];
285
0
  if (!c->sanitizer.check_array (actions, depth, tuple_count))
286
0
  {
287
0
    depth = 0;
288
0
    return;
289
0
  }
290
0
  hb_barrier ();
291
292
0
  hb_mask_t kern_mask = c->plan->kern_mask;
293
294
  /* From Apple 'kern' spec:
295
   * "Each pops one glyph from the kerning stack and applies the kerning value to it.
296
   * The end of the list is marked by an odd value... */
297
0
  bool last = false;
298
0
  while (!last && depth)
299
0
  {
300
0
    unsigned int idx = stack[--depth];
301
0
    int v = *actions;
302
0
    actions += tuple_count;
303
0
    if (idx >= buffer->len) continue;
304
305
    /* "The end of the list is marked by an odd value..." */
306
0
    last = v & 1;
307
0
    v &= ~1;
308
309
0
    hb_glyph_position_t &o = buffer->pos[idx];
310
311
0
    if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
312
0
    {
313
0
      if (crossStream)
314
0
      {
315
        /* The following flag is undocumented in the spec, but described
316
         * in the 'kern' table example. */
317
0
        if (v == -0x8000)
318
0
        {
319
0
    o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
320
0
    o.attach_chain() = 0;
321
0
    o.y_offset = 0;
322
0
        }
323
0
        else if (o.attach_type())
324
0
        {
325
0
    o.y_offset += c->font->em_scale_y (v);
326
0
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
327
0
        }
328
0
      }
329
0
      else if (buffer->info[idx].mask & kern_mask)
330
0
      {
331
0
        auto scaled = c->font->em_scale_x (v);
332
0
        o.x_advance += scaled;
333
0
        o.x_offset += scaled;
334
0
      }
335
0
    }
336
0
    else
337
0
    {
338
0
      if (crossStream)
339
0
      {
340
        /* CoreText doesn't do crossStream kerning in vertical.  We do. */
341
0
        if (v == -0x8000)
342
0
        {
343
0
    o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE;
344
0
    o.attach_chain() = 0;
345
0
    o.x_offset = 0;
346
0
        }
347
0
        else if (o.attach_type())
348
0
        {
349
0
    o.x_offset += c->font->em_scale_x (v);
350
0
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
351
0
        }
352
0
      }
353
0
      else if (buffer->info[idx].mask & kern_mask)
354
0
      {
355
0
        o.y_advance += c->font->em_scale_y (v);
356
0
        o.y_offset += c->font->em_scale_y (v);
357
0
      }
358
0
    }
359
0
  }
360
0
      }
361
0
    }
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::Flags>*, AAT::Entry<void> const&)
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::Flags>*, AAT::Entry<void> const&)
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, AAT::Format1Entry<true>::EntryData, AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::Flags>*, AAT::Entry<AAT::Format1Entry<true>::EntryData> const&)
362
363
    public:
364
    hb_aat_apply_context_t *c;
365
    const KerxSubTableFormat1 *table;
366
    private:
367
    const UnsizedArrayOf<FWORD> &kernAction;
368
    unsigned int stack[8];
369
    unsigned int depth;
370
    bool crossStream;
371
  };
372
373
  bool apply (hb_aat_apply_context_t *c) const
374
0
  {
375
0
    TRACE_APPLY (this);
376
377
0
    if (!c->plan->requested_kerning &&
378
0
  !(header.coverage & header.CrossStream))
379
0
      return false;
380
381
0
    driver_context_t dc (this, c);
382
383
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
384
385
0
    driver.drive (&dc, c);
386
387
0
    return_trace (true);
388
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
389
390
  bool sanitize (hb_sanitize_context_t *c) const
391
0
  {
392
0
    TRACE_SANITIZE (this);
393
    /* The rest of array sanitizations are done at run-time. */
394
0
    return_trace (likely (c->check_struct (this) &&
395
0
        machine.sanitize (c)));
396
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const
397
398
  template <typename set_t>
399
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
400
0
  {
401
0
    machine.collect_initial_glyphs (first_set, num_glyphs, *this);
402
    //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
403
0
  }
Unexecuted instantiation: void AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
404
405
  protected:
406
  KernSubTableHeader        header;
407
  StateTable<Types, EntryData>      machine;
408
  NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
409
  public:
410
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
411
};
412
413
template <typename KernSubTableHeader>
414
struct KerxSubTableFormat2
415
{
416
  typedef typename KernSubTableHeader::Types Types;
417
  typedef typename Types::HBUINT HBUINT;
418
419
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
420
       hb_aat_apply_context_t *c) const
421
0
  {
422
0
    unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
423
0
    unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0);
424
0
    unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0);
425
426
0
    const UnsizedArrayOf<FWORD> &arrayZ = this+array;
427
0
    unsigned int kern_idx = l + r;
428
0
    kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
429
0
    const FWORD *v = &arrayZ[kern_idx];
430
0
    if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
431
0
    hb_barrier ();
432
433
0
    return kerxTupleKern (*v, header.tuple_count (), this, c);
434
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const
435
436
  bool apply (hb_aat_apply_context_t *c) const
437
0
  {
438
0
    TRACE_APPLY (this);
439
440
0
    if (!c->plan->requested_kerning)
441
0
      return_trace (false);
442
443
0
    if (header.coverage & header.Backwards)
444
0
      return_trace (false);
445
446
0
    accelerator_t accel (*this, c);
447
0
    hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
448
0
    machine.kern (c->font, c->buffer, c->plan->kern_mask);
449
450
0
    return_trace (true);
451
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const
452
453
  template <typename set_t>
454
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
455
0
  {
456
0
    (this+leftClassTable).collect_glyphs (first_set, num_glyphs);
457
0
    (this+rightClassTable).collect_glyphs (second_set, num_glyphs);
458
0
  }
Unexecuted instantiation: void AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
459
460
  struct accelerator_t
461
  {
462
    const KerxSubTableFormat2 &table;
463
    hb_aat_apply_context_t *c;
464
465
    accelerator_t (const KerxSubTableFormat2 &table_,
466
       hb_aat_apply_context_t *c_) :
467
0
         table (table_), c (c_) {}
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader> const&, AAT::hb_aat_apply_context_t*)
468
469
    int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
470
0
    {
471
0
      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
472
0
      return table.get_kerning (left, right, c);
473
0
    }
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const
474
  };
475
476
  bool sanitize (hb_sanitize_context_t *c) const
477
0
  {
478
0
    TRACE_SANITIZE (this);
479
0
    return_trace (likely (c->check_struct (this) &&
480
0
        leftClassTable.sanitize (c, this) &&
481
0
        rightClassTable.sanitize (c, this) &&
482
0
        hb_barrier () &&
483
0
        c->check_range (this, array)));
484
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const
485
486
  protected:
487
  KernSubTableHeader  header;
488
  HBUINT    rowWidth; /* The width, in bytes, of a row in the table. */
489
  NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
490
      leftClassTable; /* Offset from beginning of this subtable to
491
           * left-hand class table. */
492
  NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
493
      rightClassTable;/* Offset from beginning of this subtable to
494
           * right-hand class table. */
495
  NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>
496
       array;   /* Offset from beginning of this subtable to
497
           * the start of the kerning array. */
498
  public:
499
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT));
500
};
501
502
template <typename KernSubTableHeader>
503
struct KerxSubTableFormat4
504
{
505
  typedef ExtendedTypes Types;
506
507
  struct EntryData
508
  {
509
    HBUINT16  ankrActionIndex;/* Either 0xFFFF (for no action) or the index of
510
         * the action to perform. */
511
    public:
512
    DEFINE_SIZE_STATIC (2);
513
  };
514
515
  enum Flags
516
  {
517
    Mark    = 0x8000, /* If set, remember this glyph as the marked glyph. */
518
    DontAdvance   = 0x4000, /* If set, don't advance to the next glyph before
519
           * going to the new state. */
520
    Reserved    = 0x3FFF, /* Not used; set to 0. */
521
  };
522
523
  bool is_action_initiable (const Entry<EntryData> &entry) const
524
0
  {
525
0
    return (entry.flags & Mark);
526
0
  }
527
  bool is_actionable (const Entry<EntryData> &entry) const
528
0
  {
529
0
    return entry.data.ankrActionIndex != 0xFFFF;
530
0
  }
531
532
  struct driver_context_t
533
  {
534
    static constexpr bool in_place = true;
535
    enum SubTableFlags
536
    {
537
      ActionType  = 0xC0000000, /* A two-bit field containing the action type. */
538
      Unused    = 0x3F000000, /* Unused - must be zero. */
539
      Offset    = 0x00FFFFFF, /* Masks the offset in bytes from the beginning
540
           * of the subtable to the beginning of the control
541
           * point table. */
542
    };
543
544
    driver_context_t (const KerxSubTableFormat4 *table_,
545
          hb_aat_apply_context_t *c_) :
546
0
  c (c_),
547
0
  table (table_),
548
0
  action_type ((table->flags & ActionType) >> 30),
549
0
  ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
550
0
  mark_set (false),
551
0
  mark (0) {}
552
553
    void transition (hb_buffer_t *buffer,
554
         StateTableDriver<Types, EntryData, Flags> *driver,
555
         const Entry<EntryData> &entry)
556
0
    {
557
0
      if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
558
0
      {
559
0
  hb_glyph_position_t &o = buffer->cur_pos();
560
0
  switch (action_type)
561
0
  {
562
0
    case 0: /* Control Point Actions.*/
563
0
    {
564
      /* Indexed into glyph outline. */
565
      /* Each action (record in ankrData) contains two 16-bit fields, so we must
566
         double the ankrActionIndex to get the correct offset here. */
567
0
      const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
568
0
      if (!c->sanitizer.check_array (data, 2)) return;
569
0
      hb_barrier ();
570
0
      unsigned int markControlPoint = *data++;
571
0
      unsigned int currControlPoint = *data++;
572
0
      hb_position_t markX = 0;
573
0
      hb_position_t markY = 0;
574
0
      hb_position_t currX = 0;
575
0
      hb_position_t currY = 0;
576
0
      if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint,
577
0
                    markControlPoint,
578
0
                    HB_DIRECTION_LTR /*XXX*/,
579
0
                    &markX, &markY) ||
580
0
    !c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint,
581
0
                    currControlPoint,
582
0
                    HB_DIRECTION_LTR /*XXX*/,
583
0
                    &currX, &currY))
584
0
        return;
585
586
0
      o.x_offset = markX - currX;
587
0
      o.y_offset = markY - currY;
588
0
    }
589
0
    break;
590
591
0
    case 1: /* Anchor Point Actions. */
592
0
    {
593
      /* Indexed into 'ankr' table. */
594
      /* Each action (record in ankrData) contains two 16-bit fields, so we must
595
         double the ankrActionIndex to get the correct offset here. */
596
0
      const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
597
0
      if (!c->sanitizer.check_array (data, 2)) return;
598
0
      hb_barrier ();
599
0
      unsigned int markAnchorPoint = *data++;
600
0
      unsigned int currAnchorPoint = *data++;
601
0
      const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
602
0
                  markAnchorPoint,
603
0
                  c->sanitizer.get_num_glyphs ());
604
0
      const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
605
0
                  currAnchorPoint,
606
0
                  c->sanitizer.get_num_glyphs ());
607
608
0
      o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
609
0
      o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
610
0
    }
611
0
    break;
612
613
0
    case 2: /* Control Point Coordinate Actions. */
614
0
    {
615
      /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
616
         by 4 to get the correct offset for the given action. */
617
0
      const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
618
0
      if (!c->sanitizer.check_array (data, 4)) return;
619
0
      hb_barrier ();
620
0
      int markX = *data++;
621
0
      int markY = *data++;
622
0
      int currX = *data++;
623
0
      int currY = *data++;
624
625
0
      o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX);
626
0
      o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY);
627
0
    }
628
0
    break;
629
0
  }
630
0
  o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
631
0
  o.attach_chain() = (int) mark - (int) buffer->idx;
632
0
  if (c->buffer_is_reversed)
633
0
    o.attach_chain() = -o.attach_chain();
634
0
  buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
635
0
      }
636
637
0
      if (entry.flags & Mark)
638
0
      {
639
0
  mark_set = true;
640
0
  mark = buffer->idx;
641
0
      }
642
0
    }
643
644
    public:
645
    hb_aat_apply_context_t *c;
646
    const KerxSubTableFormat4 *table;
647
    private:
648
    unsigned int action_type;
649
    const HBUINT16 *ankrData;
650
    bool mark_set;
651
    unsigned int mark;
652
  };
653
654
  bool apply (hb_aat_apply_context_t *c) const
655
0
  {
656
0
    TRACE_APPLY (this);
657
658
0
    driver_context_t dc (this, c);
659
660
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
661
662
0
    driver.drive (&dc, c);
663
664
0
    return_trace (true);
665
0
  }
666
667
  bool sanitize (hb_sanitize_context_t *c) const
668
0
  {
669
0
    TRACE_SANITIZE (this);
670
    /* The rest of array sanitizations are done at run-time. */
671
0
    return_trace (likely (c->check_struct (this) &&
672
0
        machine.sanitize (c)));
673
0
  }
674
675
  template <typename set_t>
676
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
677
0
  {
678
0
    machine.collect_initial_glyphs (first_set, num_glyphs, *this);
679
    //machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
680
0
  }
681
682
  protected:
683
  KernSubTableHeader    header;
684
  StateTable<Types, EntryData>  machine;
685
  HBUINT32      flags;
686
  public:
687
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
688
};
689
690
template <typename KernSubTableHeader>
691
struct KerxSubTableFormat6
692
{
693
  enum Flags
694
  {
695
    ValuesAreLong = 0x00000001,
696
  };
697
698
0
  bool is_long () const { return flags & ValuesAreLong; }
699
700
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
701
       hb_aat_apply_context_t *c) const
702
0
  {
703
0
    unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
704
0
    if (is_long ())
705
0
    {
706
0
      const auto &t = u.l;
707
0
      unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
708
0
      unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
709
0
      unsigned int offset = l + r;
710
0
      if (unlikely (offset < l)) return 0; /* Addition overflow. */
711
0
      if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
712
0
      const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
713
0
      if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
714
0
      hb_barrier ();
715
0
      return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
716
0
    }
717
0
    else
718
0
    {
719
0
      const auto &t = u.s;
720
0
      unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
721
0
      unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
722
0
      unsigned int offset = l + r;
723
0
      const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
724
0
      if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
725
0
      hb_barrier ();
726
0
      return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
727
0
    }
728
0
  }
729
730
  bool apply (hb_aat_apply_context_t *c) const
731
0
  {
732
0
    TRACE_APPLY (this);
733
734
0
    if (!c->plan->requested_kerning)
735
0
      return_trace (false);
736
737
0
    if (header.coverage & header.Backwards)
738
0
      return_trace (false);
739
740
0
    accelerator_t accel (*this, c);
741
0
    hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
742
0
    machine.kern (c->font, c->buffer, c->plan->kern_mask);
743
744
0
    return_trace (true);
745
0
  }
746
747
  bool sanitize (hb_sanitize_context_t *c) const
748
0
  {
749
0
    TRACE_SANITIZE (this);
750
0
    return_trace (likely (c->check_struct (this) &&
751
0
        hb_barrier () &&
752
0
        (is_long () ?
753
0
         (
754
0
           u.l.rowIndexTable.sanitize (c, this) &&
755
0
           u.l.columnIndexTable.sanitize (c, this) &&
756
0
           c->check_range (this, u.l.array)
757
0
         ) : (
758
0
           u.s.rowIndexTable.sanitize (c, this) &&
759
0
           u.s.columnIndexTable.sanitize (c, this) &&
760
0
           c->check_range (this, u.s.array)
761
0
         )) &&
762
0
        (header.tuple_count () == 0 ||
763
0
         c->check_range (this, vector))));
764
0
  }
765
766
  template <typename set_t>
767
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
768
0
  {
769
0
    if (is_long ())
770
0
    {
771
0
      const auto &t = u.l;
772
0
      (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
773
0
      (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
774
0
    }
775
0
    else
776
0
    {
777
0
      const auto &t = u.s;
778
0
      (this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
779
0
      (this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
780
0
    }
781
0
  }
782
783
  struct accelerator_t
784
  {
785
    const KerxSubTableFormat6 &table;
786
    hb_aat_apply_context_t *c;
787
788
    accelerator_t (const KerxSubTableFormat6 &table_,
789
       hb_aat_apply_context_t *c_) :
790
0
         table (table_), c (c_) {}
791
792
    int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
793
0
    {
794
0
      if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
795
0
      return table.get_kerning (left, right, c);
796
0
    }
797
  };
798
799
  protected:
800
  KernSubTableHeader    header;
801
  HBUINT32      flags;
802
  HBUINT16      rowCount;
803
  HBUINT16      columnCount;
804
  union U
805
  {
806
    struct Long
807
    {
808
      NNOffset32To<Lookup<HBUINT32>>    rowIndexTable;
809
      NNOffset32To<Lookup<HBUINT32>>    columnIndexTable;
810
      NNOffset32To<UnsizedArrayOf<FWORD32>> array;
811
    } l;
812
    struct Short
813
    {
814
      NNOffset32To<Lookup<HBUINT16>>    rowIndexTable;
815
      NNOffset32To<Lookup<HBUINT16>>    columnIndexTable;
816
      NNOffset32To<UnsizedArrayOf<FWORD>> array;
817
    } s;
818
  } u;
819
  NNOffset32To<UnsizedArrayOf<FWORD>> vector;
820
  public:
821
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
822
};
823
824
825
struct KerxSubTableHeader
826
{
827
  typedef ExtendedTypes Types;
828
829
0
  unsigned   tuple_count () const { return tupleCount; }
830
0
  bool     is_horizontal () const { return !(coverage & Vertical); }
831
832
  enum Coverage
833
  {
834
    Vertical  = 0x80000000u,  /* Set if table has vertical kerning values. */
835
    CrossStream = 0x40000000u,  /* Set if table has cross-stream kerning values. */
836
    Variation = 0x20000000u,  /* Set if table has variation kerning values. */
837
    Backwards = 0x10000000u,  /* If clear, process the glyphs forwards, that
838
         * is, from first to last in the glyph stream.
839
         * If we, process them from last to first.
840
         * This flag only applies to state-table based
841
         * 'kerx' subtables (types 1 and 4). */
842
    Reserved  = 0x0FFFFF00u,  /* Reserved, set to zero. */
843
    SubtableType= 0x000000FFu,  /* Subtable type. */
844
  };
845
846
  bool sanitize (hb_sanitize_context_t *c) const
847
0
  {
848
0
    TRACE_SANITIZE (this);
849
0
    return_trace (c->check_struct (this));
850
0
  }
851
852
  public:
853
  HBUINT32  length;
854
  HBUINT32  coverage;
855
  HBUINT32  tupleCount;
856
  public:
857
  DEFINE_SIZE_STATIC (12);
858
};
859
860
struct KerxSubTable
861
{
862
  friend struct kerx;
863
864
0
  unsigned int get_size () const { return u.header.length; }
865
0
  unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
866
867
  template <typename context_t, typename ...Ts>
868
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
869
0
  {
870
0
    unsigned int subtable_type = get_type ();
871
0
    TRACE_DISPATCH (this, subtable_type);
872
0
    switch (subtable_type) {
873
0
    case 0: return_trace (c->dispatch (u.format0, std::forward<Ts> (ds)...));
874
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
875
0
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
876
0
    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
877
0
    case 6: return_trace (c->dispatch (u.format6, std::forward<Ts> (ds)...));
878
0
    default:  return_trace (c->default_return_value ());
879
0
    }
880
0
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t AAT::KerxSubTable::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t AAT::KerxSubTable::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
881
882
  template <typename set_t>
883
  void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
884
0
  {
885
0
    unsigned int subtable_type = get_type ();
886
0
    switch (subtable_type) {
887
0
    case 0: u.format0.collect_glyphs (first_set, second_set, num_glyphs); return;
888
0
    case 1: u.format1.collect_glyphs (first_set, second_set, num_glyphs); return;
889
0
    case 2: u.format2.collect_glyphs (first_set, second_set, num_glyphs); return;
890
0
    case 4: u.format4.collect_glyphs (first_set, second_set, num_glyphs); return;
891
0
    case 6: u.format6.collect_glyphs (first_set, second_set, num_glyphs); return;
892
0
    default:  return;
893
0
    }
894
0
  }
895
896
  bool sanitize (hb_sanitize_context_t *c) const
897
0
  {
898
0
    TRACE_SANITIZE (this);
899
0
    if (!(u.header.sanitize (c) &&
900
0
    hb_barrier () &&
901
0
    u.header.length >= u.header.static_size &&
902
0
    c->check_range (this, u.header.length)))
903
0
      return_trace (false);
904
905
0
    return_trace (dispatch (c));
906
0
  }
907
908
  public:
909
  union {
910
  KerxSubTableHeader        header;
911
  KerxSubTableFormat0<KerxSubTableHeader> format0;
912
  KerxSubTableFormat1<KerxSubTableHeader> format1;
913
  KerxSubTableFormat2<KerxSubTableHeader> format2;
914
  KerxSubTableFormat4<KerxSubTableHeader> format4;
915
  KerxSubTableFormat6<KerxSubTableHeader> format6;
916
  } u;
917
  public:
918
  DEFINE_SIZE_MIN (12);
919
};
920
921
922
/*
923
 * The 'kerx' Table
924
 */
925
926
struct kern_subtable_accelerator_data_t
927
{
928
  hb_bit_set_t first_set;
929
  hb_bit_set_t second_set;
930
  mutable hb_aat_class_cache_t class_cache;
931
};
932
933
struct kern_accelerator_data_t
934
{
935
  hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
936
  hb_aat_scratch_t scratch;
937
};
938
939
template <typename T>
940
struct KerxTable
941
{
942
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
943
7.88k
  const T* thiz () const { return static_cast<const T *> (this); }
AAT::KerxTable<AAT::kerx>::thiz() const
Line
Count
Source
943
3.56k
  const T* thiz () const { return static_cast<const T *> (this); }
AAT::KerxTable<OT::KernOT>::thiz() const
Line
Count
Source
943
4.31k
  const T* thiz () const { return static_cast<const T *> (this); }
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::thiz() const
944
945
  bool has_state_machine () const
946
18
  {
947
18
    typedef typename T::SubTable SubTable;
948
949
18
    const SubTable *st = &thiz()->firstSubTable;
950
18
    unsigned int count = thiz()->tableCount;
951
81
    for (unsigned int i = 0; i < count; i++)
952
63
    {
953
63
      if (st->get_type () == 1)
954
0
  return true;
955
956
      // TODO: What about format 4? What's this API used for anyway?
957
958
63
      st = &StructAfter<SubTable> (*st);
959
63
    }
960
18
    return false;
961
18
  }
AAT::KerxTable<OT::KernOT>::has_state_machine() const
Line
Count
Source
946
18
  {
947
18
    typedef typename T::SubTable SubTable;
948
949
18
    const SubTable *st = &thiz()->firstSubTable;
950
18
    unsigned int count = thiz()->tableCount;
951
81
    for (unsigned int i = 0; i < count; i++)
952
63
    {
953
63
      if (st->get_type () == 1)
954
0
  return true;
955
956
      // TODO: What about format 4? What's this API used for anyway?
957
958
63
      st = &StructAfter<SubTable> (*st);
959
63
    }
960
18
    return false;
961
18
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_state_machine() const
962
963
  bool has_cross_stream () const
964
0
  {
965
0
    typedef typename T::SubTable SubTable;
966
967
0
    const SubTable *st = &thiz()->firstSubTable;
968
0
    unsigned int count = thiz()->tableCount;
969
0
    for (unsigned int i = 0; i < count; i++)
970
0
    {
971
0
      if (st->u.header.coverage & st->u.header.CrossStream)
972
0
  return true;
973
0
      st = &StructAfter<SubTable> (*st);
974
0
    }
975
0
    return false;
976
0
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::has_cross_stream() const
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_cross_stream() const
977
978
  int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
979
0
  {
980
0
    typedef typename T::SubTable SubTable;
981
0
982
0
    int v = 0;
983
0
    const SubTable *st = &thiz()->firstSubTable;
984
0
    unsigned int count = thiz()->tableCount;
985
0
    for (unsigned int i = 0; i < count; i++)
986
0
    {
987
0
      if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
988
0
    !st->u.header.is_horizontal ())
989
0
  continue;
990
0
      v += st->get_kerning (left, right);
991
0
      st = &StructAfter<SubTable> (*st);
992
0
    }
993
0
    return v;
994
0
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::get_h_kerning(unsigned int, unsigned int) const
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::get_h_kerning(unsigned int, unsigned int) const
995
996
  bool apply (AAT::hb_aat_apply_context_t *c,
997
        const kern_accelerator_data_t &accel_data) const
998
304
  {
999
304
    c->buffer->unsafe_to_concat ();
1000
1001
304
    c->setup_buffer_glyph_set ();
1002
1003
304
    typedef typename T::SubTable SubTable;
1004
1005
304
    bool ret = false;
1006
304
    bool seenCrossStream = false;
1007
304
    c->set_lookup_index (0);
1008
304
    const SubTable *st = &thiz()->firstSubTable;
1009
304
    unsigned int count = thiz()->tableCount;
1010
1.44k
    for (unsigned int i = 0; i < count; i++)
1011
1.13k
    {
1012
1.13k
      bool reverse;
1013
1014
1.13k
      auto &subtable_accel = accel_data.subtable_accels[i];
1015
1016
1.13k
      if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
1017
0
  goto skip;
1018
1019
1.13k
      if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
1020
0
  goto skip;
1021
1022
1.13k
      c->first_set = &subtable_accel.first_set;
1023
1.13k
      c->second_set = &subtable_accel.second_set;
1024
1.13k
      c->machine_class_cache = &subtable_accel.class_cache;
1025
1026
1.13k
      if (!c->buffer_intersects_machine ())
1027
1.13k
      {
1028
1.13k
  (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
1029
1.13k
  goto skip;
1030
1.13k
      }
1031
1032
0
      reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
1033
0
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1034
1035
0
      if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
1036
0
  goto skip;
1037
1038
0
      if (!seenCrossStream &&
1039
0
    (st->u.header.coverage & st->u.header.CrossStream))
1040
0
      {
1041
  /* Attach all glyphs into a chain. */
1042
0
  seenCrossStream = true;
1043
0
  hb_glyph_position_t *pos = c->buffer->pos;
1044
0
  unsigned int count = c->buffer->len;
1045
0
  for (unsigned int i = 0; i < count; i++)
1046
0
  {
1047
0
    pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
1048
0
    pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
1049
    /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
1050
     * since there needs to be a non-zero attachment for post-positioning to
1051
     * be needed. */
1052
0
  }
1053
0
      }
1054
1055
0
      if (reverse != c->buffer_is_reversed)
1056
0
        c->reverse_buffer ();
1057
1058
0
      {
1059
  /* See comment in sanitize() for conditional here. */
1060
0
  hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
1061
0
  ret |= st->dispatch (c);
1062
0
      }
1063
1064
0
      (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
1065
1066
1.13k
    skip:
1067
1.13k
      st = &StructAfter<SubTable> (*st);
1068
1.13k
      c->set_lookup_index (c->lookup_index + 1);
1069
1.13k
    }
1070
304
    if (c->buffer_is_reversed)
1071
0
      c->reverse_buffer ();
1072
1073
304
    return ret;
1074
304
  }
AAT::KerxTable<OT::KernOT>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const
Line
Count
Source
998
304
  {
999
304
    c->buffer->unsafe_to_concat ();
1000
1001
304
    c->setup_buffer_glyph_set ();
1002
1003
304
    typedef typename T::SubTable SubTable;
1004
1005
304
    bool ret = false;
1006
304
    bool seenCrossStream = false;
1007
304
    c->set_lookup_index (0);
1008
304
    const SubTable *st = &thiz()->firstSubTable;
1009
304
    unsigned int count = thiz()->tableCount;
1010
1.44k
    for (unsigned int i = 0; i < count; i++)
1011
1.13k
    {
1012
1.13k
      bool reverse;
1013
1014
1.13k
      auto &subtable_accel = accel_data.subtable_accels[i];
1015
1016
1.13k
      if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
1017
0
  goto skip;
1018
1019
1.13k
      if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
1020
0
  goto skip;
1021
1022
1.13k
      c->first_set = &subtable_accel.first_set;
1023
1.13k
      c->second_set = &subtable_accel.second_set;
1024
1.13k
      c->machine_class_cache = &subtable_accel.class_cache;
1025
1026
1.13k
      if (!c->buffer_intersects_machine ())
1027
1.13k
      {
1028
1.13k
  (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
1029
1.13k
  goto skip;
1030
1.13k
      }
1031
1032
0
      reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
1033
0
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1034
1035
0
      if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
1036
0
  goto skip;
1037
1038
0
      if (!seenCrossStream &&
1039
0
    (st->u.header.coverage & st->u.header.CrossStream))
1040
0
      {
1041
  /* Attach all glyphs into a chain. */
1042
0
  seenCrossStream = true;
1043
0
  hb_glyph_position_t *pos = c->buffer->pos;
1044
0
  unsigned int count = c->buffer->len;
1045
0
  for (unsigned int i = 0; i < count; i++)
1046
0
  {
1047
0
    pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
1048
0
    pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
1049
    /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
1050
     * since there needs to be a non-zero attachment for post-positioning to
1051
     * be needed. */
1052
0
  }
1053
0
      }
1054
1055
0
      if (reverse != c->buffer_is_reversed)
1056
0
        c->reverse_buffer ();
1057
1058
0
      {
1059
  /* See comment in sanitize() for conditional here. */
1060
0
  hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
1061
0
  ret |= st->dispatch (c);
1062
0
      }
1063
1064
0
      (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
1065
1066
1.13k
    skip:
1067
1.13k
      st = &StructAfter<SubTable> (*st);
1068
1.13k
      c->set_lookup_index (c->lookup_index + 1);
1069
1.13k
    }
1070
304
    if (c->buffer_is_reversed)
1071
0
      c->reverse_buffer ();
1072
1073
304
    return ret;
1074
304
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const
Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const
1075
1076
  bool sanitize (hb_sanitize_context_t *c) const
1077
18
  {
1078
18
    TRACE_SANITIZE (this);
1079
18
    if (unlikely (!(thiz()->version.sanitize (c) &&
1080
18
        hb_barrier () &&
1081
18
        (unsigned) thiz()->version >= (unsigned) T::minVersion &&
1082
18
        thiz()->tableCount.sanitize (c))))
1083
0
      return_trace (false);
1084
1085
18
    typedef typename T::SubTable SubTable;
1086
1087
18
    const SubTable *st = &thiz()->firstSubTable;
1088
18
    unsigned int count = thiz()->tableCount;
1089
81
    for (unsigned int i = 0; i < count; i++)
1090
63
    {
1091
63
      if (unlikely (!st->u.header.sanitize (c)))
1092
0
  return_trace (false);
1093
63
      hb_barrier ();
1094
      /* OpenType kern table has 2-byte subtable lengths.  That's limiting.
1095
       * MS implementation also only supports one subtable, of format 0,
1096
       * anyway.  Certain versions of some fonts, like Calibry, contain
1097
       * kern subtable that exceeds 64kb.  Looks like, the subtable length
1098
       * is simply ignored.  Which makes sense.  It's only needed if you
1099
       * have multiple subtables.  To handle such fonts, we just ignore
1100
       * the length for the last subtable. */
1101
63
      hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr);
1102
1103
63
      if (unlikely (!st->sanitize (c)))
1104
0
  return_trace (false);
1105
1106
63
      st = &StructAfter<SubTable> (*st);
1107
63
    }
1108
1109
18
    unsigned majorVersion = thiz()->version;
1110
18
    if (sizeof (thiz()->version) == 4)
1111
0
      majorVersion = majorVersion >> 16;
1112
18
    if (majorVersion >= 3)
1113
0
    {
1114
0
      const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
1115
0
      if (!coverage->sanitize (c, count))
1116
0
        return_trace (false);
1117
0
    }
1118
1119
18
    return_trace (true);
1120
18
  }
Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::sanitize(hb_sanitize_context_t*) const
AAT::KerxTable<OT::KernOT>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
1077
18
  {
1078
18
    TRACE_SANITIZE (this);
1079
18
    if (unlikely (!(thiz()->version.sanitize (c) &&
1080
18
        hb_barrier () &&
1081
18
        (unsigned) thiz()->version >= (unsigned) T::minVersion &&
1082
18
        thiz()->tableCount.sanitize (c))))
1083
0
      return_trace (false);
1084
1085
18
    typedef typename T::SubTable SubTable;
1086
1087
18
    const SubTable *st = &thiz()->firstSubTable;
1088
18
    unsigned int count = thiz()->tableCount;
1089
81
    for (unsigned int i = 0; i < count; i++)
1090
63
    {
1091
63
      if (unlikely (!st->u.header.sanitize (c)))
1092
0
  return_trace (false);
1093
63
      hb_barrier ();
1094
      /* OpenType kern table has 2-byte subtable lengths.  That's limiting.
1095
       * MS implementation also only supports one subtable, of format 0,
1096
       * anyway.  Certain versions of some fonts, like Calibry, contain
1097
       * kern subtable that exceeds 64kb.  Looks like, the subtable length
1098
       * is simply ignored.  Which makes sense.  It's only needed if you
1099
       * have multiple subtables.  To handle such fonts, we just ignore
1100
       * the length for the last subtable. */
1101
63
      hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr);
1102
1103
63
      if (unlikely (!st->sanitize (c)))
1104
0
  return_trace (false);
1105
1106
63
      st = &StructAfter<SubTable> (*st);
1107
63
    }
1108
1109
18
    unsigned majorVersion = thiz()->version;
1110
18
    if (sizeof (thiz()->version) == 4)
1111
0
      majorVersion = majorVersion >> 16;
1112
18
    if (majorVersion >= 3)
1113
0
    {
1114
0
      const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
1115
0
      if (!coverage->sanitize (c, count))
1116
0
        return_trace (false);
1117
0
    }
1118
1119
18
    return_trace (true);
1120
18
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::sanitize(hb_sanitize_context_t*) const
1121
1122
  kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
1123
3.56k
  {
1124
3.56k
    kern_accelerator_data_t accel_data;
1125
1126
3.56k
    typedef typename T::SubTable SubTable;
1127
1128
3.56k
    const SubTable *st = &thiz()->firstSubTable;
1129
3.56k
    unsigned int count = thiz()->tableCount;
1130
3.62k
    for (unsigned int i = 0; i < count; i++)
1131
63
    {
1132
63
      auto &subtable_accel = *accel_data.subtable_accels.push ();
1133
63
      if (unlikely (accel_data.subtable_accels.in_error ()))
1134
0
    return accel_data;
1135
1136
63
      st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
1137
63
      subtable_accel.class_cache.clear ();
1138
1139
63
      st = &StructAfter<SubTable> (*st);
1140
63
    }
1141
1142
3.56k
    return accel_data;
1143
3.56k
  }
AAT::KerxTable<AAT::kerx>::create_accelerator_data(unsigned int) const
Line
Count
Source
1123
1.78k
  {
1124
1.78k
    kern_accelerator_data_t accel_data;
1125
1126
1.78k
    typedef typename T::SubTable SubTable;
1127
1128
1.78k
    const SubTable *st = &thiz()->firstSubTable;
1129
1.78k
    unsigned int count = thiz()->tableCount;
1130
1.78k
    for (unsigned int i = 0; i < count; i++)
1131
0
    {
1132
0
      auto &subtable_accel = *accel_data.subtable_accels.push ();
1133
0
      if (unlikely (accel_data.subtable_accels.in_error ()))
1134
0
    return accel_data;
1135
1136
0
      st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
1137
0
      subtable_accel.class_cache.clear ();
1138
1139
0
      st = &StructAfter<SubTable> (*st);
1140
0
    }
1141
1142
1.78k
    return accel_data;
1143
1.78k
  }
AAT::KerxTable<OT::KernOT>::create_accelerator_data(unsigned int) const
Line
Count
Source
1123
1.78k
  {
1124
1.78k
    kern_accelerator_data_t accel_data;
1125
1126
1.78k
    typedef typename T::SubTable SubTable;
1127
1128
1.78k
    const SubTable *st = &thiz()->firstSubTable;
1129
1.78k
    unsigned int count = thiz()->tableCount;
1130
1.84k
    for (unsigned int i = 0; i < count; i++)
1131
63
    {
1132
63
      auto &subtable_accel = *accel_data.subtable_accels.push ();
1133
63
      if (unlikely (accel_data.subtable_accels.in_error ()))
1134
0
    return accel_data;
1135
1136
63
      st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
1137
63
      subtable_accel.class_cache.clear ();
1138
1139
63
      st = &StructAfter<SubTable> (*st);
1140
63
    }
1141
1142
1.78k
    return accel_data;
1143
1.78k
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::create_accelerator_data(unsigned int) const
1144
1145
  struct accelerator_t
1146
  {
1147
    accelerator_t (hb_face_t *face)
1148
1.78k
    {
1149
1.78k
      hb_sanitize_context_t sc;
1150
1.78k
      this->table = sc.reference_table<T> (face);
1151
1.78k
      this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
1152
1.78k
    }
1153
    ~accelerator_t ()
1154
1.78k
    {
1155
1.78k
      this->table.destroy ();
1156
1.78k
    }
1157
1158
0
    hb_blob_t *get_blob () const { return table.get_blob (); }
1159
1160
    bool apply (AAT::hb_aat_apply_context_t *c) const
1161
0
    {
1162
0
      return table->apply (c, accel_data);
1163
0
    }
1164
1165
    hb_blob_ptr_t<T> table;
1166
    kern_accelerator_data_t accel_data;
1167
    hb_aat_scratch_t scratch;
1168
  };
1169
};
1170
1171
struct kerx : KerxTable<kerx>
1172
{
1173
  friend struct KerxTable<kerx>;
1174
1175
  static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
1176
  static constexpr unsigned minVersion = 2u;
1177
1178
  typedef KerxSubTableHeader SubTableHeader;
1179
  typedef SubTableHeader::Types Types;
1180
  typedef KerxSubTable SubTable;
1181
1182
2.05k
  bool has_data () const { return version; }
1183
1184
  protected:
1185
  HBUINT16  version;  /* The version number of the extended kerning table
1186
         * (currently 2, 3, or 4). */
1187
  HBUINT16  unused;   /* Set to 0. */
1188
  HBUINT32  tableCount; /* The number of subtables included in the extended kerning
1189
         * table. */
1190
  SubTable  firstSubTable;  /* Subtables. */
1191
/*subtableGlyphCoverageArray*/  /* Only if version >= 3. We don't use. */
1192
1193
  public:
1194
  DEFINE_SIZE_MIN (8);
1195
};
1196
1197
struct kerx_accelerator_t : kerx::accelerator_t {
1198
1.78k
  kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {}
1199
};
1200
1201
} /* namespace AAT */
1202
1203
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */