Coverage Report

Created: 2025-07-16 07:53

/src/qtbase/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
Line
Count
Source (jump to first uncovered line)
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-ot-layout.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*)
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 &left_set, set_t &right_set, unsigned num_glyphs) const
124
0
  {
125
0
    for (const KernPair& pair : pairs)
126
0
    {
127
0
      left_set.add (pair.left);
128
0
      right_set.add (pair.right);
129
0
    }
130
0
  }
Unexecuted instantiation: void AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const
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<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*)
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader> 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->left_set)[left] || !(*c->right_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
0
  {
151
0
    TRACE_SANITIZE (this);
152
0
    return_trace (likely (pairs.sanitize (c)));
153
0
  }
Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const
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<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*)
Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader> 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 &left_set, set_t &right_set, unsigned num_glyphs) const
400
0
  {
401
0
    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
402
    //machine.collect_glyphs (right_set, num_glyphs); // right_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 &left_set, set_t &right_set, unsigned num_glyphs) const
455
0
  {
456
0
    (this+leftClassTable).collect_glyphs (left_set, num_glyphs);
457
0
    (this+rightClassTable).collect_glyphs (right_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<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*)
Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader> 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->left_set)[left] || !(*c->right_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
  buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
633
0
      }
634
635
0
      if (entry.flags & Mark)
636
0
      {
637
0
  mark_set = true;
638
0
  mark = buffer->idx;
639
0
      }
640
0
    }
641
642
    public:
643
    hb_aat_apply_context_t *c;
644
    const KerxSubTableFormat4 *table;
645
    private:
646
    unsigned int action_type;
647
    const HBUINT16 *ankrData;
648
    bool mark_set;
649
    unsigned int mark;
650
  };
651
652
  bool apply (hb_aat_apply_context_t *c) const
653
0
  {
654
0
    TRACE_APPLY (this);
655
656
0
    driver_context_t dc (this, c);
657
658
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
659
660
0
    driver.drive (&dc, c);
661
662
0
    return_trace (true);
663
0
  }
664
665
  bool sanitize (hb_sanitize_context_t *c) const
666
0
  {
667
0
    TRACE_SANITIZE (this);
668
    /* The rest of array sanitizations are done at run-time. */
669
0
    return_trace (likely (c->check_struct (this) &&
670
0
        machine.sanitize (c)));
671
0
  }
672
673
  template <typename set_t>
674
  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
675
0
  {
676
0
    machine.collect_initial_glyphs (left_set, num_glyphs, *this);
677
    //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
678
0
  }
679
680
  protected:
681
  KernSubTableHeader    header;
682
  StateTable<Types, EntryData>  machine;
683
  HBUINT32      flags;
684
  public:
685
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
686
};
687
688
template <typename KernSubTableHeader>
689
struct KerxSubTableFormat6
690
{
691
  enum Flags
692
  {
693
    ValuesAreLong = 0x00000001,
694
  };
695
696
0
  bool is_long () const { return flags & ValuesAreLong; }
697
698
  int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
699
       hb_aat_apply_context_t *c) const
700
0
  {
701
0
    unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
702
0
    if (is_long ())
703
0
    {
704
0
      const auto &t = u.l;
705
0
      unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
706
0
      unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
707
0
      unsigned int offset = l + r;
708
0
      if (unlikely (offset < l)) return 0; /* Addition overflow. */
709
0
      if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
710
0
      const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
711
0
      if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
712
0
      hb_barrier ();
713
0
      return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
714
0
    }
715
0
    else
716
0
    {
717
0
      const auto &t = u.s;
718
0
      unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
719
0
      unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
720
0
      unsigned int offset = l + r;
721
0
      const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
722
0
      if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
723
0
      hb_barrier ();
724
0
      return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
725
0
    }
726
0
  }
727
728
  bool apply (hb_aat_apply_context_t *c) const
729
0
  {
730
0
    TRACE_APPLY (this);
731
732
0
    if (!c->plan->requested_kerning)
733
0
      return_trace (false);
734
735
0
    if (header.coverage & header.Backwards)
736
0
      return_trace (false);
737
738
0
    accelerator_t accel (*this, c);
739
0
    hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
740
0
    machine.kern (c->font, c->buffer, c->plan->kern_mask);
741
742
0
    return_trace (true);
743
0
  }
744
745
  bool sanitize (hb_sanitize_context_t *c) const
746
0
  {
747
0
    TRACE_SANITIZE (this);
748
0
    return_trace (likely (c->check_struct (this) &&
749
0
        hb_barrier () &&
750
0
        (is_long () ?
751
0
         (
752
0
           u.l.rowIndexTable.sanitize (c, this) &&
753
0
           u.l.columnIndexTable.sanitize (c, this) &&
754
0
           c->check_range (this, u.l.array)
755
0
         ) : (
756
0
           u.s.rowIndexTable.sanitize (c, this) &&
757
0
           u.s.columnIndexTable.sanitize (c, this) &&
758
0
           c->check_range (this, u.s.array)
759
0
         )) &&
760
0
        (header.tuple_count () == 0 ||
761
0
         c->check_range (this, vector))));
762
0
  }
763
764
  template <typename set_t>
765
  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
766
0
  {
767
0
    if (is_long ())
768
0
    {
769
0
      const auto &t = u.l;
770
0
      (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
771
0
      (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
772
0
    }
773
0
    else
774
0
    {
775
0
      const auto &t = u.s;
776
0
      (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
777
0
      (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
778
0
    }
779
0
  }
780
781
  struct accelerator_t
782
  {
783
    const KerxSubTableFormat6 &table;
784
    hb_aat_apply_context_t *c;
785
786
    accelerator_t (const KerxSubTableFormat6 &table_,
787
       hb_aat_apply_context_t *c_) :
788
0
         table (table_), c (c_) {}
789
790
    int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
791
0
    {
792
0
      if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
793
0
      return table.get_kerning (left, right, c);
794
0
    }
795
  };
796
797
  protected:
798
  KernSubTableHeader    header;
799
  HBUINT32      flags;
800
  HBUINT16      rowCount;
801
  HBUINT16      columnCount;
802
  union U
803
  {
804
    struct Long
805
    {
806
      NNOffset32To<Lookup<HBUINT32>>    rowIndexTable;
807
      NNOffset32To<Lookup<HBUINT32>>    columnIndexTable;
808
      NNOffset32To<UnsizedArrayOf<FWORD32>> array;
809
    } l;
810
    struct Short
811
    {
812
      NNOffset32To<Lookup<HBUINT16>>    rowIndexTable;
813
      NNOffset32To<Lookup<HBUINT16>>    columnIndexTable;
814
      NNOffset32To<UnsizedArrayOf<FWORD>> array;
815
    } s;
816
  } u;
817
  NNOffset32To<UnsizedArrayOf<FWORD>> vector;
818
  public:
819
  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
820
};
821
822
823
struct KerxSubTableHeader
824
{
825
  typedef ExtendedTypes Types;
826
827
0
  unsigned   tuple_count () const { return tupleCount; }
828
0
  bool     is_horizontal () const { return !(coverage & Vertical); }
829
830
  enum Coverage
831
  {
832
    Vertical  = 0x80000000u,  /* Set if table has vertical kerning values. */
833
    CrossStream = 0x40000000u,  /* Set if table has cross-stream kerning values. */
834
    Variation = 0x20000000u,  /* Set if table has variation kerning values. */
835
    Backwards = 0x10000000u,  /* If clear, process the glyphs forwards, that
836
         * is, from first to last in the glyph stream.
837
         * If we, process them from last to first.
838
         * This flag only applies to state-table based
839
         * 'kerx' subtables (types 1 and 4). */
840
    Reserved  = 0x0FFFFF00u,  /* Reserved, set to zero. */
841
    SubtableType= 0x000000FFu,  /* Subtable type. */
842
  };
843
844
  bool sanitize (hb_sanitize_context_t *c) const
845
0
  {
846
0
    TRACE_SANITIZE (this);
847
0
    return_trace (c->check_struct (this));
848
0
  }
849
850
  public:
851
  HBUINT32  length;
852
  HBUINT32  coverage;
853
  HBUINT32  tupleCount;
854
  public:
855
  DEFINE_SIZE_STATIC (12);
856
};
857
858
struct KerxSubTable
859
{
860
  friend struct kerx;
861
862
0
  unsigned int get_size () const { return u.header.length; }
863
0
  unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
864
865
  template <typename context_t, typename ...Ts>
866
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
867
0
  {
868
0
    unsigned int subtable_type = get_type ();
869
0
    TRACE_DISPATCH (this, subtable_type);
870
0
    switch (subtable_type) {
871
0
    case 0: return_trace (c->dispatch (u.format0, std::forward<Ts> (ds)...));
872
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
873
0
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
874
0
    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
875
0
    case 6: return_trace (c->dispatch (u.format6, std::forward<Ts> (ds)...));
876
0
    default:  return_trace (c->default_return_value ());
877
0
    }
878
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
879
880
  template <typename set_t>
881
  void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
882
0
  {
883
0
    unsigned int subtable_type = get_type ();
884
0
    switch (subtable_type) {
885
0
    case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
886
0
    case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
887
0
    case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
888
0
    case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
889
0
    case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
890
0
    default:  return;
891
0
    }
892
0
  }
893
894
  bool sanitize (hb_sanitize_context_t *c) const
895
0
  {
896
0
    TRACE_SANITIZE (this);
897
0
    if (!(u.header.sanitize (c) &&
898
0
    hb_barrier () &&
899
0
    u.header.length >= u.header.static_size &&
900
0
    c->check_range (this, u.header.length)))
901
0
      return_trace (false);
902
903
0
    return_trace (dispatch (c));
904
0
  }
905
906
  public:
907
  union {
908
  KerxSubTableHeader        header;
909
  KerxSubTableFormat0<KerxSubTableHeader> format0;
910
  KerxSubTableFormat1<KerxSubTableHeader> format1;
911
  KerxSubTableFormat2<KerxSubTableHeader> format2;
912
  KerxSubTableFormat4<KerxSubTableHeader> format4;
913
  KerxSubTableFormat6<KerxSubTableHeader> format6;
914
  } u;
915
  public:
916
  DEFINE_SIZE_MIN (12);
917
};
918
919
920
/*
921
 * The 'kerx' Table
922
 */
923
924
struct kern_subtable_accelerator_data_t
925
{
926
  hb_bit_set_t left_set;
927
  hb_bit_set_t right_set;
928
  mutable hb_aat_class_cache_t class_cache;
929
};
930
931
struct kern_accelerator_data_t
932
{
933
  hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
934
  hb_aat_scratch_t scratch;
935
};
936
937
template <typename T>
938
struct KerxTable
939
{
940
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
941
0
  const T* thiz () const { return static_cast<const T *> (this); }
Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::thiz() const
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::thiz() const
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::thiz() const
942
943
  bool has_state_machine () const
944
0
  {
945
0
    typedef typename T::SubTable SubTable;
946
947
0
    const SubTable *st = &thiz()->firstSubTable;
948
0
    unsigned int count = thiz()->tableCount;
949
0
    for (unsigned int i = 0; i < count; i++)
950
0
    {
951
0
      if (st->get_type () == 1)
952
0
  return true;
953
954
      // TODO: What about format 4? What's this API used for anyway?
955
956
0
      st = &StructAfter<SubTable> (*st);
957
0
    }
958
0
    return false;
959
0
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::has_state_machine() const
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_state_machine() const
960
961
  bool has_cross_stream () const
962
0
  {
963
0
    typedef typename T::SubTable SubTable;
964
965
0
    const SubTable *st = &thiz()->firstSubTable;
966
0
    unsigned int count = thiz()->tableCount;
967
0
    for (unsigned int i = 0; i < count; i++)
968
0
    {
969
0
      if (st->u.header.coverage & st->u.header.CrossStream)
970
0
  return true;
971
0
      st = &StructAfter<SubTable> (*st);
972
0
    }
973
0
    return false;
974
0
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::has_cross_stream() const
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_cross_stream() const
975
976
  int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
977
0
  {
978
0
    typedef typename T::SubTable SubTable;
979
0
980
0
    int v = 0;
981
0
    const SubTable *st = &thiz()->firstSubTable;
982
0
    unsigned int count = thiz()->tableCount;
983
0
    for (unsigned int i = 0; i < count; i++)
984
0
    {
985
0
      if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
986
0
    !st->u.header.is_horizontal ())
987
0
  continue;
988
0
      v += st->get_kerning (left, right);
989
0
      st = &StructAfter<SubTable> (*st);
990
0
    }
991
0
    return v;
992
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
993
994
  bool apply (AAT::hb_aat_apply_context_t *c,
995
        const kern_accelerator_data_t &accel_data) const
996
0
  {
997
0
    c->buffer->unsafe_to_concat ();
998
999
0
    c->setup_buffer_glyph_set ();
1000
1001
0
    typedef typename T::SubTable SubTable;
1002
1003
0
    bool ret = false;
1004
0
    bool seenCrossStream = false;
1005
0
    c->set_lookup_index (0);
1006
0
    const SubTable *st = &thiz()->firstSubTable;
1007
0
    unsigned int count = thiz()->tableCount;
1008
0
    for (unsigned int i = 0; i < count; i++)
1009
0
    {
1010
0
      bool reverse;
1011
1012
0
      auto &subtable_accel = accel_data.subtable_accels[i];
1013
1014
0
      if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
1015
0
  goto skip;
1016
1017
0
      if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
1018
0
  goto skip;
1019
1020
0
      c->left_set = &subtable_accel.left_set;
1021
0
      c->right_set = &subtable_accel.right_set;
1022
0
      c->machine_glyph_set = &subtable_accel.left_set;
1023
0
      c->machine_class_cache = &subtable_accel.class_cache;
1024
1025
0
      if (!c->buffer_intersects_machine ())
1026
0
      {
1027
0
  (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
1028
0
  goto skip;
1029
0
      }
1030
1031
0
      reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
1032
0
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1033
1034
0
      if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
1035
0
  goto skip;
1036
1037
0
      if (!seenCrossStream &&
1038
0
    (st->u.header.coverage & st->u.header.CrossStream))
1039
0
      {
1040
  /* Attach all glyphs into a chain. */
1041
0
  seenCrossStream = true;
1042
0
  hb_glyph_position_t *pos = c->buffer->pos;
1043
0
  unsigned int count = c->buffer->len;
1044
0
  for (unsigned int i = 0; i < count; i++)
1045
0
  {
1046
0
    pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE;
1047
0
    pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
1048
    /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
1049
     * since there needs to be a non-zero attachment for post-positioning to
1050
     * be needed. */
1051
0
  }
1052
0
      }
1053
1054
0
      if (reverse)
1055
0
  c->buffer->reverse ();
1056
1057
0
      {
1058
  /* See comment in sanitize() for conditional here. */
1059
0
  hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
1060
0
  ret |= st->dispatch (c);
1061
0
      }
1062
1063
0
      if (reverse)
1064
0
  c->buffer->reverse ();
1065
1066
0
      (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
1067
1068
0
    skip:
1069
0
      st = &StructAfter<SubTable> (*st);
1070
0
      c->set_lookup_index (c->lookup_index + 1);
1071
0
    }
1072
1073
0
    return ret;
1074
0
  }
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const
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
0
  {
1078
0
    TRACE_SANITIZE (this);
1079
0
    if (unlikely (!(thiz()->version.sanitize (c) &&
1080
0
        hb_barrier () &&
1081
0
        (unsigned) thiz()->version >= (unsigned) T::minVersion &&
1082
0
        thiz()->tableCount.sanitize (c))))
1083
0
      return_trace (false);
1084
1085
0
    typedef typename T::SubTable SubTable;
1086
1087
0
    const SubTable *st = &thiz()->firstSubTable;
1088
0
    unsigned int count = thiz()->tableCount;
1089
0
    for (unsigned int i = 0; i < count; i++)
1090
0
    {
1091
0
      if (unlikely (!st->u.header.sanitize (c)))
1092
0
  return_trace (false);
1093
0
      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
0
      hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr);
1102
1103
0
      if (unlikely (!st->sanitize (c)))
1104
0
  return_trace (false);
1105
1106
0
      st = &StructAfter<SubTable> (*st);
1107
0
    }
1108
1109
0
    unsigned majorVersion = thiz()->version;
1110
0
    if (sizeof (thiz()->version) == 4)
1111
0
      majorVersion = majorVersion >> 16;
1112
0
    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
0
    return_trace (true);
1120
0
  }
Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::sanitize(hb_sanitize_context_t*) const
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
0
  {
1124
0
    kern_accelerator_data_t accel_data;
1125
1126
0
    typedef typename T::SubTable SubTable;
1127
1128
0
    const SubTable *st = &thiz()->firstSubTable;
1129
0
    unsigned int count = thiz()->tableCount;
1130
0
    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.left_set, subtable_accel.right_set, num_glyphs);
1137
0
      subtable_accel.class_cache.clear ();
1138
1139
0
      st = &StructAfter<SubTable> (*st);
1140
0
    }
1141
1142
0
    return accel_data;
1143
0
  }
Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::create_accelerator_data(unsigned int) const
Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::create_accelerator_data(unsigned int) const
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
0
    {
1149
0
      hb_sanitize_context_t sc;
1150
0
      this->table = sc.reference_table<T> (face);
1151
0
      this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
1152
0
    }
1153
    ~accelerator_t ()
1154
0
    {
1155
0
      this->table.destroy ();
1156
0
    }
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
0
  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
0
  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 */